void Gobby::CertificateManager::make_credentials() { InfCertificateCredentials* creds = inf_certificate_credentials_new(); gnutls_certificate_credentials_t gnutls_creds = inf_certificate_credentials_get(creds); if(m_preferences.security.authentication_enabled && m_key != NULL && m_certificates != NULL) { gnutls_certificate_set_x509_key( gnutls_creds, inf_certificate_chain_get_raw(m_certificates), inf_certificate_chain_get_n_certificates(m_certificates), m_key ); } if(m_preferences.security.use_system_trust) { const int n_cas = gnutls_certificate_set_x509_system_trust( gnutls_creds); if(n_cas < 0) { g_warning("Failed to add system CAs: %s\n", gnutls_strerror(n_cas)); } } if(!m_trust.empty()) { gnutls_certificate_set_x509_trust( gnutls_creds, &m_trust[0], m_trust.size() ); } if(m_dh_params != NULL) gnutls_certificate_set_dh_params(gnutls_creds, m_dh_params); gnutls_certificate_set_verify_flags( gnutls_creds, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); InfCertificateCredentials* old_creds = m_credentials; m_credentials = creds; m_signal_credentials_changed.emit(); if(old_creds != NULL) inf_certificate_credentials_unref(old_creds); }
static int ssl_set_ca_location(void) { int num = 0; /* A user defined CA PEM bundle overrides any built-ins or fall-backs */ if (ca_trust_file) { num = gnutls_certificate_set_x509_trust_file(xcred, ca_trust_file, GNUTLS_X509_FMT_PEM); goto done; } #ifdef gnutls_certificate_set_x509_system_trust /* Since 3.0.20 */ num = gnutls_certificate_set_x509_system_trust(xcred); #endif if (num <= 0) num = gnutls_certificate_set_x509_trust_file(xcred, CAFILE1, GNUTLS_X509_FMT_PEM); if (num <= 0) num = gnutls_certificate_set_x509_trust_file(xcred, CAFILE2, GNUTLS_X509_FMT_PEM); done: if (num <= 0) 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; }
gboolean _lm_ssl_begin (LmSSL *ssl, gint fd, const gchar *server, GError **error) { int ret; LmSSLBase *base; gboolean auth_ok = TRUE; base = LM_SSL_BASE(ssl); gnutls_init (&ssl->gnutls_session, GNUTLS_CLIENT); if (base->cipher_list) { gnutls_priority_set_direct (ssl->gnutls_session, base->cipher_list, NULL); } else { gnutls_priority_set_direct (ssl->gnutls_session, "NORMAL", NULL); } if (base->ca_path) { _lm_ssl_set_ca(ssl, base->ca_path); } else { gnutls_certificate_set_x509_system_trust(ssl->gnutls_xcred); } gnutls_credentials_set (ssl->gnutls_session, GNUTLS_CRD_CERTIFICATE, ssl->gnutls_xcred); gnutls_transport_set_ptr (ssl->gnutls_session, (gnutls_transport_ptr_t)(glong) fd); ret = gnutls_handshake (ssl->gnutls_session); if (ret >= 0) { auth_ok = ssl_verify_certificate (ssl, server); } if (ret < 0 || !auth_ok) { char *errmsg; if (!auth_ok) { errmsg = "authentication error"; } else { errmsg = "handshake failed"; } g_set_error (error, LM_ERROR, LM_ERROR_CONNECTION_OPEN, "*** GNUTLS %s: %s", errmsg, gnutls_strerror (ret)); return FALSE; } lm_verbose ("GNUTLS negotiated cipher suite: %s", gnutls_cipher_suite_get_name(gnutls_kx_get(ssl->gnutls_session), gnutls_cipher_get(ssl->gnutls_session), gnutls_mac_get(ssl->gnutls_session))); lm_verbose ("GNUTLS negotiated compression: %s", gnutls_compression_get_name (gnutls_compression_get (ssl->gnutls_session))); ssl->started = TRUE; return TRUE; }
static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; gnutls_session_t session; int rc; void *ssl_sessionid; size_t ssl_idsize; bool sni = TRUE; /* default is SNI enabled */ #ifdef ENABLE_IPV6 struct in6_addr addr; #else struct in_addr addr; #endif #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT static const int cipher_priority[] = { /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, but this code path is only ever used for ver. < 2.12.0. GNUTLS_CIPHER_AES_128_GCM, GNUTLS_CIPHER_AES_256_GCM, */ GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_CIPHER_3DES_CBC, }; static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; static int protocol_priority[] = { 0, 0, 0, 0 }; #else #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" /* If GnuTLS was compiled without support for SRP it will error out if SRP is requested in the priority string, so treat it specially */ #define GNUTLS_SRP "+SRP" const char* prioritylist; const char *err = NULL; #endif if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ return CURLE_OK; if(!gtls_inited) Curl_gtls_init(); /* GnuTLS only supports SSLv3 and TLSv1 */ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } #ifdef USE_TLS_SRP if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); rc = gnutls_srp_allocate_client_credentials( &conn->ssl[sockindex].srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_allocate_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_OUT_OF_MEMORY; } rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. srp_client_cred, data->set.ssl.username, data->set.ssl.password); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_set_client_cred() failed: %s", gnutls_strerror(rc)); return CURLE_BAD_FUNCTION_ARGUMENT; } } #endif if(data->set.ssl.CAfile) { /* set the trusted CA cert bundle file */ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, data->set.ssl.CAfile, GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); if(data->set.ssl.verifypeer) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", rc, data->set.ssl.CAfile); } #ifdef HAS_CAPATH if(data->set.ssl.CApath) { /* set the trusted CA cert directory */ rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, data->set.ssl.CApath, GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", data->set.ssl.CAfile, gnutls_strerror(rc)); if(data->set.ssl.verifypeer) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", rc, data->set.ssl.CApath); } #endif #ifdef CURL_CA_FALLBACK /* use system ca certificate store as fallback */ if(data->set.ssl.verifypeer && !(data->set.ssl.CAfile || data->set.ssl.CApath)) { gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred); } #endif if(data->set.ssl.CRLfile) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, data->set.ssl.CRLfile, GNUTLS_X509_FMT_PEM); if(rc < 0) { failf(data, "error reading crl file %s (%s)", data->set.ssl.CRLfile, gnutls_strerror(rc)); return CURLE_SSL_CRL_BADFILE; } else infof(data, "found %d CRL in %s\n", rc, data->set.ssl.CRLfile); } /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } /* convenient assign */ session = conn->ssl[sockindex].session; if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && #endif sni && (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, strlen(conn->host.name)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); /* Use default priorities */ rc = gnutls_set_default_priority(session); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT rc = gnutls_cipher_set_priority(session, cipher_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; /* Sets the priority on the certificate types supported by gnutls. Priority is higher for types specified before others. After specifying the types you want, you must append a 0. */ rc = gnutls_certificate_type_set_priority(session, cert_type_priority); if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; if(data->set.ssl.cipher_list != NULL) { failf(data, "can't pass a custom cipher list to older GnuTLS" " versions"); return CURLE_SSL_CONNECT_ERROR; } switch (data->set.ssl.version) { case CURL_SSLVERSION_SSLv3: protocol_priority[0] = GNUTLS_SSL3; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: protocol_priority[0] = GNUTLS_TLS1_0; protocol_priority[1] = GNUTLS_TLS1_1; protocol_priority[2] = GNUTLS_TLS1_2; break; case CURL_SSLVERSION_TLSv1_0: protocol_priority[0] = GNUTLS_TLS1_0; break; case CURL_SSLVERSION_TLSv1_1: protocol_priority[0] = GNUTLS_TLS1_1; break; case CURL_SSLVERSION_TLSv1_2: protocol_priority[0] = GNUTLS_TLS1_2; break; case CURL_SSLVERSION_SSLv2: default: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; break; } rc = gnutls_protocol_set_priority(session, protocol_priority); if(rc != GNUTLS_E_SUCCESS) { failf(data, "Did you pass a valid GnuTLS cipher list?"); return CURLE_SSL_CONNECT_ERROR; } #else /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ switch (data->set.ssl.version) { case CURL_SSLVERSION_SSLv3: prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; sni = false; break; case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_0: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.0:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_1: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.1:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_2: prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.2:" GNUTLS_SRP; break; case CURL_SSLVERSION_SSLv2: default: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; break; } rc = gnutls_priority_set_direct(session, prioritylist, &err); if((rc == GNUTLS_E_INVALID_REQUEST) && err) { if(!strcmp(err, GNUTLS_SRP)) { /* This GnuTLS was probably compiled without support for SRP. * Note that fact and try again without it. */ int validprioritylen = curlx_uztosi(err - prioritylist); char *prioritycopy = strdup(prioritylist); if(!prioritycopy) return CURLE_OUT_OF_MEMORY; infof(data, "This GnuTLS does not support SRP\n"); if(validprioritylen) /* Remove the :+SRP */ prioritycopy[validprioritylen - 1] = 0; rc = gnutls_priority_set_direct(session, prioritycopy, &err); free(prioritycopy); } } if(rc != GNUTLS_E_SUCCESS) { failf(data, "Error %d setting GnuTLS cipher list starting with %s", rc, err); return CURLE_SSL_CONNECT_ERROR; } #endif #ifdef HAS_ALPN if(data->set.ssl_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; cur++; infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); } #endif protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; protocols[cur].size = ALPN_HTTP_1_1_LENGTH; cur++; infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); gnutls_alpn_set_protocols(session, protocols, cur, 0); } #endif if(data->set.str[STRING_CERT]) { if(data->set.str[STRING_KEY_PASSWD]) { #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( conn->ssl[sockindex].cred, data->set.str[STRING_CERT], data->set.str[STRING_KEY] ? data->set.str[STRING_KEY] : data->set.str[STRING_CERT], do_file_type(data->set.str[STRING_CERT_TYPE]), data->set.str[STRING_KEY_PASSWD], supported_key_encryption_algorithms); if(rc != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 potentially-encrypted key file: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } #else failf(data, "gnutls lacks support for encrypted key files"); return CURLE_SSL_CONNECT_ERROR; #endif } else { rc = gnutls_certificate_set_x509_key_file( conn->ssl[sockindex].cred, data->set.str[STRING_CERT], data->set.str[STRING_KEY] ? data->set.str[STRING_KEY] : data->set.str[STRING_CERT], do_file_type(data->set.str[STRING_CERT_TYPE]) ); if(rc != GNUTLS_E_SUCCESS) { failf(data, "error reading X.509 key or certificate file: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } } #ifdef USE_TLS_SRP /* put the credentials to the current session */ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, conn->ssl[sockindex].srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } else #endif { rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, conn->ssl[sockindex].cred); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); return CURLE_SSL_CONNECT_ERROR; } } /* set the connection handle (file descriptor for the socket) */ gnutls_transport_set_ptr(session, GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); /* register callback functions to send and receive data. */ gnutls_transport_set_push_function(session, Curl_gtls_push); gnutls_transport_set_pull_function(session, Curl_gtls_pull); /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); #ifdef HAS_OCSP if(data->set.ssl.verifystatus) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; } } #endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { /* we got a session id, use it! */ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); /* Informational message */ infof (data, "SSL re-using session ID\n"); } return CURLE_OK; }
TDSRET tds_ssl_init(TDSSOCKET *tds) { gnutls_session_t session; gnutls_certificate_credentials_t xcred; int ret; const char *tls_msg; xcred = NULL; session = NULL; tls_msg = "initializing tls"; if (!tls_initialized) { ret = 0; tds_mutex_lock(&tls_mutex); if (!tls_initialized) { tds_gcry_init(); ret = gnutls_global_init(); if (ret == 0) tls_initialized = 1; } tds_mutex_unlock(&tls_mutex); if (ret != 0) goto cleanup; } if (tds_write_dump && tls_initialized < 2) { gnutls_global_set_log_level(11); gnutls_global_set_log_function(tds_tls_log); tls_initialized = 2; } tls_msg = "allocating credentials"; ret = gnutls_certificate_allocate_credentials(&xcred); if (ret != 0) goto cleanup; if (!tds_dstr_isempty(&tds->login->cafile)) { tls_msg = "loading CA file"; if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0) ret = gnutls_certificate_set_x509_system_trust(xcred); else ret = gnutls_certificate_set_x509_trust_file(xcred, tds_dstr_cstr(&tds->login->cafile), GNUTLS_X509_FMT_PEM); if (ret <= 0) goto cleanup; if (!tds_dstr_isempty(&tds->login->crlfile)) { tls_msg = "loading CRL file"; ret = gnutls_certificate_set_x509_crl_file(xcred, tds_dstr_cstr(&tds->login->crlfile), GNUTLS_X509_FMT_PEM); if (ret <= 0) goto cleanup; } #ifdef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION gnutls_certificate_set_verify_function(xcred, tds_verify_certificate); #endif } /* Initialize TLS session */ tls_msg = "initializing session"; ret = gnutls_init(&session, GNUTLS_CLIENT); if (ret != 0) goto cleanup; gnutls_transport_set_ptr(session, tds); gnutls_transport_set_pull_function(session, tds_pull_func_login); gnutls_transport_set_push_function(session, tds_push_func_login); /* NOTE: there functions return int however they cannot fail */ /* use default priorities... */ gnutls_set_default_priority(session); /* ... but overwrite some */ ret = gnutls_priority_set_direct (session, "NORMAL:%COMPAT:-VERS-SSL3.0", NULL); if (ret != 0) goto cleanup; /* mssql does not like padding too much */ #ifdef HAVE_GNUTLS_RECORD_DISABLE_PADDING gnutls_record_disable_padding(session); #endif /* put the anonymous credentials to the current session */ tls_msg = "setting credential"; ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); if (ret != 0) goto cleanup; /* Perform the TLS handshake */ tls_msg = "handshake"; ret = gnutls_handshake (session); if (ret != 0) goto cleanup; #ifndef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION ret = tds_verify_certificate(session); if (ret != 0) goto cleanup; #endif tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n"); gnutls_transport_set_ptr(session, tds->conn); gnutls_transport_set_pull_function(session, tds_pull_func); gnutls_transport_set_push_function(session, tds_push_func); tds->conn->tls_session = session; tds->conn->tls_credentials = xcred; return TDS_SUCCESS; cleanup: if (session) gnutls_deinit(session); if (xcred) gnutls_certificate_free_credentials(xcred); tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret)); return TDS_FAIL; }
bool ssl_init (void) { /* Becomes true if GnuTLS is initialized. */ static bool ssl_initialized = false; const char *ca_directory; DIR *dir; int ncerts = -1; /* GnuTLS should be initialized only once. */ if (ssl_initialized) return true; gnutls_global_init (); gnutls_certificate_allocate_credentials (&credentials); gnutls_certificate_set_verify_flags (credentials, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); #if GNUTLS_VERSION_MAJOR >= 3 if (!opt.ca_directory) ncerts = gnutls_certificate_set_x509_system_trust (credentials); #endif /* If GnuTLS version is too old or CA loading failed, fallback to old behaviour. * Also use old behaviour if the CA directory is user-provided. */ if (ncerts <= 0) { ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs"; if ((dir = opendir (ca_directory)) == NULL) { if (opt.ca_directory && *opt.ca_directory) logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"), opt.ca_directory); } else { struct hash_table *inode_map = hash_table_new (196, NULL, NULL); struct dirent *dent; size_t dirlen = strlen(ca_directory); int rc; ncerts = 0; while ((dent = readdir (dir)) != NULL) { struct stat st; size_t ca_file_length = dirlen + strlen(dent->d_name) + 2; char *ca_file = alloca(ca_file_length); snprintf (ca_file, ca_file_length, "%s/%s", ca_directory, dent->d_name); if (stat (ca_file, &st) != 0) continue; if (! S_ISREG (st.st_mode)) continue; /* avoid loading the same file twice by checking the inode. */ if (hash_table_contains (inode_map, (void *)(intptr_t) st.st_ino)) continue; hash_table_put (inode_map, (void *)(intptr_t) st.st_ino, NULL); if ((rc = gnutls_certificate_set_x509_trust_file (credentials, ca_file, GNUTLS_X509_FMT_PEM)) <= 0) DEBUGP (("WARNING: Failed to open cert %s: (%d).\n", ca_file, rc)); else ncerts += rc; } hash_table_destroy (inode_map); closedir (dir); } } if (opt.ca_cert) { int rc; ncerts = 0; if ((rc = gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert, GNUTLS_X509_FMT_PEM)) <= 0) logprintf (LOG_NOTQUIET, _ ("ERROR: Failed to open cert %s: (%d).\n"), opt.ca_cert, rc); else { ncerts += rc; logprintf (LOG_NOTQUIET, _ ("Loaded CA certificate '%s'\n"), opt.ca_cert); } } if (opt.crl_file) { int rc; if ((rc = gnutls_certificate_set_x509_crl_file (credentials, opt.crl_file, GNUTLS_X509_FMT_PEM)) <= 0) { logprintf (LOG_NOTQUIET, _("ERROR: Failed to load CRL file '%s': (%d)\n"), opt.crl_file, rc); return false; } logprintf (LOG_NOTQUIET, _ ("Loaded CRL file '%s'\n"), opt.crl_file); } DEBUGP (("Certificates loaded: %d\n", ncerts)); /* Use the private key from the cert file unless otherwise specified. */ if (opt.cert_file && !opt.private_key) { opt.private_key = xstrdup (opt.cert_file); opt.private_key_type = opt.cert_type; } /* Use the cert from the private key file unless otherwise specified. */ if (!opt.cert_file && opt.private_key) { opt.cert_file = xstrdup (opt.private_key); opt.cert_type = opt.private_key_type; } if (opt.cert_file && opt.private_key) { int type; if (opt.private_key_type != opt.cert_type) { /* GnuTLS can't handle this */ logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \ cert to be of the same type.\n")); }
int main(void) { int ret, sd, ii; gnutls_session_t session; char buffer[MAX_BUF + 1]; gnutls_certificate_credentials_t xcred; if (gnutls_check_version("3.1.4") == NULL) { fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n"); exit(1); } /* for backwards compatibility with gnutls < 3.3.0 */ CHECK(gnutls_global_init()); /* X509 stuff */ CHECK(gnutls_certificate_allocate_credentials(&xcred)); /* sets the system trusted CAs for Internet PKI */ CHECK(gnutls_certificate_set_x509_system_trust(xcred)); /* Initialize TLS session */ CHECK(gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM)); /* Use default priorities */ CHECK(gnutls_set_default_priority(session)); /* put the x509 credentials to the current session */ CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred)); CHECK(gnutls_server_name_set(session, GNUTLS_NAME_DNS, "www.example.com", strlen("www.example.com"))); gnutls_session_set_verify_cert(session, "www.example.com", 0); /* connect to the peer */ sd = udp_connect(); gnutls_transport_set_int(session, sd); /* set the connection MTU */ gnutls_dtls_set_mtu(session, 1000); /* gnutls_dtls_set_timeouts(session, 1000, 60000); */ /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET */ if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG))); LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF)); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } if (ret > 0) { printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); } /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS * connections because the peer's closure message might * be lost */ CHECK(gnutls_bye(session, GNUTLS_SHUT_WR)); end: udp_close(sd); gnutls_deinit(session); gnutls_certificate_free_credentials(xcred); gnutls_global_deinit(); return 0; }
static int tls_open(URLContext *h, const char *uri, int flags) { TLSContext *c = h->priv_data; int ret; int port; const char *p; char buf[200], host[200], opts[50] = ""; int numerichost = 0; struct addrinfo hints = { 0 }, *ai = NULL; const char *proxy_path; int use_proxy; if ((ret = ff_tls_init()) < 0) return ret; if (c->listen) snprintf(opts, sizeof(opts), "?listen=1"); av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri); p = strchr(uri, '?'); if (!p) { p = opts; } else { if (av_find_info_tag(opts, sizeof(opts), "listen", p)) c->listen = 1; } ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", p); hints.ai_flags = AI_NUMERICHOST; if (!getaddrinfo(host, NULL, &hints, &ai)) { numerichost = 1; freeaddrinfo(ai); } proxy_path = getenv("http_proxy"); use_proxy = !ff_http_match_no_proxy(getenv("no_proxy"), host) && proxy_path && av_strstart(proxy_path, "http://", NULL); if (use_proxy) { char proxy_host[200], proxy_auth[200], dest[200]; int proxy_port; av_url_split(NULL, 0, proxy_auth, sizeof(proxy_auth), proxy_host, sizeof(proxy_host), &proxy_port, NULL, 0, proxy_path); ff_url_join(dest, sizeof(dest), NULL, NULL, host, port, NULL); ff_url_join(buf, sizeof(buf), "httpproxy", proxy_auth, proxy_host, proxy_port, "/%s", dest); } ret = ffurl_open(&c->tcp, buf, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, NULL); if (ret) goto fail; c->fd = ffurl_get_file_handle(c->tcp); #if CONFIG_GNUTLS gnutls_init(&c->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT); if (!c->listen && !numerichost) gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host)); gnutls_certificate_allocate_credentials(&c->cred); set_options(h, uri); if (c->ca_file) { ret = gnutls_certificate_set_x509_trust_file(c->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(c->cred); #endif gnutls_certificate_set_verify_flags(c->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(c->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(c->session, GNUTLS_CRD_CERTIFICATE, c->cred); gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t) (intptr_t) c->fd); gnutls_priority_set_direct(c->session, "NORMAL", NULL); while (1) { ret = gnutls_handshake(c->session); if (ret == 0) break; if ((ret = do_tls_poll(h, ret)) < 0) goto fail; } 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(c->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(c->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(c->session, &cert_list_size); gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER); ret = gnutls_x509_crt_check_hostname(cert, host); gnutls_x509_crt_deinit(cert); if (!ret) { av_log(h, AV_LOG_ERROR, "The certificate's owner does not match hostname %s\n", host); ret = AVERROR(EIO); goto fail; } } #elif CONFIG_OPENSSL c->ctx = SSL_CTX_new(c->listen ? TLSv1_server_method() : TLSv1_client_method()); if (!c->ctx) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } set_options(h, uri); if (c->ca_file) { if (!SSL_CTX_load_verify_locations(c->ctx, c->ca_file, NULL)) av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL)); } if (c->cert_file && !SSL_CTX_use_certificate_chain_file(c->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(c->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(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); c->ssl = SSL_new(c->ctx); if (!c->ssl) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } SSL_set_fd(c->ssl, c->fd); if (!c->listen && !numerichost) SSL_set_tlsext_host_name(c->ssl, host); while (1) { ret = c->listen ? SSL_accept(c->ssl) : SSL_connect(c->ssl); if (ret > 0) break; if (ret == 0) { av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session\n"); ret = AVERROR(EIO); goto fail; } if ((ret = do_tls_poll(h, ret)) < 0) goto fail; } #endif return 0; fail: TLS_free(c); if (c->tcp) ffurl_close(c->tcp); ff_tls_deinit(); return ret; }
static void init_global_tls_stuff (void) { int ret; /* X509 stuff */ if (gnutls_certificate_allocate_credentials (&xcred) < 0) { fprintf (stderr, "Certificate allocation memory error\n"); exit (1); } gnutls_certificate_set_pin_function(xcred, pin_callback, NULL); if (x509_cafile != NULL) { ret = gnutls_certificate_set_x509_trust_file (xcred, x509_cafile, x509ctype); } else { ret = gnutls_certificate_set_x509_system_trust (xcred); } if (ret < 0) { fprintf (stderr, "Error setting the x509 trust file\n"); } else { printf ("Processed %d CA certificate(s).\n", ret); } if (x509_crlfile != NULL) { ret = gnutls_certificate_set_x509_crl_file (xcred, x509_crlfile, x509ctype); if (ret < 0) { fprintf (stderr, "Error setting the x509 CRL file\n"); } else { printf ("Processed %d CRL(s).\n", ret); } } load_keys (); #ifdef ENABLE_OPENPGP if (pgp_keyring != NULL) { ret = gnutls_certificate_set_openpgp_keyring_file (xcred, pgp_keyring, GNUTLS_OPENPGP_FMT_BASE64); if (ret < 0) { fprintf (stderr, "Error setting the OpenPGP keyring file\n"); } } #endif #ifdef ENABLE_SRP if (srp_username && srp_passwd) { /* SRP stuff */ if (gnutls_srp_allocate_client_credentials (&srp_cred) < 0) { fprintf (stderr, "SRP authentication error\n"); } gnutls_srp_set_client_credentials_function (srp_cred, srp_username_callback); } #endif #ifdef ENABLE_PSK /* PSK stuff */ if (gnutls_psk_allocate_client_credentials (&psk_cred) < 0) { fprintf (stderr, "PSK authentication error\n"); } if (psk_username && psk_key.data) { ret = gnutls_psk_set_client_credentials (psk_cred, psk_username, &psk_key, GNUTLS_PSK_KEY_HEX); if (ret < 0) { fprintf (stderr, "Error setting the PSK credentials: %s\n", gnutls_strerror (ret)); } } else gnutls_psk_set_client_credentials_function (psk_cred, psk_callback); #endif #ifdef ENABLE_ANON /* ANON stuff */ if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0) { fprintf (stderr, "Anonymous authentication error\n"); } #endif }