[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [gnurl] 142/254: SecureTransport/DarwinSSL: Implement publi
From: |
gnunet |
Subject: |
[GNUnet-SVN] [gnurl] 142/254: SecureTransport/DarwinSSL: Implement public key pinning |
Date: |
Sat, 17 Jun 2017 16:52:54 +0200 |
This is an automated email from the git hooks/post-receive script.
ng0 pushed a commit to annotated tag gnurl-7.54.1
in repository gnurl.
commit eb16305e6ab1b3d660b6de326f61fd4c7df086ac
Author: moparisthebest <address@hidden>
AuthorDate: Mon Apr 17 19:47:51 2017 -0400
SecureTransport/DarwinSSL: Implement public key pinning
Closes #1400
---
docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 | 6 +-
lib/vtls/darwinssl.c | 156 ++++++++++++++++++++++++++++
lib/vtls/darwinssl.h | 24 +++++
tests/runtests.pl | 1 +
4 files changed, 186 insertions(+), 1 deletion(-)
diff --git a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
index 1951c88a6..47646474e 100644
--- a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
+++ b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
@@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
-.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
@@ -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
@@ -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
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 5533dfe2f..270b3ddfb 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -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,
@@ -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)
{
@@ -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);
@@ -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
diff --git a/lib/vtls/darwinssl.h b/lib/vtls/darwinssl.h
index 4bd41ca47..fd372ffa0 100644
--- a/lib/vtls/darwinssl.h
+++ b/lib/vtls/darwinssl.h
@@ -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
@@ -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 */
diff --git a/tests/runtests.pl b/tests/runtests.pl
index f23fc1d68..309b7085a 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -2412,6 +2412,7 @@ sub checksystem {
}
elsif ($libcurl =~ /securetransport/i) {
$has_darwinssl=1;
+ $has_sslpinning=1;
$ssllib="DarwinSSL";
}
elsif ($libcurl =~ /BoringSSL/i) {
--
To stop receiving notification emails like this one, please contact
address@hidden
- [GNUnet-SVN] [gnurl] 147/254: oauth2-bearer.d: mention the <token> argument, (continued)
- [GNUnet-SVN] [gnurl] 147/254: oauth2-bearer.d: mention the <token> argument, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 122/254: tests: removed redundant --trace-ascii arguments, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 174/254: runtests.pl: removed unused arguments to valgrindparse, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 128/254: cookie_interface: fix -Wcomma warning, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 123/254: tests: make test file names more unique, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 116/254: rand: treat fake entropy the same regardless of endianness, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 161/254: memdebug: fix compilation failure, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 145/254: curl_sasl: fix build error with CURL_DISABLE_CRYPTO_AUTH + USE_NTLM, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 150/254: asiohiper.cpp / evhiperfifo.c: deal with negative timerfunction input, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 168/254: winbuild: fix the nghttp2 build, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 142/254: SecureTransport/DarwinSSL: Implement public key pinning,
gnunet <=
- [GNUnet-SVN] [gnurl] 181/254: transfer: init the infilesize from the postfields..., gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 144/254: docs/cmdline-opts/config.d: edit for language, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 118/254: curl: generate the --help output, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 231/254: lib1521: fix compiler warnings, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 190/254: libtest/lib574.c: use correct callback proto, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 196/254: lib583: fix compiler warning, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 151/254: ghiper.c/hiperfifo.c: add comment about missing timer functionality, gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 225/254: test1262: verify ftp download with -z for "if older than this", gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 167/254: LDAP: documentation update per #878 changes (#1506), gnunet, 2017/06/17
- [GNUnet-SVN] [gnurl] 172/254: docs/CURLOPT_SSLVERSION.3: Correct define name in example, gnunet, 2017/06/17