From 30c131f51f605d35e5d90f4be1727045fef17351 Mon Sep 17 00:00:00 2001 From: Daniel Hwang Date: Sat, 12 Sep 2015 14:35:12 -0700 Subject: [PATCH] ssl: add server cert's "sha256//" hash to verbose Add a "pinnedpubkey" section to the "Server Certificate" verbose Bug: https://github.com/bagder/curl/issues/410 Reported-by: W. Mark Kubacki Closes #430 Closes #410 --- lib/vtls/cyassl.c | 3 ++- lib/vtls/gskit.c | 2 +- lib/vtls/gtls.c | 7 ++++--- lib/vtls/nss.c | 3 +-- lib/vtls/openssl.c | 7 ++++--- lib/vtls/vtls.c | 43 +++++++++++++++++++++++-------------------- lib/vtls/vtls.h | 3 ++- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index 3ded7f11d58287..052996e14637a3 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -434,7 +434,8 @@ cyassl_connect_step2(struct connectdata *conn, return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } - result = Curl_pin_peer_pubkey(data->set.str[STRING_SSL_PINNEDPUBLICKEY], + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index d884bd4c4d1a42..a5b7ea2033e9e6 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -874,7 +874,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) return CURLE_SSL_PINNEDPUBKEYNOTMATCH; Curl_parseX509(&x509, cert, certend); p = &x509.subjectPublicKeyInfo; - result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header); + result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index c54dfc1d2e158b..5f7041a3069cb6 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -724,7 +724,8 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_OK; } -static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert, +static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, + gnutls_x509_crt_t cert, const char *pinnedpubkey) { /* Scratch */ @@ -769,7 +770,7 @@ static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert, /* End Gyrations */ /* The one good exit point */ - result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); if(NULL != key) @@ -1152,7 +1153,7 @@ gtls_connect_step3(struct connectdata *conn, ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(ptr) { - result = pkp_pin_peer_pubkey(x509_cert, ptr); + result = pkp_pin_peer_pubkey(data, x509_cert, ptr); if(result != CURLE_OK) { failf(data, "SSL: public key does not match pinned public key!"); gnutls_x509_crt_deinit(x509_cert); diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index 09214a52b6cf7d..c8bd0cef6077a1 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -973,8 +973,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, SECItem *cert_der = PK11_DEREncodePublicKey(pubkey); if(cert_der) { /* compare the public key with the pinned public key */ - result = Curl_pin_peer_pubkey(pinnedpubkey, - cert_der->data, + result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data, cert_der->len); SECITEM_FreeItem(cert_der, PR_TRUE); } diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index a5103cd42558b4..998ab2bacd67a5 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2420,7 +2420,8 @@ static CURLcode get_cert_chain(struct connectdata *conn, * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL */ -static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey) +static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, X509* cert, + const char *pinnedpubkey) { /* Scratch */ int len1 = 0, len2 = 0; @@ -2465,7 +2466,7 @@ static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey) /* End Gyrations */ /* The one good exit point */ - result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); /* https://www.openssl.org/docs/crypto/buffer.html */ @@ -2629,7 +2630,7 @@ static CURLcode servercert(struct connectdata *conn, ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(!result && ptr) { - result = pkp_pin_peer_pubkey(connssl->server_cert, ptr); + result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr); if(result) failf(data, "SSL: public key does not match pinned public key!"); } diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 01bbc613095d1b..692ff5c9eba78d 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -765,7 +765,8 @@ static CURLcode pubkey_pem_to_der(const char *pem, * Generic pinned public key check. */ -CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, +CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, + const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen) { FILE *fp; @@ -775,9 +776,10 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, CURLcode pem_read; CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; #ifdef curlssl_sha256sum - size_t pinkeylen; - char *pinkeycopy, *begin_pos, *end_pos; - unsigned char *sha256sumdigest = NULL, *expectedsha256sumdigest = NULL; + CURLcode encode; + size_t encodedlen, pinkeylen; + char *encoded, *pinkeycopy, *begin_pos, *end_pos; + unsigned char *sha256sumdigest = NULL; #endif /* if a path wasn't specified, don't pin */ @@ -796,11 +798,21 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, curlssl_sha256sum(pubkey, pubkeylen, sha256sumdigest, SHA256_DIGEST_LENGTH); + encode = Curl_base64_encode(data, (char *)sha256sumdigest, + SHA256_DIGEST_LENGTH, &encoded, &encodedlen); + Curl_safefree(sha256sumdigest); + + if(!encode) { + infof(data, "\t pinnedpubkey: sha256//%s\n", encoded); + } + else + return encode; + /* it starts with sha256//, copy so we can modify it */ pinkeylen = strlen(pinnedpubkey) + 1; pinkeycopy = malloc(pinkeylen); if(!pinkeycopy) { - Curl_safefree(sha256sumdigest); + Curl_safefree(encoded); return CURLE_OUT_OF_MEMORY; } memcpy(pinkeycopy, pinnedpubkey, pinkeylen); @@ -815,20 +827,11 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, if(end_pos) end_pos[0] = '\0'; - /* decode base64 pinnedpubkey, 8 is length of "sha256//" */ - pem_read = Curl_base64_decode(begin_pos + 8, - &expectedsha256sumdigest, &size); - /* if not valid base64, don't bother comparing or freeing */ - if(!pem_read) { - /* compare sha256 digests directly */ - if(SHA256_DIGEST_LENGTH == size && - !memcmp(sha256sumdigest, expectedsha256sumdigest, - SHA256_DIGEST_LENGTH)) { - result = CURLE_OK; - Curl_safefree(expectedsha256sumdigest); - break; - } - Curl_safefree(expectedsha256sumdigest); + /* compare base64 sha256 digests, 8 is the length of "sha256//" */ + if(encodedlen == strlen(begin_pos + 8) && + !memcmp(encoded, begin_pos + 8, encodedlen)) { + result = CURLE_OK; + break; } /* @@ -840,7 +843,7 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, begin_pos = strstr(end_pos, "sha256//"); } } while(end_pos && begin_pos); - Curl_safefree(sha256sumdigest); + Curl_safefree(encoded); Curl_safefree(pinkeycopy); return result; } diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index 2349e5b93b53e4..d6224903a663c1 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -117,7 +117,8 @@ CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ unsigned char *md5sum, /* output */ size_t md5len); /* Check pinned public key. */ -CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, +CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, + const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen); bool Curl_ssl_cert_status_request(void);