|
47 | 47 | extern Sockets mod_s;
|
48 | 48 |
|
49 | 49 | static int SSLSocket_error(char* aString, SSL* ssl, SOCKET sock, int rc, int (*cb)(const char *str, size_t len, void *u), void* u);
|
| 50 | +static int SSLSocket_certificate_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx); |
50 | 51 | char* SSL_get_verify_result_string(int rc);
|
51 | 52 | void SSL_CTX_info_callback(const SSL* ssl, int where, int ret);
|
52 | 53 | char* SSLSocket_get_version_string(int version);
|
@@ -78,6 +79,8 @@ static ssl_mutex_type sslCoreMutex;
|
78 | 79 |
|
79 | 80 | /* Used to store MQTTClient_SSLOptions for TLS-PSK callback */
|
80 | 81 | static int tls_ex_index_ssl_opts;
|
| 82 | +/* Used to store MQTTClient_SSLOptions for TLS Certificate verify callback */ |
| 83 | +static int tls_ex_index_ssl_opts_for_verify_cb; |
81 | 84 |
|
82 | 85 | #if defined(_WIN32) || defined(_WIN64)
|
83 | 86 | #define iov_len len
|
@@ -122,6 +125,92 @@ static int SSLSocket_error(char* aString, SSL* ssl, SOCKET sock, int rc, int (*c
|
122 | 125 | return error;
|
123 | 126 | }
|
124 | 127 |
|
| 128 | +static int SSLSocket_certificate_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) |
| 129 | +{ |
| 130 | + int error = X509_STORE_CTX_get_error(x509_ctx); |
| 131 | + FUNC_ENTRY; |
| 132 | + |
| 133 | + int iVerifyOK = 0; |
| 134 | + |
| 135 | + /* depth==0 server certificate */ |
| 136 | + int depth = X509_STORE_CTX_get_error_depth(x509_ctx); |
| 137 | + Log(TRACE_MIN, -1, "preverify_ok=%d depth=%d", preverify_ok, depth); |
| 138 | + if (depth == 0) |
| 139 | + { |
| 140 | + /* 1. Extracting the public key from a certificate. */ |
| 141 | + X509* cert = X509_STORE_CTX_get_current_cert(x509_ctx); |
| 142 | + if (cert == NULL) |
| 143 | + goto exit; |
| 144 | + |
| 145 | + EVP_PKEY* pubkey_from_cert = X509_get_pubkey(cert); |
| 146 | + if (pubkey_from_cert == NULL) |
| 147 | + { |
| 148 | + Log(TRACE_MIN, -1, "Error extracting public key from certificate"); |
| 149 | + goto exit; |
| 150 | + } |
| 151 | + |
| 152 | + /* 2. The public key from the configuration. */ |
| 153 | + SSL* ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
| 154 | + if (ssl == NULL) |
| 155 | + { |
| 156 | + Log(TRACE_MIN, -1, "Error SSL get_ex_data"); |
| 157 | + goto exit; |
| 158 | + } |
| 159 | + SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); |
| 160 | + if (ssl_ctx == NULL) |
| 161 | + { |
| 162 | + Log(TRACE_MIN, -1, "Error SSL_CTX get_ex_data"); |
| 163 | + goto exit; |
| 164 | + } |
| 165 | + |
| 166 | + MQTTClient_SSLOptions* opts = SSL_CTX_get_ex_data(ssl_ctx, tls_ex_index_ssl_opts_for_verify_cb); |
| 167 | + if (opts == NULL) |
| 168 | + { |
| 169 | + Log(TRACE_MIN, -1, "Error opts get_ex_data"); |
| 170 | + goto exit; |
| 171 | + } |
| 172 | + |
| 173 | + if (opts->publicKey == NULL || strlen(opts->publicKey) <= 0 || access(opts->publicKey, R_OK) != 0) |
| 174 | + { |
| 175 | + Log(TRACE_MIN, -1, "Error opts pubKey invalid"); |
| 176 | + goto exit; |
| 177 | + } |
| 178 | + |
| 179 | + FILE* pubkey_file = fopen(opts->publicKey, "r"); |
| 180 | + if (pubkey_file == NULL) |
| 181 | + { |
| 182 | + Log(TRACE_MIN, -1,"Error opening public key file"); |
| 183 | + goto exit; |
| 184 | + } |
| 185 | + |
| 186 | + EVP_PKEY* pubkey_from_file = PEM_read_PUBKEY(pubkey_file, NULL, NULL, NULL); |
| 187 | + fclose(pubkey_file); |
| 188 | + if (pubkey_from_file == NULL) |
| 189 | + { |
| 190 | + Log(TRACE_MIN, -1, "Error reading public key file"); |
| 191 | + goto exit; |
| 192 | + } |
| 193 | + |
| 194 | + // 3. compare |
| 195 | +#if (OPENSSL_VERSION_NUMBER >= 0x030000000) /* 3.0.0 and later */ |
| 196 | + if (EVP_PKEY_eq(pubkey_from_file, pubkey_from_cert) == 1) |
| 197 | +#else |
| 198 | + if (EVP_PKEY_cmp(pubkey_from_file, pubkey_from_cert) == 1) |
| 199 | +#endif |
| 200 | + iVerifyOK = 1; |
| 201 | + |
| 202 | + // 4. cleanup |
| 203 | + EVP_PKEY_free(pubkey_from_cert); |
| 204 | + EVP_PKEY_free(pubkey_from_file); |
| 205 | + } |
| 206 | + else |
| 207 | + iVerifyOK = preverify_ok; |
| 208 | + |
| 209 | +exit: |
| 210 | + FUNC_EXIT_RC(error); |
| 211 | + return iVerifyOK; |
| 212 | +} |
| 213 | + |
125 | 214 | static struct
|
126 | 215 | {
|
127 | 216 | int code;
|
@@ -490,6 +579,7 @@ int SSLSocket_initialize(void)
|
490 | 579 | SSL_create_mutex(&sslCoreMutex);
|
491 | 580 |
|
492 | 581 | tls_ex_index_ssl_opts = SSL_get_ex_new_index(0, "paho ssl options", NULL, NULL, NULL);
|
| 582 | + tls_ex_index_ssl_opts_for_verify_cb = SSL_get_ex_new_index(0, "paho ssl options", NULL, NULL, NULL); |
493 | 583 |
|
494 | 584 | exit:
|
495 | 585 | FUNC_EXIT_RC(rc);
|
@@ -675,6 +765,8 @@ int SSLSocket_createContext(networkHandles* net, MQTTClient_SSLOptions* opts)
|
675 | 765 | SSL_CTX_set_psk_client_callback(net->ctx, call_ssl_psk_cb);
|
676 | 766 | }
|
677 | 767 | #endif
|
| 768 | + if (opts->publicKey !=NULL ) |
| 769 | + SSL_CTX_set_ex_data(net->ctx, tls_ex_index_ssl_opts_for_verify_cb, opts); |
678 | 770 |
|
679 | 771 | #if (OPENSSL_VERSION_NUMBER >= 0x010002000) /* 1.0.2 and later */
|
680 | 772 | if (opts->protos != NULL && opts->protos_len > 0)
|
@@ -722,7 +814,7 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
|
722 | 814 | SSL_CTX_set_info_callback(net->ctx, SSL_CTX_info_callback);
|
723 | 815 | SSL_CTX_set_msg_callback(net->ctx, SSL_CTX_msg_callback);
|
724 | 816 | if (opts->enableServerCertAuth)
|
725 |
| - SSL_CTX_set_verify(net->ctx, SSL_VERIFY_PEER, NULL); |
| 817 | + SSL_CTX_set_verify(net->ctx, SSL_VERIFY_PEER, opts->publicKey != NULL ? SSLSocket_certificate_verify_cb : NULL); |
726 | 818 |
|
727 | 819 | net->ssl = SSL_new(net->ctx);
|
728 | 820 |
|
|
0 commit comments