单向认证时,使用上一篇文章openssl 内存加载CA证书说到的方法可以正常连接上MQTT服务器,但是改成双向认证时,由于还有两个证书需要加载,所以还需要修改库源码才行。其实查看openssl库的源码可以发现,加载文件的接口,实际上就是先从文件中读取到证书内容,然后再配置给相应结构体。 我们要做的工作就是找到源码接口,然后把从文件读取替换成从内存读取。
SSL_CTX_use_PrivateKey_file和SSL_CTX_use_certificate_chain_file接口在ssl_rsa.c文件中
SSL_CTX_load_verify_locations接口跟踪到最后的实现在by_file.c中
直接贴出修改后的源文件,主要还是修改SSLSocket_createContext接口,将加载证书文件的地方修改成加载内存。
#if defined(OPENSSL) #include "SocketBuffer.h" #include "MQTTClient.h" #include "MQTTProtocolOut.h" #include "SSLSocket.h" #include "Log.h" #include "StackTrace.h" #include "Socket.h" #include "Heap.h" #include#include #include #include #include extern Sockets mod_s; static int SSLSocket_error(char* aString, SSL* ssl, int sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u); char* SSL_get_verify_result_string(int rc); void SSL_CTX_info_callback(const SSL* ssl, int where, int ret); char* SSLSocket_get_version_string(int version); void SSL_CTX_msg_callback( int write_p, int version, int content_type, const void* buf, size_t len, SSL* ssl, void* arg); int pem_passwd_cb(char* buf, int size, int rwflag, void* userdata); int SSL_create_mutex(ssl_mutex_type* mutex); int SSL_lock_mutex(ssl_mutex_type* mutex); int SSL_unlock_mutex(ssl_mutex_type* mutex); int SSL_destroy_mutex(ssl_mutex_type* mutex); #if (OPENSSL_VERSION_NUMBER >= 0x010000000) extern void SSLThread_id(CRYPTO_THREADID *id); #else extern unsigned long SSLThread_id(void); #endif extern void SSLLocks_callback(int mode, int n, const char *file, int line); int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts); void SSLSocket_destroyContext(networkHandles* net); void SSLSocket_addPendingRead(int sock); static int handle_openssl_init = 1; static ssl_mutex_type* sslLocks = NULL; static ssl_mutex_type sslCoreMutex; static int tls_ex_index_ssl_opts; #if defined(_WIN32) || defined(_WIN64) #define iov_len len #define iov_base buf #define snprintf _snprintf #endif static int SSLSocket_error(char* aString, SSL* ssl, int sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u) { int error; FUNC_ENTRY; if (ssl) error = SSL_get_error(ssl, rc); else error = ERR_get_error(); if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) { Log(TRACE_MIN, -1, "SSLSocket error WANT_READ/WANT_WRITE"); } else { static char buf[120]; if (strcmp(aString, "shutdown") != 0) Log(TRACE_MIN, -1, "SSLSocket error %s(%d) in %s for socket %d rc %d errno %d %sn", buf, error, aString, sock, rc, errno, strerror(errno)); if (cb) ERR_print_errors_cb(cb, u); if (error == SSL_ERROR_SSL || error == SSL_ERROR_SYSCALL) error = SSL_FATAL; } FUNC_EXIT_RC(error); return error; } static struct { int code; char* string; } X509_message_table[] = { { X509_V_OK, "X509_V_OK" }, { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT" }, { X509_V_ERR_UNABLE_TO_GET_CRL, "X509_V_ERR_UNABLE_TO_GET_CRL" }, { X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE" }, { X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE" }, { X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY" }, { X509_V_ERR_CERT_SIGNATURE_FAILURE, "X509_V_ERR_CERT_SIGNATURE_FAILURE" }, { X509_V_ERR_CRL_SIGNATURE_FAILURE, "X509_V_ERR_CRL_SIGNATURE_FAILURE" }, { X509_V_ERR_CERT_NOT_YET_VALID, "X509_V_ERR_CERT_NOT_YET_VALID" }, { X509_V_ERR_CERT_HAS_EXPIRED, "X509_V_ERR_CERT_HAS_EXPIRED" }, { X509_V_ERR_CRL_NOT_YET_VALID, "X509_V_ERR_CRL_NOT_YET_VALID" }, { X509_V_ERR_CRL_HAS_EXPIRED, "X509_V_ERR_CRL_HAS_EXPIRED" }, { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD" }, { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD" }, { X509_V_ERR_ERROR_IN_CRL_LAST_UPDATe_FIELD, "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD" }, { X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD" }, { X509_V_ERR_OUT_OF_MEM, "X509_V_ERR_OUT_OF_MEM" }, { X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT" }, { X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN" }, { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY" }, { X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE" }, { X509_V_ERR_CERT_CHAIN_TOO_LONG, "X509_V_ERR_CERT_CHAIN_TOO_LONG" }, { X509_V_ERR_CERT_REVOKED, "X509_V_ERR_CERT_REVOKED" }, { X509_V_ERR_INVALID_CA, "X509_V_ERR_INVALID_CA" }, { X509_V_ERR_PATH_LENGTH_EXCEEDED, "X509_V_ERR_PATH_LENGTH_EXCEEDED" }, { X509_V_ERR_INVALID_PURPOSE, "X509_V_ERR_INVALID_PURPOSE" }, { X509_V_ERR_CERT_UNTRUSTED, "X509_V_ERR_CERT_UNTRUSTED" }, { X509_V_ERR_CERT_REJECTED, "X509_V_ERR_CERT_REJECTED" }, { X509_V_ERR_SUBJECT_ISSUER_MISMATCH, "X509_V_ERR_SUBJECT_ISSUER_MISMATCH" }, { X509_V_ERR_AKID_SKID_MISMATCH, "X509_V_ERR_AKID_SKID_MISMATCH" }, { X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH" }, { X509_V_ERR_KEYUSAGE_NO_CERTSIGN, "X509_V_ERR_KEYUSAGE_NO_CERTSIGN" }, { X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER" }, { X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION" }, { X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN" }, { X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION" }, { X509_V_ERR_INVALID_NON_CA, "X509_V_ERR_INVALID_NON_CA" }, { X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED" }, { X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE" }, { X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED" }, { X509_V_ERR_INVALID_EXTENSION, "X509_V_ERR_INVALID_EXTENSION" }, { X509_V_ERR_INVALID_POLICY_EXTENSION, "X509_V_ERR_INVALID_POLICY_EXTENSION" }, { X509_V_ERR_NO_EXPLICIT_POLICY, "X509_V_ERR_NO_EXPLICIT_POLICY" }, { X509_V_ERR_UNNESTED_RESOURCE, "X509_V_ERR_UNNESTED_RESOURCE" }, #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE) { X509_V_ERR_DIFFERENT_CRL_SCOPE, "X509_V_ERR_DIFFERENT_CRL_SCOPE" }, { X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE" }, { X509_V_ERR_PERMITTED_VIOLATION, "X509_V_ERR_PERMITTED_VIOLATION" }, { X509_V_ERR_EXCLUDED_VIOLATION, "X509_V_ERR_EXCLUDED_VIOLATION" }, { X509_V_ERR_SUBTREE_MINMAX, "X509_V_ERR_SUBTREE_MINMAX" }, { X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE" }, { X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX" }, { X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX" }, #endif }; #if !defined(ARRAY_SIZE) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #endif char* SSL_get_verify_result_string(int rc) { int i; char* retstring = "undef"; for (i = 0; i < ARRAY_SIZE(X509_message_table); ++i) { if (X509_message_table[i].code == rc) { retstring = X509_message_table[i].string; break; } } return retstring; } void SSL_CTX_info_callback(const SSL* ssl, int where, int ret) { if (where & SSL_CB_LOOP) { Log(TRACE_PROTOCOL, 1, "SSL state %s:%s:%s", (where & SSL_ST_CONNECT) ? "connect" : (where & SSL_ST_ACCEPT) ? "accept" : "undef", SSL_state_string_long(ssl), SSL_get_cipher_name(ssl)); } else if (where & SSL_CB_EXIT) { Log(TRACE_PROTOCOL, 1, "SSL %s:%s", (where & SSL_ST_CONNECT) ? "connect" : (where & SSL_ST_ACCEPT) ? "accept" : "undef", SSL_state_string_long(ssl)); } else if (where & SSL_CB_alert) { Log(TRACE_PROTOCOL, 1, "SSL alert %s:%s:%s", (where & SSL_CB_READ) ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_HANDSHAKE_START) { Log(TRACE_PROTOCOL, 1, "SSL handshake started %s:%s:%s", (where & SSL_CB_READ) ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_HANDSHAKE_DONE) { Log(TRACE_PROTOCOL, 1, "SSL handshake done %s:%s:%s", (where & SSL_CB_READ) ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); Log(TRACE_PROTOCOL, 1, "SSL certificate verification: %s", SSL_get_verify_result_string(SSL_get_verify_result(ssl))); } else { Log(TRACE_PROTOCOL, 1, "SSL state %s:%s:%s", SSL_state_string_long(ssl), SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } } char* SSLSocket_get_version_string(int version) { int i; static char buf[20]; char* retstring = NULL; static struct { int code; char* string; } version_string_table[] = { { SSL2_VERSION, "SSL 2.0" }, { SSL3_VERSION, "SSL 3.0" }, { TLS1_VERSION, "TLS 1.0" }, #if defined(TLS2_VERSION) { TLS2_VERSION, "TLS 1.1" }, #endif #if defined(TLS3_VERSION) { TLS3_VERSION, "TLS 1.2" }, #endif }; for (i = 0; i < ARRAY_SIZE(version_string_table); ++i) { if (version_string_table[i].code == version) { retstring = version_string_table[i].string; break; } } if (retstring == NULL) { if (snprintf(buf, sizeof(buf), "%i", version) >= sizeof(buf)) buf[sizeof(buf)-1] = ' '; retstring = buf; } return retstring; } void SSL_CTX_msg_callback(int write_p, int version, int content_type, const void* buf, size_t len, SSL* ssl, void* arg) { Log(TRACE_MINIMUM, -1, "%s %s %d buflen %d", (write_p ? "sent" : "received"), SSLSocket_get_version_string(version), content_type, (int)len); } int pem_passwd_cb(char* buf, int size, int rwflag, void* userdata) { int rc = 0; FUNC_ENTRY; if (!rwflag) { strncpy(buf, (char*)(userdata), size); buf[size-1] = ' '; rc = (int)strlen(buf); } FUNC_EXIT_RC(rc); return rc; } int SSL_create_mutex(ssl_mutex_type* mutex) { int rc = 0; FUNC_ENTRY; #if defined(_WIN32) || defined(_WIN64) *mutex = CreateMutex(NULL, 0, NULL); #else rc = pthread_mutex_init(mutex, NULL); #endif FUNC_EXIT_RC(rc); return rc; } int SSL_lock_mutex(ssl_mutex_type* mutex) { int rc = -1; #if defined(_WIN32) || defined(_WIN64) if (WaitForSingleObject(*mutex, INFINITE) != WAIT_FAILED) #else if ((rc = pthread_mutex_lock(mutex)) == 0) #endif rc = 0; return rc; } int SSL_unlock_mutex(ssl_mutex_type* mutex) { int rc = -1; #if defined(_WIN32) || defined(_WIN64) if (ReleaseMutex(*mutex) != 0) #else if ((rc = pthread_mutex_unlock(mutex)) == 0) #endif rc = 0; return rc; } int SSL_destroy_mutex(ssl_mutex_type* mutex) { int rc = 0; FUNC_ENTRY; #if defined(_WIN32) || defined(_WIN64) rc = CloseHandle(*mutex); #else rc = pthread_mutex_destroy(mutex); #endif FUNC_EXIT_RC(rc); return rc; } #if (OPENSSL_VERSION_NUMBER >= 0x010000000) extern void SSLThread_id(CRYPTO_THREADID *id) { #if defined(_WIN32) || defined(_WIN64) CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId()); #else CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self()); #endif } #else extern unsigned long SSLThread_id(void) { #if defined(_WIN32) || defined(_WIN64) return (unsigned long)GetCurrentThreadId(); #else return (unsigned long)pthread_self(); #endif } #endif extern void SSLLocks_callback(int mode, int n, const char *file, int line) { if (sslLocks) { if (mode & CRYPTO_LOCK) SSL_lock_mutex(&sslLocks[n]); else SSL_unlock_mutex(&sslLocks[n]); } } void SSLSocket_handleOpensslInit(int bool_value) { handle_openssl_init = bool_value; } int SSLSocket_initialize(void) { int rc = 0; int i; int lockMemSize; FUNC_ENTRY; if (handle_openssl_init) { if ((rc = SSL_library_init()) != 1) rc = -1; ERR_load_crypto_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); lockMemSize = CRYPTO_num_locks() * sizeof(ssl_mutex_type); sslLocks = malloc(lockMemSize); if (!sslLocks) { rc = -1; goto exit; } else memset(sslLocks, 0, lockMemSize); for (i = 0; i < CRYPTO_num_locks(); i++) { SSL_create_mutex(&sslLocks[i]); } #if (OPENSSL_VERSION_NUMBER >= 0x010000000) CRYPTO_THREADID_set_callback(SSLThread_id); #else CRYPTO_set_id_callback(SSLThread_id); #endif CRYPTO_set_locking_callback(SSLLocks_callback); } SSL_create_mutex(&sslCoreMutex); tls_ex_index_ssl_opts = SSL_get_ex_new_index(0, "paho ssl options", NULL, NULL, NULL); exit: FUNC_EXIT_RC(rc); return rc; } void SSLSocket_terminate(void) { FUNC_ENTRY; if (handle_openssl_init) { CRYPTO_set_locking_callback(NULL); ERR_free_strings(); EVP_cleanup(); if (sslLocks) { int i = 0; for (i = 0; i < CRYPTO_num_locks(); i++) { SSL_destroy_mutex(&sslLocks[i]); } free(sslLocks); } } SSL_destroy_mutex(&sslCoreMutex); FUNC_EXIT; } static unsigned int call_ssl_psk_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { int rc = 0; FUNC_ENTRY; { SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); MQTTClient_SSLOptions* opts = SSL_CTX_get_ex_data(ctx, tls_ex_index_ssl_opts); if (opts == NULL) goto exit; if (opts->ssl_psk_cb != NULL) rc = opts->ssl_psk_cb(hint, identity, max_identity_len, psk, max_psk_len, opts->ssl_psk_context); } exit: FUNC_EXIT_RC(rc); return rc; } char *prikey="-----BEGIN RSA PRIVATE KEY-----n MIIEpAIBAAKCAQEA4hX5HGlQbIq1sekgcGN4denOY9BOcfThKbZhjlUP7pepNgtun n6XMbyNrU3bwWsI7IVrffTWBckAXSfmh3U98vCFT56+jzaFVny2/cd2JBI5ZA1MZn RIY5XqGTZMHUoPsDi75G24G6KNbT5uKujXOBhnlDLOVstgRXL8N8ZIZZceHPUiuPn LZBA7AXyVmh98F6vsH1LLk4sFS6oU+Uab4WHjloe0j/eDK/mnX5Xk6SqA7MwaAGmn Pt7SbPMg/5uyqftfPJgg1BNnAQvQ1pX0BnVhjqZbgPOE1ym+ffUpsGNF1oJST5Hln hOceq9TtpfA+d73ZJ6+xqjI268ysCsaM5fEhwwIDAQABAoIBAFqu85eoymBvFsgAn uUk7LMMm/+jbUcu1rGbdx62eguBxpqaN2VZh22ksrMzypR/SToNnfsMrJfvcpzq9n zWYGjwKq34vL0IkXUE+juumCMYZJynzd5QGuUO6bIpLEiHP1mwt/S86Z70CYQrCWn des4zFhS5VXpxDwR66K153wuw0vAdPsnn4TGJCIwif09Em8WkrqThHKa08J0t96Kn ruE/wdsTWVIvn4Rjjac1lilX/hv7AuPN+BCttILcT53bYJi7DpvgMBFQb7f+2ugun 7wZtDyAo+kfHVPy7FL2EdFy552ttcMvuLJWBgM946l90pdYl0wptZgYP1k+Mw9kfn gfqLjGkCgYEA/MuiM+AIEjf/HK2V15HE2QPa3p9Y7W/7J5LNbg9XxY1VQG4Va3Zvn jCKjRqQIXanuG5MMsIuC53GCdLhR7r+Qj8xYbV2dTVNUlMcQyc+4jxwMRg/EGgLPn ojhmDNZ45y4ZJP2ISjJ0NaDrPdvYdLqUD/n9BDIgCMX0yPXsDJKuWsUCgYEA5POpn eliHvEBYK4v8VQ7/QjoCE66qFAa1rSZ3a3BjLF8GNXMa/sjS0ofVw8R++wECtXaIn QhgUFW/tB+rlyKrHS4TyCSrxYbEUaj2u1aZLBUCI0pQzD9S2L1CP0yW39ghCkiGin /sk6+mgpwkATWnyC+HoI9SuVwW50N8Aaso6D8ucCgYEAufq6V33Pkk++EQQoGKy6n bIoogLYsv2ouFTwshHcnNMC44pDak1fr0uY8xyCwwu/crE6v/EZ3RPy+ZE6igIpQn uWo1+CfyLUxMIrSdRkva1PZmlTjOJfDBfvANLA6xnirM9ujLVwLtefLsfnL6ZXKun sV5SZb7W0H2KjDpYshtLyJ0CgYA2a9zLIiQRkVHj+ABgz5HJUjSQLSJsZDPnFo+on UCyirWuyZMvz6BSEypj7UcfFLjZQn/4/h62ucs5q5WD9U+rPfqhxmW2LBSaPIl5en loqakv5y35tLlgpAMOwfCoYxy0DXr3spCPgl8YCLleODzLjtC0T50gRk2DZz0gwGn iW2/3QKBgQDgXbsRZWu4/Fy0Ev/RZxHov/wkeDsHZVxbuLOXaSuPM9Xz8umn2brfn muWAAaKt+hdxhIonJpEMGvkAak1ZSR1T+CW9vOotcla6V8oZ/u/kMTdKT5XTWbtvn 5zqShbujNYAiJBvIPb6ZE1A/uvMGAlSFZT2IaUpTaFrwCggyTjZuXw==n -----END RSA PRIVATE KEY-----n"; char *cacrt="-----BEGIN CERTIFICATE-----n MIIDmzCCAoOgAwIBAgIJAPDSM1KhTBCVMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNVn BAYTAm1nMRAwDgYDVQQIDAdtb29yZ2VuMQ0wCwYDVQQHDAR0ZXN0MRAwDgYDVQQKn DAdtb29yZ2VuMRAwDgYDVQQLDAdtb29yZ2VuMRAwDgYDVQQDDAdtb29yZ2VuMB4Xn DTIxMDkyOTA1MjU0OFoXDTMxMDkyNzA1MjU0OFowZDELMAkGA1UEBhMCbWcxEDAOn BgNVBAgMB21vb3JnZW4xDTALBgNVBAcMBHRlc3QxEDAOBgNVBAoMB21vb3JnZW4xn EDAOBgNVBAsMB21vb3JnZW4xEDAOBgNVBAMMB21vb3JnZW4wggEiMA0GCSqGSIb3n DQEBAQUAA4IBDwAwggEKAoIBAQDZPtIfZMYm4zecCugaW2UyzwR29Eydm4cUVQw2n Mv3r3PR082eWKEVJuE8imq4pBX8iVFQPxz+0R2fSzc7sMlWYhWazgWX7r9uYFO8yn HHjIjnE/U+uECw3Nk3O8OKYCEJ98ox8RkswjJ4cDP/Cboi1/kx7UykUXbvkxttqcn Th0uBHf7BjQ7KH8ezlI4qJafBhJzNS7ae+YfdwSAFv3zh97eurL4DZjCj+uUGcQfn ZOmRKvEeWazcxLH7mBeErF6r+lnGPjYRS8PbQ9zqiwszXAdTBzHpD6G3mSBsT3ZIn CTARrlSjL17aj4FcH7NlHQmH6jE+lf0m3ktzXo2y+V0aeX+zAgMBAAGjUDBOMB0Gn A1UdDgQWBBTmqUNbzJumi92sMLzQBXVie0+APTAfBgNVHSMEGDAWgBTmqUNbzJumn i92sMLzQBXVie0+APTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDCn 6UBadJxukIsSQMKCA5J2SOGzQp28IkVOmD+xoKp7ewp8GW6m4GVZg1Jnoi1FfC3Rn MCjVFgXHsDY8rAAhlIt9aMSeElquN/9R/y7WzYzRQflf6Pz8RcPDIepz113DFCXkn jmIXedBWHJBkN6WuK5UMcMhUYfTqy/jbD3ZsbfF//zNsJrLOhHOVOn+oXkDZVbWXn P5E5LI7B+cYMNRHusqyWPX1J78dgM+xikKZere7iY0Y38muOiPlcLmEty4uYgB4Mn xrqau3x80HvzhBzmdXfmAIpLLwQpCeUe805EAfewYPUDstwyOy00THTzZdAqFw8vn /gQNfYEUcxYWky4bgFwQn -----END CERTIFICATE-----n"; char *clentcrt="-----BEGIN CERTIFICATE-----n MIIDOjCCAiICCQC1a0mwFdos4zANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJtn ZzEQMA4GA1UECAwHbW9vcmdlbjENMAsGA1UEBwwEdGVzdDEQMA4GA1UECgwHbW9vn cmdlbjEQMA4GA1UECwwHbW9vcmdlbjEQMA4GA1UEAwwHbW9vcmdlbjAeFw0yMTA5n MjkwNjE1MDRaFw0zMTA5MjcwNjE1MDRaMFoxCzAJBgNVBAYTAm1nMQswCQYDVQQIn DAJtZzELMAkGA1UEBwwCbWcxCzAJBgNwBAoMAm1nMQswCQYDVQQLDAJtZzEXMBUGn A1UEAwwOMTkyLjE2OC4zMS4xOTUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKn AoIBAQDiFfkcaVBsirWx6SBwY3h16c5f0E5x9OEptmGOVQ/ul6k2C26fpcxvI2tTn dvBawjshWt99NYFyQBdJ+aHdT3y8IVPnr6PNoVWfLb9x3YkEjlkDUxlEhjleoZNkn wdSg+wOLvkbbgboo1tPm4q6Nc4GGeUMd5Wy2BFcvw3xkhllx4c9SK48tkEDsBfJWn aH3wXq+wfUsuTiwVLqhT5RpvhYeOWh7SP94Mr+adfleTpKoDszBoAaY+3tJs8yD/n m7Kp+188mCDUE2cBC9DWlfQGdWGOpluq84TXKb599SmwY0XWglJPkeWE5x6r1O2ln 8D53vdknr7GqMjbrzKwKxozl8SHDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHtKn b89PQ96tpy0tl+QZwJkc/fG7yRp25aSFC4LBILrrEnZaqCazHK1qVo8jyBQNIdlAn Ek1DlEEVIKsyCCDBBvn2Ygwv+gE1GhC1TmHQbTSEA75cWCrPocnSuPBO3nMMfMJin zkijYKFsUiN2/y1SCoaLXsv5RnJBk4TmqMHJDFwpOQYD9V3XdOYReD2zNYvtE5hwn riHXynZHV3fNX98d0i2ocfectPiVFZt1nax9g7N02ooUzhp5aP92ESZEG7rZmFLUn cjijvjUhz9XpbowL3OKKCtlCK1yD3dwZNZSw3SUSJwfn8Ys/it7lA3cFaIIYM2CAn xB4OFykkA2zK5ZMVock=n -----END CERTIFICATE-----n"; int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, const char *file) { BIO *in; int ret = 0; X509 *x = NULL; ERR_clear_error(); in = BIO_new_mem_buf(clentcrt, strlen(clentcrt)); if (in == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); goto end; } x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } ret = SSL_CTX_use_certificate(ctx, x); if (ERR_peek_error() != 0) ret = 0; if (ret) { X509 *ca; int r; unsigned long err; SSL_CTX_clear_chain_certs(ctx); while ((ca = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata)) != NULL) { r = SSL_CTX_add0_chain_cert(ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } } err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) ERR_clear_error(); else ret = 0; } end: if (x != NULL) X509_free(x); if (in != NULL) BIO_free(in); return (ret); } int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts) { int rc = 1; FUNC_ENTRY; if (net->ctx == NULL) { #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) net->ctx = SSL_CTX_new(TLS_client_method()); #else int sslVersion = MQTT_SSL_VERSION_DEFAULT; if (opts->struct_version >= 1) sslVersion = opts->sslVersion; switch (sslVersion) { case MQTT_SSL_VERSION_DEFAULT: net->ctx = SSL_CTX_new(SSLv23_client_method()); break; #if defined(SSL_OP_NO_TLSv1) && !defined(OPENSSL_NO_TLS1) case MQTT_SSL_VERSION_TLS_1_0: net->ctx = SSL_CTX_new(TLSv1_client_method()); break; #endif #if defined(SSL_OP_NO_TLSv1_1) && !defined(OPENSSL_NO_TLS1) case MQTT_SSL_VERSION_TLS_1_1: net->ctx = SSL_CTX_new(TLSv1_1_client_method()); break; #endif #if defined(SSL_OP_NO_TLSv1_2) && !defined(OPENSSL_NO_TLS1) case MQTT_SSL_VERSION_TLS_1_2: net->ctx = SSL_CTX_new(TLSv1_2_client_method()); break; #endif default: break; } #endif if (net->ctx == NULL) { if (opts->struct_version >= 3) SSLSocket_error("SSL_CTX_new", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_CTX_new", NULL, net->socket, rc, NULL, NULL); goto exit; } } if (opts->keyStore) { if ((rc = SSL_CTX_use_certificate_chain_file(net->ctx, opts->keyStore)) != 1) // if ((rc = SSL_CTX_use_certificate_chain(net->ctx, opts->keyStore)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_CTX_use_certificate_chain_file", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_CTX_use_certificate_chain_file", NULL, net->socket, rc, NULL, NULL); goto free_ctx; } if (opts->privateKey == NULL) opts->privateKey = opts->keyStore; if (opts->privateKeyPassword != NULL) { SSL_CTX_set_default_passwd_cb(net->ctx, pem_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(net->ctx, (void*)opts->privateKeyPassword); } BIO * cbio = BIO_new_mem_buf(prikey, strlen(prikey)); EVP_PKEY *pkey = NULL; pkey = PEM_read_bio_PrivateKey(cbio, NULL, pem_passwd_cb, (void*)opts->privateKeyPassword); SSL_CTX_use_PrivateKey(net->ctx, pkey); EVP_PKEY_free(pkey); BIO_free(cbio); // rc = SSL_CTX_use_PrivateKey_file(net->ctx, opts->privateKey, SSL_FILETYPE_PEM); // if (opts->privateKey == opts->keyStore) // opts->privateKey = NULL; // if (rc != 1) // { // if (opts->struct_version >= 3) // SSLSocket_error("SSL_CTX_use_PrivateKey_file", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); // else // SSLSocket_error("SSL_CTX_use_PrivateKey_file", NULL, net->socket, rc, NULL, NULL); // goto free_ctx; // } } if (opts->trustStore || opts->CApath) { BIO * cbio = BIO_new_mem_buf(cacrt, strlen(cacrt)); X509 * cert = PEM_read_bio_X509(cbio, NULL, 0, NULL); //PEM格式 X509_STORE_add_cert(net->ctx->cert_store, cert); X509_free(cert); BIO_free(cbio); // if ((rc = SSL_CTX_load_verify_locations(net->ctx, opts->trustStore, opts->CApath)) != 1) // { // if (opts->struct_version >= 3) // SSLSocket_error("SSL_CTX_load_verify_locations", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); // else // SSLSocket_error("SSL_CTX_load_verify_locations", NULL, net->socket, rc, NULL, NULL); // goto free_ctx; // } } else if (!opts->disableDefaultTrustStore) { if ((rc = SSL_CTX_set_default_verify_paths(net->ctx)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_CTX_set_default_verify_paths", NULL, net->socket, rc, NULL, NULL); goto free_ctx; } } if (opts->enabledCipherSuites) { if ((rc = SSL_CTX_set_cipher_list(net->ctx, opts->enabledCipherSuites)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_CTX_set_cipher_list", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_CTX_set_cipher_list", NULL, net->socket, rc, NULL, NULL); goto free_ctx; } } #ifndef OPENSSL_NO_PSK if (opts->ssl_psk_cb != NULL) { SSL_CTX_set_ex_data(net->ctx, tls_ex_index_ssl_opts, opts); SSL_CTX_set_psk_client_callback(net->ctx, call_ssl_psk_cb); } #endif #if (OPENSSL_VERSION_NUMBER >= 0x010002000) if (opts->protos != NULL && opts->protos_len > 0) { if ((rc = SSL_CTX_set_alpn_protos(net->ctx, opts->protos, opts->protos_len)) != 0) { if (opts->struct_version >= 3) SSLSocket_error("SSL_CTX_set_alpn_protos", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_CTX_set_alpn_protos", NULL, net->socket, rc, NULL, NULL); rc = 0; goto free_ctx; } rc = 1; } #endif SSL_CTX_set_mode(net->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); goto exit; free_ctx: SSL_CTX_free(net->ctx); net->ctx = NULL; exit: FUNC_EXIT_RC(rc); return rc; } int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, const char* hostname, size_t hostname_len) { int rc = 1; FUNC_ENTRY; if (net->ctx != NULL || (rc = SSLSocket_createContext(net, opts)) == 1) { char *hostname_plus_null; int i; SSL_CTX_set_info_callback(net->ctx, SSL_CTX_info_callback); SSL_CTX_set_msg_callback(net->ctx, SSL_CTX_msg_callback); if (opts->enableServerCertAuth) SSL_CTX_set_verify(net->ctx, SSL_VERIFY_PEER, NULL); net->ssl = SSL_new(net->ctx); for (i = 0; ;i++) { const char* cipher = SSL_get_cipher_list(net->ssl, i); if (cipher == NULL) break; Log(TRACE_PROTOCOL, 1, "SSL cipher available: %d:%s", i, cipher); } if ((rc = SSL_set_fd(net->ssl, net->socket)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_set_fd", net->ssl, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_set_fd", net->ssl, net->socket, rc, NULL, NULL); } hostname_plus_null = malloc(hostname_len + 1u ); if (hostname_plus_null) { MQTTStrncpy(hostname_plus_null, hostname, hostname_len + 1u); if ((rc = SSL_set_tlsext_host_name(net->ssl, hostname_plus_null)) != 1) { if (opts->struct_version >= 3) SSLSocket_error("SSL_set_tlsext_host_name", NULL, net->socket, rc, opts->ssl_error_cb, opts->ssl_error_context); else SSLSocket_error("SSL_set_tlsext_host_name", NULL, net->socket, rc, NULL, NULL); } free(hostname_plus_null); } else rc = PAHO_MEMORY_ERROR; } FUNC_EXIT_RC(rc); return rc; } int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify, int (*cb)(const char *str, size_t len, void *u), void* u) { int rc = 0; FUNC_ENTRY; ERR_clear_error(); rc = SSL_connect(ssl); if (rc != 1) { int error; error = SSLSocket_error("SSL_connect", ssl, sock, rc, cb, u); if (error == SSL_FATAL) rc = error; if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) rc = TCPSOCKET_INTERRUPTED; } #if (OPENSSL_VERSION_NUMBER >= 0x010002000) else if (verify) { char* peername = NULL; int port; size_t hostname_len; X509* cert = SSL_get_peer_certificate(ssl); hostname_len = MQTTProtocol_addressPort(hostname, &port, NULL, MQTT_DEFAULT_PORT); rc = X509_check_host(cert, hostname, hostname_len, 0, &peername); if (rc == 1) Log(TRACE_PROTOCOL, -1, "peername from X509_check_host is %s", peername); else Log(TRACE_PROTOCOL, -1, "X509_check_host for hostname %.*s failed, rc %d", (int)hostname_len, hostname, rc); if (peername != NULL) OPENSSL_free(peername); if (rc == 0 || rc == -1 || rc == -2) { char* ip_addr = malloc(hostname_len + 1); if (ip_addr) { strncpy(ip_addr, hostname, hostname_len); ip_addr[hostname_len] = ' '; rc = X509_check_ip_asc(cert, ip_addr, 0); Log(TRACE_MIN, -1, "rc from X509_check_ip_asc is %d", rc); free(ip_addr); } if (rc == 0 || rc == -1 || rc == -2) rc = SSL_FATAL; } if (cert) X509_free(cert); } #endif FUNC_EXIT_RC(rc); return rc; } int SSLSocket_getch(SSL* ssl, int socket, char* c) { int rc = SOCKET_ERROR; FUNC_ENTRY; if ((rc = SocketBuffer_getQueuedChar(socket, c)) != SOCKETBUFFER_INTERRUPTED) goto exit; ERR_clear_error(); if ((rc = SSL_read(ssl, c, (size_t)1)) < 0) { int err = SSLSocket_error("SSL_read - getch", ssl, socket, rc, NULL, NULL); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { rc = TCPSOCKET_INTERRUPTED; SocketBuffer_interrupted(socket, 0); } } else if (rc == 0) rc = SOCKET_ERROR; else if (rc == 1) { SocketBuffer_queueChar(socket, *c); rc = TCPSOCKET_COMPLETE; } exit: FUNC_EXIT_RC(rc); return rc; } char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len, int* rc) { char* buf; FUNC_ENTRY; if (bytes == 0) { buf = SocketBuffer_complete(socket); goto exit; } buf = SocketBuffer_getQueuedData(socket, bytes, actual_len); ERR_clear_error(); if ((*rc = SSL_read(ssl, buf + (*actual_len), (int)(bytes - (*actual_len)))) < 0) { *rc = SSLSocket_error("SSL_read - getdata", ssl, socket, *rc, NULL, NULL); if (*rc != SSL_ERROR_WANT_READ && *rc != SSL_ERROR_WANT_WRITE) { buf = NULL; goto exit; } } else if (*rc == 0) { buf = NULL; goto exit; } else *actual_len += *rc; if (*actual_len == bytes) { SocketBuffer_complete(socket); if (SSL_pending(ssl) > 0) SSLSocket_addPendingRead(socket); } else { SocketBuffer_interrupted(socket, *actual_len); Log(TRACE_MAX, -1, "SSL_read: %lu bytes expected but %lu bytes now received", bytes, *actual_len); } exit: FUNC_EXIT; return buf; } void SSLSocket_destroyContext(networkHandles* net) { FUNC_ENTRY; if (net->ctx) SSL_CTX_free(net->ctx); net->ctx = NULL; FUNC_EXIT; } static List pending_reads = {NULL, NULL, NULL, 0, 0}; int SSLSocket_close(networkHandles* net) { int rc = 1; FUNC_ENTRY; if (pending_reads.count > 0 && ListFindItem(&pending_reads, &net->socket, intcompare)) ListRemoveItem(&pending_reads, &net->socket, intcompare); if (net->ssl) { ERR_clear_error(); rc = SSL_shutdown(net->ssl); SSL_free(net->ssl); net->ssl = NULL; } SSLSocket_destroyContext(net); FUNC_EXIT_RC(rc); return rc; } int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, PacketBuffers bufs) { int rc = 0; int i; char *ptr; iobuf iovec; int sslerror; FUNC_ENTRY; iovec.iov_len = (ULONG)buf0len; for (i = 0; i < bufs.count; i++) iovec.iov_len += (ULONG)bufs.buflens[i]; ptr = iovec.iov_base = (char *)malloc(iovec.iov_len); if (!ptr) { rc = PAHO_MEMORY_ERROR; goto exit; } memcpy(ptr, buf0, buf0len); ptr += buf0len; for (i = 0; i < bufs.count; i++) { if (bufs.buffers[i] != NULL && bufs.buflens[i] > 0) { memcpy(ptr, bufs.buffers[i], bufs.buflens[i]); ptr += bufs.buflens[i]; } } SSL_lock_mutex(&sslCoreMutex); ERR_clear_error(); if ((rc = SSL_write(ssl, iovec.iov_base, iovec.iov_len)) == iovec.iov_len) rc = TCPSOCKET_COMPLETE; else { sslerror = SSLSocket_error("SSL_write", ssl, socket, rc, NULL, NULL); if (sslerror == SSL_ERROR_WANT_WRITE) { int* sockmem = (int*)malloc(sizeof(int)); int free = 1; if (!sockmem) { rc = PAHO_MEMORY_ERROR; SSL_unlock_mutex(&sslCoreMutex); goto exit; } Log(TRACE_MIN, -1, "Partial write: incomplete write of %lu bytes on SSL socket %d", iovec.iov_len, socket); SocketBuffer_pendingWrite(socket, ssl, 1, &iovec, &free, iovec.iov_len, 0); *sockmem = socket; ListAppend(mod_s.write_pending, sockmem, sizeof(int)); FD_SET(socket, &(mod_s.pending_wset)); rc = TCPSOCKET_INTERRUPTED; } else rc = SOCKET_ERROR; } SSL_unlock_mutex(&sslCoreMutex); if (rc != TCPSOCKET_INTERRUPTED) free(iovec.iov_base); else { int i; free(buf0); for (i = 0; i < bufs.count; ++i) { if (bufs.frees[i]) { free(bufs.buffers[i]); bufs.buffers[i] = NULL; } } } exit: FUNC_EXIT_RC(rc); return rc; } void SSLSocket_addPendingRead(int sock) { FUNC_ENTRY; if (ListFindItem(&pending_reads, &sock, intcompare) == NULL) { int* psock = (int*)malloc(sizeof(sock)); if (psock) { *psock = sock; ListAppend(&pending_reads, psock, sizeof(sock)); } } else Log(TRACE_MIN, -1, "SSLSocket_addPendingRead: socket %d already in the list", sock); FUNC_EXIT; } int SSLSocket_getPendingRead(void) { int sock = -1; if (pending_reads.count > 0) { sock = *(int*)(pending_reads.first->content); ListRemoveHead(&pending_reads); } return sock; } int SSLSocket_continueWrite(pending_writes* pw) { int rc = 0; FUNC_ENTRY; ERR_clear_error(); if ((rc = SSL_write(pw->ssl, pw->iovecs[0].iov_base, pw->iovecs[0].iov_len)) == pw->iovecs[0].iov_len) { free(pw->iovecs[0].iov_base); Log(TRACE_MIN, -1, "SSL continueWrite: partial write now complete for socket %d", pw->socket); rc = 1; } else { int sslerror = SSLSocket_error("SSL_write", pw->ssl, pw->socket, rc, NULL, NULL); if (sslerror == SSL_ERROR_WANT_WRITE) rc = 0; } FUNC_EXIT_RC(rc); return rc; } #endif



