Advertisement
Guest User

Untitled

a guest
Oct 4th, 2015
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.76 KB | None | 0 0
  1. /*
  2.  * Copyright (c) 2015 Hendrik Leppkes
  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. /** Based on the CURL SChannel module */
  22.  
  23. #include "avformat.h"
  24. #include "internal.h"
  25. #include "network.h"
  26. #include "os_support.h"
  27. #include "url.h"
  28. #include "tls.h"
  29.  
  30. #define SECURITY_WIN32
  31. #include <security.h>
  32. #include <schnlsp.h>
  33.  
  34. #define SCHANNEL_INITIAL_BUFFER_SIZE   4096
  35. #define SCHANNEL_FREE_BUFFER_SIZE      1024
  36.  
  37. #ifndef SECBUFFER_ALERT
  38. #define SECBUFFER_ALERT                17
  39. #endif
  40.  
  41. typedef struct TLSContext {
  42.     const AVClass *class;
  43.     TLSShared tls_shared;
  44.    
  45.     CredHandle cred_handle;
  46.     TimeStamp cred_timestamp;
  47.    
  48.     CtxtHandle ctxt_handle;
  49.     TimeStamp ctxt_timestamp;
  50.    
  51.     ULONG request_flags;
  52.     ULONG context_flags;
  53.    
  54.     uint8_t *enc_buf;
  55.     int enc_buf_size;
  56.     int enc_buf_offset;
  57. } TLSContext;
  58.  
  59. static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
  60.                           void *BufDataPtr, unsigned long BufByteSize)
  61. {
  62.     buffer->cbBuffer   = BufByteSize;
  63.     buffer->BufferType = BufType;
  64.     buffer->pvBuffer   = BufDataPtr;
  65. }
  66.  
  67. static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
  68.                               unsigned long NumArrElem)
  69. {
  70.     desc->ulVersion = SECBUFFER_VERSION;
  71.     desc->pBuffers = BufArr;
  72.     desc->cBuffers = NumArrElem;
  73. }
  74.  
  75. static int tls_client_handshake_loop(URLContext *h, int initial)
  76. {
  77.     TLSContext *c = h->priv_data;
  78.     TLSShared *s = &c->tls_shared;
  79.     SECURITY_STATUS sspi_ret = SEC_I_CONTINUE_NEEDED;
  80.     SecBuffer outbuf[3];
  81.     SecBufferDesc outbuf_desc;
  82.     SecBuffer inbuf[2];
  83.     SecBufferDesc inbuf_desc;
  84.     int i, ret = 0, read_data = initial;
  85.    
  86.     if (c->enc_buf == NULL) {
  87.         c->enc_buf_offset = 0;
  88.         c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
  89.         ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
  90.         if (ret < 0)
  91.             goto fail;
  92.     }
  93.  
  94.     while (sspi_ret == SEC_I_CONTINUE_NEEDED ||
  95.            sspi_ret == SEC_E_INCOMPLETE_MESSAGE ||
  96.            sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS)
  97.     {
  98.         if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {
  99.             c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
  100.             ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
  101.             if (ret < 0)
  102.                 goto fail;
  103.         }
  104.        
  105.         if (read_data) {
  106.             ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
  107.             if (ret < 0) {
  108.                 av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");
  109.                 goto fail;
  110.             }
  111.             c->enc_buf_offset += ret;
  112.         }
  113.        
  114.         /* input buffers */
  115.         InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);
  116.         InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
  117.         InitSecBufferDesc(&inbuf_desc, inbuf, 2);
  118.        
  119.         if (inbuf[0].pvBuffer == NULL) {
  120.             av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n");
  121.             ret = AVERROR(ENOMEM);
  122.             goto fail;
  123.         }
  124.        
  125.         memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset);
  126.        
  127.         /* output buffers */
  128.         InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
  129.         InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
  130.         InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
  131.         InitSecBufferDesc(&outbuf_desc, outbuf, 3);
  132.        
  133.         sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
  134.         av_freep(&inbuf[0].pvBuffer);
  135.        
  136.         if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
  137.             av_log(h, AV_LOG_DEBUG, "Received incomplete handshake, need more data\n");
  138.             read_data = 1;
  139.             continue;
  140.         }
  141.        
  142.         /* remote requests a client certificate - attempt to continue without one anyway */
  143.         if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&
  144.             !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
  145.             av_log(h, AV_LOG_VERBOSE, "Client certificate has been requested, ignoring\n");
  146.             c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
  147.             read_data = 0;
  148.             continue;
  149.         }
  150.        
  151.         /* continue handshake */
  152.         if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_E_OK) {
  153.             for(i = 0; i < 3; i++) {
  154.                 if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
  155.                     ret = ffurl_write(c->tls_shared.tcp, outbuf[i].pvBuffer, outbuf[i].cbBuffer);
  156.                     if (ret < 0 || ret != outbuf[i].cbBuffer) {
  157.                         av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");
  158.                         ret = AVERROR(EIO);
  159.                         goto fail;
  160.                     }
  161.                 }
  162.                
  163.                 if (outbuf[i].pvBuffer != NULL) {
  164.                     FreeContextBuffer(outbuf[i].pvBuffer);
  165.                 }
  166.             }
  167.         } else {
  168.             if (sspi_ret == SEC_E_WRONG_PRINCIPAL)
  169.                 av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n");
  170.             else
  171.                 av_log(h, AV_LOG_ERROR, "Creating security context failed (%ld)\n", sspi_ret);
  172.             ret = AVERROR_UNKNOWN;
  173.             goto fail;
  174.         }
  175.  
  176.         if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
  177.             if (c->enc_buf_offset > inbuf[1].cbBuffer) {
  178.                 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer);
  179.                 c->enc_buf_offset = inbuf[1].cbBuffer;
  180.                 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
  181.                     read_data = 0;
  182.                     continue;
  183.                 }
  184.             }
  185.         } else {
  186.             c->enc_buf_offset  = 0;
  187.         }
  188.  
  189.         if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
  190.             read_data = 1;
  191.             continue;
  192.         }
  193.  
  194.         break;
  195.     }
  196.  
  197.     return 0;
  198.  
  199. fail:
  200.     return ret;
  201. }
  202.  
  203. static int tls_client_handshake(URLContext *h)
  204. {
  205.     TLSContext *c = h->priv_data;
  206.     TLSShared *s = &c->tls_shared;
  207.     SecBuffer outbuf;
  208.     SecBufferDesc outbuf_desc;
  209.     SECURITY_STATUS sspi_ret;
  210.     int ret;
  211.    
  212.     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
  213.     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
  214.    
  215.     c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
  216.                        ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
  217.                        ISC_REQ_STREAM;
  218.  
  219.     sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
  220.     if(sspi_ret != SEC_I_CONTINUE_NEEDED) {
  221.         av_log(h, AV_LOG_ERROR, "Unable to create initial security context (%ld)\n", sspi_ret);
  222.         ret = AVERROR_UNKNOWN;
  223.         goto fail;
  224.     }
  225.    
  226.     ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);
  227.     FreeContextBuffer(outbuf.pvBuffer);
  228.     if (ret < 0 || ret != outbuf.cbBuffer) {
  229.         av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n");
  230.         ret = AVERROR(EIO);
  231.         goto fail;
  232.     }
  233.    
  234.     return tls_client_handshake_loop(h, 1);
  235.  
  236. fail:
  237.     DeleteSecurityContext(&c->ctxt_handle);
  238.     return ret;
  239. }
  240.  
  241. static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
  242. {
  243.     TLSContext *c = h->priv_data;
  244.     TLSShared *s = &c->tls_shared;
  245.     SECURITY_STATUS sspi_ret;
  246.     SCHANNEL_CRED schannel_cred;
  247.     int ret;
  248.  
  249.     if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
  250.         goto fail;
  251.    
  252.     if (s->listen) {
  253.         av_log(h, AV_LOG_ERROR, "TLS Listen Sockets are not supported\n");
  254.         ret = -1;
  255.         goto fail;
  256.     }
  257.  
  258.     /* SChannel Options */
  259.     memset(&schannel_cred, 0, sizeof(schannel_cred));
  260.     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
  261.  
  262.     if (s->verify)
  263.         schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_REVOCATION_CHECK_CHAIN;
  264.     else
  265.         schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE;
  266.  
  267.     /* Get credential handle */
  268.     sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, s->listen ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL,  &schannel_cred, NULL, NULL, &c->cred_handle, &c->cred_timestamp);
  269.     if (sspi_ret != SEC_E_OK) {
  270.         av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (%ld)\n", sspi_ret);
  271.         ret = AVERROR_UNKNOWN;
  272.         goto fail;
  273.     }
  274.  
  275.     ret = tls_client_handshake(h);
  276.     if (ret < 0)
  277.         goto fail;
  278.    
  279.     av_log(h, AV_LOG_VERBOSE, "TLS connection established\n");
  280.     return 0;
  281.  
  282. fail:
  283.     FreeCredentialsHandle(&c->cred_handle);
  284.     return ret;
  285. }
  286.  
  287. static int tls_close(URLContext *h)
  288. {
  289.     TLSContext *c = h->priv_data;
  290.    
  291.     DeleteSecurityContext(&c->ctxt_handle);
  292.     FreeCredentialsHandle(&c->cred_handle);
  293.    
  294.     av_freep(&c->enc_buf);
  295.    
  296.     if (c->tls_shared.tcp)
  297.         ffurl_close(c->tls_shared.tcp);
  298.     return 0;
  299. }
  300.  
  301. static int tls_read(URLContext *h, uint8_t *buf, int size)
  302. {
  303.     return -1;
  304. }
  305.  
  306. static int tls_write(URLContext *h, const uint8_t *buf, int size)
  307. {
  308.     return -1;
  309. }
  310.  
  311. static const AVOption options[] = {
  312.     TLS_COMMON_OPTIONS(TLSContext, tls_shared),
  313.     { NULL }
  314. };
  315.  
  316. static const AVClass tls_class = {
  317.     .class_name = "tls",
  318.     .item_name  = av_default_item_name,
  319.     .option     = options,
  320.     .version    = LIBAVUTIL_VERSION_INT,
  321. };
  322.  
  323. URLProtocol ff_tls_schannel_protocol = {
  324.     .name           = "tls",
  325.     .url_open2      = tls_open,
  326.     .url_read       = tls_read,
  327.     .url_write      = tls_write,
  328.     .url_close      = tls_close,
  329.     .priv_data_size = sizeof(TLSContext),
  330.     .flags          = URL_PROTOCOL_FLAG_NETWORK,
  331.     .priv_data_class = &tls_class,
  332. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement