1/* 2 * TLS/SSL Protocol 3 * Copyright (c) 2011 Martin Storsjo 4 * Copyright (c) 2017 sfan5 <sfan5@live.de> 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include "avformat.h" 24#include "internal.h" 25#include "network.h" 26#include "url.h" 27#include "tls.h" 28#include "libavcodec/internal.h" 29#include "libavutil/avutil.h" 30#include "libavutil/opt.h" 31 32#include <tls.h> 33 34typedef struct TLSContext { 35 const AVClass *class; 36 TLSShared tls_shared; 37 struct tls *ctx; 38} TLSContext; 39 40static int ff_tls_close(URLContext *h) 41{ 42 TLSContext *p = h->priv_data; 43 if (p->ctx) { 44 tls_close(p->ctx); 45 tls_free(p->ctx); 46 } 47 ffurl_closep(&p->tls_shared.tcp); 48 return 0; 49} 50 51static ssize_t tls_read_callback(struct tls *ctx, void *buf, size_t buflen, void *cb_arg) 52{ 53 URLContext *h = (URLContext*) cb_arg; 54 int ret = ffurl_read(h, buf, buflen); 55 if (ret == AVERROR(EAGAIN)) 56 return TLS_WANT_POLLIN; 57 else if (ret == AVERROR_EXIT) 58 return 0; 59 return ret >= 0 ? ret : -1; 60} 61 62static ssize_t tls_write_callback(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg) 63{ 64 URLContext *h = (URLContext*) cb_arg; 65 int ret = ffurl_write(h, buf, buflen); 66 if (ret == AVERROR(EAGAIN)) 67 return TLS_WANT_POLLOUT; 68 else if (ret == AVERROR_EXIT) 69 return 0; 70 return ret >= 0 ? ret : -1; 71} 72 73static int ff_tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) 74{ 75 TLSContext *p = h->priv_data; 76 TLSShared *c = &p->tls_shared; 77 struct tls_config *cfg = NULL; 78 int ret; 79 80 if (tls_init() == -1) { 81 ret = AVERROR(EIO); 82 goto fail; 83 } 84 85 if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) 86 goto fail; 87 88 p->ctx = !c->listen ? tls_client() : tls_server(); 89 if (!p->ctx) { 90 ret = AVERROR(EIO); 91 goto fail; 92 } 93 94 cfg = tls_config_new(); 95 if (!p->ctx) { 96 ret = AVERROR(EIO); 97 goto fail; 98 } 99 if (tls_config_set_protocols(cfg, TLS_PROTOCOLS_ALL) == -1) 100 goto err_config; 101 // While TLSv1.0 and TLSv1.1 are already enabled by the above, 102 // we need to be less strict with ciphers so it works in practice. 103 if (tls_config_set_ciphers(cfg, "compat") == -1) 104 goto err_config; 105 if (c->ca_file && tls_config_set_ca_file(cfg, c->ca_file) == -1) 106 goto err_config; 107 if (c->cert_file && tls_config_set_cert_file(cfg, c->cert_file) == -1) 108 goto err_config; 109 if (c->key_file && tls_config_set_key_file(cfg, c->key_file) == -1) 110 goto err_config; 111 if (!c->verify) { 112 tls_config_insecure_noverifycert(cfg); 113 tls_config_insecure_noverifyname(cfg); 114 tls_config_insecure_noverifytime(cfg); 115 } 116 if (tls_configure(p->ctx, cfg) == -1) 117 goto err_ctx; 118 119 if (!c->listen) { 120 ret = tls_connect_cbs(p->ctx, tls_read_callback, tls_write_callback, 121 c->tcp, c->host); 122 } else { 123 struct tls *ctx_new; 124 ret = tls_accept_cbs(p->ctx, &ctx_new, tls_read_callback, 125 tls_write_callback, c->tcp); 126 if (ret == 0) { 127 // free "server" context and replace by "connection" context 128 tls_free(p->ctx); 129 p->ctx = ctx_new; 130 } 131 } 132 if (ret == -1) 133 goto err_ctx; 134 135 tls_config_free(cfg); 136 return 0; 137err_config: 138 av_log(h, AV_LOG_ERROR, "%s\n", tls_config_error(cfg)); 139 ret = AVERROR(EIO); 140 goto fail; 141err_ctx: 142 av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); 143 ret = AVERROR(EIO); 144 /* fallthrough */ 145fail: 146 if (cfg) 147 tls_config_free(cfg); 148 ff_tls_close(h); 149 return ret; 150} 151 152static int ff_tls_read(URLContext *h, uint8_t *buf, int size) 153{ 154 TLSContext *p = h->priv_data; 155 ssize_t ret; 156 ret = tls_read(p->ctx, buf, size); 157 if (ret > 0) 158 return ret; 159 else if (ret == 0) 160 return AVERROR_EOF; 161 else if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) 162 return AVERROR(EAGAIN); 163 av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); 164 return AVERROR(EIO); 165} 166 167static int ff_tls_write(URLContext *h, const uint8_t *buf, int size) 168{ 169 TLSContext *p = h->priv_data; 170 ssize_t ret; 171 ret = tls_write(p->ctx, buf, size); 172 if (ret > 0) 173 return ret; 174 else if (ret == 0) 175 return AVERROR_EOF; 176 else if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) 177 return AVERROR(EAGAIN); 178 av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); 179 return AVERROR(EIO); 180} 181 182static int tls_get_file_handle(URLContext *h) 183{ 184 TLSContext *c = h->priv_data; 185 return ffurl_get_file_handle(c->tls_shared.tcp); 186} 187 188static int tls_get_short_seek(URLContext *h) 189{ 190 TLSContext *s = h->priv_data; 191 return ffurl_get_short_seek(s->tls_shared.tcp); 192} 193 194static const AVOption options[] = { 195 TLS_COMMON_OPTIONS(TLSContext, tls_shared), 196 { NULL } 197}; 198 199static const AVClass tls_class = { 200 .class_name = "tls", 201 .item_name = av_default_item_name, 202 .option = options, 203 .version = LIBAVUTIL_VERSION_INT, 204}; 205 206const URLProtocol ff_tls_protocol = { 207 .name = "tls", 208 .url_open2 = ff_tls_open, 209 .url_read = ff_tls_read, 210 .url_write = ff_tls_write, 211 .url_close = ff_tls_close, 212 .url_get_file_handle = tls_get_file_handle, 213 .url_get_short_seek = tls_get_short_seek, 214 .priv_data_size = sizeof(TLSContext), 215 .flags = URL_PROTOCOL_FLAG_NETWORK, 216 .priv_data_class = &tls_class, 217}; 218