00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "url.h"
00024 #include "libavutil/avstring.h"
00025 #include "libavutil/parseutils.h"
00026 #if CONFIG_GNUTLS
00027 #include <gnutls/gnutls.h>
00028 #define TLS_read(c, buf, size) gnutls_record_recv(c->session, buf, size)
00029 #define TLS_write(c, buf, size) gnutls_record_send(c->session, buf, size)
00030 #define TLS_shutdown(c) gnutls_bye(c->session, GNUTLS_SHUT_RDWR)
00031 #define TLS_free(c) do { \
00032 if (c->session) \
00033 gnutls_deinit(c->session); \
00034 if (c->cred) \
00035 gnutls_certificate_free_credentials(c->cred); \
00036 } while (0)
00037 #elif CONFIG_OPENSSL
00038 #include <openssl/bio.h>
00039 #include <openssl/ssl.h>
00040 #include <openssl/err.h>
00041 #define TLS_read(c, buf, size) SSL_read(c->ssl, buf, size)
00042 #define TLS_write(c, buf, size) SSL_write(c->ssl, buf, size)
00043 #define TLS_shutdown(c) SSL_shutdown(c->ssl)
00044 #define TLS_free(c) do { \
00045 if (c->ssl) \
00046 SSL_free(c->ssl); \
00047 if (c->ctx) \
00048 SSL_CTX_free(c->ctx); \
00049 } while (0)
00050 #endif
00051 #include "network.h"
00052 #include "os_support.h"
00053 #include "internal.h"
00054 #if HAVE_POLL_H
00055 #include <poll.h>
00056 #endif
00057
00058 typedef struct {
00059 const AVClass *class;
00060 URLContext *tcp;
00061 #if CONFIG_GNUTLS
00062 gnutls_session_t session;
00063 gnutls_certificate_credentials_t cred;
00064 #elif CONFIG_OPENSSL
00065 SSL_CTX *ctx;
00066 SSL *ssl;
00067 #endif
00068 int fd;
00069 } TLSContext;
00070
00071 static int do_tls_poll(URLContext *h, int ret)
00072 {
00073 TLSContext *c = h->priv_data;
00074 struct pollfd p = { c->fd, 0, 0 };
00075 #if CONFIG_GNUTLS
00076 if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED) {
00077 av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
00078 return AVERROR(EIO);
00079 }
00080 if (gnutls_record_get_direction(c->session))
00081 p.events = POLLOUT;
00082 else
00083 p.events = POLLIN;
00084 #elif CONFIG_OPENSSL
00085 ret = SSL_get_error(c->ssl, ret);
00086 if (ret == SSL_ERROR_WANT_READ) {
00087 p.events = POLLIN;
00088 } else if (ret == SSL_ERROR_WANT_WRITE) {
00089 p.events = POLLOUT;
00090 } else {
00091 av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
00092 return AVERROR(EIO);
00093 }
00094 #endif
00095 if (h->flags & AVIO_FLAG_NONBLOCK)
00096 return AVERROR(EAGAIN);
00097 while (1) {
00098 int n = poll(&p, 1, 100);
00099 if (n > 0)
00100 break;
00101 if (ff_check_interrupt(&h->interrupt_callback))
00102 return AVERROR(EINTR);
00103 }
00104 return 0;
00105 }
00106
00107 static void set_options(URLContext *h, const char *uri)
00108 {
00109 TLSContext *c = h->priv_data;
00110 char buf[1024], key[1024];
00111 int has_cert, has_key, verify = 0;
00112 #if CONFIG_GNUTLS
00113 int ret;
00114 #endif
00115 const char *p = strchr(uri, '?');
00116 if (!p)
00117 return;
00118
00119 if (av_find_info_tag(buf, sizeof(buf), "cafile", p)) {
00120 #if CONFIG_GNUTLS
00121 ret = gnutls_certificate_set_x509_trust_file(c->cred, buf, GNUTLS_X509_FMT_PEM);
00122 if (ret < 0)
00123 av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
00124 #elif CONFIG_OPENSSL
00125 if (!SSL_CTX_load_verify_locations(c->ctx, buf, NULL))
00126 av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL));
00127 #endif
00128 }
00129
00130 if (av_find_info_tag(buf, sizeof(buf), "verify", p)) {
00131 char *endptr = NULL;
00132 verify = strtol(buf, &endptr, 10);
00133 if (buf == endptr)
00134 verify = 1;
00135 }
00136
00137 has_cert = av_find_info_tag(buf, sizeof(buf), "cert", p);
00138 has_key = av_find_info_tag(key, sizeof(key), "key", p);
00139 #if CONFIG_GNUTLS
00140 if (has_cert && has_key) {
00141 ret = gnutls_certificate_set_x509_key_file(c->cred, buf, key, GNUTLS_X509_FMT_PEM);
00142 if (ret < 0)
00143 av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
00144 } else if (has_cert ^ has_key) {
00145 av_log(h, AV_LOG_ERROR, "cert and key required\n");
00146 }
00147 gnutls_certificate_set_verify_flags(c->cred, verify);
00148 #elif CONFIG_OPENSSL
00149 if (has_cert && !SSL_CTX_use_certificate_chain_file(c->ctx, buf))
00150 av_log(h, AV_LOG_ERROR, "SSL_CTX_use_certificate_chain_file %s\n", ERR_error_string(ERR_get_error(), NULL));
00151 if (has_key && !SSL_CTX_use_PrivateKey_file(c->ctx, key, SSL_FILETYPE_PEM))
00152 av_log(h, AV_LOG_ERROR, "SSL_CTX_use_PrivateKey_file %s\n", ERR_error_string(ERR_get_error(), NULL));
00153 if (verify)
00154 SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
00155 #endif
00156 }
00157
00158 static int tls_open(URLContext *h, const char *uri, int flags)
00159 {
00160 TLSContext *c = h->priv_data;
00161 int ret;
00162 int port;
00163 char buf[200], host[200], path[1024];
00164 int numerichost = 0;
00165 struct addrinfo hints = { 0 }, *ai = NULL;
00166 const char *proxy_path;
00167 int use_proxy;
00168 int server = 0;
00169 const char *p = strchr(uri, '?');
00170 if (p && av_find_info_tag(buf, sizeof(buf), "listen", p))
00171 server = 1;
00172
00173 ff_tls_init();
00174
00175 proxy_path = getenv("http_proxy");
00176 use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
00177 av_strstart(proxy_path, "http://", NULL);
00178
00179 av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), uri);
00180 ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", path);
00181
00182 hints.ai_flags = AI_NUMERICHOST;
00183 if (!getaddrinfo(host, NULL, &hints, &ai)) {
00184 numerichost = 1;
00185 freeaddrinfo(ai);
00186 }
00187
00188 if (use_proxy) {
00189 char proxy_host[200], proxy_auth[200], dest[200];
00190 int proxy_port;
00191 av_url_split(NULL, 0, proxy_auth, sizeof(proxy_auth),
00192 proxy_host, sizeof(proxy_host), &proxy_port, NULL, 0,
00193 proxy_path);
00194 ff_url_join(dest, sizeof(dest), NULL, NULL, host, port, NULL);
00195 ff_url_join(buf, sizeof(buf), "httpproxy", proxy_auth, proxy_host,
00196 proxy_port, "/%s", dest);
00197 }
00198
00199 ret = ffurl_open(&c->tcp, buf, AVIO_FLAG_READ_WRITE,
00200 &h->interrupt_callback, NULL);
00201 if (ret)
00202 goto fail;
00203 c->fd = ffurl_get_file_handle(c->tcp);
00204
00205 #if CONFIG_GNUTLS
00206 gnutls_init(&c->session, server ? GNUTLS_SERVER : GNUTLS_CLIENT);
00207 if (!numerichost)
00208 gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host));
00209 gnutls_certificate_allocate_credentials(&c->cred);
00210 set_options(h, uri);
00211 gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
00212 gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t)
00213 (intptr_t) c->fd);
00214 gnutls_priority_set_direct(c->session, "NORMAL", NULL);
00215 while (1) {
00216 ret = gnutls_handshake(c->session);
00217 if (ret == 0)
00218 break;
00219 if ((ret = do_tls_poll(h, ret)) < 0)
00220 goto fail;
00221 }
00222 #elif CONFIG_OPENSSL
00223 c->ctx = SSL_CTX_new(server ? TLSv1_server_method() : TLSv1_client_method());
00224 if (!c->ctx) {
00225 av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
00226 ret = AVERROR(EIO);
00227 goto fail;
00228 }
00229 set_options(h, uri);
00230 c->ssl = SSL_new(c->ctx);
00231 if (!c->ssl) {
00232 av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
00233 ret = AVERROR(EIO);
00234 goto fail;
00235 }
00236 SSL_set_fd(c->ssl, c->fd);
00237 if (!server && !numerichost)
00238 SSL_set_tlsext_host_name(c->ssl, host);
00239 while (1) {
00240 ret = server ? SSL_accept(c->ssl) : SSL_connect(c->ssl);
00241 if (ret > 0)
00242 break;
00243 if (ret == 0) {
00244 av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n");
00245 ret = AVERROR(EIO);
00246 goto fail;
00247 }
00248 if ((ret = do_tls_poll(h, ret)) < 0)
00249 goto fail;
00250 }
00251 #endif
00252 return 0;
00253 fail:
00254 TLS_free(c);
00255 if (c->tcp)
00256 ffurl_close(c->tcp);
00257 ff_tls_deinit();
00258 return ret;
00259 }
00260
00261 static int tls_read(URLContext *h, uint8_t *buf, int size)
00262 {
00263 TLSContext *c = h->priv_data;
00264 while (1) {
00265 int ret = TLS_read(c, buf, size);
00266 if (ret > 0)
00267 return ret;
00268 if (ret == 0)
00269 return AVERROR_EOF;
00270 if ((ret = do_tls_poll(h, ret)) < 0)
00271 return ret;
00272 }
00273 return 0;
00274 }
00275
00276 static int tls_write(URLContext *h, const uint8_t *buf, int size)
00277 {
00278 TLSContext *c = h->priv_data;
00279 while (1) {
00280 int ret = TLS_write(c, buf, size);
00281 if (ret > 0)
00282 return ret;
00283 if (ret == 0)
00284 return AVERROR_EOF;
00285 if ((ret = do_tls_poll(h, ret)) < 0)
00286 return ret;
00287 }
00288 return 0;
00289 }
00290
00291 static int tls_close(URLContext *h)
00292 {
00293 TLSContext *c = h->priv_data;
00294 TLS_shutdown(c);
00295 TLS_free(c);
00296 ffurl_close(c->tcp);
00297 ff_tls_deinit();
00298 return 0;
00299 }
00300
00301 URLProtocol ff_tls_protocol = {
00302 .name = "tls",
00303 .url_open = tls_open,
00304 .url_read = tls_read,
00305 .url_write = tls_write,
00306 .url_close = tls_close,
00307 .priv_data_size = sizeof(TLSContext),
00308 .flags = URL_PROTOCOL_FLAG_NETWORK,
00309 };