Tested the latest version of your patch and now the configure autodetection works properly. I tested it on a few https streams and it works great, thank you!
On Wed, May 20, 2015 at 2:29 PM, Rodger Combs <rodger.co...@gmail.com> wrote: > --- > configure | 10 +- > libavformat/tls.c | 307 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 316 insertions(+), 1 deletion(-) > > diff --git a/configure b/configure > index a02fe4a..d4429f1 100755 > --- a/configure > +++ b/configure > @@ -274,6 +274,8 @@ External library support: > --enable-openssl enable openssl, needed for https support > if gnutls is not used [no] > --disable-sdl disable sdl [autodetect] > + --disable-securetransport disable Secure Transport, needed for TLS > support > + on OSX if openssl and gnutls are not used > [autodetect] > --enable-x11grab enable X11 grabbing (legacy) [no] > --disable-xlib disable xlib [autodetect] > --disable-zlib disable zlib [autodetect] > @@ -1422,6 +1424,7 @@ EXTERNAL_LIBRARY_LIST=" > opengl > openssl > sdl > + securetransport > x11grab > xlib > zlib > @@ -2617,7 +2620,7 @@ sctp_protocol_deps="struct_sctp_event_subscribe" > sctp_protocol_select="network" > srtp_protocol_select="rtp_protocol" > tcp_protocol_select="network" > -tls_protocol_deps_any="openssl gnutls" > +tls_protocol_deps_any="openssl gnutls securetransport" > tls_protocol_select="tcp_protocol" > udp_protocol_select="network" > udplite_protocol_select="network" > @@ -5185,6 +5188,11 @@ if ! disabled sdl; then > fi > enabled sdl && add_cflags $sdl_cflags && add_extralibs $sdl_libs > > +{ enabled openssl || enabled gnutls; } && disable securetransport > + > +disabled securetransport || check_lib2 Security/SecureTransport.h > SSLCreateContext "-Wl,-framework,CoreFoundation -Wl,-framework,Security" && > + enable securetransport > + > makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable > makeinfo > enabled makeinfo && (makeinfo --version | \ > grep -q 'makeinfo (GNU texinfo) 5' > /dev/null 2>&1) > \ > diff --git a/libavformat/tls.c b/libavformat/tls.c > index 2a415c9..70596f8 100644 > --- a/libavformat/tls.c > +++ b/libavformat/tls.c > @@ -52,7 +52,26 @@ > if ((c)->ctx) \ > SSL_CTX_free((c)->ctx); \ > } while (0) > +#elif CONFIG_SECURETRANSPORT > +#include "libavutil/base64.h" > +#include "libavformat/subtitles.h" > + > +#include <Security/Security.h> > +#include <Security/SecureTransport.h> > +#include <CoreFoundation/CoreFoundation.h> > +// We use a private API call here; it's good enough for WebKit. > +SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, > SecCertificateRef certificate, SecKeyRef privateKey); > + > +#define ioErr -36 > +#define TLS_shutdown(c) SSLClose((c)->ssl_context) > +#define TLS_free(c) do { \ > + if ((c)->ssl_context) \ > + CFRelease((c)->ssl_context); \ > + if ((c)->ca_array) \ > + CFRelease((c)->ca_array); \ > + } while (0) > #endif > + > #if HAVE_POLL_H > #include <poll.h> > #endif > @@ -66,6 +85,10 @@ typedef struct TLSContext { > #elif CONFIG_OPENSSL > SSL_CTX *ctx; > SSL *ssl; > +#elif CONFIG_SECURETRANSPORT > + SSLContextRef ssl_context; > + CFArrayRef ca_array; > + int lastErr; > #endif > int fd; > char *ca_file; > @@ -125,6 +148,20 @@ static int do_tls_poll(URLContext *h, int ret) > av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), > NULL)); > return AVERROR(EIO); > } > +#elif CONFIG_SECURETRANSPORT > + switch (ret) { > + case errSSLWouldBlock: > + break; > + case errSSLXCertChainInvalid: > + av_log(h, AV_LOG_ERROR, "Invalid certificate chain\n"); > + return AVERROR(EIO); > + case ioErr: > + return c->lastErr; > + default: > + av_log(h, AV_LOG_ERROR, "IO Error: %i\n", ret); > + return AVERROR(EIO); > + } > + p.events = POLLIN | POLLOUT; > #endif > if (h->flags & AVIO_FLAG_NONBLOCK) > return AVERROR(EAGAIN); > @@ -163,6 +200,200 @@ static void set_options(URLContext *h, const char > *uri) > c->key_file = av_strdup(buf); > } > > +#if CONFIG_SECURETRANSPORT > +static int import_pem(URLContext *h, char *path, CFArrayRef *array) > +{ > + AVIOContext *s = NULL; > + CFDataRef data = NULL; > + int64_t ret = 0; > + char *buf = NULL; > + SecExternalFormat format = kSecFormatPEMSequence; > + SecExternalFormat type = kSecItemTypeAggregate; > + CFStringRef pathStr = CFStringCreateWithCString(NULL, path, > 0x08000100); > + if (!pathStr) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > + if ((ret = avio_open2(&s, path, AVIO_FLAG_READ, > + &h->interrupt_callback, NULL)) < 0) > + goto end; > + > + if ((ret = avio_size(s)) < 0) > + goto end; > + > + if (ret == 0) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + if (!(buf = av_malloc(ret))) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > + if ((ret = avio_read(s, buf, ret)) < 0) > + goto end; > + > + data = CFDataCreate(kCFAllocatorDefault, buf, ret); > + > + if (SecItemImport(data, pathStr, &format, &type, > + 0, NULL, NULL, array) != noErr || !array) { > + ret = AVERROR_UNKNOWN; > + goto end; > + } > + > + if (CFArrayGetCount(*array) == 0) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > +end: > + av_free(buf); > + if (pathStr) > + CFRelease(pathStr); > + if (data) > + CFRelease(data); > + if (s) > + avio_close(s); > + return ret; > +} > + > +static int load_ca(URLContext *h) > +{ > + TLSContext *c = h->priv_data; > + int ret = 0; > + CFArrayRef array = NULL; > + > + if ((ret = import_pem(h, c->ca_file, &array)) < 0) > + goto end; > + > + if (!(c->ca_array = CFRetain(array))) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > +end: > + if (array) > + CFRelease(array); > + return ret; > +} > + > +static int load_cert(URLContext *h) > +{ > + TLSContext *c = h->priv_data; > + int ret = 0; > + CFArrayRef array = NULL; > + CFArrayRef keyArray = NULL; > + SecIdentityRef id = NULL; > + CFMutableArrayRef outArray = NULL; > + > + if ((ret = import_pem(h, c->cert_file, &array)) < 0) > + goto end; > + > + if ((ret = import_pem(h, c->key_file, &keyArray)) < 0) > + goto end; > + > + if (!(id = SecIdentityCreate(kCFAllocatorDefault, > + CFArrayGetValueAtIndex(array, 0), > + CFArrayGetValueAtIndex(keyArray, 0)))) { > + ret = AVERROR_UNKNOWN; > + goto end; > + } > + > + if (!(outArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, > array))) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > + CFArraySetValueAtIndex(outArray, 0, id); > + > + SSLSetCertificate(c->ssl_context, outArray); > + > +end: > + if (array) > + CFRelease(array); > + if (keyArray) > + CFRelease(keyArray); > + if (outArray) > + CFRelease(outArray); > + if (id) > + CFRelease(id); > + return ret; > +} > + > +static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, > size_t *dataLength) > +{ > + URLContext *h = (URLContext*)connection; > + TLSContext *c = h->priv_data; > + int read = ffurl_read_complete(c->tcp, data, *dataLength); > + if (read <= 0) { > + *dataLength = 0; > + switch(AVUNERROR(read)) { > + case ENOENT: > + case 0: > + return errSSLClosedGraceful; > + case ECONNRESET: > + return errSSLClosedAbort; > + case EAGAIN: > + return errSSLWouldBlock; > + default: > + c->lastErr = read; > + return ioErr; > + } > + } else { > + *dataLength = read; > + return noErr; > + } > +} > + > +static OSStatus tls_write_cb(SSLConnectionRef connection, const void > *data, size_t *dataLength) > +{ > + URLContext *h = (URLContext*)connection; > + TLSContext *c = h->priv_data; > + int written = ffurl_write(c->tcp, data, *dataLength); > + if (written <= 0) { > + *dataLength = 0; > + switch(AVUNERROR(written)) { > + case EAGAIN: > + return errSSLWouldBlock; > + default: > + c->lastErr = read; > + return ioErr; > + } > + } else { > + *dataLength = written; > + return noErr; > + } > +} > + > +static int TLS_read(TLSContext *c, uint8_t *buf, int size) > +{ > + size_t processed; > + OSStatus status = SSLRead(c->ssl_context, buf, size, &processed); > + switch (status) { > + case noErr: > + return processed; > + case errSSLClosedGraceful: > + case errSSLClosedNoNotify: > + return 0; > + default: > + return (int)status; > + } > +} > +static int TLS_write(TLSContext *c, const uint8_t *buf, int size) > +{ > + size_t processed; > + OSStatus status = SSLWrite(c->ssl_context, buf, size, &processed); > + switch (status) { > + case noErr: > + return processed; > + default: > + return (int)status; > + } > +} > +#endif > + > static int tls_open(URLContext *h, const char *uri, int flags, > AVDictionary **options) > { > TLSContext *c = h->priv_data; > @@ -343,6 +574,82 @@ static int tls_open(URLContext *h, const char *uri, > int flags, AVDictionary **op > if ((ret = do_tls_poll(h, ret)) < 0) > goto fail; > } > +#elif CONFIG_SECURETRANSPORT > + #define CHECK_ERROR(func, ...) do { \ > + OSStatus status = func(__VA_ARGS__); \ > + if (status != noErr) { \ > + ret = AVERROR_UNKNOWN; \ > + av_log(h, AV_LOG_ERROR, #func ": Error %i\n", (int)status); \ > + goto fail; \ > + } \ > + } while (0) > + c->ssl_context = SSLCreateContext(NULL, c->listen ? kSSLServerSide : > kSSLClientSide, kSSLStreamType); > + if (!c->ssl_context) { > + av_log(h, AV_LOG_ERROR, "Unable to create SSL context\n"); > + ret = AVERROR(ENOMEM); > + goto fail; > + } > + set_options(h, uri); > + if (c->ca_file) { > + if ((ret = load_ca(h)) < 0) > + goto fail; > + CHECK_ERROR(SSLSetSessionOption, c->ssl_context, > kSSLSessionOptionBreakOnServerAuth, true); > + } > + if (c->cert_file) > + if ((ret = load_cert(h)) < 0) > + goto fail; > + if (c->verify) > + CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, host, > strlen(host)); > + CHECK_ERROR(SSLSetIOFuncs, c->ssl_context, tls_read_cb, tls_write_cb); > + CHECK_ERROR(SSLSetConnection, c->ssl_context, h); > + while (1) { > + OSStatus status = SSLHandshake(c->ssl_context); > + if (status == errSSLServerAuthCompleted) { > + SecTrustRef peerTrust; > + SecTrustResultType trustResult; > + if (!c->verify) > + continue; > + > + if (SSLCopyPeerTrust(c->ssl_context, &peerTrust) != noErr) { > + ret = AVERROR(ENOMEM); > + goto fail; > + } > + > + if (SecTrustSetAnchorCertificates(peerTrust, c->ca_array) != > noErr) { > + ret = AVERROR_UNKNOWN; > + goto fail; > + } > + > + if (SecTrustEvaluate(peerTrust, &trustResult) != noErr) { > + ret = AVERROR_UNKNOWN; > + goto fail; > + } > + > + if (trustResult == kSecTrustResultProceed || > + trustResult == kSecTrustResultUnspecified) { > + // certificate is trusted > + status = errSSLWouldBlock; // so we call SSLHandshake > again > + } else if (trustResult == > kSecTrustResultRecoverableTrustFailure) { > + // not trusted, for some reason other than being expired > + status = errSSLXCertChainInvalid; > + } else { > + // cannot use this certificate (fatal) > + status = errSSLBadCert; > + } > + > + if (peerTrust) > + CFRelease(peerTrust); > + } > + if (status == noErr) > + break; > + if (status != errSSLWouldBlock) { > + av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: > %i\n", (int)status); > + ret = AVERROR(EIO); > + goto fail; > + } > + if ((ret = do_tls_poll(h, status)) < 0) > + goto fail; > + } > #endif > return 0; > fail: > -- > 2.3.5 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel