[vlc-devel] [PATCH] securetransport: Add ALPN support
Thomas Guillem
thomas at gllm.fr
Fri Apr 6 11:18:58 CEST 2018
Pushed after checking the SSLCopyALPNProtocols symbol availability too.
On Thu, Apr 5, 2018, at 20:32, Marvin Scholz wrote:
> ---
>
> This new version adds _SSLCopyALPNProtocols and _SSLSetALPNProtocols
> to symbols that are allowed to be undefined. This will not be a
> problem as those are weak-linked (given that we target 10.10) and
> explicitly checked in the code for availability.
>
> ---
> modules/misc/Makefile.am | 1 +
> modules/misc/securetransport.c | 149 +++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 145 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..11bb43228d 100644
> --- a/modules/misc/securetransport.c
> +++ b/modules/misc/securetransport.c
> @@ -40,6 +40,80 @@
> # define ioErr -36
> #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
>
> *****************************************************************************/
> @@ -393,10 +467,39 @@ 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) {
> + 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;
> + }
> + }
> +
> +#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 +749,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 +763,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 */
>
> --
> 2.14.3 (Apple Git-98)
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list