From 1250db8a529fcda4d7d21c7b8144ca84a16483c4 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Fri, 29 May 2015 01:07:32 -0400 Subject: [PATCH] SSL: Pinned public key hash support, for comments --- lib/vtls/openssl.c | 12 +++++++++++ lib/vtls/openssl.h | 5 +++++ lib/vtls/vtls.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 96a7d6e..8931e2c 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3237,6 +3237,18 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */ MD5_Final(md5sum, &MD5pw); } +void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused) +{ + SHA256_CTX SHA256pw; + (void)unused; + SHA256_Init(&SHA256pw); + SHA256_Update(&SHA256pw, tmp, tmplen); + SHA256_Final(sha256sum, &SHA256pw); +} + bool Curl_ossl_cert_status_request(void) { #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h index 499b4fe..ebac542 100644 --- a/lib/vtls/openssl.h +++ b/lib/vtls/openssl.h @@ -72,6 +72,10 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum /* output */, size_t unused); +void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *sha256sum /* output */, + size_t unused); bool Curl_ossl_cert_status_request(void); @@ -104,6 +108,7 @@ bool Curl_ossl_cert_status_request(void); #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y) #define curlssl_random(x,y,z) Curl_ossl_random(x,y,z) #define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d) +#define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d) #define curlssl_cert_status_request() Curl_ossl_cert_status_request() #define DEFAULT_CIPHER_SELECTION \ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 42a2b58..94aff35 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -774,12 +774,74 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, size_t size, pem_len; CURLcode pem_read; CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; +#ifdef curlssl_sha256sum + size_t pinkeylen; + char *pinkeycopy, *begin_pos, *end_pos; + unsigned char sha256sumdigest[SHA256_DIGEST_LENGTH]; + unsigned char *expectedsha256sumdigest = NULL; +#endif /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; if(!pubkey || !pubkeylen) return result; + +#ifdef curlssl_sha256sum + /* only do this if pinnedpubkey starts with "sha256/" */ + begin_pos = strstr(pinnedpubkey, "sha256/"); + if(begin_pos && 0 == (begin_pos - pinnedpubkey)) { + /* compute sha256sum of public key */ + curlssl_sha256sum(pubkey, pubkeylen, + sha256sumdigest, SHA256_DIGEST_LENGTH); + + /* it starts with sha256/, copy so we can modify it */ + pinkeylen = strlen(pinnedpubkey); + pinkeycopy = malloc(pinkeylen); + if(!pinkeycopy) + return CURLE_OUT_OF_MEMORY; + memcpy(pinkeycopy, pinnedpubkey, pinkeylen); + /* point begin_pos to the copy, and start extracting keys */ + begin_pos = pinkeycopy; + do { + end_pos = strstr(begin_pos, ";sha256/"); + /* + * if there is an end_pos, null terminate, + * otherwise it'll go to the end of the original string + */ + if(end_pos) + end_pos[0] = '\0'; + + /* decode base64 pinnedpubkey, 7 is length of "sha256/" */ + pem_read = Curl_base64_decode(begin_pos + 7, + &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); + } + + /* + * change back the null-terminator we changed earlier, + * and look for next begin + */ + if(end_pos) { + end_pos[0] = ';'; + begin_pos = strstr(end_pos, "sha256/"); + } + } while(end_pos && begin_pos); + Curl_safefree(pinkeycopy); + return result; + } +#endif + fp = fopen(pinnedpubkey, "rb"); if(!fp) return result; -- 1.9.2