You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
12KB

  1. /*
  2. * TLS/SSL Protocol
  3. * Copyright (c) 2011 Martin Storsjo
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * Libav is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avformat.h"
  22. #include "url.h"
  23. #include "libavutil/avstring.h"
  24. #include "libavutil/opt.h"
  25. #include "libavutil/parseutils.h"
  26. #if CONFIG_GNUTLS
  27. #include <gnutls/gnutls.h>
  28. #include <gnutls/x509.h>
  29. #define TLS_read(c, buf, size) gnutls_record_recv(c->session, buf, size)
  30. #define TLS_write(c, buf, size) gnutls_record_send(c->session, buf, size)
  31. #define TLS_shutdown(c) gnutls_bye(c->session, GNUTLS_SHUT_RDWR)
  32. #define TLS_free(c) do { \
  33. if (c->session) \
  34. gnutls_deinit(c->session); \
  35. if (c->cred) \
  36. gnutls_certificate_free_credentials(c->cred); \
  37. } while (0)
  38. #elif CONFIG_OPENSSL
  39. #include <openssl/bio.h>
  40. #include <openssl/ssl.h>
  41. #include <openssl/err.h>
  42. #define TLS_read(c, buf, size) SSL_read(c->ssl, buf, size)
  43. #define TLS_write(c, buf, size) SSL_write(c->ssl, buf, size)
  44. #define TLS_shutdown(c) SSL_shutdown(c->ssl)
  45. #define TLS_free(c) do { \
  46. if (c->ssl) \
  47. SSL_free(c->ssl); \
  48. if (c->ctx) \
  49. SSL_CTX_free(c->ctx); \
  50. } while (0)
  51. #endif
  52. #include "network.h"
  53. #include "os_support.h"
  54. #include "internal.h"
  55. #if HAVE_POLL_H
  56. #include <poll.h>
  57. #endif
  58. typedef struct {
  59. const AVClass *class;
  60. URLContext *tcp;
  61. #if CONFIG_GNUTLS
  62. gnutls_session_t session;
  63. gnutls_certificate_credentials_t cred;
  64. #elif CONFIG_OPENSSL
  65. SSL_CTX *ctx;
  66. SSL *ssl;
  67. #endif
  68. int fd;
  69. char *ca_file;
  70. int verify;
  71. char *cert_file;
  72. char *key_file;
  73. int listen;
  74. } TLSContext;
  75. #define OFFSET(x) offsetof(TLSContext, x)
  76. #define D AV_OPT_FLAG_DECODING_PARAM
  77. #define E AV_OPT_FLAG_ENCODING_PARAM
  78. static const AVOption options[] = {
  79. {"ca_file", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E },
  80. {"tls_verify", "Verify the peer certificate", OFFSET(verify), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
  81. {"cert_file", "Certificate file", OFFSET(cert_file), AV_OPT_TYPE_STRING, .flags = D|E },
  82. {"key_file", "Private key file", OFFSET(key_file), AV_OPT_TYPE_STRING, .flags = D|E },
  83. {"listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
  84. { NULL }
  85. };
  86. static const AVClass tls_class = {
  87. .class_name = "tls",
  88. .item_name = av_default_item_name,
  89. .option = options,
  90. .version = LIBAVUTIL_VERSION_INT,
  91. };
  92. static int do_tls_poll(URLContext *h, int ret)
  93. {
  94. TLSContext *c = h->priv_data;
  95. struct pollfd p = { c->fd, 0, 0 };
  96. #if CONFIG_GNUTLS
  97. switch (ret) {
  98. case GNUTLS_E_AGAIN:
  99. case GNUTLS_E_INTERRUPTED:
  100. break;
  101. case GNUTLS_E_WARNING_ALERT_RECEIVED:
  102. av_log(h, AV_LOG_WARNING, "%s\n", gnutls_strerror(ret));
  103. break;
  104. default:
  105. av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
  106. return AVERROR(EIO);
  107. }
  108. if (gnutls_record_get_direction(c->session))
  109. p.events = POLLOUT;
  110. else
  111. p.events = POLLIN;
  112. #elif CONFIG_OPENSSL
  113. ret = SSL_get_error(c->ssl, ret);
  114. if (ret == SSL_ERROR_WANT_READ) {
  115. p.events = POLLIN;
  116. } else if (ret == SSL_ERROR_WANT_WRITE) {
  117. p.events = POLLOUT;
  118. } else {
  119. av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
  120. return AVERROR(EIO);
  121. }
  122. #endif
  123. if (h->flags & AVIO_FLAG_NONBLOCK)
  124. return AVERROR(EAGAIN);
  125. while (1) {
  126. int n = poll(&p, 1, 100);
  127. if (n > 0)
  128. break;
  129. if (ff_check_interrupt(&h->interrupt_callback))
  130. return AVERROR(EINTR);
  131. }
  132. return 0;
  133. }
  134. static int tls_open(URLContext *h, const char *uri, int flags)
  135. {
  136. TLSContext *c = h->priv_data;
  137. int ret;
  138. int port;
  139. char buf[200], host[200], opts[50] = "";
  140. int numerichost = 0;
  141. struct addrinfo hints = { 0 }, *ai = NULL;
  142. const char *proxy_path;
  143. int use_proxy;
  144. ff_tls_init();
  145. if (c->listen)
  146. snprintf(opts, sizeof(opts), "?listen=1");
  147. av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri);
  148. ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", opts);
  149. hints.ai_flags = AI_NUMERICHOST;
  150. if (!getaddrinfo(host, NULL, &hints, &ai)) {
  151. numerichost = 1;
  152. freeaddrinfo(ai);
  153. }
  154. proxy_path = getenv("http_proxy");
  155. use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), host) &&
  156. proxy_path != NULL && av_strstart(proxy_path, "http://", NULL);
  157. if (use_proxy) {
  158. char proxy_host[200], proxy_auth[200], dest[200];
  159. int proxy_port;
  160. av_url_split(NULL, 0, proxy_auth, sizeof(proxy_auth),
  161. proxy_host, sizeof(proxy_host), &proxy_port, NULL, 0,
  162. proxy_path);
  163. ff_url_join(dest, sizeof(dest), NULL, NULL, host, port, NULL);
  164. ff_url_join(buf, sizeof(buf), "httpproxy", proxy_auth, proxy_host,
  165. proxy_port, "/%s", dest);
  166. }
  167. ret = ffurl_open(&c->tcp, buf, AVIO_FLAG_READ_WRITE,
  168. &h->interrupt_callback, NULL);
  169. if (ret)
  170. goto fail;
  171. c->fd = ffurl_get_file_handle(c->tcp);
  172. #if CONFIG_GNUTLS
  173. gnutls_init(&c->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT);
  174. if (!c->listen && !numerichost)
  175. gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host));
  176. gnutls_certificate_allocate_credentials(&c->cred);
  177. if (c->ca_file)
  178. gnutls_certificate_set_x509_trust_file(c->cred, c->ca_file, GNUTLS_X509_FMT_PEM);
  179. #if GNUTLS_VERSION_MAJOR >= 3
  180. else
  181. gnutls_certificate_set_x509_system_trust(c->cred);
  182. #endif
  183. gnutls_certificate_set_verify_flags(c->cred, c->verify ?
  184. GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0);
  185. if (c->cert_file && c->key_file) {
  186. ret = gnutls_certificate_set_x509_key_file(c->cred,
  187. c->cert_file, c->key_file,
  188. GNUTLS_X509_FMT_PEM);
  189. if (ret < 0) {
  190. av_log(h, AV_LOG_ERROR,
  191. "Unable to set cert/key files %s and %s: %s\n",
  192. c->cert_file, c->key_file, gnutls_strerror(ret));
  193. ret = AVERROR(EIO);
  194. goto fail;
  195. }
  196. }
  197. gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
  198. gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t)
  199. (intptr_t) c->fd);
  200. gnutls_priority_set_direct(c->session, "NORMAL", NULL);
  201. while (1) {
  202. ret = gnutls_handshake(c->session);
  203. if (ret == 0)
  204. break;
  205. if ((ret = do_tls_poll(h, ret)) < 0)
  206. goto fail;
  207. }
  208. if (c->verify) {
  209. unsigned int status, cert_list_size;
  210. gnutls_x509_crt_t cert;
  211. const gnutls_datum_t *cert_list;
  212. if ((ret = gnutls_certificate_verify_peers2(c->session, &status)) < 0) {
  213. av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n",
  214. gnutls_strerror(ret));
  215. ret = AVERROR(EIO);
  216. goto fail;
  217. }
  218. if (status & GNUTLS_CERT_INVALID) {
  219. av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n");
  220. ret = AVERROR(EIO);
  221. goto fail;
  222. }
  223. if (gnutls_certificate_type_get(c->session) != GNUTLS_CRT_X509) {
  224. av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n");
  225. ret = AVERROR(EIO);
  226. goto fail;
  227. }
  228. gnutls_x509_crt_init(&cert);
  229. cert_list = gnutls_certificate_get_peers(c->session, &cert_list_size);
  230. gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER);
  231. ret = gnutls_x509_crt_check_hostname(cert, host);
  232. gnutls_x509_crt_deinit(cert);
  233. if (!ret) {
  234. av_log(h, AV_LOG_ERROR,
  235. "The certificate's owner does not match hostname %s\n", host);
  236. ret = AVERROR(EIO);
  237. goto fail;
  238. }
  239. }
  240. #elif CONFIG_OPENSSL
  241. c->ctx = SSL_CTX_new(c->listen ? TLSv1_server_method() : TLSv1_client_method());
  242. if (!c->ctx) {
  243. av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
  244. ret = AVERROR(EIO);
  245. goto fail;
  246. }
  247. if (c->ca_file)
  248. SSL_CTX_load_verify_locations(c->ctx, c->ca_file, NULL);
  249. if (c->cert_file && !SSL_CTX_use_certificate_chain_file(c->ctx, c->cert_file)) {
  250. av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n",
  251. c->cert_file, ERR_error_string(ERR_get_error(), NULL));
  252. ret = AVERROR(EIO);
  253. goto fail;
  254. }
  255. if (c->key_file && !SSL_CTX_use_PrivateKey_file(c->ctx, c->key_file, SSL_FILETYPE_PEM)) {
  256. av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n",
  257. c->key_file, ERR_error_string(ERR_get_error(), NULL));
  258. ret = AVERROR(EIO);
  259. goto fail;
  260. }
  261. // Note, this doesn't check that the peer certificate actually matches
  262. // the requested hostname.
  263. if (c->verify)
  264. SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER, NULL);
  265. c->ssl = SSL_new(c->ctx);
  266. if (!c->ssl) {
  267. av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
  268. ret = AVERROR(EIO);
  269. goto fail;
  270. }
  271. SSL_set_fd(c->ssl, c->fd);
  272. if (!c->listen && !numerichost)
  273. SSL_set_tlsext_host_name(c->ssl, host);
  274. while (1) {
  275. ret = c->listen ? SSL_accept(c->ssl) : SSL_connect(c->ssl);
  276. if (ret > 0)
  277. break;
  278. if (ret == 0) {
  279. av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n");
  280. ret = AVERROR(EIO);
  281. goto fail;
  282. }
  283. if ((ret = do_tls_poll(h, ret)) < 0)
  284. goto fail;
  285. }
  286. #endif
  287. return 0;
  288. fail:
  289. TLS_free(c);
  290. if (c->tcp)
  291. ffurl_close(c->tcp);
  292. ff_tls_deinit();
  293. return ret;
  294. }
  295. static int tls_read(URLContext *h, uint8_t *buf, int size)
  296. {
  297. TLSContext *c = h->priv_data;
  298. while (1) {
  299. int ret = TLS_read(c, buf, size);
  300. if (ret > 0)
  301. return ret;
  302. if (ret == 0)
  303. return AVERROR_EOF;
  304. if ((ret = do_tls_poll(h, ret)) < 0)
  305. return ret;
  306. }
  307. return 0;
  308. }
  309. static int tls_write(URLContext *h, const uint8_t *buf, int size)
  310. {
  311. TLSContext *c = h->priv_data;
  312. while (1) {
  313. int ret = TLS_write(c, buf, size);
  314. if (ret > 0)
  315. return ret;
  316. if (ret == 0)
  317. return AVERROR_EOF;
  318. if ((ret = do_tls_poll(h, ret)) < 0)
  319. return ret;
  320. }
  321. return 0;
  322. }
  323. static int tls_close(URLContext *h)
  324. {
  325. TLSContext *c = h->priv_data;
  326. TLS_shutdown(c);
  327. TLS_free(c);
  328. ffurl_close(c->tcp);
  329. ff_tls_deinit();
  330. return 0;
  331. }
  332. URLProtocol ff_tls_protocol = {
  333. .name = "tls",
  334. .url_open = tls_open,
  335. .url_read = tls_read,
  336. .url_write = tls_write,
  337. .url_close = tls_close,
  338. .priv_data_size = sizeof(TLSContext),
  339. .flags = URL_PROTOCOL_FLAG_NETWORK,
  340. .priv_data_class = &tls_class,
  341. };