diff options
-rw-r--r-- | lib/vtls/mbedtls.c | 115 |
1 files changed, 66 insertions, 49 deletions
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 05af46212..26959e041 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -148,45 +148,7 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = #define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES) #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ - RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) - -static int -mbedtls_verify_pinned_crt(void *p, mbedtls_x509_crt *crt, - int depth, unsigned int *flags) -{ - struct SessionHandle *data = p; - unsigned char pubkey[PUB_DER_MAX_BYTES]; - int ret; - int size; - char *pinned_cert = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; - - /* Skip intermediate and root certificates */ - if(depth) { - return 0; - } - - if(pinned_cert == NULL || crt == NULL) { - *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - return 1; - } - - /* Extract pubkey */ - size = mbedtls_pk_write_pubkey_der(&crt->pk, pubkey, PUB_DER_MAX_BYTES); - if(size <= 0) { - *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - return 1; - } - - /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ - ret = Curl_pin_peer_pubkey(data, pinned_cert, - &pubkey[PUB_DER_MAX_BYTES - size], size); - if(ret == CURLE_OK) { - return 0; - } - - *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; - return 1; -} + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) static Curl_recv mbedtls_recv; static Curl_send mbedtls_send; @@ -455,7 +417,7 @@ mbedtls_connect_step2(struct connectdata *conn, int ret; struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - char buffer[1024]; + const mbedtls_x509_crt *peercert; #ifdef HAS_ALPN const char* next_protocol; @@ -510,13 +472,72 @@ mbedtls_connect_step2(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - if(mbedtls_ssl_get_peer_cert(&(connssl->ssl))) { - /* If the session was resumed, there will be no peer certs */ - memset(buffer, 0, sizeof(buffer)); + peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl); - if(mbedtls_x509_crt_info(buffer, sizeof(buffer), (char *)"* ", - mbedtls_ssl_get_peer_cert(&(connssl->ssl))) != -1) + if(peercert && data->set.verbose) { + const size_t bufsize = 16384; + char *buffer = malloc(bufsize); + + if(!buffer) + return CURLE_OUT_OF_MEMORY; + + if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) infof(data, "Dumping cert info:\n%s\n", buffer); + else + infof(data, "Unable to dump certificate information.\n"); + + free(buffer); + } + + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + int size; + CURLcode result; + mbedtls_x509_crt *p; + unsigned char pubkey[PUB_DER_MAX_BYTES]; + + if(!peercert || !peercert->raw.p || !peercert->raw.len) { + failf(data, "Failed due to missing peer certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + p = calloc(1, sizeof(*p)); + + if(!p) + return CURLE_OUT_OF_MEMORY; + + mbedtls_x509_crt_init(p); + + /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der + needs a non-const key, for now. + https://github.com/ARMmbed/mbedtls/issues/396 */ + if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { + failf(data, "Failed copying peer certificate"); + mbedtls_x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); + + if(size <= 0) { + failf(data, "Failed copying public key from peer certificate"); + mbedtls_x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], + &pubkey[PUB_DER_MAX_BYTES - size], size); + if(result) { + mbedtls_x509_crt_free(p); + free(p); + return result; + } + + mbedtls_x509_crt_free(p); + free(p); } #ifdef HAS_ALPN @@ -683,10 +704,6 @@ mbedtls_connect_common(struct connectdata *conn, long timeout_ms; int what; - if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { - mbedtls_ssl_conf_verify(&connssl->config, mbedtls_verify_pinned_crt, data); - } - /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; |