[vlc-commits] securetransport: Add ALPN support
Marvin Scholz
git at videolan.org
Fri Apr 6 11:18:06 CEST 2018
vlc | branch: master | Marvin Scholz <epirat07 at gmail.com> | Thu Apr 5 20:32:26 2018 +0200| [29df9379c316fd7728a9e2b9505dd1b7b1e9c638] | committer: Thomas Guillem
securetransport: Add ALPN support
Signed-off-by: Thomas Guillem <thomas at gllm.fr>
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=29df9379c316fd7728a9e2b9505dd1b7b1e9c638
---
modules/misc/Makefile.am | 1 +
modules/misc/securetransport.c | 153 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 149 insertions(+), 5 deletions(-)
diff --git a/modules/misc/Makefile.am b/modules/misc/Makefile.am
index f53fc4dabf..b5a8db5379 100644
--- a/modules/misc/Makefile.am
+++ b/modules/misc/Makefile.am
@@ -42,6 +42,7 @@ libsecuretransport_plugin_la_SOURCES = misc/securetransport.c
libsecuretransport_plugin_la_CFLAGS = $(AM_CFLAGS) $(SECURETRANSPORT_CFLAGS)
libsecuretransport_plugin_la_LIBADD = $(SECURETRANSPORT_LIBS)
libsecuretransport_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(miscdir)' -Wl,-framework,Security,-framework,CoreFoundation
+libsecuretransport_plugin_la_LDFLAGS += -Wl,-U,_SSLCopyALPNProtocols,-U,_SSLSetALPNProtocols
misc_LTLIBRARIES += libsecuretransport_plugin.la
endif
diff --git a/modules/misc/securetransport.c b/modules/misc/securetransport.c
index fcd5e8bc72..7bf8e9e566 100644
--- a/modules/misc/securetransport.c
+++ b/modules/misc/securetransport.c
@@ -41,6 +41,80 @@
#endif
/*****************************************************************************
+ * ALPN helper functions
+ *****************************************************************************/
+
+/* Converts the VLC ALPN C array (null-terminated) to a ALPN
+ * CFMutableArray as expected by the Secure Transport API
+ * Returns CFMutableArrayRef on success, else NULL.
+ */
+static CFMutableArrayRef alpnToCFArray(const char *const *alpn)
+{
+ CFMutableArrayRef alpnValues =
+ CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+ for (size_t i = 0; alpn[i] != NULL; i++) {
+ CFStringRef alpnVal =
+ CFStringCreateWithCString(kCFAllocatorDefault, alpn[i], kCFStringEncodingASCII);
+ if (alpnVal == NULL) {
+ // Failed to convert the ALPN value to CFString, error out.
+ CFRelease(alpnValues);
+ return NULL;
+ }
+ CFArrayAppendValue(alpnValues, alpnVal);
+ CFRelease(alpnVal);
+ }
+ return alpnValues;
+}
+
+/* Obtains a copy of the contents of a CFString in ASCII encoding.
+ * Returns char* (must be freed by caller) or NULL on failure.
+ */
+static char* CFStringCopyASCIICString(CFStringRef cfString)
+{
+ // Try the quick way to obtain the buffer
+ const char *tmpBuffer = CFStringGetCStringPtr(cfString, kCFStringEncodingASCII);
+
+ if (tmpBuffer != NULL) {
+ return strdup(tmpBuffer);
+ }
+
+ // The quick way did not work, try the long way
+ CFIndex length = CFStringGetLength(cfString);
+ CFIndex maxSize =
+ CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingASCII);
+
+ // If result would exceed LONG_MAX, kCFNotFound is returned
+ if (unlikely(maxSize == kCFNotFound)) {
+ return NULL;
+ }
+
+ // Account for the null terminator
+ maxSize++;
+
+ char *buffer = (char *)malloc(maxSize);
+ Boolean success = CFStringGetCString(cfString, buffer, maxSize, kCFStringEncodingASCII);
+
+ if (!success)
+ FREENULL(buffer);
+ return buffer;
+}
+
+/* Returns the first entry copy of the ALPN array as char*
+ * or NULL on failure.
+ */
+static char* CFArrayALPNCopyFirst(CFArrayRef alpnArray)
+{
+ CFIndex count = CFArrayGetCount(alpnArray);
+
+ if (count <= 0)
+ return NULL;
+
+ CFStringRef alpnVal = CFArrayGetValueAtIndex(alpnArray, 0);
+ return CFStringCopyASCIICString(alpnVal);
+}
+
+/*****************************************************************************
* Module descriptor
*****************************************************************************/
static int OpenClient (vlc_tls_creds_t *);
@@ -393,10 +467,43 @@ static int st_Handshake (vlc_tls_creds_t *crd, vlc_tls_t *session,
VLC_UNUSED(service);
OSStatus retValue = SSLHandshake(sys->p_context);
+
+// Only try to use ALPN on recent enough SDKs
+// macOS 10.13.2, iOS 11, tvOS 11, watchOS 4
+#if (TARGET_OS_OSX && MAC_OS_X_VERSION_MAX_ALLOWED >= 101302) || \
+ (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000) || \
+ (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 110000) || \
+ (TARGET_OS_WATCH && __WATCH_OS_VERSION_MAX_ALLOWED >= 40000)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpartial-availability"
+
+ /* Handle ALPN data */
+ if (alp != NULL) {
+ if (SSLCopyALPNProtocols != NULL) {
+ CFArrayRef alpnArray = NULL;
+ OSStatus res = SSLCopyALPNProtocols(sys->p_context, &alpnArray);
+ if (res == noErr && alpnArray) {
+ *alp = CFArrayALPNCopyFirst(alpnArray);
+ if (unlikely(*alp == NULL))
+ return -1;
+ } else {
+ *alp = NULL;
+ }
+ } else {
+ *alp = NULL;
+ }
+ }
+
+#pragma clang diagnostic pop
+#else
+
+ /* No ALPN support */
if (alp != NULL) {
*alp = NULL;
}
+#endif
+
if (retValue == errSSLWouldBlock) {
msg_Dbg(crd, "handshake is blocked, try again later");
return 1 + (sys->b_blocking_send ? 1 : 0);
@@ -646,11 +753,6 @@ error:
static vlc_tls_t *st_ClientSessionOpen(vlc_tls_creds_t *crd, vlc_tls_t *sock,
const char *hostname, const char *const *alpn)
{
- if (alpn != NULL) {
- msg_Warn(crd, "Ignoring ALPN request due to lack of support in the backend. Proxy behavior potentially undefined.");
-#warning ALPN support missing, proxy behavior potentially undefined (rdar://29127318, #17721)
- }
-
msg_Dbg(crd, "open TLS session for %s", hostname);
vlc_tls_t *tls = st_SessionOpenCommon(crd, sock, false);
@@ -665,6 +767,47 @@ static vlc_tls_t *st_ClientSessionOpen(vlc_tls_creds_t *crd, vlc_tls_t *sock,
goto error;
}
+// Only try to use ALPN on recent enough SDKs
+// macOS 10.13.2, iOS 11, tvOS 11, watchOS 4
+#if (TARGET_OS_OSX && MAC_OS_X_VERSION_MAX_ALLOWED >= 101302) || \
+ (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000) || \
+ (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 110000) || \
+ (TARGET_OS_WATCH && __WATCH_OS_VERSION_MAX_ALLOWED >= 40000)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpartial-availability"
+
+ /* Handle ALPN */
+ if (alpn != NULL) {
+ if (SSLSetALPNProtocols != NULL) {
+ CFMutableArrayRef alpnValues = alpnToCFArray(alpn);
+
+ if (alpnValues == NULL) {
+ msg_Err(crd, "cannot create CFMutableArray for ALPN values");
+ goto error;
+ }
+
+ OSStatus ret = SSLSetALPNProtocols(sys->p_context, alpnValues);
+ if (ret != noErr){
+ msg_Err(crd, "failed setting ALPN protocols (%i)", ret);
+ }
+ CFRelease(alpnValues);
+ } else {
+ msg_Warn(crd, "Ignoring ALPN request due to lack of support in the backend. Proxy behavior potentially undefined.");
+ }
+ }
+
+#pragma clang diagnostic pop
+#else
+
+ /* No ALPN support */
+ if (alpn != NULL) {
+ // Fallback if SDK does not has SSLSetALPNProtocols
+ msg_Warn(crd, "Compiled in SDK without ALPN support. Proxy behavior potentially undefined.");
+ #warning ALPN support in your SDK version missing (need 10.13.2), proxy behavior potentially undefined (rdar://29127318, #17721)
+ }
+
+#endif
+
/* disable automatic validation. We do so manually to also handle invalid
certificates */
More information about the vlc-commits
mailing list