00001 /* 00002 * TLS/SSL Protocol 00003 * Copyright (c) 2011 Martin Storsjo 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 };