/* Load private key and certificate from file */ int tls_load_key_cert(char *file, mbedtls_pk_context **private_key, mbedtls_x509_crt **certificate) { int result; if (file == NULL) { return -1; } if ((*private_key = (mbedtls_pk_context*)malloc(sizeof(mbedtls_pk_context))) == NULL) { return -1; } mbedtls_pk_init(*private_key); if ((result = mbedtls_pk_parse_keyfile(*private_key, file, NULL)) != 0) { print_tls_error(result, "Error loading private key from %s", file); return -1; } if ((*certificate = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt))) == NULL) { return -1; } mbedtls_x509_crt_init(*certificate); if ((result = mbedtls_x509_crt_parse_file(*certificate, file)) != 0) { print_tls_error(result, "Error loading X.509 certificates from %s", file); return -1; } return 0; }
static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; int ret = SSL_write(c->ssl, buf, size); if (ret > 0) return ret; if (ret == 0) return AVERROR_EOF; return print_tls_error(h, ret); }
static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; int ret = gnutls_record_send(c->session, buf, size); if (ret > 0) return ret; if (ret == 0) return AVERROR_EOF; return print_tls_error(h, ret); }
static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; size_t processed = 0; int ret = SSLWrite(c->ssl_context, buf, size, &processed); ret = map_ssl_error(ret, processed); if (ret > 0) return ret; if (ret == 0) return AVERROR_EOF; return print_tls_error(h, ret); }
/* Load CA root certificates */ int tls_load_ca_root_certs(char *source, mbedtls_x509_crt **ca_root_certs) { int result; char *error_msg = "Error loading root CA certificates from %s"; if ((*ca_root_certs = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt))) == NULL) { return -1; } mbedtls_x509_crt_init(*ca_root_certs); if (is_directory(source)) { if ((result = mbedtls_x509_crt_parse_path(*ca_root_certs, source)) != 0) { print_tls_error(result, error_msg, source); return -1; } } else { if ((result = mbedtls_x509_crt_parse_file(*ca_root_certs, source)) != 0) { print_tls_error(result, error_msg, source); return -1; } } return 0; }
static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; int ret; // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; ret = SSL_write(c->ssl, buf, size); if (ret > 0) return ret; if (ret == 0) return AVERROR_EOF; return print_tls_error(h, ret); }
/* Load CA CRL from file */ int tls_load_ca_crl(char *file, mbedtls_x509_crl **ca_crl) { int result; if (file == NULL) { return -1; } if ((*ca_crl = (mbedtls_x509_crl*)malloc(sizeof(mbedtls_x509_crl))) == NULL) { return -1; } mbedtls_x509_crl_init(*ca_crl); if ((result = mbedtls_x509_crl_parse_file(*ca_crl, file)) != 0) { print_tls_error(result, "Error loading X.509 CA CRL from %s", file); return -1; } return 0; }
/* Load CA certificate from file. */ int tls_load_ca_cert(char *file, mbedtls_x509_crt **ca_certificate) { int result; if (file == NULL) { return -1; } if ((*ca_certificate = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt))) == NULL) { return -1; } mbedtls_x509_crt_init(*ca_certificate); if ((result = mbedtls_x509_crt_parse_file(*ca_certificate, file)) != 0) { print_tls_error(result, "Error loading X.509 CA certificate from %s", file); return -1; } return 0; }
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { TLSContext *p = h->priv_data; TLSShared *c = &p->tls_shared; int ret; ff_gnutls_init(); if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) goto fail; gnutls_init(&p->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT); if (!c->listen && !c->numerichost) gnutls_server_name_set(p->session, GNUTLS_NAME_DNS, c->host, strlen(c->host)); gnutls_certificate_allocate_credentials(&p->cred); if (c->ca_file) { ret = gnutls_certificate_set_x509_trust_file(p->cred, c->ca_file, GNUTLS_X509_FMT_PEM); if (ret < 0) av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret)); } #if GNUTLS_VERSION_MAJOR >= 3 else gnutls_certificate_set_x509_system_trust(p->cred); #endif gnutls_certificate_set_verify_flags(p->cred, c->verify ? GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0); if (c->cert_file && c->key_file) { ret = gnutls_certificate_set_x509_key_file(p->cred, c->cert_file, c->key_file, GNUTLS_X509_FMT_PEM); if (ret < 0) { av_log(h, AV_LOG_ERROR, "Unable to set cert/key files %s and %s: %s\n", c->cert_file, c->key_file, gnutls_strerror(ret)); ret = AVERROR(EIO); goto fail; } } else if (c->cert_file || c->key_file) av_log(h, AV_LOG_ERROR, "cert and key required\n"); gnutls_credentials_set(p->session, GNUTLS_CRD_CERTIFICATE, p->cred); gnutls_transport_set_pull_function(p->session, gnutls_url_pull); gnutls_transport_set_push_function(p->session, gnutls_url_push); gnutls_transport_set_ptr(p->session, c->tcp); gnutls_priority_set_direct(p->session, "NORMAL", NULL); ret = gnutls_handshake(p->session); if (ret) { ret = print_tls_error(h, ret); goto fail; } p->need_shutdown = 1; if (c->verify) { unsigned int status, cert_list_size; gnutls_x509_crt_t cert; const gnutls_datum_t *cert_list; if ((ret = gnutls_certificate_verify_peers2(p->session, &status)) < 0) { av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n", gnutls_strerror(ret)); ret = AVERROR(EIO); goto fail; } if (status & GNUTLS_CERT_INVALID) { av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n"); ret = AVERROR(EIO); goto fail; } if (gnutls_certificate_type_get(p->session) != GNUTLS_CRT_X509) { av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n"); ret = AVERROR(EIO); goto fail; } gnutls_x509_crt_init(&cert); cert_list = gnutls_certificate_get_peers(p->session, &cert_list_size); gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER); ret = gnutls_x509_crt_check_hostname(cert, c->host); gnutls_x509_crt_deinit(cert); if (!ret) { av_log(h, AV_LOG_ERROR, "The certificate's owner does not match hostname %s\n", c->host); ret = AVERROR(EIO); goto fail; } } return 0; fail: tls_close(h); return ret; }
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { TLSContext *p = h->priv_data; TLSShared *c = &p->tls_shared; BIO *bio; int ret; ff_openssl_init(); if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) goto fail; p->ctx = SSL_CTX_new(c->listen ? TLSv1_server_method() : TLSv1_client_method()); if (!p->ctx) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } if (c->ca_file) SSL_CTX_load_verify_locations(p->ctx, c->ca_file, NULL); if (c->cert_file && !SSL_CTX_use_certificate_chain_file(p->ctx, c->cert_file)) { av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n", c->cert_file, ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } if (c->key_file && !SSL_CTX_use_PrivateKey_file(p->ctx, c->key_file, SSL_FILETYPE_PEM)) { av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n", c->key_file, ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } // Note, this doesn't check that the peer certificate actually matches // the requested hostname. if (c->verify) SSL_CTX_set_verify(p->ctx, SSL_VERIFY_PEER, NULL); p->ssl = SSL_new(p->ctx); if (!p->ssl) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } bio = BIO_new(&url_bio_method); bio->ptr = c->tcp; SSL_set_bio(p->ssl, bio, bio); if (!c->listen && !c->numerichost) SSL_set_tlsext_host_name(p->ssl, c->host); ret = c->listen ? SSL_accept(p->ssl) : SSL_connect(p->ssl); if (ret == 0) { av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n"); ret = AVERROR(EIO); goto fail; } else if (ret < 0) { ret = print_tls_error(h, ret); goto fail; } return 0; fail: tls_close(h); return ret; }
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { TLSContext *p = h->priv_data; TLSShared *c = &p->tls_shared; BIO *bio; int ret; ff_openssl_init(); if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) goto fail; // We want to support all versions of TLS >= 1.0, but not the deprecated // and insecure SSLv2 and SSLv3. Despite the name, SSLv23_*_method() // enables support for all versions of SSL and TLS, and we then disable // support for the old protocols immediately after creating the context. p->ctx = SSL_CTX_new(c->listen ? SSLv23_server_method() : SSLv23_client_method()); if (!p->ctx) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } SSL_CTX_set_options(p->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); if (c->ca_file) SSL_CTX_load_verify_locations(p->ctx, c->ca_file, NULL); if (c->cert_file && !SSL_CTX_use_certificate_chain_file(p->ctx, c->cert_file)) { av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n", c->cert_file, ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } if (c->key_file && !SSL_CTX_use_PrivateKey_file(p->ctx, c->key_file, SSL_FILETYPE_PEM)) { av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n", c->key_file, ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } // Note, this doesn't check that the peer certificate actually matches // the requested hostname. if (c->verify) SSL_CTX_set_verify(p->ctx, SSL_VERIFY_PEER, NULL); p->ssl = SSL_new(p->ctx); if (!p->ssl) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } #if OPENSSL_VERSION_NUMBER >= 0x1010000fL p->url_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "urlprotocol bio"); BIO_meth_set_write(p->url_bio_method, url_bio_bwrite); BIO_meth_set_read(p->url_bio_method, url_bio_bread); BIO_meth_set_puts(p->url_bio_method, url_bio_bputs); BIO_meth_set_ctrl(p->url_bio_method, url_bio_ctrl); BIO_meth_set_create(p->url_bio_method, url_bio_create); BIO_meth_set_destroy(p->url_bio_method, url_bio_destroy); bio = BIO_new(p->url_bio_method); BIO_set_data(bio, c->tcp); #else bio = BIO_new(&url_bio_method); bio->ptr = c->tcp; #endif SSL_set_bio(p->ssl, bio, bio); if (!c->listen && !c->numerichost) SSL_set_tlsext_host_name(p->ssl, c->host); ret = c->listen ? SSL_accept(p->ssl) : SSL_connect(p->ssl); if (ret == 0) { av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n"); ret = AVERROR(EIO); goto fail; } else if (ret < 0) { ret = print_tls_error(h, ret); goto fail; } return 0; fail: tls_close(h); return ret; }