Loading docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 +5 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * .\" * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms Loading Loading @@ -103,6 +103,8 @@ PEM/DER support: 7.49.0: PolarSSL 7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+ sha256 support: 7.44.0: OpenSSL, GnuTLS, NSS and wolfSSL/CyaSSL Loading @@ -111,6 +113,8 @@ sha256 support: 7.49.0: PolarSSL 7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+ Other SSL backends not supported. .SH RETURN VALUE Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or Loading lib/vtls/darwinssl.c +156 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,36 @@ #define ioErr -36 #define paramErr -50 #ifdef DARWIN_SSL_PINNEDPUBKEY /* both new and old APIs return rsa keys missing the spki header (not DER) */ static const unsigned char rsa4096SpkiHeader[] = { 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00}; static const unsigned char rsa2048SpkiHeader[] = { 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00}; #ifdef DARWIN_SSL_PINNEDPUBKEY_V1 /* the *new* version doesn't return DER encoded ecdsa certs like the old... */ static const unsigned char ecDsaSecp256r1SpkiHeader[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00}; static const unsigned char ecDsaSecp384r1SpkiHeader[] = { 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00}; #endif /* DARWIN_SSL_PINNEDPUBKEY_V1 */ #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* The following two functions were ripped from Apple sample code, * with some modifications: */ static OSStatus SocketRead(SSLConnectionRef connection, Loading Loading @@ -1996,6 +2026,112 @@ static int verify_cert(const char *cafile, struct Curl_easy *data, } } #ifdef DARWIN_SSL_PINNEDPUBKEY static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, SSLContextRef ctx, const char *pinnedpubkey) { /* Scratch */ size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; unsigned char *pubkey = NULL, *realpubkey = NULL, *spkiHeader = NULL; CFDataRef publicKeyBits = NULL; /* Result is returned to caller */ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; if(!ctx) return result; do { SecTrustRef trust; OSStatus ret = SSLCopyPeerTrust(ctx, &trust); if(ret != noErr || trust == NULL) break; SecKeyRef keyRef = SecTrustCopyPublicKey(trust); CFRelease(trust); if(keyRef == NULL) break; #ifdef DARWIN_SSL_PINNEDPUBKEY_V1 publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL); CFRelease(keyRef); if(publicKeyBits == NULL) break; #elif DARWIN_SSL_PINNEDPUBKEY_V2 OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, &publicKeyBits); CFRelease(keyRef); if(success != errSecSuccess || publicKeyBits == NULL) break; #endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ pubkeylen = CFDataGetLength(publicKeyBits); pubkey = CFDataGetBytePtr(publicKeyBits); switch(pubkeylen) { case 526: /* 4096 bit RSA pubkeylen == 526 */ spkiHeader = rsa4096SpkiHeader; break; case 270: /* 2048 bit RSA pubkeylen == 270 */ spkiHeader = rsa2048SpkiHeader; break; #ifdef DARWIN_SSL_PINNEDPUBKEY_V1 case 65: /* ecDSA secp256r1 pubkeylen == 65 */ spkiHeader = ecDsaSecp256r1SpkiHeader; spkiHeaderLength = 26; break; case 97: /* ecDSA secp384r1 pubkeylen == 97 */ spkiHeader = ecDsaSecp384r1SpkiHeader; spkiHeaderLength = 23; break; default: infof(data, "SSL: unhandled public key length: %d\n", pubkeylen); #elif DARWIN_SSL_PINNEDPUBKEY_V2 default: /* ecDSA secp256r1 pubkeylen == 91 header already included? * ecDSA secp384r1 header already included too * we assume rest of algorithms do same, so do nothing */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey, pubkeylen); #endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ continue; /* break from loop */ } realpubkeylen = pubkeylen + spkiHeaderLength; realpubkey = malloc(realpubkeylen); if(!realpubkey) break; memcpy(realpubkey, spkiHeader, spkiHeaderLength); memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen); result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey, realpubkeylen); } while(0); Curl_safefree(realpubkey); if(publicKeyBits != NULL) CFRelease(publicKeyBits); return result; } #endif /* DARWIN_SSL_PINNEDPUBKEY */ static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { Loading Loading @@ -2102,6 +2238,17 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; #ifdef DARWIN_SSL_PINNEDPUBKEY if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { CURLcode result = pkp_pin_peer_pubkey(data, connssl->ssl_ctx, data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } } #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); Loading Loading @@ -2573,6 +2720,15 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); } void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len) { assert(sha256len >= SHA256_DIGEST_LENGTH); (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); } bool Curl_darwinssl_false_start(void) { #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 Loading lib/vtls/darwinssl.h +24 −0 Original line number Diff line number Diff line Loading @@ -48,11 +48,34 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len); bool Curl_darwinssl_false_start(void); /* Set the API backend definition to SecureTransport */ #define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL /* pinned public key support tests */ /* version 1 supports macOS 10.12+ and iOS 10+ */ #if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) #define DARWIN_SSL_PINNEDPUBKEY_V1 1 #endif /* version 2 supports MacOSX 10.7+ */ #if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) #define DARWIN_SSL_PINNEDPUBKEY_V2 1 #endif #if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2) /* this backend supports CURLOPT_PINNEDPUBLICKEY */ #define DARWIN_SSL_PINNEDPUBKEY 1 #define have_curlssl_pinnedpubkey 1 #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* API setup for SecureTransport */ #define curlssl_init() (1) #define curlssl_cleanup() Curl_nop_stmt Loading @@ -70,6 +93,7 @@ bool Curl_darwinssl_false_start(void); #define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y) #define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z)) #define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d) #define curlssl_sha256sum(a,b,c,d) Curl_darwinssl_sha256sum(a,b,c,d) #define curlssl_false_start() Curl_darwinssl_false_start() #endif /* USE_DARWINSSL */ Loading tests/runtests.pl +1 −0 Original line number Diff line number Diff line Loading @@ -2412,6 +2412,7 @@ sub checksystem { } elsif ($libcurl =~ /securetransport/i) { $has_darwinssl=1; $has_sslpinning=1; $ssllib="DarwinSSL"; } elsif ($libcurl =~ /BoringSSL/i) { Loading Loading
docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 +5 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * .\" * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms Loading Loading @@ -103,6 +103,8 @@ PEM/DER support: 7.49.0: PolarSSL 7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+ sha256 support: 7.44.0: OpenSSL, GnuTLS, NSS and wolfSSL/CyaSSL Loading @@ -111,6 +113,8 @@ sha256 support: 7.49.0: PolarSSL 7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+ Other SSL backends not supported. .SH RETURN VALUE Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or Loading
lib/vtls/darwinssl.c +156 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,36 @@ #define ioErr -36 #define paramErr -50 #ifdef DARWIN_SSL_PINNEDPUBKEY /* both new and old APIs return rsa keys missing the spki header (not DER) */ static const unsigned char rsa4096SpkiHeader[] = { 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00}; static const unsigned char rsa2048SpkiHeader[] = { 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00}; #ifdef DARWIN_SSL_PINNEDPUBKEY_V1 /* the *new* version doesn't return DER encoded ecdsa certs like the old... */ static const unsigned char ecDsaSecp256r1SpkiHeader[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00}; static const unsigned char ecDsaSecp384r1SpkiHeader[] = { 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00}; #endif /* DARWIN_SSL_PINNEDPUBKEY_V1 */ #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* The following two functions were ripped from Apple sample code, * with some modifications: */ static OSStatus SocketRead(SSLConnectionRef connection, Loading Loading @@ -1996,6 +2026,112 @@ static int verify_cert(const char *cafile, struct Curl_easy *data, } } #ifdef DARWIN_SSL_PINNEDPUBKEY static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, SSLContextRef ctx, const char *pinnedpubkey) { /* Scratch */ size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; unsigned char *pubkey = NULL, *realpubkey = NULL, *spkiHeader = NULL; CFDataRef publicKeyBits = NULL; /* Result is returned to caller */ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; /* if a path wasn't specified, don't pin */ if(!pinnedpubkey) return CURLE_OK; if(!ctx) return result; do { SecTrustRef trust; OSStatus ret = SSLCopyPeerTrust(ctx, &trust); if(ret != noErr || trust == NULL) break; SecKeyRef keyRef = SecTrustCopyPublicKey(trust); CFRelease(trust); if(keyRef == NULL) break; #ifdef DARWIN_SSL_PINNEDPUBKEY_V1 publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL); CFRelease(keyRef); if(publicKeyBits == NULL) break; #elif DARWIN_SSL_PINNEDPUBKEY_V2 OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, &publicKeyBits); CFRelease(keyRef); if(success != errSecSuccess || publicKeyBits == NULL) break; #endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ pubkeylen = CFDataGetLength(publicKeyBits); pubkey = CFDataGetBytePtr(publicKeyBits); switch(pubkeylen) { case 526: /* 4096 bit RSA pubkeylen == 526 */ spkiHeader = rsa4096SpkiHeader; break; case 270: /* 2048 bit RSA pubkeylen == 270 */ spkiHeader = rsa2048SpkiHeader; break; #ifdef DARWIN_SSL_PINNEDPUBKEY_V1 case 65: /* ecDSA secp256r1 pubkeylen == 65 */ spkiHeader = ecDsaSecp256r1SpkiHeader; spkiHeaderLength = 26; break; case 97: /* ecDSA secp384r1 pubkeylen == 97 */ spkiHeader = ecDsaSecp384r1SpkiHeader; spkiHeaderLength = 23; break; default: infof(data, "SSL: unhandled public key length: %d\n", pubkeylen); #elif DARWIN_SSL_PINNEDPUBKEY_V2 default: /* ecDSA secp256r1 pubkeylen == 91 header already included? * ecDSA secp384r1 header already included too * we assume rest of algorithms do same, so do nothing */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey, pubkeylen); #endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */ continue; /* break from loop */ } realpubkeylen = pubkeylen + spkiHeaderLength; realpubkey = malloc(realpubkeylen); if(!realpubkey) break; memcpy(realpubkey, spkiHeader, spkiHeaderLength); memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen); result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey, realpubkeylen); } while(0); Curl_safefree(realpubkey); if(publicKeyBits != NULL) CFRelease(publicKeyBits); return result; } #endif /* DARWIN_SSL_PINNEDPUBKEY */ static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { Loading Loading @@ -2102,6 +2238,17 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; #ifdef DARWIN_SSL_PINNEDPUBKEY if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) { CURLcode result = pkp_pin_peer_pubkey(data, connssl->ssl_ctx, data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]); if(result) { failf(data, "SSL: public key does not match pinned public key!"); return result; } } #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); Loading Loading @@ -2573,6 +2720,15 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); } void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len) { assert(sha256len >= SHA256_DIGEST_LENGTH); (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); } bool Curl_darwinssl_false_start(void) { #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 Loading
lib/vtls/darwinssl.h +24 −0 Original line number Diff line number Diff line Loading @@ -48,11 +48,34 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t sha256len); bool Curl_darwinssl_false_start(void); /* Set the API backend definition to SecureTransport */ #define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL /* pinned public key support tests */ /* version 1 supports macOS 10.12+ and iOS 10+ */ #if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) #define DARWIN_SSL_PINNEDPUBKEY_V1 1 #endif /* version 2 supports MacOSX 10.7+ */ #if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) #define DARWIN_SSL_PINNEDPUBKEY_V2 1 #endif #if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2) /* this backend supports CURLOPT_PINNEDPUBLICKEY */ #define DARWIN_SSL_PINNEDPUBKEY 1 #define have_curlssl_pinnedpubkey 1 #endif /* DARWIN_SSL_PINNEDPUBKEY */ /* API setup for SecureTransport */ #define curlssl_init() (1) #define curlssl_cleanup() Curl_nop_stmt Loading @@ -70,6 +93,7 @@ bool Curl_darwinssl_false_start(void); #define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y) #define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z)) #define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d) #define curlssl_sha256sum(a,b,c,d) Curl_darwinssl_sha256sum(a,b,c,d) #define curlssl_false_start() Curl_darwinssl_false_start() #endif /* USE_DARWINSSL */ Loading
tests/runtests.pl +1 −0 Original line number Diff line number Diff line Loading @@ -2412,6 +2412,7 @@ sub checksystem { } elsif ($libcurl =~ /securetransport/i) { $has_darwinssl=1; $has_sslpinning=1; $ssllib="DarwinSSL"; } elsif ($libcurl =~ /BoringSSL/i) { Loading