From 092f6815c808489f1cea3df8449e16dff2c35e6b Mon Sep 17 00:00:00 2001 From: Rodger Combs Date: Wed, 11 Jul 2018 02:45:14 -0500 Subject: [PATCH] darwinssl: add support for ALPN negotiation --- docs/HTTP2.md | 17 ++++++------ lib/vtls/darwinssl.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/docs/HTTP2.md b/docs/HTTP2.md index efbe699910..e20ce0cab3 100644 --- a/docs/HTTP2.md +++ b/docs/HTTP2.md @@ -55,14 +55,15 @@ The challenge is the ALPN and NPN support and all our different SSL backends. You may need a fairly updated SSL library version for it to provide the necessary TLS features. Right now we support: - - OpenSSL: ALPN and NPN - - libressl: ALPN and NPN - - BoringSSL: ALPN and NPN - - NSS: ALPN and NPN - - GnuTLS: ALPN - - mbedTLS: ALPN - - SChannel: ALPN - - wolfSSL: ALPN + - OpenSSL: ALPN and NPN + - libressl: ALPN and NPN + - BoringSSL: ALPN and NPN + - NSS: ALPN and NPN + - GnuTLS: ALPN + - mbedTLS: ALPN + - SChannel: ALPN + - wolfSSL: ALPN + - Secure Transport: ALPN Multiplexing ------------ diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index f29b5acad8..1aea0dc3dd 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -1573,6 +1573,35 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ +#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(conn->bits.tls_enable_alpn) { + if(__builtin_available(macOS 10.13.4, iOS 11, *)) { + CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0, + &kCFTypeArrayCallBacks); + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { + CFArrayAppendValue(alpnArr, CFSTR(NGHTTP2_PROTO_VERSION_ID)); + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1)); + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + /* expects length prefixed preference ordered list of protocols in wire + * format + */ + err = SSLSetALPNProtocols(BACKEND->ssl_ctx, alpnArr); + if(err != noErr) + infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n", + err); + CFRelease(alpnArr); + } + } +#endif + if(SSL_SET_OPTION(key)) { infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " "Transport. The private key must be in the Keychain.\n"); @@ -2467,6 +2496,39 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) break; } +#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1 + if(conn->bits.tls_enable_alpn) { + if(__builtin_available(macOS 10.13.4, iOS 11, *)) { + CFArrayRef alpnArr = NULL; + CFStringRef chosenProtocol = NULL; + err = SSLCopyALPNProtocols(BACKEND->ssl_ctx, &alpnArr); + + if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1) + chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0); + +#ifdef USE_NGHTTP2 + if(chosenProtocol && + !CFStringCompare(chosenProtocol, CFSTR(NGHTTP2_PROTO_VERSION_ID), + 0)) { + conn->negnpn = CURL_HTTP_VERSION_2; + } + else +#endif + if(chosenProtocol && + !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } + else + infof(data, "ALPN, server did not agree to a protocol\n"); + + /* chosenProtocol is a reference to the string within alpnArr + and doesn't need to be freed separately */ + if(alpnArr) + CFRelease(alpnArr); + } + } +#endif + return CURLE_OK; } }