in Tools/TlsClient/TlsClient.cpp [27:198]
int main(int argc, char* argv[])
{
BOOL useChain;
char dir[128], deviceCertChain[128], aliasKey[128], serverCA[128], aliasCert[128];;
if (argc == 1) return Usage();
if (argc > 3)return Usage();
if (strcmp(argv[1], "B") == 0)
{
useChain = FALSE;
}
else
if (strcmp(argv[1], "C")==0)
{
useChain = TRUE;
}
else
return Usage();
if (argc == 3)
{
strcpy(dir, argv[2]);
}
else
{
strcpy(dir, ".");
}
//strcat(dir, "/");
strcpy(aliasKey, dir); strcat(aliasKey, "AliasKey.PEM");
strcpy(deviceCertChain, dir); strcat(deviceCertChain, "DeviceCertChainIncAlias.PEM");
strcpy(serverCA, dir); strcat(serverCA, "ServerCA.PEM");
strcpy(aliasCert, dir); strcat(aliasCert, "AliasCert.PEM");
printf("Attempting to establish a TLS connection on localhost\n");
long res = 1;
int ret = 1;
unsigned long ssl_err = 0;
SSL_CTX* ctx = NULL;
BIO *web = NULL, *out = NULL;
SSL *ssl = NULL;
do {
// for interactive debugging
Sleep(3000);
init_openssl_library();
const SSL_METHOD* method = SSLv23_method();
CheckIsNotNull((void*) method, "SSLv23_method");
ctx = SSL_CTX_new(method);
CheckIsNotNull((void*)ctx, "SSL_CTX_new");
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
SSL_CTX_set_verify_depth(ctx, 10);
/* Remove the most egregious. Because SSLv2 and SSLv3 have been */
/* removed, a TLSv1.0 handshake is used. The client accepts TLSv1.0 */
/* and above. An added benefit of TLS 1.0 and above are TLS */
/* extensions like Server Name Indicatior (SNI). */
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
long old_opts = SSL_CTX_set_options(ctx, flags);
UNUSED(old_opts);
// <PAUL> - the following three setup lines are the only substantive changes to the
// OSSL sample code
res = SSL_CTX_use_PrivateKey_file(ctx, aliasKey, SSL_FILETYPE_PEM);
CheckIsOne(res, "SSL_CTX_use_PrivateKey_file");
if (useChain)
{
res = SSL_CTX_use_certificate_chain_file(ctx, deviceCertChain);
CheckIsOne(res, "SSL_CTX_use_certificate_chain_file");
}
else
{
res = SSL_CTX_use_certificate_chain_file(ctx, aliasCert);
CheckIsOne(res, "SSL_CTX_use_certificate_chain_file");
}
res = SSL_CTX_load_verify_locations(ctx, serverCA, NULL);
CheckIsOne(res, "SSL_CTX_load_verify_locations");
// </PAUL>
web = BIO_new_ssl_connect(ctx);
CheckIsNotNull((void*)web, "BIO_new_ssl_connect");
res = BIO_set_conn_hostname(web, "localhost:5556");
CheckIsOne(res, "BIO_set_conn_hostname");
BIO_get_ssl(web, &ssl);
res = SSL_set_cipher_list(ssl, PREFERRED_CIPHERS);
CheckIsOne(res, "SSL_set_cipher_list");
res = SSL_set_tlsext_host_name(ssl, HOST_NAME);
CheckIsOne(res, "SSL_set_tlsext_host_name");
res = BIO_do_connect(web);
CheckIsOne(res, "BIO_do_connect");
res = BIO_do_handshake(web);
CheckIsOne(res, "BIO_do_handshake");
X509* cert = SSL_get_peer_certificate(ssl);
if (cert) { X509_free(cert); } /* Free immediately */
CheckIsNotNull(cert, "SSL_get_peer_certificate");
/* Error codes: http://www.openssl.org/docs/apps/verify.html */
res = SSL_get_verify_result(ssl);
ASSERT(X509_V_OK == res);
if (!(X509_V_OK == res))
{
/* Hack a code into print_error_string. */
print_error_string((unsigned long)res, "SSL_get_verify_results");
break; /* failed */
}
/* Step 3: hostname verifcation. */
/* An exercise left to the reader. */
/**************************************************************************************/
/**************************************************************************************/
/* Now, we can finally start reading and writing to the BIO... */
/**************************************************************************************/
/**************************************************************************************/
printf("Connection was successful. Terminating");
BIO_puts(web, "GET " HOST_RESOURCE " HTTP/1.1\r\nHost: " HOST_NAME "\r\nConnection: close\r\n\r\n");
BIO_puts(out, "\nFetching: " HOST_RESOURCE "\n\n");
#ifdef USE_CONNECTION
int len = 0;
do {
char buff[1536] = {};
/* https://www.openssl.org/docs/crypto/BIO_read.html */
len = BIO_read(web, buff, sizeof(buff));
if (len > 0)
BIO_write(out, buff, len);
/* BIO_should_retry returns TRUE unless there's an */
/* error. We expect an error when the server */
/* provides the response and closes the connection. */
} while (len > 0 || BIO_should_retry(web));
#endif
ret = 0;
} while (0);
if (out)
BIO_free(out);
if (web != NULL)
BIO_free_all(web);
if (NULL != ctx)
SSL_CTX_free(ctx);
// for interactive debugging
Sleep(3000);
return ret;
}