Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2015 Rodger Combs
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public License
  8.  * as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public License
  17.  * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
  18.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. #include <errno.h>
  22.  
  23.  
  24. #include "avformat.h"
  25. #include "internal.h"
  26. #include "network.h"
  27. #include "os_support.h"
  28. #include "url.h"
  29. #include "tls.h"
  30. #include "libavcodec/internal.h"
  31. #include "libavutil/avstring.h"
  32. #include "libavutil/opt.h"
  33. #include "libavutil/parseutils.h"
  34.  
  35. #include <Security/Security.h>
  36. #include <Security/SecureTransport.h>
  37. #include <CoreFoundation/CoreFoundation.h>
  38.  
  39. // We use a private API call here; it's good enough for WebKit.
  40. SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey);
  41. #define ioErr -36
  42.  
  43. typedef struct TLSContext {
  44.     const AVClass *class;
  45.     TLSShared tls_shared;
  46.     SSLContextRef ssl_context;
  47.     CFArrayRef ca_array;
  48.     int lastErr;
  49. } TLSContext;
  50.  
  51. static int print_tls_error(URLContext *h, int ret)
  52. {
  53.     TLSContext *c = h->priv_data;
  54.     switch (ret) {
  55.     case errSSLWouldBlock:
  56.         break;
  57.     case errSSLXCertChainInvalid:
  58.         av_log(h, AV_LOG_ERROR, "Invalid certificate chain\n");
  59.         return AVERROR(EIO);
  60.     case ioErr:
  61.         return c->lastErr;
  62.     default:
  63.         av_log(h, AV_LOG_ERROR, "IO Error: %i\n", ret);
  64.         return AVERROR(EIO);
  65.     }
  66.     return AVERROR(EIO);
  67. }
  68.  
  69. static int import_pem(URLContext *h, char *path, CFArrayRef *array)
  70. {
  71.     AVIOContext *s = NULL;
  72.     CFDataRef data = NULL;
  73.     int64_t ret = 0;
  74.     char *buf = NULL;
  75.     SecExternalFormat format = kSecFormatPEMSequence;
  76.     SecExternalFormat type = kSecItemTypeAggregate;
  77.     CFStringRef pathStr = CFStringCreateWithCString(NULL, path, 0x08000100);
  78.     if (!pathStr) {
  79.         ret = AVERROR(ENOMEM);
  80.         goto end;
  81.     }
  82.  
  83.     if ((ret = avio_open2(&s, path, AVIO_FLAG_READ,
  84.                           &h->interrupt_callback, NULL)) < 0)
  85.         goto end;
  86.  
  87.     if ((ret = avio_size(s)) < 0)
  88.         goto end;
  89.  
  90.     if (ret == 0) {
  91.         ret = AVERROR_INVALIDDATA;
  92.         goto end;
  93.     }
  94.  
  95.     if (!(buf = av_malloc(ret))) {
  96.         ret = AVERROR(ENOMEM);
  97.         goto end;
  98.     }
  99.  
  100.     if ((ret = avio_read(s, buf, ret)) < 0)
  101.         goto end;
  102.  
  103.     data = CFDataCreate(kCFAllocatorDefault, buf, ret);
  104.  
  105.     if (SecItemImport(data, pathStr, &format, &type,
  106.                       0, NULL, NULL, array) != noErr || !array) {
  107.         ret = AVERROR_UNKNOWN;
  108.         goto end;
  109.     }
  110.  
  111.     if (CFArrayGetCount(*array) == 0) {
  112.         ret = AVERROR_INVALIDDATA;
  113.         goto end;
  114.     }
  115.  
  116. end:
  117.     av_free(buf);
  118.     if (pathStr)
  119.         CFRelease(pathStr);
  120.     if (data)
  121.         CFRelease(data);
  122.     if (s)
  123.         avio_close(s);
  124.     return ret;
  125. }
  126.  
  127. static int load_ca(URLContext *h)
  128. {
  129.     TLSContext *c = h->priv_data;
  130.     int ret = 0;
  131.     CFArrayRef array = NULL;
  132.  
  133.     if ((ret = import_pem(h, c->tls_shared.ca_file, &array)) < 0)
  134.         goto end;
  135.  
  136.     if (!(c->ca_array = CFRetain(array))) {
  137.         ret = AVERROR(ENOMEM);
  138.         goto end;
  139.     }
  140.  
  141. end:
  142.     if (array)
  143.         CFRelease(array);
  144.     return ret;
  145. }
  146.  
  147. static int load_cert(URLContext *h)
  148. {
  149.     TLSContext *c = h->priv_data;
  150.     int ret = 0;
  151.     CFArrayRef certArray = NULL;
  152.     CFArrayRef keyArray = NULL;
  153.     SecIdentityRef id = NULL;
  154.     CFMutableArrayRef outArray = NULL;
  155.  
  156.     if ((ret = import_pem(h, c->tls_shared.cert_file, &certArray)) < 0)
  157.         goto end;
  158.  
  159.     if ((ret = import_pem(h, c->tls_shared.key_file, &keyArray)) < 0)
  160.         goto end;
  161.  
  162.     if (!(id = SecIdentityCreate(kCFAllocatorDefault,
  163.                                  (SecCertificateRef)CFArrayGetValueAtIndex(certArray, 0),
  164.                                  (SecKeyRef)CFArrayGetValueAtIndex(keyArray, 0)))) {
  165.         ret = AVERROR_UNKNOWN;
  166.         goto end;
  167.     }
  168.  
  169.     if (!(outArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, certArray))) {
  170.         ret = AVERROR(ENOMEM);
  171.         goto end;
  172.     }
  173.  
  174.     CFArraySetValueAtIndex(outArray, 0, id);
  175.  
  176.     SSLSetCertificate(c->ssl_context, outArray);
  177.  
  178. end:
  179.     if (certArray)
  180.         CFRelease(certArray);
  181.     if (keyArray)
  182.         CFRelease(keyArray);
  183.     if (outArray)
  184.         CFRelease(outArray);
  185.     if (id)
  186.         CFRelease(id);
  187.     return ret;
  188. }
  189.  
  190. static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dataLength)
  191. {
  192.     URLContext *h = (URLContext*)connection;
  193.     TLSContext *c = h->priv_data;
  194.     int read = ffurl_read_complete(c->tls_shared.tcp, data, *dataLength);
  195.     if (read <= 0) {
  196.         *dataLength = 0;
  197.         switch(AVUNERROR(read)) {
  198.             case ENOENT:
  199.             case 0:
  200.                 return errSSLClosedGraceful;
  201.             case ECONNRESET:
  202.                 return errSSLClosedAbort;
  203.             case EAGAIN:
  204.                 return errSSLWouldBlock;
  205.             default:
  206.                 c->lastErr = read;
  207.                 return ioErr;
  208.         }
  209.     } else {
  210.         *dataLength = read;
  211.         return noErr;
  212.     }
  213. }
  214.  
  215. static OSStatus tls_write_cb(SSLConnectionRef connection, const void *data, size_t *dataLength)
  216. {
  217.     URLContext *h = (URLContext*)connection;
  218.     TLSContext *c = h->priv_data;
  219.     int written = ffurl_write(c->tls_shared.tcp, data, *dataLength);
  220.     if (written <= 0) {
  221.         *dataLength = 0;
  222.         switch(AVUNERROR(written)) {
  223.             case EAGAIN:
  224.                 return errSSLWouldBlock;
  225.             default:
  226.                 c->lastErr = written;
  227.                 return ioErr;
  228.         }
  229.     } else {
  230.         *dataLength = written;
  231.         return noErr;
  232.     }
  233. }
  234.  
  235. static int tls_close(URLContext *h)
  236. {
  237.     TLSContext *c = h->priv_data;
  238.     if (c->ssl_context) {
  239.         SSLClose(c->ssl_context);
  240.         CFRelease(c->ssl_context);
  241.     }
  242.     if (c->ca_array)
  243.         CFRelease(c->ca_array);
  244.     if (c->tls_shared.tcp)
  245.         ffurl_close(c->tls_shared.tcp);
  246.     return 0;
  247. }
  248.  
  249. #define CHECK_ERROR(func, ...) do {                                     \
  250.         OSStatus status = func(__VA_ARGS__);                            \
  251.         if (status != noErr) {                                          \
  252.             ret = AVERROR_UNKNOWN;                                      \
  253.             av_log(h, AV_LOG_ERROR, #func ": Error %i\n", (int)status); \
  254.             goto fail;                                                  \
  255.         }                                                               \
  256.     } while (0)
  257.  
  258. static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
  259. {
  260.     TLSContext *c = h->priv_data;
  261.     TLSShared *s = &c->tls_shared;
  262.     int ret;
  263.  
  264.     if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
  265.         goto fail;
  266.  
  267.     c->ssl_context = SSLCreateContext(NULL, s->listen ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
  268.     if (!c->ssl_context) {
  269.         av_log(h, AV_LOG_ERROR, "Unable to create SSL context\n");
  270.         ret = AVERROR(ENOMEM);
  271.         goto fail;
  272.     }
  273.     if (s->ca_file) {
  274.         if ((ret = load_ca(h)) < 0)
  275.             goto fail;
  276.     }
  277.     if (s->ca_file || !s->verify)
  278.         CHECK_ERROR(SSLSetSessionOption, c->ssl_context, kSSLSessionOptionBreakOnServerAuth, true);
  279.     if (s->cert_file)
  280.         if ((ret = load_cert(h)) < 0)
  281.             goto fail;
  282.     CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, s->host, strlen(s->host));
  283.     CHECK_ERROR(SSLSetIOFuncs, c->ssl_context, tls_read_cb, tls_write_cb);
  284.     CHECK_ERROR(SSLSetConnection, c->ssl_context, h);
  285.     while (1) {
  286.         OSStatus status = SSLHandshake(c->ssl_context);
  287.         if (status == errSSLServerAuthCompleted) {
  288.             SecTrustRef peerTrust;
  289.             SecTrustResultType trustResult;
  290.             if (!s->verify)
  291.                 continue;
  292.  
  293.             if (SSLCopyPeerTrust(c->ssl_context, &peerTrust) != noErr) {
  294.                 ret = AVERROR(ENOMEM);
  295.                 goto fail;
  296.             }
  297.  
  298.             if (SecTrustSetAnchorCertificates(peerTrust, c->ca_array) != noErr) {
  299.                 ret = AVERROR_UNKNOWN;
  300.                 goto fail;
  301.             }
  302.  
  303.             if (SecTrustEvaluate(peerTrust, &trustResult) != noErr) {
  304.                 ret = AVERROR_UNKNOWN;
  305.                 goto fail;
  306.             }
  307.  
  308.             if (trustResult == kSecTrustResultProceed ||
  309.                 trustResult == kSecTrustResultUnspecified) {
  310.                 // certificate is trusted
  311.                 status = errSSLWouldBlock; // so we call SSLHandshake again
  312.             } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
  313.                 // not trusted, for some reason other than being expired
  314.                 status = errSSLXCertChainInvalid;
  315.             } else {
  316.                 // cannot use this certificate (fatal)
  317.                 status = errSSLBadCert;
  318.             }
  319.  
  320.             if (peerTrust)
  321.                 CFRelease(peerTrust);
  322.         }
  323.         if (status == noErr)
  324.             break;
  325.  
  326.         av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status);
  327.         ret = AVERROR(EIO);
  328.         goto fail;
  329.     }
  330.  
  331.     return 0;
  332. fail:
  333.     tls_close(h);
  334.     return ret;
  335. }
  336.  
  337. static int map_ssl_error(OSStatus status, size_t processed)
  338. {
  339.     switch (status) {
  340.     case noErr:
  341.         return processed;
  342.     case errSSLClosedGraceful:
  343.     case errSSLClosedNoNotify:
  344.         return 0;
  345.     default:
  346.         return (int)status;
  347.     }
  348. }
  349.  
  350. static int tls_read(URLContext *h, uint8_t *buf, int size)
  351. {
  352.     TLSContext *c = h->priv_data;
  353.     size_t processed;
  354.     int ret = map_ssl_error(SSLRead(c->ssl_context, buf, size, &processed), processed);
  355.     if (ret > 0)
  356.         return ret;
  357.     if (ret == 0)
  358.         return AVERROR_EOF;
  359.     return print_tls_error(h, ret);
  360. }
  361.  
  362. static int tls_write(URLContext *h, const uint8_t *buf, int size)
  363. {
  364.     TLSContext *c = h->priv_data;
  365.     size_t processed;
  366.     int ret = map_ssl_error(SSLWrite(c->ssl_context, buf, size, &processed), processed);
  367.     if (ret > 0)
  368.         return ret;
  369.     if (ret == 0)
  370.         return AVERROR_EOF;
  371.     return print_tls_error(h, ret);
  372. }
  373.  
  374. static const AVOption options[] = {
  375.     TLS_COMMON_OPTIONS(TLSContext, tls_shared),
  376.     { NULL }
  377. };
  378.  
  379. static const AVClass tls_class = {
  380.     .class_name = "tls",
  381.     .item_name  = av_default_item_name,
  382.     .option     = options,
  383.     .version    = LIBAVUTIL_VERSION_INT,
  384. };
  385.  
  386. URLProtocol ff_tls_securetransport_protocol = {
  387.     .name           = "tls",
  388.     .url_open2      = tls_open,
  389.     .url_read       = tls_read,
  390.     .url_write      = tls_write,
  391.     .url_close      = tls_close,
  392.     .priv_data_size = sizeof(TLSContext),
  393.     .flags          = URL_PROTOCOL_FLAG_NETWORK,
  394.     .priv_data_class = &tls_class,
  395. };
  396.