20 #include <openssl/bio.h>
21 #include <openssl/ssl.h>
22 #include <openssl/err.h>
23 #include <openssl/pem.h>
24 #include <openssl/x509.h>
25 #include <openssl/x509_vfy.h>
26 #include <openssl/sha.h>
27 #include <openssl/md5.h>
29 #include <openssl/opensslv.h>
31 #define openssl_version TW_SSL_VERSION()
33 #define TW_SSL_DEFAULT_CIPHER_STRING "ALL:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ADH:!IDEA:!3DES:!SRP"
43 #define TW_SSL_CTX SSL_CTX
45 #define TW_SSL_SESSION_ID_SIZE sizeof(void *)
46 #define TW_SSL_SESSION_ID(a) SSL_get1_session(a)
47 #define TW_GET_CERT_SIZE ssl_get_config(SSL_MAX_CERT_CFG_OFFSET)
48 #define TW_GET_CA_CERT_SIZE ssl_get_config(SSL_MAX_CA_CERT_CFG_OFFSET)
49 #define TW_HANDSHAKE_SUCCEEDED(a) (a && SSL_get_state(a) == SSL_ST_OK)
50 #define TW_SSL_FREE(a) SSL_free(a)
51 #define TW_SSL_CTX_FREE(a) SSL_CTX_free(a)
52 #define DATA_AVAILABLE(a,b,c) (twSocket_WaitFor(a, b) || (c && SSL_pending(c)))
54 #define TW_FIPS_CAPABLE FALSE
56 #define TW_FIPS_CAPABLE TRUE
65 #define TW_SHA1_CTX SHA_CTX
66 #define TW_SHA1_INIT(a) SHA1_Init(a)
67 #define TW_SHA1_UPDATE(a,b,c) SHA1_Update(a,b,c)
68 #define TW_SHA1_FINAL(a,b) SHA1_Final(a,b)
70 #define TW_MD5_CTX MD5_CTX
71 #define TW_MD5_INIT(a) MD5_Init(a)
72 #define TW_MD5_UPDATE(a,b,c) MD5_Update(a,b,c)
73 #define TW_MD5_FINAL(a,b) MD5_Final(a,b)
78 static char tls_full_version[64] = {0};
79 const char* raw_tls_full_version = SSLeay_version(SSLEAY_VERSION);
81 if(strncmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT,64) != 0){
82 TW_LOG(
TW_WARN,
"TW_SSL_VERSION: Error tls runtime version: %s, does not match compiled version: %s",SSLeay_version(SSLEAY_VERSION),OPENSSL_VERSION_TEXT);
85 memcpy (tls_full_version, raw_tls_full_version, strnlen(raw_tls_full_version, 63));
87 strtok(tls_full_version,
" ");
88 return strtok(NULL,
" ");
93 int32_t ret = SSL_CTX_use_certificate_file(ctx, cert, type);
95 TW_LOG(
TW_ERROR,
"TW_USE_CERT_FILE: Error setting the certificate file.");
108 if (TW_FIPS_CAPABLE == TRUE) {
111 return TW_FIPS_MODE_NOT_SUPPORTED;
120 if (TW_FIPS_CAPABLE == TRUE) {
143 ret = FIPS_mode_set(1);
145 TW_LOG(
TW_ERROR,
"TW_ENABLE_FIPS_MODE: FIPS_mode_set(on) failed: %s.", ERR_error_string(ERR_get_error(), NULL));
146 ret = TW_ENABLE_FIPS_MODE_FAILED;
164 ret = FIPS_mode_set(0);
166 TW_LOG(
TW_ERROR,
"TW_DISABLE_FIPS_MODE: FIPS_mode_set(off) failed: %s.", ERR_error_string(ERR_get_error(), NULL));
167 return TW_DISABLE_FIPS_MODE_FAILED;
195 TW_LOG(
TW_ERROR,
"TW_NEW_SSL_CLIENT: Error creating SSL session. Error: %s", ERR_error_string(ERR_get_error(), NULL));
198 if (session_id) SSL_set_session(ssl, (
SSL_SESSION *)session_id);
199 bio=BIO_new_socket(sock->
sock,BIO_NOCLOSE);
201 TW_LOG(
TW_ERROR,
"TW_NEW_SSL_CLIENT: Error creating SSL BIO. Error: %s.", ERR_error_string(ERR_get_error(), NULL));
206 SSL_set_bio(ssl,bio,bio);
207 res = SSL_connect(ssl);
209 const char * tmp = NULL;
211 TW_LOG(
TW_ERROR,
"TW_NEW_SSL_CLIENT: SSL handshake error. Error: %s.", ERR_error_string(ERR_get_error(), NULL));
213 tmp = SSL_get_cipher_list(ssl,index);
215 TW_LOG(
TW_TRACE,
"TW_NEW_SSL_CLIENT: Ciphers Supported: %s", tmp);
226 static const unsigned char s_server_session_id_context[SSL_MAX_SSL_SESSION_ID_LENGTH] = {0};
239 char *ciphers = NULL;
246 p = SSL_get_cipher_list(ssl, i);
258 TW_LOG(
TW_TRACE,
"Listing all available ciphers: %s", ciphers);
282 unsigned char * p = NULL;
285 if (!ctx || !sock)
return NULL;
288 SSL_CTX_set_ecdh_auto(ctx, 1);
290 ret = SSL_CTX_check_private_key(ctx);
292 TW_LOG(
TW_ERROR,
"TW_NEW_SERVER: Error validating server certificate/key pair. Error: %s", ERR_error_string(ERR_get_error(), NULL));
295 SSL_CTX_set_session_id_context(ctx, s_server_session_id_context,
sizeof(s_server_session_id_context));
298 TW_LOG(
TW_ERROR,
"TW_NEW_SERVER: Error creating SSL session. Error: %s", ERR_error_string(ERR_get_error(), NULL));
301 bio=BIO_new_socket(sock->
sock,BIO_NOCLOSE);
303 TW_LOG(
TW_ERROR,
"TW_NEW_SERVER: Error creating SSL BIO. Error: %s.", ERR_error_string(ERR_get_error(), NULL));
307 SSL_set_bio(ssl,bio,bio);
320 int res = SSL_accept(s);
322 const char * tmp = NULL;
324 TW_LOG(
TW_ERROR,
"TW_SSL_ACCEPT: SSL handshake error. Error: %s.", ERR_error_string(ERR_get_error(), NULL));
326 tmp = SSL_get_cipher_list(s,index);
328 TW_LOG(
TW_TRACE,
" Ciphers Supported: %s", tmp);
352 SSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
353 ret = SSL_CTX_use_PrivateKey_file(ctx, file, type);
356 TW_LOG(
TW_ERROR,
"TW_USE_KEY_FILE: Error setting the key file - %s", ERR_error_string(ERR_get_error(), NULL));
376 ret = SSL_CTX_load_verify_locations(ctx, CAfile, CAPAth);
380 TW_LOG (
TW_ERROR,
"TW_SET_CLIENT_CA_LIST: Loading a certificate authority chain from file into the ctx: %s.", ERR_error_string(ERR_get_error(), NULL));
381 return TW_TLS_ERROR_LOADING_FILE;
398 ret = SSL_CTX_use_certificate_chain_file(ctx, file);
402 TW_LOG (
TW_ERROR,
"TW_USE_CERT_CHAIN_FILE: Error setting the default location for certificate chain: %s.", ERR_error_string(ERR_get_error(), NULL));
403 return TW_TLS_ERROR_LOADING_FILE;
418 const char *cipher_string = NULL;
422 if (SSL_library_init () != 1)
424 TW_LOG (
TW_ERROR,
"TW_NEW_SSL_CTX_FUNC: Error initializing OpenSSL library: %lx.", ERR_get_error ());
427 OpenSSL_add_all_algorithms ();
428 SSL_load_error_strings ();
429 ERR_load_crypto_strings ();
431 ctx = SSL_CTX_new(SSLv23_method());
433 if (ctx) SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
437 cipher_string =
"TLSv1.2+FIPS:kRSA+FIPS:!eNULL:!aNULL";
440 cipher_string = TW_SSL_DEFAULT_CIPHER_STRING;
447 ret = SSL_CTX_set_cipher_list(ctx, cipher_string);
449 TW_LOG(
TW_ERROR,
"TW_NEW_SSL_CTX_FUNC: Setting SSL cipher string Error: %s", ERR_error_string(ERR_get_error(), NULL));
459 TW_LOG(
TW_ERROR,
"TW_NEW_SSL_CTX_FUNC: Error getting valid cipher list: %s", ERR_error_string(ERR_get_error(), NULL));
463 #define TW_NEW_SSL_CTX TW_NEW_SSL_CTX_FUNC()
480 int32_t ret = SSL_ERROR_NONE;
484 if (!ssl || !buf)
return -1;
487 ret = SSL_read(ssl, buf, len);
488 switch (SSL_get_error(ssl,ret)) {
491 case SSL_ERROR_WANT_WRITE:
492 case SSL_ERROR_WANT_READ:
493 case SSL_ERROR_WANT_X509_LOOKUP:
495 TW_LOG(
TW_INFO,
"TW_SSL_READ: Read BLOCK on try %d. Error: %s", retries, ERR_error_string(ret, NULL));
499 case SSL_ERROR_SYSCALL:
501 TW_LOG(
TW_ERROR,
"TW_SSL_READ: Error reading from SSL stream");
503 case SSL_ERROR_ZERO_RETURN:
504 TW_LOG(
TW_TRACE,
"TW_SSL_READ: Read 0 bytes");
512 TW_LOG(
TW_ERROR,
"TW_SSL_READ: Timed out or error waiting reading from socket. Error: %s", ERR_error_string(ret, NULL));
513 return TW_TIMEOUT_READING_FROM_SOCKET;
537 TW_SOCKET_TYPE sslSocket;
540 while (retries < 3) {
541 bio = SSL_get_wbio(ssl);
542 BIO_get_fd(bio, &sslSocket);
544 FD_ZERO(&sslSocketFd);
545 FD_SET(sslSocket, &sslSocketFd);
548 socketReady = select(FD_SETSIZE, 0, &sslSocketFd, 0, 0);
552 result = SSL_write(ssl, buf, len);
554 switch (SSL_get_error(ssl,result)) {
557 case SSL_ERROR_WANT_WRITE:
558 case SSL_ERROR_WANT_READ:
559 case SSL_ERROR_WANT_X509_LOOKUP:
562 TW_LOG(
TW_ERROR,
"TW_SSL_WRITE: Write BLOCK. Retry %d in 5 msec", retries);
565 case SSL_ERROR_SYSCALL:
567 TW_LOG(
TW_ERROR,
"TW_SSL_WRITE: Write failed. Error: %s", ERR_error_string(result, NULL));
569 case SSL_ERROR_ZERO_RETURN:
570 TW_LOG(
TW_WARN,
"TW_SSL_WRITE: Zero bytes written.");
577 result = SSL_ERROR_SSL;
580 TW_LOG(
TW_ERROR,
"TW_SSL_WRITE Error: Socket not ready: %d", socketReady);
584 TW_LOG(
TW_ERROR,
"TW_SSL_WRITE Error occurred reading socket state: %d", socketReady);
602 int32_t res = SSL_get_verify_result(ssl);
603 if( res != X509_V_OK && !(selfSignedOk && (res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))) {
604 TW_LOG(
TW_ERROR,
"TW_VALIDATE_CERT: Certificate rejected. Code: %d, Reason = %s",res, X509_verify_cert_error_string(res));
605 return TW_INVALID_SSL_CERT;
629 if (!ssl)
return NULL;
630 cert = SSL_get_peer_certificate(ssl);
631 if (!cert)
return NULL;
634 nid = OBJ_txt2nid(
"CN");
635 name = X509_get_subject_name(cert);
636 X509_NAME_get_text_by_NID(name, nid, tmp, 255);
639 nid = OBJ_txt2nid(
"O");
640 name = X509_get_subject_name(cert);
641 X509_NAME_get_text_by_NID(name, nid, tmp, 255);
644 nid = OBJ_txt2nid(
"OU");
645 name = X509_get_subject_name(cert);
646 X509_NAME_get_text_by_NID(name, nid, tmp, 255);
649 nid = OBJ_txt2nid(
"CN");
650 name = X509_get_issuer_name(cert);
651 X509_NAME_get_text_by_NID(name, nid, tmp, 255);
654 nid = OBJ_txt2nid(
"O");
655 name = X509_get_issuer_name(cert);
656 X509_NAME_get_text_by_NID(name, nid, tmp, 255);
659 nid = OBJ_txt2nid(
"OU");
660 name = X509_get_issuer_name(cert);
661 X509_NAME_get_text_by_NID(name, nid, tmp, 255);
static INLINE TW_SSL * TW_NEW_SSL_CLIENT(TW_SSL_CTX *ctx, twSocket *sock, void *session_id, int session_size)
Creates a new TW_SSL structure for connection with the specified settings (see SSL_new(), SSL_connect()).
Definition: twOpenSSL.h:189
char twTimeGreaterThan(DATETIME t1, DATETIME t2)
Compares two DATETIME variables to see if one is greater.
Definition: twIos.c:34
DATETIME twGetSystemTime(char utc)
Gets the current system time.
Definition: twIos.c:46
TW_SOCKET_TYPE sock
Definition: twOSPort.h:175
#define TW_USE_CERT_FILE(a, b, c)
Calls a function to load the first certificate stored in a file into the TW_SSL_CTX structure...
Definition: twTemplateSSL.h:57
Definition: twDefinitions.h:213
static INLINE int TW_SSL_READ(TW_SSL *ssl, char *buf, int len, int32_t timeout)
Reads len bytes of data from ssl into buf (see SSL_read()).
Definition: twOpenSSL.h:479
String utility function prototypes.
int concatenateStrings(char **dest, const char *src)
concatenates strings.
Definition: stringUtils.c:96
Definition: twDefinitions.h:210
static INLINE char * TW_GET_X509_FIELD(TW_SSL *ssl, char field)
Gets an X509 field of ssl.
Definition: twOpenSSL.h:623
char twTimeLessThan(DATETIME t1, DATETIME t2)
Compares two DATETIME variables to see if one is smaller.
Definition: twIos.c:38
twSocket base type definition.
Definition: twOSPort.h:174
static INLINE int TW_IS_FIPS_MODE_ENABLED()
Queries the TLS backend to determine if FIPS mode is enabled.
Definition: twOpenSSL.h:119
Wrappers for OS-specific functionality.
#define TW_SSL
The base SSL structure for your SSL library.
Definition: twTemplateSSL.h:21
#define TW_SSL_FREE(a)
Calls a function to free the TW_SSL structure.
Definition: twTemplateSSL.h:27
#define TW_SSL_CTX
The SSL context structure for your SSL library.
Definition: twTemplateSSL.h:38
static INLINE TW_SSL * TW_NEW_SERVER(TW_SSL_CTX *ctx, twSocket *sock)
Creates a new TW_SSL connection structure (see SSL_new()).
Definition: twOpenSSL.h:277
static INLINE int TW_ENABLE_FIPS_MODE()
Enables FIPS mode for the entire application.
Definition: twOpenSSL.h:139
static INLINE int TW_SSL_ACCEPT(TW_SSL *s)
Waits for a TW_SSL client to initiate a handshake with the server. Wrapper function for SSL_accept()...
Definition: twOpenSSL.h:319
static INLINE int TW_SSL_LIST_CIPHERS(TW_SSL_CTX *ctx)
Logs a list of all available ciphers for the ctx to the logs.
Definition: twOpenSSL.h:237
#define TW_SSL_VERSION()
Output ssl library version.
Definition: twTemplateSSL.h:133
char initialize_encryption_library
Definition: twDefaultSettings.h:224
#define TW_SSL_CTX_FREE(a)
Calls a function to free a TW_SSL_CTX structure.
Definition: twTemplateSSL.h:48
Default settings for ThingWorx C SDK.
static INLINE int TW_VALIDATE_CERT(TW_SSL *ssl, char selfSignedOk)
Validates the certificate of ssl.
Definition: twOpenSSL.h:601
static INLINE SSL_CTX * TW_NEW_SSL_CTX_FUNC()
Create a new #SSL_CTX stucture as framework for TLS/SSL enabled functions. Wrapper function for SSL_C...
Definition: twOpenSSL.h:417
uint32_t default_message_timeout
Definition: twDefaultSettings.h:200
static INLINE int TW_DISABLE_FIPS_MODE()
Disable FIPS mode for the entire application.
Definition: twOpenSSL.h:161
const char * cipher_set
Definition: twDefaultSettings.h:225
Definition: twDefinitions.h:212
static INLINE int TW_USE_CERT_CHAIN_FILE(SSL_CTX *ctx, const char *file, int type)
loads a certificate chain from file into ctx. The certificates must be in PEM format. Wrapper function for SSL_CTX_use_certificate_chain_file().
Definition: twOpenSSL.h:396
static INLINE int TW_SET_CLIENT_CA_LIST(SSL_CTX *ctx, const char *CAfile, const char *CAPAth)
sets the default location for trusted CA certs. Wrapper function for SSL_CTX_load_verify_locations()...
Definition: twOpenSSL.h:374
DATETIME twAddMilliseconds(DATETIME t1, int32_t msec)
Adds milliseconds to a DATETIME.
Definition: twIos.c:42
static INLINE int TW_USE_KEY_FILE(SSL_CTX *ctx, const char *file, int type, char *passwd)
Loads the certificate authority cert chain used to validate the server's certificate in file into ctx...
Definition: twOpenSSL.h:350
static INLINE int TW_SSL_WRITE(TW_SSL *ssl, char *buf, int len)
Writes len bytes of data in buf to ssl.
Definition: twOpenSSL.h:531
Structure definitions and function prototypes for the ThingWorx logging facility. ...
char * duplicateString(const char *input)
Copies a string.
Definition: stringUtils.c:50
static INLINE int TW_IS_FIPS_COMPATIBLE()
Queries the TLS backend to determine whether it is FIPS compatible.
Definition: twOpenSSL.h:107
Definition: twDefinitions.h:214
Definition: gzappend.c:170