Advertisement
Guest User

Untitled

a guest
Oct 4th, 2015
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.98 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
  8.  * License 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 GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 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.    
  58.     uint8_t *dec_buf;
  59.     int dec_buf_size;
  60.     int dec_buf_offset;
  61.    
  62.     SecPkgContext_StreamSizes Sizes;
  63.    
  64.     int connection_closed;
  65.     int sspi_close_notify;
  66. } TLSContext;
  67.  
  68. static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
  69.                           void *BufDataPtr, unsigned long BufByteSize)
  70. {
  71.     buffer->cbBuffer   = BufByteSize;
  72.     buffer->BufferType = BufType;
  73.     buffer->pvBuffer   = BufDataPtr;
  74. }
  75.  
  76. static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
  77.                               unsigned long NumArrElem)
  78. {
  79.     desc->ulVersion = SECBUFFER_VERSION;
  80.     desc->pBuffers = BufArr;
  81.     desc->cBuffers = NumArrElem;
  82. }
  83.  
  84. static int tls_client_handshake_loop(URLContext *h, int initial)
  85. {
  86.     TLSContext *c = h->priv_data;
  87.     TLSShared *s = &c->tls_shared;
  88.     SECURITY_STATUS sspi_ret = SEC_I_CONTINUE_NEEDED;
  89.     SecBuffer outbuf[3];
  90.     SecBufferDesc outbuf_desc;
  91.     SecBuffer inbuf[2];
  92.     SecBufferDesc inbuf_desc;
  93.     int i, ret = 0, read_data = initial;
  94.  
  95.     if (c->enc_buf == NULL) {
  96.         c->enc_buf_offset = 0;
  97.         c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
  98.         ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
  99.         if (ret < 0)
  100.             goto fail;
  101.     }
  102.    
  103.     if (c->dec_buf == NULL) {
  104.         c->dec_buf_offset = 0;
  105.         c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
  106.         ret = av_reallocp(&c->dec_buf, c->dec_buf_size);
  107.         if (ret < 0)
  108.             goto fail;
  109.     }
  110.  
  111.     while (1)
  112.     {
  113.         if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {
  114.             c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
  115.             ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
  116.             if (ret < 0)
  117.                 goto fail;
  118.         }
  119.  
  120.         if (read_data) {
  121.             ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
  122.             if (ret < 0) {
  123.                 av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");
  124.                 goto fail;
  125.             }
  126.             c->enc_buf_offset += ret;
  127.         }
  128.  
  129.         /* input buffers */
  130.         InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);
  131.         InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
  132.         InitSecBufferDesc(&inbuf_desc, inbuf, 2);
  133.  
  134.         if (inbuf[0].pvBuffer == NULL) {
  135.             av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n");
  136.             ret = AVERROR(ENOMEM);
  137.             goto fail;
  138.         }
  139.  
  140.         memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset);
  141.  
  142.         /* output buffers */
  143.         InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
  144.         InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
  145.         InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
  146.         InitSecBufferDesc(&outbuf_desc, outbuf, 3);
  147.  
  148.         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);
  149.         av_freep(&inbuf[0].pvBuffer);
  150.  
  151.         if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
  152.             av_log(h, AV_LOG_DEBUG, "Received incomplete handshake, need more data\n");
  153.             read_data = 1;
  154.             continue;
  155.         }
  156.  
  157.         /* remote requests a client certificate - attempt to continue without one anyway */
  158.         if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&
  159.             !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
  160.             av_log(h, AV_LOG_VERBOSE, "Client certificate has been requested, ignoring\n");
  161.             c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
  162.             read_data = 0;
  163.             continue;
  164.         }
  165.  
  166.         /* continue handshake */
  167.         if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_E_OK) {
  168.             for(i = 0; i < 3; i++) {
  169.                 if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
  170.                     ret = ffurl_write(c->tls_shared.tcp, outbuf[i].pvBuffer, outbuf[i].cbBuffer);
  171.                     if (ret < 0 || ret != outbuf[i].cbBuffer) {
  172.                         av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");
  173.                         ret = AVERROR(EIO);
  174.                         goto fail;
  175.                     }
  176.                 }
  177.  
  178.                 if (outbuf[i].pvBuffer != NULL) {
  179.                     FreeContextBuffer(outbuf[i].pvBuffer);
  180.                     outbuf[i].pvBuffer = NULL;
  181.                 }
  182.             }
  183.         } else {
  184.             if (sspi_ret == SEC_E_WRONG_PRINCIPAL)
  185.                 av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n");
  186.             else
  187.                 av_log(h, AV_LOG_ERROR, "Creating security context failed (%ld)\n", sspi_ret);
  188.             ret = AVERROR_UNKNOWN;
  189.             goto fail;
  190.         }
  191.  
  192.         if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
  193.             if (c->enc_buf_offset > inbuf[1].cbBuffer) {
  194.                 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer);
  195.                 c->enc_buf_offset = inbuf[1].cbBuffer;
  196.                 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
  197.                     read_data = 0;
  198.                     continue;
  199.                 }
  200.             }
  201.         } else {
  202.             c->enc_buf_offset  = 0;
  203.         }
  204.  
  205.         if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
  206.             read_data = 1;
  207.             continue;
  208.         }
  209.  
  210.         break;
  211.     }
  212.  
  213.     return 0;
  214.  
  215. fail:
  216.     /* free any remaining output data */
  217.     for(i = 0; i < 3; i++) {
  218.         if (outbuf[i].pvBuffer != NULL) {
  219.             FreeContextBuffer(outbuf[i].pvBuffer);
  220.             outbuf[i].pvBuffer = NULL;
  221.         }
  222.     }
  223.  
  224.     return ret;
  225. }
  226.  
  227. static int tls_client_handshake(URLContext *h)
  228. {
  229.     TLSContext *c = h->priv_data;
  230.     TLSShared *s = &c->tls_shared;
  231.     SecBuffer outbuf;
  232.     SecBufferDesc outbuf_desc;
  233.     SECURITY_STATUS sspi_ret;
  234.     int ret;
  235.  
  236.     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
  237.     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
  238.  
  239.     c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
  240.                        ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
  241.                        ISC_REQ_STREAM;
  242.  
  243.     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);
  244.     if(sspi_ret != SEC_I_CONTINUE_NEEDED) {
  245.         av_log(h, AV_LOG_ERROR, "Unable to create initial security context (%ld)\n", sspi_ret);
  246.         ret = AVERROR_UNKNOWN;
  247.         goto fail;
  248.     }
  249.  
  250.     ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);
  251.     FreeContextBuffer(outbuf.pvBuffer);
  252.     if (ret < 0 || ret != outbuf.cbBuffer) {
  253.         av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n");
  254.         ret = AVERROR(EIO);
  255.         goto fail;
  256.     }
  257.  
  258.     return tls_client_handshake_loop(h, 1);
  259.  
  260. fail:
  261.     DeleteSecurityContext(&c->ctxt_handle);
  262.     return ret;
  263. }
  264.  
  265. static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
  266. {
  267.     TLSContext *c = h->priv_data;
  268.     TLSShared *s = &c->tls_shared;
  269.     SECURITY_STATUS sspi_ret;
  270.     SCHANNEL_CRED schannel_cred;
  271.     int ret;
  272.  
  273.     if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
  274.         goto fail;
  275.  
  276.     if (s->listen) {
  277.         av_log(h, AV_LOG_ERROR, "TLS Listen Sockets are not supported\n");
  278.         ret = -1;
  279.         goto fail;
  280.     }
  281.  
  282.     /* SChannel Options */
  283.     memset(&schannel_cred, 0, sizeof(schannel_cred));
  284.     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
  285.  
  286.     if (s->verify)
  287.         schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_REVOCATION_CHECK_CHAIN;
  288.     else
  289.         schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE;
  290.  
  291.     /* Get credential handle */
  292.     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);
  293.     if (sspi_ret != SEC_E_OK) {
  294.         av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (%ld)\n", sspi_ret);
  295.         ret = AVERROR_UNKNOWN;
  296.         goto fail;
  297.     }
  298.  
  299.     ret = tls_client_handshake(h);
  300.     if (ret < 0)
  301.         goto fail;
  302.  
  303.     return 0;
  304.  
  305. fail:
  306.     FreeCredentialsHandle(&c->cred_handle);
  307.     return ret;
  308. }
  309.  
  310. static int tls_close(URLContext *h)
  311. {
  312.     TLSContext *c = h->priv_data;
  313.  
  314.     DeleteSecurityContext(&c->ctxt_handle);
  315.     FreeCredentialsHandle(&c->cred_handle);
  316.  
  317.     av_freep(&c->enc_buf);
  318.  
  319.     if (c->tls_shared.tcp)
  320.         ffurl_close(c->tls_shared.tcp);
  321.     return 0;
  322. }
  323.  
  324. static int tls_read(URLContext *h, uint8_t *buf, int len)
  325. {
  326.     TLSContext *c = h->priv_data;
  327.     TLSShared *s = &c->tls_shared;
  328.     SECURITY_STATUS sspi_ret = SEC_E_OK;
  329.     SecBuffer inbuf[4];
  330.     SecBufferDesc inbuf_desc;
  331.     int size, ret;
  332.     int min_enc_buf_size = len + SCHANNEL_FREE_BUFFER_SIZE;
  333.    
  334.     if (len && len <= c->dec_buf_offset)
  335.         goto cleanup;
  336.    
  337.     if (c->sspi_close_notify)
  338.         goto cleanup;
  339.    
  340.     if (!c->connection_closed) {
  341.         size = c->enc_buf_size - c->enc_buf_offset;
  342.         if (size < SCHANNEL_FREE_BUFFER_SIZE || c->enc_buf_size < min_enc_buf_size) {
  343.             c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
  344.             if (c->enc_buf_size < min_enc_buf_size)
  345.                 c->enc_buf_size = min_enc_buf_size;
  346.             ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
  347.             if (ret < 0)
  348.                 goto fail;
  349.         }
  350.        
  351.         ret = ffurl_read(s->tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
  352.         if (ret < 0) {
  353.             av_log(h, AV_LOG_ERROR, "Unable to read from socket\n");
  354.             goto fail;
  355.         } else if (ret == 0)
  356.             c->connection_closed = 1;
  357.        
  358.         c->enc_buf_offset += ret;
  359.     }
  360.    
  361.     while (c->enc_buf_offset > 0 && sspi_ret == SEC_E_OK && (!len || c->dec_buf_offset < len || c->connection_closed)) {
  362.         /*  input buffer */
  363.         InitSecBuffer(&inbuf[0], SECBUFFER_DATA, c->enc_buf, c->enc_buf_offset);
  364.  
  365.         /* additional buffers for possible output */
  366.         InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
  367.         InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
  368.         InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
  369.         InitSecBufferDesc(&inbuf_desc, inbuf, 4);
  370.        
  371.         sspi_ret = DecryptMessage(&c->ctxt_handle, &inbuf_desc, 0, NULL);
  372.         if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_RENEGOTIATE || sspi_ret == SEC_I_CONTEXT_EXPIRED) {
  373.             /* handle decrypted data */
  374.             if (inbuf[1].BufferType == SECBUFFER_DATA) {
  375.                 /* grow buffer if needed */
  376.                 size = inbuf[1].cbBuffer > SCHANNEL_FREE_BUFFER_SIZE ? inbuf[1].cbBuffer : SCHANNEL_FREE_BUFFER_SIZE;
  377.                 if (c->dec_buf_size - c->dec_buf_offset < size || c->dec_buf_size < len)  {
  378.                     c->dec_buf_size = c->dec_buf_offset + size;
  379.                     if (c->dec_buf_size < len)
  380.                         c->dec_buf_size = len;
  381.                     ret = av_reallocp(&c->dec_buf, c->dec_buf_size);
  382.                     if (ret < 0)
  383.                         goto fail;
  384.                 }
  385.                
  386.                 /* copy decrypted data to buffer */
  387.                 size = inbuf[1].cbBuffer;
  388.                 if (size) {
  389.                     memcpy(c->dec_buf + c->dec_buf_offset, inbuf[1].pvBuffer, size);
  390.                     c->dec_buf_offset += size;
  391.                 }
  392.             }
  393.             if (inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
  394.                 if (c->enc_buf_offset > inbuf[3].cbBuffer) {
  395.                     memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[3].cbBuffer, inbuf[3].cbBuffer);
  396.                     c->enc_buf_offset = inbuf[3].cbBuffer;
  397.                 }
  398.             } else
  399.                 c->enc_buf_offset = 0;
  400.            
  401.             if (sspi_ret == SEC_I_RENEGOTIATE) {
  402.                 if (c->enc_buf_offset) {
  403.                     av_log(h, AV_LOG_ERROR, "Cannot renegotiate, encrypted data buffer not empty\n");
  404.                     ret = AVERROR_UNKNOWN;
  405.                     goto cleanup;
  406.                 }
  407.                
  408.                 av_log(h, AV_LOG_VERBOSE, "Re-negotiating security context\n");
  409.                 ret = tls_client_handshake_loop(h, 0);
  410.                 if (ret < 0) {
  411.                     goto cleanup;
  412.                 }
  413.                 sspi_ret = SEC_E_OK;
  414.                 continue;
  415.             } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) {
  416.                 c->sspi_close_notify = 1;
  417.                 if (!c->connection_closed) {
  418.                     c->connection_closed = 1;
  419.                     av_log(h, AV_LOG_VERBOSE, "Server closed the connection\n");
  420.                 }
  421.                 ret = 0;
  422.                 goto cleanup;
  423.             }
  424.         } else if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
  425.             ret = AVERROR(EAGAIN);
  426.             goto cleanup;
  427.         } else {
  428.             av_log(h, AV_LOG_ERROR, "Unable to decrypt message\n");
  429.             ret = AVERROR(EIO);
  430.             goto cleanup;
  431.         }
  432.     }
  433.    
  434.     ret = 0;
  435.    
  436. cleanup:
  437.     size = len < c->dec_buf_offset ? len : c->dec_buf_offset;
  438.     if (size) {
  439.         memcpy(buf, c->dec_buf, size);
  440.         memmove(c->dec_buf, c->dec_buf + size, c->dec_buf_offset - size);
  441.         c->dec_buf_offset -= size;
  442.        
  443.         return size;
  444.     }
  445.    
  446.     if (ret == 0 && !c->connection_closed)
  447.         ret = AVERROR(EAGAIN);
  448.    
  449.     return ret < 0 ? ret : 0;
  450.    
  451. fail:
  452.     return -1;
  453. }
  454.  
  455. static int tls_write(URLContext *h, const uint8_t *buf, int len)
  456. {
  457.     TLSContext *c = h->priv_data;
  458.     TLSShared *s = &c->tls_shared;
  459.     SECURITY_STATUS sspi_ret;
  460.     int ret, data_size;
  461.     uint8_t *data = NULL;
  462.     SecBuffer outbuf[4];
  463.     SecBufferDesc outbuf_desc;
  464.    
  465.     if (c->Sizes.cbMaximumMessage == 0) {
  466.         sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->Sizes);
  467.         if (sspi_ret != SEC_E_OK)
  468.             return AVERROR_UNKNOWN;
  469.     }
  470.    
  471.     if (len > c->Sizes.cbMaximumMessage) {
  472.         av_log(h, AV_LOG_ERROR, "Message exceeds max message size\n");
  473.         return AVERROR(EIO);
  474.     }
  475.    
  476.     data_size = c->Sizes.cbHeader + len + c->Sizes.cbTrailer;
  477.     data = av_malloc(data_size);
  478.     if (data == NULL)
  479.         return AVERROR(ENOMEM);
  480.    
  481.     InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
  482.                   data, c->Sizes.cbHeader);
  483.     InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
  484.                   data + c->Sizes.cbHeader, len);
  485.     InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
  486.                   data + c->Sizes.cbHeader + len,
  487.                   c->Sizes.cbTrailer);
  488.     InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
  489.     InitSecBufferDesc(&outbuf_desc, outbuf, 4);
  490.    
  491.     memcpy(outbuf[1].pvBuffer, buf, len);
  492.    
  493.     sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0);
  494.     if (sspi_ret == SEC_E_OK)  {
  495.         len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
  496.         ret = ffurl_write(s->tcp, data, len);
  497.         if (ret < 0 || ret != len) {
  498.             ret = AVERROR(EIO);
  499.             av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n");
  500.             goto fail;
  501.         }
  502.     } else {
  503.         av_log(h, AV_LOG_ERROR, "Encrypting data failed\n");
  504.         if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY)
  505.             ret = AVERROR(ENOMEM);
  506.         else
  507.             ret = AVERROR(EIO);
  508.         goto fail;
  509.     }
  510.  
  511.     av_freep(&data);
  512.     return outbuf[1].cbBuffer;
  513.  
  514. fail:
  515.     av_freep(&data);
  516.     return ret;
  517. }
  518.  
  519. static const AVOption options[] = {
  520.     TLS_COMMON_OPTIONS(TLSContext, tls_shared),
  521.     { NULL }
  522. };
  523.  
  524. static const AVClass tls_class = {
  525.     .class_name = "tls",
  526.     .item_name  = av_default_item_name,
  527.     .option     = options,
  528.     .version    = LIBAVUTIL_VERSION_INT,
  529. };
  530.  
  531. URLProtocol ff_tls_schannel_protocol = {
  532.     .name           = "tls",
  533.     .url_open2      = tls_open,
  534.     .url_read       = tls_read,
  535.     .url_write      = tls_write,
  536.     .url_close      = tls_close,
  537.     .priv_data_size = sizeof(TLSContext),
  538.     .flags          = URL_PROTOCOL_FLAG_NETWORK,
  539.     .priv_data_class = &tls_class,
  540. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement