summaryrefslogtreecommitdiff
path: root/libcurl/src/lib/vtls
diff options
context:
space:
mode:
authorMichał Cichoń <michcic@gmail.com>2015-08-27 21:12:00 +0200
committerMichał Cichoń <michcic@gmail.com>2015-08-27 21:12:00 +0200
commit02f5c2ed34d16c9809b488b5a5082c40bb0f3188 (patch)
tree2a63a7fee2e6ef3533593577b0eb8d7f66301af4 /libcurl/src/lib/vtls
parent731f60aae7bcba92c1bca2c0dbec2903bb753b29 (diff)
downloadpianobar-windows-build-02f5c2ed34d16c9809b488b5a5082c40bb0f3188.tar.gz
pianobar-windows-build-02f5c2ed34d16c9809b488b5a5082c40bb0f3188.tar.bz2
pianobar-windows-build-02f5c2ed34d16c9809b488b5a5082c40bb0f3188.zip
Remove libcurl as it was replaced by WinHTTP.
Diffstat (limited to 'libcurl/src/lib/vtls')
-rw-r--r--libcurl/src/lib/vtls/axtls.c696
-rw-r--r--libcurl/src/lib/vtls/axtls.h71
-rw-r--r--libcurl/src/lib/vtls/cyassl.c734
-rw-r--r--libcurl/src/lib/vtls/cyassl.h70
-rw-r--r--libcurl/src/lib/vtls/darwinssl.c2484
-rw-r--r--libcurl/src/lib/vtls/darwinssl.h76
-rw-r--r--libcurl/src/lib/vtls/gskit.c1069
-rw-r--r--libcurl/src/lib/vtls/gskit.h71
-rw-r--r--libcurl/src/lib/vtls/gtls.c1480
-rw-r--r--libcurl/src/lib/vtls/gtls.h83
-rw-r--r--libcurl/src/lib/vtls/nss.c2006
-rw-r--r--libcurl/src/lib/vtls/nssg.h96
-rw-r--r--libcurl/src/lib/vtls/openssl.c3226
-rw-r--r--libcurl/src/lib/vtls/openssl.h113
-rw-r--r--libcurl/src/lib/vtls/polarssl.c753
-rw-r--r--libcurl/src/lib/vtls/polarssl.h75
-rw-r--r--libcurl/src/lib/vtls/polarssl_threadlock.c153
-rw-r--r--libcurl/src/lib/vtls/polarssl_threadlock.h53
-rw-r--r--libcurl/src/lib/vtls/schannel.c1364
-rw-r--r--libcurl/src/lib/vtls/schannel.h117
-rw-r--r--libcurl/src/lib/vtls/vtls.c895
-rw-r--r--libcurl/src/lib/vtls/vtls.h153
22 files changed, 0 insertions, 15838 deletions
diff --git a/libcurl/src/lib/vtls/axtls.c b/libcurl/src/lib/vtls/axtls.c
deleted file mode 100644
index 8d7e0f9..0000000
--- a/libcurl/src/lib/vtls/axtls.c
+++ /dev/null
@@ -1,696 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>.
- * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all axTLS-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_AXTLS
-#include <axTLS/config.h>
-#include <axTLS/ssl.h>
-#include "axtls.h"
-
-#include "../sendf.h"
-#include "../inet_pton.h"
-#include "vtls.h"
-#include "../parsedate.h"
-#include "../connect.h" /* for the connect timeout */
-#include "../select.h"
-#include "../curl_printf.h"
-#include "../hostcheck.h"
-#if !defined(_MSC_VER)
-#include <unistd.h>
-#endif
-
-/* The last #include files should be: */
-#include "../curl_memory.h"
-#include "../memdebug.h"
-
-
-/* Global axTLS init, called from Curl_ssl_init() */
-CURL_STATIC int Curl_axtls_init(void)
-{
-/* axTLS has no global init. Everything is done through SSL and SSL_CTX
- * structs stored in connectdata structure. Perhaps can move to axtls.h.
- */
- return 1;
-}
-
-CURL_STATIC int Curl_axtls_cleanup(void)
-{
- /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */
- return 1;
-}
-
-static CURLcode map_error_to_curl(int axtls_err)
-{
- switch (axtls_err) {
- case SSL_ERROR_NOT_SUPPORTED:
- case SSL_ERROR_INVALID_VERSION:
- case -70: /* protocol version alert from server */
- return CURLE_UNSUPPORTED_PROTOCOL;
- break;
- case SSL_ERROR_NO_CIPHER:
- return CURLE_SSL_CIPHER;
- break;
- case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
- case SSL_ERROR_NO_CERT_DEFINED:
- case -42: /* bad certificate alert from server */
- case -43: /* unsupported cert alert from server */
- case -44: /* cert revoked alert from server */
- case -45: /* cert expired alert from server */
- case -46: /* cert unknown alert from server */
- return CURLE_SSL_CERTPROBLEM;
- break;
- case SSL_X509_ERROR(X509_NOT_OK):
- case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
- case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
- case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
- case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
- case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
- case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
- case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
- case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
- return CURLE_PEER_FAILED_VERIFICATION;
- break;
- case -48: /* unknown ca alert from server */
- return CURLE_SSL_CACERT;
- break;
- case -49: /* access denied alert from server */
- return CURLE_REMOTE_ACCESS_DENIED;
- break;
- case SSL_ERROR_CONN_LOST:
- case SSL_ERROR_SOCK_SETUP_FAILURE:
- case SSL_ERROR_INVALID_HANDSHAKE:
- case SSL_ERROR_INVALID_PROT_MSG:
- case SSL_ERROR_INVALID_HMAC:
- case SSL_ERROR_INVALID_SESSION:
- case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */
- case SSL_ERROR_FINISHED_INVALID:
- case SSL_ERROR_NO_CLIENT_RENOG:
- default:
- return CURLE_SSL_CONNECT_ERROR;
- break;
- }
-}
-
-static Curl_recv axtls_recv;
-static Curl_send axtls_send;
-
-static void free_ssl_structs(struct ssl_connect_data *connssl)
-{
- if(connssl->ssl) {
- ssl_free (connssl->ssl);
- connssl->ssl = NULL;
- }
- if(connssl->ssl_ctx) {
- ssl_ctx_free(connssl->ssl_ctx);
- connssl->ssl_ctx = NULL;
- }
-}
-
-/*
- * For both blocking and non-blocking connects, this function sets up the
- * ssl context and state. This function is called after the TCP connect
- * has completed.
- */
-static CURLcode connect_prep(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- SSL_CTX *ssl_ctx;
- SSL *ssl = NULL;
- int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
- int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
- int i, ssl_fcn_return;
- const uint8_t *ssl_sessionid;
- size_t ssl_idsize;
-
- /* Assuming users will not compile in custom key/cert to axTLS.
- * Also, even for blocking connects, use axTLS non-blocking feature.
- */
- uint32_t client_option = SSL_NO_DEFAULT_KEY |
- SSL_SERVER_VERIFY_LATER |
- SSL_CONNECT_IN_PARTS;
-
- 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;
-
- /* axTLS only supports TLSv1 */
- /* check to see if we've been told to use an explicit SSL/TLS version */
- switch(data->set.ssl.version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- break;
- default:
- failf(data, "axTLS only supports TLS 1.0 and 1.1, "
- "and it cannot be specified which one to use");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-#ifdef AXTLSDEBUG
- client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
-#endif /* AXTLSDEBUG */
-
- /* Allocate an SSL_CTX struct */
- ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
- if(ssl_ctx == NULL) {
- failf(data, "unable to create client SSL context");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- conn->ssl[sockindex].ssl_ctx = ssl_ctx;
- conn->ssl[sockindex].ssl = NULL;
-
- /* Load the trusted CA cert bundle file */
- if(data->set.ssl.CAfile) {
- if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL)
- != SSL_OK) {
- infof(data, "error reading ca cert file %s \n",
- data->set.ssl.CAfile);
- if(data->set.ssl.verifypeer) {
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
- else
- infof(data, "found certificates in %s\n", data->set.ssl.CAfile);
- }
-
- /* gtls.c tasks we're skipping for now:
- * 1) certificate revocation list checking
- * 2) dns name assignment to host
- * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore
- * 4) set certificate priority. axTLS ignores type and sends certs in
- * order added. can probably ignore this.
- */
-
- /* Load client certificate */
- if(data->set.str[STRING_CERT]) {
- i=0;
- /* Instead of trying to analyze cert type here, let axTLS try them all. */
- while(cert_types[i] != 0) {
- ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
- data->set.str[STRING_CERT], NULL);
- if(ssl_fcn_return == SSL_OK) {
- infof(data, "successfully read cert file %s \n",
- data->set.str[STRING_CERT]);
- break;
- }
- i++;
- }
- /* Tried all cert types, none worked. */
- if(cert_types[i] == 0) {
- failf(data, "%s is not x509 or pkcs12 format",
- data->set.str[STRING_CERT]);
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- /* Load client key.
- If a pkcs12 file successfully loaded a cert, then there's nothing to do
- because the key has already been loaded. */
- if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) {
- i=0;
- /* Instead of trying to analyze key type here, let axTLS try them all. */
- while(key_types[i] != 0) {
- ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
- data->set.str[STRING_KEY], NULL);
- if(ssl_fcn_return == SSL_OK) {
- infof(data, "successfully read key file %s \n",
- data->set.str[STRING_KEY]);
- break;
- }
- i++;
- }
- /* Tried all key types, none worked. */
- if(key_types[i] == 0) {
- failf(data, "Failure: %s is not a supported key file",
- data->set.str[STRING_KEY]);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- /* gtls.c does more here that is being left out for now
- * 1) set session credentials. can probably ignore since axtls puts this
- * info in the ssl_ctx struct
- * 2) setting up callbacks. these seem gnutls specific
- */
-
- /* In axTLS, handshaking happens inside ssl_client_new. */
- if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
- /* we got a session id, use it! */
- infof (data, "SSL re-using session ID\n");
- ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
- ssl_sessionid, (uint8_t)ssl_idsize);
- }
- else
- ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
-
- conn->ssl[sockindex].ssl = ssl;
- return CURLE_OK;
-}
-
-/*
- * For both blocking and non-blocking connects, this function finalizes the
- * SSL connection.
- */
-static CURLcode connect_finish(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- SSL *ssl = conn->ssl[sockindex].ssl;
- const uint8_t *ssl_sessionid;
- size_t ssl_idsize;
- const char *peer_CN;
- uint32_t dns_altname_index;
- const char *dns_altname;
- int8_t found_subject_alt_names = 0;
- int8_t found_subject_alt_name_matching_conn = 0;
-
- /* Here, gtls.c gets the peer certificates and fails out depending on
- * settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
- */
-
- /* Verify server's certificate */
- if(data->set.ssl.verifypeer) {
- if(ssl_verify_cert(ssl) != SSL_OK) {
- Curl_axtls_close(conn, sockindex);
- failf(data, "server cert verify failed");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- }
- else
- infof(data, "\t server certificate verification SKIPPED\n");
-
- /* Here, gtls.c does issuer verification. axTLS has no straightforward
- * equivalent, so omitting for now.*/
-
- /* Here, gtls.c does the following
- * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but
- * it seems useful. This is now implemented, by Oscar Koeroo
- * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert
- * 3) displays a bunch of cert information. axTLS doesn't support most of
- * this, but a couple fields are available.
- */
-
- /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
- risk of an inifite loop */
- for(dns_altname_index = 0; ; dns_altname_index++) {
- dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
- if(dns_altname == NULL) {
- break;
- }
- found_subject_alt_names = 1;
-
- infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
- dns_altname, conn->host.name);
- if(Curl_cert_hostcheck(dns_altname, conn->host.name)) {
- found_subject_alt_name_matching_conn = 1;
- break;
- }
- }
-
- /* RFC2818 checks */
- if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
- if(data->set.ssl.verifyhost) {
- /* Break connection ! */
- Curl_axtls_close(conn, sockindex);
- failf(data, "\tsubjectAltName(s) do not match %s\n",
- conn->host.dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\tsubjectAltName(s) do not match %s\n",
- conn->host.dispname);
- }
- else if(found_subject_alt_names == 0) {
- /* Per RFC2818, when no Subject Alt Names were available, examine the peer
- CN as a legacy fallback */
- peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
- if(peer_CN == NULL) {
- if(data->set.ssl.verifyhost) {
- Curl_axtls_close(conn, sockindex);
- failf(data, "unable to obtain common name from peer certificate");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "unable to obtain common name from peer certificate");
- }
- else {
- if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
- if(data->set.ssl.verifyhost) {
- /* Break connection ! */
- Curl_axtls_close(conn, sockindex);
- failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
- peer_CN, conn->host.dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
- peer_CN, conn->host.dispname);
- }
- }
- }
-
- /* General housekeeping */
- conn->ssl[sockindex].state = ssl_connection_complete;
- conn->recv[sockindex] = axtls_recv;
- conn->send[sockindex] = axtls_send;
-
- /* Put our freshly minted SSL session in cache */
- ssl_idsize = ssl_get_session_id_size(ssl);
- ssl_sessionid = ssl_get_session_id(ssl);
- if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
- != CURLE_OK)
- infof (data, "failed to add session to cache\n");
-
- return CURLE_OK;
-}
-
-/*
- * Use axTLS's non-blocking connection feature to open an SSL connection.
- * This is called after a TCP connection is already established.
- */
-CURL_STATIC CURLcode Curl_axtls_connect_nonblocking(
- struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- CURLcode conn_step;
- int ssl_fcn_return;
- int i;
-
- *done = FALSE;
- /* connectdata is calloc'd and connecting_state is only changed in this
- function, so this is safe, as the state is effectively initialized. */
- if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
- conn_step = connect_prep(conn, sockindex);
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
- conn->ssl[sockindex].connecting_state = ssl_connect_2;
- }
-
- if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
- /* Check to make sure handshake was ok. */
- if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
- /* Loop to perform more work in between sleeps. This is work around the
- fact that axtls does not expose any knowledge about when work needs
- to be performed. This can save ~25% of time on SSL handshakes. */
- for(i=0; i<5; i++) {
- ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
- if(ssl_fcn_return < 0) {
- Curl_axtls_close(conn, sockindex);
- ssl_display_error(ssl_fcn_return); /* goes to stdout. */
- return map_error_to_curl(ssl_fcn_return);
- }
- return CURLE_OK;
- }
- }
- infof (conn->data, "handshake completed successfully\n");
- conn->ssl[sockindex].connecting_state = ssl_connect_3;
- }
-
- if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
- conn_step = connect_finish(conn, sockindex);
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
-
- /* Reset connect state */
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
-
- *done = TRUE;
- return CURLE_OK;
- }
-
- /* Unrecognized state. Things are very bad. */
- conn->ssl[sockindex].state = ssl_connection_none;
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
- /* Return value perhaps not strictly correct, but distinguishes the issue.*/
- return CURLE_BAD_FUNCTION_ARGUMENT;
-}
-
-
-/*
- * This function is called after the TCP connect has completed. Setup the TLS
- * layer and do all necessary magic for a blocking connect.
- */
-CURL_STATIC CURLcode
-Curl_axtls_connect(struct connectdata *conn,
- int sockindex)
-
-{
- struct SessionHandle *data = conn->data;
- CURLcode conn_step = connect_prep(conn, sockindex);
- int ssl_fcn_return;
- SSL *ssl = conn->ssl[sockindex].ssl;
- long timeout_ms;
-
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
-
- /* Check to make sure handshake was ok. */
- while(ssl_handshake_status(ssl) != SSL_OK) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- ssl_fcn_return = ssl_read(ssl, NULL);
- if(ssl_fcn_return < 0) {
- Curl_axtls_close(conn, sockindex);
- ssl_display_error(ssl_fcn_return); /* goes to stdout. */
- return map_error_to_curl(ssl_fcn_return);
- }
- /* TODO: avoid polling */
-#if !defined(_MSC_VER)
- usleep(10000);
-#else
- Sleep(10);
-#endif
- }
- infof (conn->data, "handshake completed successfully\n");
-
- conn_step = connect_finish(conn, sockindex);
- if(conn_step != CURLE_OK) {
- Curl_axtls_close(conn, sockindex);
- return conn_step;
- }
-
- return CURLE_OK;
-}
-
-/* return number of sent (non-SSL) bytes */
-static ssize_t axtls_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *err)
-{
- /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
- int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
-
- infof(conn->data, " axtls_send\n");
-
- if(rc < 0 ) {
- *err = map_error_to_curl(rc);
- rc = -1; /* generic error code for send failure */
- }
-
- *err = CURLE_OK;
- return rc;
-}
-
-CURL_STATIC void Curl_axtls_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- infof(conn->data, " Curl_axtls_close\n");
-
- /* line from openssl.c: (void)SSL_shutdown(connssl->ssl);
- axTLS compat layer does nothing for SSL_shutdown */
-
- /* The following line is from openssl.c. There seems to be no axTLS
- equivalent. ssl_free and ssl_ctx_free close things.
- SSL_set_connect_state(connssl->handle); */
-
- free_ssl_structs(connssl);
-}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-CURL_STATIC int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
-{
- /* Outline taken from openssl.c since functions are in axTLS compat layer.
- axTLS's error set is much smaller, so a lot of error-handling was removed.
- */
- int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- uint8_t *buf;
- ssize_t nread;
-
- infof(conn->data, " Curl_axtls_shutdown\n");
-
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
- if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(connssl->ssl);
- */
-
- if(connssl->ssl) {
- int what = Curl_socket_ready(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server. buf is managed internally by
- axTLS and will be released upon calling ssl_free via
- free_ssl_structs. */
- nread = (ssize_t)ssl_read(connssl->ssl, &buf);
-
- if(nread < SSL_OK) {
- failf(data, "close notify alert not received during shutdown");
- retval = -1;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- retval = -1;
- }
-
- free_ssl_structs(connssl);
- }
- return retval;
-}
-
-static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- CURLcode *err)
-{
- struct ssl_connect_data *connssl = &conn->ssl[num];
- ssize_t ret = 0;
- uint8_t *read_buf;
-
- infof(conn->data, " axtls_recv\n");
-
- *err = CURLE_OK;
- if(connssl) {
- ret = ssl_read(connssl->ssl, &read_buf);
- if(ret > SSL_OK) {
- /* ssl_read returns SSL_OK if there is more data to read, so if it is
- larger, then all data has been read already. */
- memcpy(buf, read_buf,
- (size_t)ret > buffersize ? buffersize : (size_t)ret);
- }
- else if(ret == SSL_OK) {
- /* more data to be read, signal caller to call again */
- *err = CURLE_AGAIN;
- ret = -1;
- }
- else if(ret == -3) {
- /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
- team approves proposed fix. */
- Curl_axtls_close(conn, num);
- }
- else {
- failf(conn->data, "axTLS recv error (%d)", ret);
- *err = map_error_to_curl((int) ret);
- ret = -1;
- }
- }
-
- return ret;
-}
-
-/*
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-CURL_STATIC int Curl_axtls_check_cxn(struct connectdata *conn)
-{
- /* openssl.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
- axTLS compat layer always returns the last argument, so connection is
- always alive? */
-
- infof(conn->data, " Curl_axtls_check_cxn\n");
- return 1; /* connection still in place */
-}
-
-CURL_STATIC void Curl_axtls_session_free(void *ptr)
-{
- (void)ptr;
- /* free the ID */
- /* both openssl.c and gtls.c do something here, but axTLS's OpenSSL
- compatibility layer does nothing, so we do nothing too. */
-}
-
-CURL_STATIC size_t Curl_axtls_version(char *buffer, size_t size)
-{
- return snprintf(buffer, size, "axTLS/%s", ssl_version());
-}
-
-CURL_STATIC int Curl_axtls_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length)
-{
- static bool ssl_seeded = FALSE;
- (void)data;
- if(!ssl_seeded) {
- ssl_seeded = TRUE;
- /* Initialize the seed if not already done. This call is not exactly thread
- * safe (and neither is the ssl_seeded check), but the worst effect of a
- * race condition is that some global resources will leak. */
- RNG_initialize();
- }
- get_random((int)length, entropy);
- return 0;
-}
-
-#endif /* USE_AXTLS */
diff --git a/libcurl/src/lib/vtls/axtls.h b/libcurl/src/lib/vtls/axtls.h
deleted file mode 100644
index e794fd9..0000000
--- a/libcurl/src/lib/vtls/axtls.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef HEADER_CURL_AXTLS_H
-#define HEADER_CURL_AXTLS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010, DirecTV, Contact: Eric Hu <ehu@directv.com>
- * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#ifdef USE_AXTLS
-#include "curl/curl.h"
-#include "../urldata.h"
-
-CURL_STATIC int Curl_axtls_init(void);
-CURL_STATIC int Curl_axtls_cleanup(void);
-CURL_STATIC CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_axtls_connect_nonblocking(
- struct connectdata *conn,
- int sockindex,
- bool *done);
-
- /* close a SSL connection */
-CURL_STATIC void Curl_axtls_close(struct connectdata *conn, int sockindex);
-
-CURL_STATIC void Curl_axtls_session_free(void *ptr);
-CURL_STATIC size_t Curl_axtls_version(char *buffer, size_t size);
-CURL_STATIC int Curl_axtls_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC int Curl_axtls_check_cxn(struct connectdata *conn);
-CURL_STATIC int Curl_axtls_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length);
-
-/* Set the API backend definition to axTLS */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS
-
-/* API setup for axTLS */
-#define curlssl_init Curl_axtls_init
-#define curlssl_cleanup Curl_axtls_cleanup
-#define curlssl_connect Curl_axtls_connect
-#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking
-#define curlssl_session_free(x) Curl_axtls_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_axtls_close
-#define curlssl_shutdown(x,y) Curl_axtls_shutdown(x,y)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_axtls_version
-#define curlssl_check_cxn(x) Curl_axtls_check_cxn(x)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
-#define curlssl_random(x,y,z) Curl_axtls_random(x,y,z)
-
-#endif /* USE_AXTLS */
-#endif /* HEADER_CURL_AXTLS_H */
-
diff --git a/libcurl/src/lib/vtls/cyassl.c b/libcurl/src/lib/vtls/cyassl.c
deleted file mode 100644
index 92ae083..0000000
--- a/libcurl/src/lib/vtls/cyassl.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- *
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_CYASSL
-
-#define WOLFSSL_OPTIONS_IGNORE_SYS
-/* CyaSSL's version.h, which should contain only the version, should come
-before all other CyaSSL includes and be immediately followed by build config
-aka options.h. http://curl.haxx.se/mail/lib-2015-04/0069.html */
-#include <cyassl/version.h>
-#if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008)
-#if defined(CYASSL_API) || defined(WOLFSSL_API)
-/* Safety measure. If either is defined some API include was already included
-and that's a problem since options.h hasn't been included yet. */
-#error "CyaSSL API was included before the CyaSSL build options."
-#endif
-#include <cyassl/options.h>
-#endif
-
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "inet_pton.h"
-#include "cyassl.h"
-#include "vtls.h"
-#include "parsedate.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "rawstr.h"
-#include "curl_printf.h"
-
-#include <cyassl/ssl.h>
-#ifdef HAVE_CYASSL_ERROR_SSL_H
-#include <cyassl/error-ssl.h>
-#else
-#include <cyassl/error.h>
-#endif
-#include <cyassl/ctaocrypt/random.h>
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */
-#define CYASSL_MAX_ERROR_SZ 80
-#endif
-
-static Curl_recv cyassl_recv;
-static Curl_send cyassl_send;
-
-
-static int do_file_type(const char *type)
-{
- if(!type || !type[0])
- return SSL_FILETYPE_PEM;
- if(Curl_raw_equal(type, "PEM"))
- return SSL_FILETYPE_PEM;
- if(Curl_raw_equal(type, "DER"))
- return SSL_FILETYPE_ASN1;
- return -1;
-}
-
-/*
- * This function loads all the client/CA certificates and CRLs. Setup the TLS
- * layer and do all necessary magic.
- */
-static CURLcode
-cyassl_connect_step1(struct connectdata *conn,
- int sockindex)
-{
- char error_buffer[CYASSL_MAX_ERROR_SZ];
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data* conssl = &conn->ssl[sockindex];
- SSL_METHOD* req_method = NULL;
- void* ssl_sessionid = NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
-#ifdef HAVE_SNI
- bool sni = FALSE;
-#define use_sni(x) sni = (x)
-#else
-#define use_sni(x) Curl_nop_stmt
-#endif
-
- if(conssl->state == ssl_connection_complete)
- return CURLE_OK;
-
- /* check to see if we've been told to use an explicit SSL/TLS version */
- switch(data->set.ssl.version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
-#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
- /* minimum protocol version is set later after the CTX object is created */
- req_method = SSLv23_client_method();
-#else
- infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
- "TLS 1.0 is used exclusively\n");
- req_method = TLSv1_client_method();
-#endif
- use_sni(TRUE);
- break;
- case CURL_SSLVERSION_TLSv1_0:
- req_method = TLSv1_client_method();
- use_sni(TRUE);
- break;
- case CURL_SSLVERSION_TLSv1_1:
- req_method = TLSv1_1_client_method();
- use_sni(TRUE);
- break;
- case CURL_SSLVERSION_TLSv1_2:
- req_method = TLSv1_2_client_method();
- use_sni(TRUE);
- break;
- case CURL_SSLVERSION_SSLv3:
- req_method = SSLv3_client_method();
- use_sni(FALSE);
- break;
- case CURL_SSLVERSION_SSLv2:
- failf(data, "CyaSSL does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- if(!req_method) {
- failf(data, "SSL: couldn't create a method!");
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(conssl->ctx)
- SSL_CTX_free(conssl->ctx);
- conssl->ctx = SSL_CTX_new(req_method);
-
- if(!conssl->ctx) {
- failf(data, "SSL: couldn't create a context!");
- return CURLE_OUT_OF_MEMORY;
- }
-
- switch(data->set.ssl.version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
-#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
- /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever
- minimum version of TLS was built in and at least TLS 1.0. For later library
- versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so
- we have this short circuit evaluation to find the minimum supported TLS
- version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
- because only the former will work before the user's CTX callback is called.
- */
- if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) &&
- (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) &&
- (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) {
- failf(data, "SSL: couldn't set the minimum protocol version");
- return CURLE_SSL_CONNECT_ERROR;
- }
-#endif
- break;
- }
-
-#ifndef NO_FILESYSTEM
- /* load trusted cacert */
- if(data->set.str[STRING_SSL_CAFILE]) {
- if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
- data->set.str[STRING_SSL_CAFILE],
- data->set.str[STRING_SSL_CAPATH])) {
- if(data->set.ssl.verifypeer) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:\n"
- " CAfile: %s\n CApath: %s",
- data->set.str[STRING_SSL_CAFILE]?
- data->set.str[STRING_SSL_CAFILE]: "none",
- data->set.str[STRING_SSL_CAPATH]?
- data->set.str[STRING_SSL_CAPATH] : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- /* Just continue with a warning if no strict certificate
- verification is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
- }
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:\n");
- }
- infof(data,
- " CAfile: %s\n"
- " CApath: %s\n",
- data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
- "none",
- data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
- "none");
- }
-
- /* Load the client certificate, and private key */
- if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
- int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);
-
- if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
- file_type) != 1) {
- failf(data, "unable to use client certificate (no key or wrong pass"
- " phrase?)");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
- if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
- file_type) != 1) {
- failf(data, "unable to set private key");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif /* !NO_FILESYSTEM */
-
- /* SSL always tries to verify the peer, this only says whether it should
- * fail to connect if the verification fails, or if it should continue
- * anyway. In the latter case the result of the verification is checked with
- * SSL_get_verify_result() below. */
- SSL_CTX_set_verify(conssl->ctx,
- data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
- NULL);
-
-#ifdef HAVE_SNI
- if(sni) {
- struct in_addr addr4;
-#ifdef ENABLE_IPV6
- struct in6_addr addr6;
-#endif
- size_t hostname_len = strlen(conn->host.name);
- if((hostname_len < USHRT_MAX) &&
- (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) &&
-#ifdef ENABLE_IPV6
- (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) &&
-#endif
- (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name,
- (unsigned short)hostname_len) != 1)) {
- infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension\n");
- }
- }
-#endif
-
- /* give application a chance to interfere with SSL set up. */
- if(data->set.ssl.fsslctx) {
- CURLcode result = CURLE_OK;
- result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
- data->set.ssl.fsslctxp);
- if(result) {
- failf(data, "error signaled by ssl ctx callback");
- return result;
- }
- }
-#ifdef NO_FILESYSTEM
- else if(data->set.ssl.verifypeer) {
- failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
- " with \"no filesystem\". Either disable peer verification"
- " (insecure) or if you are building an application with libcurl you"
- " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
- return CURLE_SSL_CONNECT_ERROR;
- }
-#endif
-
- /* Let's make an SSL structure */
- if(conssl->handle)
- SSL_free(conssl->handle);
- conssl->handle = SSL_new(conssl->ctx);
- if(!conssl->handle) {
- failf(data, "SSL: couldn't create a context (handle)!");
- return CURLE_OUT_OF_MEMORY;
- }
-
- /* Check if there's a cached ID we can/should use here! */
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
- /* we got a session id, use it! */
- if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
- failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer));
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* Informational message */
- infof (data, "SSL re-using session ID\n");
- }
-
- /* pass the raw socket into the SSL layer */
- if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
- failf(data, "SSL: SSL_set_fd failed");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- conssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
-}
-
-
-static CURLcode
-cyassl_connect_step2(struct connectdata *conn,
- int sockindex)
-{
- int ret = -1;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data* conssl = &conn->ssl[sockindex];
-
- conn->recv[sockindex] = cyassl_recv;
- conn->send[sockindex] = cyassl_send;
-
- /* Enable RFC2818 checks */
- if(data->set.ssl.verifyhost) {
- ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name);
- if(ret == SSL_FAILURE)
- return CURLE_OUT_OF_MEMORY;
- }
-
- ret = SSL_connect(conssl->handle);
- if(ret != 1) {
- char error_buffer[CYASSL_MAX_ERROR_SZ];
- int detail = SSL_get_error(conssl->handle, ret);
-
- if(SSL_ERROR_WANT_READ == detail) {
- conssl->connecting_state = ssl_connect_2_reading;
- return CURLE_OK;
- }
- else if(SSL_ERROR_WANT_WRITE == detail) {
- conssl->connecting_state = ssl_connect_2_writing;
- return CURLE_OK;
- }
- /* There is no easy way to override only the CN matching.
- * This will enable the override of both mismatching SubjectAltNames
- * as also mismatching CN fields */
- else if(DOMAIN_NAME_MISMATCH == detail) {
-#if 1
- failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
- conn->host.dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
-#else
- /* When the CyaSSL_check_domain_name() is used and you desire to continue
- * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0',
- * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
- * way to do this is currently to switch the CyaSSL_check_domain_name()
- * in and out based on the 'data->set.ssl.verifyhost' value. */
- if(data->set.ssl.verifyhost) {
- failf(data,
- "\tsubject alt name(s) or common name do not match \"%s\"\n",
- conn->host.dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else {
- infof(data,
- "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
- conn->host.dispname);
- return CURLE_OK;
- }
-#endif
- }
-#if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
- else if(ASN_NO_SIGNER_E == detail) {
- if(data->set.ssl.verifypeer) {
- failf(data, "\tCA signer not available for verification\n");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- /* Just continue with a warning if no strict certificate
- verification is required. */
- infof(data, "CA signer not available for verification, "
- "continuing anyway\n");
- }
- }
-#endif
- else {
- failf(data, "SSL_connect failed with error %d: %s", detail,
- ERR_error_string(detail, error_buffer));
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- conssl->connecting_state = ssl_connect_3;
- infof(data, "SSL connected\n");
-
- return CURLE_OK;
-}
-
-
-static CURLcode
-cyassl_connect_step3(struct connectdata *conn,
- int sockindex)
-{
- CURLcode result = CURLE_OK;
- void *old_ssl_sessionid=NULL;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- bool incache;
- SSL_SESSION *our_ssl_sessionid;
-
- DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-
- our_ssl_sessionid = SSL_get_session(connssl->handle);
-
- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
- if(incache) {
- if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing\n");
- Curl_ssl_delsessionid(conn, old_ssl_sessionid);
- incache = FALSE;
- }
- }
-
- if(!incache) {
- result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */);
- if(result) {
- failf(data, "failed to store ssl session");
- return result;
- }
- }
-
- connssl->connecting_state = ssl_connect_done;
-
- return result;
-}
-
-
-static ssize_t cyassl_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
-{
- char error_buffer[CYASSL_MAX_ERROR_SZ];
- int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
-
- if(rc < 0) {
- int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
-
- switch(err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_write() */
- *curlcode = CURLE_AGAIN;
- return -1;
- default:
- failf(conn->data, "SSL write: %s, errno %d",
- ERR_error_string(err, error_buffer),
- SOCKERRNO);
- *curlcode = CURLE_SEND_ERROR;
- return -1;
- }
- }
- return rc;
-}
-
-CURL_STATIC void Curl_cyassl_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *conssl = &conn->ssl[sockindex];
-
- if(conssl->handle) {
- (void)SSL_shutdown(conssl->handle);
- SSL_free (conssl->handle);
- conssl->handle = NULL;
- }
- if(conssl->ctx) {
- SSL_CTX_free (conssl->ctx);
- conssl->ctx = NULL;
- }
-}
-
-static ssize_t cyassl_recv(struct connectdata *conn,
- int num,
- char *buf,
- size_t buffersize,
- CURLcode *curlcode)
-{
- char error_buffer[CYASSL_MAX_ERROR_SZ];
- int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- int nread = SSL_read(conn->ssl[num].handle, buf, buffsize);
-
- if(nread < 0) {
- int err = SSL_get_error(conn->ssl[num].handle, nread);
-
- switch(err) {
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- break;
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_read() */
- *curlcode = CURLE_AGAIN;
- return -1;
- default:
- failf(conn->data, "SSL read: %s, errno %d",
- ERR_error_string(err, error_buffer),
- SOCKERRNO);
- *curlcode = CURLE_RECV_ERROR;
- return -1;
- }
- }
- return nread;
-}
-
-
-CURL_STATIC void Curl_cyassl_session_free(void *ptr)
-{
- (void)ptr;
- /* CyaSSL reuses sessions on own, no free */
-}
-
-
-CURL_STATIC size_t Curl_cyassl_version(char *buffer, size_t size)
-{
-#ifdef WOLFSSL_VERSION
- return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
-#elif defined(CYASSL_VERSION)
- return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
-#else
- return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
-#endif
-}
-
-
-CURL_STATIC int Curl_cyassl_init(void)
-{
- return (CyaSSL_Init() == SSL_SUCCESS);
-}
-
-
-CURL_STATIC bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
-{
- if(conn->ssl[connindex].handle) /* SSL is in use */
- return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
- else
- return FALSE;
-}
-
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-CURL_STATIC int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
-{
- int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->handle) {
- SSL_free (connssl->handle);
- connssl->handle = NULL;
- }
- return retval;
-}
-
-
-static CURLcode
-cyassl_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
-{
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
- int what;
-
- /* check if the connection has already been established */
- if(ssl_connection_complete == connssl->state) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- if(ssl_connect_1==connssl->connecting_state) {
- /* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- result = cyassl_connect_step1(conn, sockindex);
- if(result)
- return result;
- }
-
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
-
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
-
- curl_socket_t writefd = ssl_connect_2_writing==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-
- what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* Run transaction, and return to the caller if it failed or if
- * this connection is part of a multi handle and this loop would
- * execute again. This permits the owner of a multi handle to
- * abort a connection attempt before step2 has completed while
- * ensuring that a client using select() or epoll() will always
- * have a valid fdset to wait on.
- */
- result = cyassl_connect_step2(conn, sockindex);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
- return result;
- } /* repeat step2 until all transactions are done. */
-
- if(ssl_connect_3 == connssl->connecting_state) {
- result = cyassl_connect_step3(conn, sockindex);
- if(result)
- return result;
- }
-
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = cyassl_recv;
- conn->send[sockindex] = cyassl_send;
- *done = TRUE;
- }
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-
-CURL_STATIC CURLcode
-Curl_cyassl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- return cyassl_connect_common(conn, sockindex, TRUE, done);
-}
-
-
-CURL_STATIC CURLcode
-Curl_cyassl_connect(struct connectdata *conn,
- int sockindex)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = cyassl_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-CURL_STATIC int Curl_cyassl_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length)
-{
- RNG rng;
- (void)data;
- if(InitRng(&rng))
- return 1;
- if(length > UINT_MAX)
- return 1;
- if(RNG_GenerateBlock(&rng, entropy, (unsigned)length))
- return 1;
- return 0;
-}
-
-#endif
diff --git a/libcurl/src/lib/vtls/cyassl.h b/libcurl/src/lib/vtls/cyassl.h
deleted file mode 100644
index 0cc54a5..0000000
--- a/libcurl/src/lib/vtls/cyassl.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef HEADER_CURL_CYASSL_H
-#define HEADER_CURL_CYASSL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#ifdef USE_CYASSL
-
-CURL_STATIC CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex);
-CURL_STATIC int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex);
-
- /* close a SSL connection */
-CURL_STATIC void Curl_cyassl_close(struct connectdata *conn, int sockindex);
-
-CURL_STATIC void Curl_cyassl_session_free(void *ptr);
-CURL_STATIC size_t Curl_cyassl_version(char *buffer, size_t size);
-CURL_STATIC int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC int Curl_cyassl_init(void);
-CURL_STATIC CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-CURL_STATIC int Curl_cyassl_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length);
-
-/* Set the API backend definition to Schannel */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL
-
-/* this backend supports CURLOPT_SSL_CTX_* */
-#define have_curlssl_ssl_ctx 1
-
-/* API setup for CyaSSL */
-#define curlssl_init Curl_cyassl_init
-#define curlssl_cleanup() Curl_nop_stmt
-#define curlssl_connect Curl_cyassl_connect
-#define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking
-#define curlssl_session_free(x) Curl_cyassl_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_cyassl_close
-#define curlssl_shutdown(x,y) Curl_cyassl_shutdown(x,y)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_cyassl_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) Curl_cyassl_data_pending(x,y)
-#define curlssl_random(x,y,z) Curl_cyassl_random(x,y,z)
-
-#endif /* USE_CYASSL */
-#endif /* HEADER_CURL_CYASSL_H */
diff --git a/libcurl/src/lib/vtls/darwinssl.c b/libcurl/src/lib/vtls/darwinssl.c
deleted file mode 100644
index 11f107f..0000000
--- a/libcurl/src/lib/vtls/darwinssl.c
+++ /dev/null
@@ -1,2484 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all iOS and Mac OS X SecureTransport-specific code for the
- * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
- */
-
-#include "../curl_setup.h"
-
-#include "../urldata.h" /* for the SessionHandle definition */
-#include "../curl_base64.h"
-#include "../strtok.h"
-
-#ifdef USE_DARWINSSL
-
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include <Security/Security.h>
-#include <Security/SecureTransport.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <CommonCrypto/CommonDigest.h>
-
-/* The Security framework has changed greatly between iOS and different OS X
- versions, and we will try to support as many of them as we can (back to
- Leopard and iOS 5) by using macros and weak-linking.
-
- IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then
- you must build this project against the 10.8 SDK or later. */
-#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
-#error "The darwinssl back-end requires Leopard or later."
-#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
-
-#define CURL_BUILD_IOS 0
-#define CURL_BUILD_IOS_7 0
-#define CURL_BUILD_MAC 1
-/* This is the maximum API level we are allowed to use when building: */
-#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
-#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
-#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
-#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
-/* These macros mean "the following code is present to allow runtime backward
- compatibility with at least this cat or earlier":
- (You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET
- environmental variable.) */
-#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
-#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
-#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
-#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
-#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
-
-#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
-#define CURL_BUILD_IOS 1
-#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
-#define CURL_BUILD_MAC 0
-#define CURL_BUILD_MAC_10_5 0
-#define CURL_BUILD_MAC_10_6 0
-#define CURL_BUILD_MAC_10_7 0
-#define CURL_BUILD_MAC_10_8 0
-#define CURL_SUPPORT_MAC_10_5 0
-#define CURL_SUPPORT_MAC_10_6 0
-#define CURL_SUPPORT_MAC_10_7 0
-#define CURL_SUPPORT_MAC_10_8 0
-#define CURL_SUPPORT_MAC_10_9 0
-
-#else
-#error "The darwinssl back-end requires iOS or OS X."
-#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
-
-#if CURL_BUILD_MAC
-#include <sys/sysctl.h>
-#endif /* CURL_BUILD_MAC */
-
-#include "urldata.h"
-#include "sendf.h"
-#include "inet_pton.h"
-#include "connect.h"
-#include "select.h"
-#include "vtls.h"
-#include "darwinssl.h"
-#include "curl_printf.h"
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* From MacTypes.h (which we can't include because it isn't present in iOS: */
-#define ioErr -36
-#define paramErr -50
-
-/* The following two functions were ripped from Apple sample code,
- * with some modifications: */
-static OSStatus SocketRead(SSLConnectionRef connection,
- void *data, /* owned by
- * caller, data
- * RETURNED */
- size_t *dataLength) /* IN/OUT */
-{
- size_t bytesToGo = *dataLength;
- size_t initLen = bytesToGo;
- UInt8 *currData = (UInt8 *)data;
- /*int sock = *(int *)connection;*/
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
- int sock = connssl->ssl_sockfd;
- OSStatus rtn = noErr;
- size_t bytesRead;
- ssize_t rrtn;
- int theErr;
-
- *dataLength = 0;
-
- for(;;) {
- bytesRead = 0;
- rrtn = read(sock, currData, bytesToGo);
- if(rrtn <= 0) {
- /* this is guesswork... */
- theErr = errno;
- if(rrtn == 0) { /* EOF = server hung up */
- /* the framework will turn this into errSSLClosedNoNotify */
- rtn = errSSLClosedGraceful;
- }
- else /* do the switch */
- switch(theErr) {
- case ENOENT:
- /* connection closed */
- rtn = errSSLClosedGraceful;
- break;
- case ECONNRESET:
- rtn = errSSLClosedAbort;
- break;
- case EAGAIN:
- rtn = errSSLWouldBlock;
- connssl->ssl_direction = false;
- break;
- default:
- rtn = ioErr;
- break;
- }
- break;
- }
- else {
- bytesRead = rrtn;
- }
- bytesToGo -= bytesRead;
- currData += bytesRead;
-
- if(bytesToGo == 0) {
- /* filled buffer with incoming data, done */
- break;
- }
- }
- *dataLength = initLen - bytesToGo;
-
- return rtn;
-}
-
-static OSStatus SocketWrite(SSLConnectionRef connection,
- const void *data,
- size_t *dataLength) /* IN/OUT */
-{
- size_t bytesSent = 0;
- /*int sock = *(int *)connection;*/
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
- int sock = connssl->ssl_sockfd;
- ssize_t length;
- size_t dataLen = *dataLength;
- const UInt8 *dataPtr = (UInt8 *)data;
- OSStatus ortn;
- int theErr;
-
- *dataLength = 0;
-
- do {
- length = write(sock,
- (char*)dataPtr + bytesSent,
- dataLen - bytesSent);
- } while((length > 0) &&
- ( (bytesSent += length) < dataLen) );
-
- if(length <= 0) {
- theErr = errno;
- if(theErr == EAGAIN) {
- ortn = errSSLWouldBlock;
- connssl->ssl_direction = true;
- }
- else {
- ortn = ioErr;
- }
- }
- else {
- ortn = noErr;
- }
- *dataLength = bytesSent;
- return ortn;
-}
-
-CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) {
- switch (cipher) {
- /* SSL version 3.0 */
- case SSL_RSA_WITH_NULL_MD5:
- return "SSL_RSA_WITH_NULL_MD5";
- break;
- case SSL_RSA_WITH_NULL_SHA:
- return "SSL_RSA_WITH_NULL_SHA";
- break;
- case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
- return "SSL_RSA_EXPORT_WITH_RC4_40_MD5";
- break;
- case SSL_RSA_WITH_RC4_128_MD5:
- return "SSL_RSA_WITH_RC4_128_MD5";
- break;
- case SSL_RSA_WITH_RC4_128_SHA:
- return "SSL_RSA_WITH_RC4_128_SHA";
- break;
- case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
- return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5";
- break;
- case SSL_RSA_WITH_IDEA_CBC_SHA:
- return "SSL_RSA_WITH_IDEA_CBC_SHA";
- break;
- case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_RSA_WITH_DES_CBC_SHA:
- return "SSL_RSA_WITH_DES_CBC_SHA";
- break;
- case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
- return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DH_DSS_WITH_DES_CBC_SHA:
- return "SSL_DH_DSS_WITH_DES_CBC_SHA";
- break;
- case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DH_RSA_WITH_DES_CBC_SHA:
- return "SSL_DH_RSA_WITH_DES_CBC_SHA";
- break;
- case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DHE_DSS_WITH_DES_CBC_SHA:
- return "SSL_DHE_DSS_WITH_DES_CBC_SHA";
- break;
- case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DHE_RSA_WITH_DES_CBC_SHA:
- return "SSL_DHE_RSA_WITH_DES_CBC_SHA";
- break;
- case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
- return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5";
- break;
- case SSL_DH_anon_WITH_RC4_128_MD5:
- return "SSL_DH_anon_WITH_RC4_128_MD5";
- break;
- case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DH_anon_WITH_DES_CBC_SHA:
- return "SSL_DH_anon_WITH_DES_CBC_SHA";
- break;
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
- return "SSL_FORTEZZA_DMS_WITH_NULL_SHA";
- break;
- case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
- return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA";
- break;
- /* TLS 1.0 with AES (RFC 3268)
- (Apparently these are used in SSLv3 implementations as well.) */
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
- break;
- /* SSL version 2.0 */
- case SSL_RSA_WITH_RC2_CBC_MD5:
- return "SSL_RSA_WITH_RC2_CBC_MD5";
- break;
- case SSL_RSA_WITH_IDEA_CBC_MD5:
- return "SSL_RSA_WITH_IDEA_CBC_MD5";
- break;
- case SSL_RSA_WITH_DES_CBC_MD5:
- return "SSL_RSA_WITH_DES_CBC_MD5";
- break;
- case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
- return "SSL_RSA_WITH_3DES_EDE_CBC_MD5";
- break;
- }
- return "SSL_NULL_WITH_NULL_NULL";
-}
-
-CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
- switch(cipher) {
- /* TLS 1.0 with AES (RFC 3268) */
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
- break;
-#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
- /* TLS 1.0 with ECDSA (RFC 4492) */
- case TLS_ECDH_ECDSA_WITH_NULL_SHA:
- return "TLS_ECDH_ECDSA_WITH_NULL_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- return "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDH_RSA_WITH_NULL_SHA:
- return "TLS_ECDH_RSA_WITH_NULL_SHA";
- break;
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- return "TLS_ECDH_RSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_NULL_SHA:
- return "TLS_ECDHE_RSA_WITH_NULL_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDH_anon_WITH_NULL_SHA:
- return "TLS_ECDH_anon_WITH_NULL_SHA";
- break;
- case TLS_ECDH_anon_WITH_RC4_128_SHA:
- return "TLS_ECDH_anon_WITH_RC4_128_SHA";
- break;
- case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
- return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
- return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
- break;
-#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- /* TLS 1.2 (RFC 5246) */
- case TLS_RSA_WITH_NULL_MD5:
- return "TLS_RSA_WITH_NULL_MD5";
- break;
- case TLS_RSA_WITH_NULL_SHA:
- return "TLS_RSA_WITH_NULL_SHA";
- break;
- case TLS_RSA_WITH_RC4_128_MD5:
- return "TLS_RSA_WITH_RC4_128_MD5";
- break;
- case TLS_RSA_WITH_RC4_128_SHA:
- return "TLS_RSA_WITH_RC4_128_SHA";
- break;
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_RSA_WITH_NULL_SHA256:
- return "TLS_RSA_WITH_NULL_SHA256";
- break;
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- return "TLS_RSA_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
- return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
- return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
- return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
- return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
- return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DH_anon_WITH_RC4_128_MD5:
- return "TLS_DH_anon_WITH_RC4_128_MD5";
- break;
- case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
- return "TLS_DH_anon_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
- return "TLS_DH_anon_WITH_AES_256_CBC_SHA256";
- break;
- /* TLS 1.2 with AES GCM (RFC 5288) */
- case TLS_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
- return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
- return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
- return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
- return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
- return "TLS_DH_anon_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
- return "TLS_DH_anon_WITH_AES_256_GCM_SHA384";
- break;
- /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
- return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
- break;
-#else
- case SSL_RSA_WITH_NULL_MD5:
- return "TLS_RSA_WITH_NULL_MD5";
- break;
- case SSL_RSA_WITH_NULL_SHA:
- return "TLS_RSA_WITH_NULL_SHA";
- break;
- case SSL_RSA_WITH_RC4_128_MD5:
- return "TLS_RSA_WITH_RC4_128_MD5";
- break;
- case SSL_RSA_WITH_RC4_128_SHA:
- return "TLS_RSA_WITH_RC4_128_SHA";
- break;
- case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_anon_WITH_RC4_128_MD5:
- return "TLS_DH_anon_WITH_RC4_128_MD5";
- break;
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- /* TLS PSK (RFC 4279): */
- case TLS_PSK_WITH_RC4_128_SHA:
- return "TLS_PSK_WITH_RC4_128_SHA";
- break;
- case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
- return "TLS_PSK_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_PSK_WITH_AES_128_CBC_SHA:
- return "TLS_PSK_WITH_AES_128_CBC_SHA";
- break;
- case TLS_PSK_WITH_AES_256_CBC_SHA:
- return "TLS_PSK_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_PSK_WITH_RC4_128_SHA:
- return "TLS_DHE_PSK_WITH_RC4_128_SHA";
- break;
- case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA";
- break;
- case TLS_RSA_PSK_WITH_RC4_128_SHA:
- return "TLS_RSA_PSK_WITH_RC4_128_SHA";
- break;
- case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
- return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
- return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA";
- break;
- case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
- return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA";
- break;
- /* More TLS PSK (RFC 4785): */
- case TLS_PSK_WITH_NULL_SHA:
- return "TLS_PSK_WITH_NULL_SHA";
- break;
- case TLS_DHE_PSK_WITH_NULL_SHA:
- return "TLS_DHE_PSK_WITH_NULL_SHA";
- break;
- case TLS_RSA_PSK_WITH_NULL_SHA:
- return "TLS_RSA_PSK_WITH_NULL_SHA";
- break;
- /* Even more TLS PSK (RFC 5487): */
- case TLS_PSK_WITH_AES_128_GCM_SHA256:
- return "TLS_PSK_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_PSK_WITH_AES_256_GCM_SHA384:
- return "TLS_PSK_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
- return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
- return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
- return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
- return "TLS_PSK_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_PSK_WITH_AES_128_CBC_SHA256:
- return "TLS_PSK_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_PSK_WITH_AES_256_CBC_SHA384:
- return "TLS_PSK_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_PSK_WITH_NULL_SHA256:
- return "TLS_PSK_WITH_NULL_SHA256";
- break;
- case TLS_PSK_WITH_NULL_SHA384:
- return "TLS_PSK_WITH_NULL_SHA384";
- break;
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
- return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
- return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_DHE_PSK_WITH_NULL_SHA256:
- return "TLS_DHE_PSK_WITH_NULL_SHA256";
- break;
- case TLS_DHE_PSK_WITH_NULL_SHA384:
- return "TLS_RSA_PSK_WITH_NULL_SHA384";
- break;
- case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
- return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
- return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_RSA_PSK_WITH_NULL_SHA256:
- return "TLS_RSA_PSK_WITH_NULL_SHA256";
- break;
- case TLS_RSA_PSK_WITH_NULL_SHA384:
- return "TLS_RSA_PSK_WITH_NULL_SHA384";
- break;
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
- }
- return "TLS_NULL_WITH_NULL_NULL";
-}
-
-#if CURL_BUILD_MAC
-CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
-{
- int mib[2];
- char *os_version;
- size_t os_version_len;
- char *os_version_major, *os_version_minor/*, *os_version_point*/;
- char *tok_buf;
-
- /* Get the Darwin kernel version from the kernel using sysctl(): */
- mib[0] = CTL_KERN;
- mib[1] = KERN_OSRELEASE;
- if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
- return;
- os_version = malloc(os_version_len*sizeof(char));
- if(!os_version)
- return;
- if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
- free(os_version);
- return;
- }
-
- /* Parse the version: */
- os_version_major = strtok_r(os_version, ".", &tok_buf);
- os_version_minor = strtok_r(NULL, ".", &tok_buf);
- /*os_version_point = strtok_r(NULL, ".", &tok_buf);*/
- *major = atoi(os_version_major);
- *minor = atoi(os_version_minor);
- free(os_version);
-}
-#endif /* CURL_BUILD_MAC */
-
-/* Apple provides a myriad of ways of getting information about a certificate
- into a string. Some aren't available under iOS or newer cats. So here's
- a unified function for getting a string describing the certificate that
- ought to work in all cats starting with Leopard. */
-CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
-{
- CFStringRef server_cert_summary = CFSTR("(null)");
-
-#if CURL_BUILD_IOS
- /* iOS: There's only one way to do this. */
- server_cert_summary = SecCertificateCopySubjectSummary(cert);
-#else
-#if CURL_BUILD_MAC_10_7
- /* Lion & later: Get the long description if we can. */
- if(SecCertificateCopyLongDescription != NULL)
- server_cert_summary =
- SecCertificateCopyLongDescription(NULL, cert, NULL);
- else
-#endif /* CURL_BUILD_MAC_10_7 */
-#if CURL_BUILD_MAC_10_6
- /* Snow Leopard: Get the certificate summary. */
- if(SecCertificateCopySubjectSummary != NULL)
- server_cert_summary = SecCertificateCopySubjectSummary(cert);
- else
-#endif /* CURL_BUILD_MAC_10_6 */
- /* Leopard is as far back as we go... */
- (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
-#endif /* CURL_BUILD_IOS */
- return server_cert_summary;
-}
-
-#if CURL_SUPPORT_MAC_10_6
-/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
- deprecation warnings, so let's not compile this unless it's necessary: */
-static OSStatus CopyIdentityWithLabelOldSchool(char *label,
- SecIdentityRef *out_c_a_k)
-{
- OSStatus status = errSecItemNotFound;
- SecKeychainAttributeList attr_list;
- SecKeychainAttribute attr;
- SecKeychainSearchRef search = NULL;
- SecCertificateRef cert = NULL;
-
- /* Set up the attribute list: */
- attr_list.count = 1L;
- attr_list.attr = &attr;
-
- /* Set up our lone search criterion: */
- attr.tag = kSecLabelItemAttr;
- attr.data = label;
- attr.length = (UInt32)strlen(label);
-
- /* Start searching: */
- status = SecKeychainSearchCreateFromAttributes(NULL,
- kSecCertificateItemClass,
- &attr_list,
- &search);
- if(status == noErr) {
- status = SecKeychainSearchCopyNext(search,
- (SecKeychainItemRef *)&cert);
- if(status == noErr && cert) {
- /* If we found a certificate, does it have a private key? */
- status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
- CFRelease(cert);
- }
- }
-
- if(search)
- CFRelease(search);
- return status;
-}
-#endif /* CURL_SUPPORT_MAC_10_6 */
-
-static OSStatus CopyIdentityWithLabel(char *label,
- SecIdentityRef *out_cert_and_key)
-{
- OSStatus status = errSecItemNotFound;
-
-#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
- /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
- kSecClassIdentity was introduced in Lion. If both exist, let's use them
- to find the certificate. */
- if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
- CFTypeRef keys[4];
- CFTypeRef values[4];
- CFDictionaryRef query_dict;
- CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
- kCFStringEncodingUTF8);
-
- /* Set up our search criteria and expected results: */
- values[0] = kSecClassIdentity; /* we want a certificate and a key */
- keys[0] = kSecClass;
- values[1] = kCFBooleanTrue; /* we want a reference */
- keys[1] = kSecReturnRef;
- values[2] = kSecMatchLimitOne; /* one is enough, thanks */
- keys[2] = kSecMatchLimit;
- /* identity searches need a SecPolicyRef in order to work */
- values[3] = SecPolicyCreateSSL(false, label_cf);
- keys[3] = kSecMatchPolicy;
- query_dict = CFDictionaryCreate(NULL, (const void **)keys,
- (const void **)values, 4L,
- &kCFCopyStringDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CFRelease(values[3]);
- CFRelease(label_cf);
-
- /* Do we have a match? */
- status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
- CFRelease(query_dict);
- }
- else {
-#if CURL_SUPPORT_MAC_10_6
- /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */
- status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
-#endif /* CURL_SUPPORT_MAC_10_7 */
- }
-#elif CURL_SUPPORT_MAC_10_6
- /* For developers building on older cats, we have no choice but to fall back
- to SecKeychainSearch. */
- status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
-#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
- return status;
-}
-
-static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
- const char *cPassword,
- SecIdentityRef *out_cert_and_key)
-{
- OSStatus status = errSecItemNotFound;
- CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
- (const UInt8 *)cPath, strlen(cPath), false);
- CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
- cPassword, kCFStringEncodingUTF8) : NULL;
- CFDataRef pkcs_data = NULL;
-
- /* We can import P12 files on iOS or OS X 10.7 or later: */
- /* These constants are documented as having first appeared in 10.6 but they
- raise linker errors when used on that cat for some reason. */
-#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
- if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
- NULL, NULL, &status)) {
- const void *cKeys[] = {kSecImportExportPassphrase};
- const void *cValues[] = {password};
- CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
- password ? 1L : 0L, NULL, NULL);
- CFArrayRef items = NULL;
-
- /* Here we go: */
- status = SecPKCS12Import(pkcs_data, options, &items);
- if(status == noErr && items && CFArrayGetCount(items)) {
- CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L);
- const void *temp_identity = CFDictionaryGetValue(identity_and_trust,
- kSecImportItemIdentity);
-
- /* Retain the identity; we don't care about any other data... */
- CFRetain(temp_identity);
- *out_cert_and_key = (SecIdentityRef)temp_identity;
- }
-
- if(items)
- CFRelease(items);
- CFRelease(options);
- CFRelease(pkcs_data);
- }
-#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
- if(password)
- CFRelease(password);
- CFRelease(pkcs_url);
- return status;
-}
-
-/* This code was borrowed from nss.c, with some modifications:
- * Determine whether the nickname passed in is a filename that needs to
- * be loaded as a PEM or a regular NSS nickname.
- *
- * returns 1 for a file
- * returns 0 for not a file
- */
-CF_INLINE bool is_file(const char *filename)
-{
- struct_stat st;
-
- if(filename == NULL)
- return false;
-
- if(stat(filename, &st) == 0)
- return S_ISREG(st.st_mode);
- return false;
-}
-
-static CURLcode darwinssl_connect_step1(struct connectdata *conn,
- int sockindex)
-{
- struct SessionHandle *data = conn->data;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif /* ENABLE_IPV6 */
- size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
- SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
- char *ssl_sessionid;
- size_t ssl_sessionid_len;
- OSStatus err = noErr;
-#if CURL_BUILD_MAC
- int darwinver_maj = 0, darwinver_min = 0;
-
- GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
-#endif /* CURL_BUILD_MAC */
-
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
- if(connssl->ssl_ctx)
- CFRelease(connssl->ssl_ctx);
- connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
- if(!connssl->ssl_ctx) {
- failf(data, "SSL: couldn't create a context!");
- return CURLE_OUT_OF_MEMORY;
- }
- }
- else {
- /* The old ST API does not exist under iOS, so don't compile it: */
-#if CURL_SUPPORT_MAC_10_8
- if(connssl->ssl_ctx)
- (void)SSLDisposeContext(connssl->ssl_ctx);
- err = SSLNewContext(false, &(connssl->ssl_ctx));
- if(err != noErr) {
- failf(data, "SSL: couldn't create a context: OSStatus %d", err);
- return CURLE_OUT_OF_MEMORY;
- }
-#endif /* CURL_SUPPORT_MAC_10_8 */
- }
-#else
- if(connssl->ssl_ctx)
- (void)SSLDisposeContext(connssl->ssl_ctx);
- err = SSLNewContext(false, &(connssl->ssl_ctx));
- if(err != noErr) {
- failf(data, "SSL: couldn't create a context: OSStatus %d", err);
- return CURLE_OUT_OF_MEMORY;
- }
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
- connssl->ssl_write_buffered_length = 0UL; /* reset buffered write length */
-
- /* check to see if we've been told to use an explicit SSL/TLS version */
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLSetProtocolVersionMax != NULL) {
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
- break;
- case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1);
- break;
- case CURL_SSLVERSION_TLSv1_1:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11);
- break;
- case CURL_SSLVERSION_TLSv1_2:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
- break;
- case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
- break;
- case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2);
- }
- }
- else {
-#if CURL_SUPPORT_MAC_10_8
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocolAll,
- false);
- switch (data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol1,
- true);
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol11,
- true);
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol12,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol1,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_1:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol11,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_2:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol12,
- true);
- break;
- case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol3,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol2,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- }
-#endif /* CURL_SUPPORT_MAC_10_8 */
- }
-#else
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kTLSProtocol1,
- true);
- break;
- case CURL_SSLVERSION_TLSv1_1:
- failf(data, "Your version of the OS does not support TLSv1.1");
- return CURLE_SSL_CONNECT_ERROR;
- case CURL_SSLVERSION_TLSv1_2:
- failf(data, "Your version of the OS does not support TLSv1.2");
- return CURLE_SSL_CONNECT_ERROR;
- case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol2,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
- kSSLProtocol3,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- }
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-
- if(data->set.str[STRING_KEY]) {
- infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
- "Transport. The private key must be in the Keychain.\n");
- }
-
- if(data->set.str[STRING_CERT]) {
- SecIdentityRef cert_and_key = NULL;
- bool is_cert_file = is_file(data->set.str[STRING_CERT]);
-
- /* User wants to authenticate with a client cert. Look for it:
- If we detect that this is a file on disk, then let's load it.
- Otherwise, assume that the user wants to use an identity loaded
- from the Keychain. */
- if(is_cert_file) {
- if(!data->set.str[STRING_CERT_TYPE])
- infof(data, "WARNING: SSL: Certificate type not set, assuming "
- "PKCS#12 format.\n");
- else if(strncmp(data->set.str[STRING_CERT_TYPE], "P12",
- strlen(data->set.str[STRING_CERT_TYPE])) != 0)
- infof(data, "WARNING: SSL: The Security framework only supports "
- "loading identities that are in PKCS#12 format.\n");
-
- err = CopyIdentityFromPKCS12File(data->set.str[STRING_CERT],
- data->set.str[STRING_KEY_PASSWD], &cert_and_key);
- }
- else
- err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key);
-
- if(err == noErr) {
- SecCertificateRef cert = NULL;
- CFTypeRef certs_c[1];
- CFArrayRef certs;
-
- /* If we found one, print it out: */
- err = SecIdentityCopyCertificate(cert_and_key, &cert);
- if(err == noErr) {
- CFStringRef cert_summary = CopyCertSubject(cert);
- char cert_summary_c[128];
-
- if(cert_summary) {
- memset(cert_summary_c, 0, 128);
- if(CFStringGetCString(cert_summary,
- cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Client certificate: %s\n", cert_summary_c);
- }
- CFRelease(cert_summary);
- CFRelease(cert);
- }
- }
- certs_c[0] = cert_and_key;
- certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
- &kCFTypeArrayCallBacks);
- err = SSLSetCertificate(connssl->ssl_ctx, certs);
- if(certs)
- CFRelease(certs);
- if(err != noErr) {
- failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
- return CURLE_SSL_CERTPROBLEM;
- }
- CFRelease(cert_and_key);
- }
- else {
- switch(err) {
- case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
- failf(data, "SSL: Incorrect password for the certificate \"%s\" "
- "and its private key.", data->set.str[STRING_CERT]);
- break;
- case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
- failf(data, "SSL: Couldn't make sense of the data in the "
- "certificate \"%s\" and its private key.",
- data->set.str[STRING_CERT]);
- break;
- case -25260: /* errSecPassphraseRequired */
- failf(data, "SSL The certificate \"%s\" requires a password.",
- data->set.str[STRING_CERT]);
- break;
- case errSecItemNotFound:
- failf(data, "SSL: Can't find the certificate \"%s\" and its private "
- "key in the Keychain.", data->set.str[STRING_CERT]);
- break;
- default:
- failf(data, "SSL: Can't load the certificate \"%s\" and its private "
- "key: OSStatus %d", data->set.str[STRING_CERT], err);
- break;
- }
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- /* SSL always tries to verify the peer, this only says whether it should
- * fail to connect if the verification fails, or if it should continue
- * anyway. In the latter case the result of the verification is checked with
- * SSL_get_verify_result() below. */
-#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
- /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
- a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
- works, it doesn't work as expected under Snow Leopard or Lion.
- So we need to call SSLSetEnableCertVerify() on those older cats in order
- to disable certificate validation if the user turned that off.
- (SecureTransport will always validate the certificate chain by
- default.) */
- /* (Note: Darwin 12.x.x is Mountain Lion.) */
-#if CURL_BUILD_MAC
- if(SSLSetSessionOption != NULL && darwinver_maj >= 12) {
-#else
- if(SSLSetSessionOption != NULL) {
-#endif /* CURL_BUILD_MAC */
- bool break_on_auth = !data->set.ssl.verifypeer ||
- data->set.str[STRING_SSL_CAFILE];
- err = SSLSetSessionOption(connssl->ssl_ctx,
- kSSLSessionOptionBreakOnServerAuth,
- break_on_auth);
- if(err != noErr) {
- failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- else {
-#if CURL_SUPPORT_MAC_10_8
- err = SSLSetEnableCertVerify(connssl->ssl_ctx,
- data->set.ssl.verifypeer?true:false);
- if(err != noErr) {
- failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
-#endif /* CURL_SUPPORT_MAC_10_8 */
- }
-#else
- err = SSLSetEnableCertVerify(connssl->ssl_ctx,
- data->set.ssl.verifypeer?true:false);
- if(err != noErr) {
- failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
-#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
-
- if(data->set.str[STRING_SSL_CAFILE]) {
- bool is_cert_file = is_file(data->set.str[STRING_SSL_CAFILE]);
-
- if(!is_cert_file) {
- failf(data, "SSL: can't load CA certificate file %s",
- data->set.str[STRING_SSL_CAFILE]);
- return CURLE_SSL_CACERT_BADFILE;
- }
- if(!data->set.ssl.verifypeer) {
- failf(data, "SSL: CA certificate set, but certificate verification "
- "is disabled");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- /* Configure hostname check. SNI is used if available.
- * Both hostname check and SNI require SSLSetPeerDomainName().
- * Also: the verifyhost setting influences SNI usage */
- if(data->set.ssl.verifyhost) {
- err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name,
- strlen(conn->host.name));
-
- if(err != noErr) {
- infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
- err);
- }
-
- if((Curl_inet_pton(AF_INET, conn->host.name, &addr))
- #ifdef ENABLE_IPV6
- || (Curl_inet_pton(AF_INET6, conn->host.name, &addr))
- #endif
- ) {
- infof(data, "WARNING: using IP address, SNI is being disabled by "
- "the OS.\n");
- }
- }
-
- /* Disable cipher suites that ST supports but are not safe. These ciphers
- are unlikely to be used in any case since ST gives other ciphers a much
- higher priority, but it's probably better that we not connect at all than
- to give the user a false sense of security if the server only supports
- insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
- (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count);
- all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- if(all_ciphers && allowed_ciphers &&
- SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers,
- &all_ciphers_count) == noErr) {
- for(i = 0UL ; i < all_ciphers_count ; i++) {
-#if CURL_BUILD_MAC
- /* There's a known bug in early versions of Mountain Lion where ST's ECC
- ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
- Work around the problem here by disabling those ciphers if we are
- running in an affected version of OS X. */
- if(darwinver_maj == 12 && darwinver_min <= 3 &&
- all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
- continue;
- }
-#endif /* CURL_BUILD_MAC */
- switch(all_ciphers[i]) {
- /* Disable NULL ciphersuites: */
- case SSL_NULL_WITH_NULL_NULL:
- case SSL_RSA_WITH_NULL_MD5:
- case SSL_RSA_WITH_NULL_SHA:
- case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */
- case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
- case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
- case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
- case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */
- case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */
- case 0x002C: /* TLS_PSK_WITH_NULL_SHA */
- case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */
- case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */
- case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */
- case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */
- case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */
- case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */
- case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */
- case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */
- /* Disable anonymous ciphersuites: */
- case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
- case SSL_DH_anon_WITH_RC4_128_MD5:
- case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_anon_WITH_DES_CBC_SHA:
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */
- case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */
- case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
- case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
- case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
- case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
- case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
- case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
- case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
- /* Disable weak key ciphersuites: */
- case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
- case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
- case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_RSA_WITH_DES_CBC_SHA:
- case SSL_DH_DSS_WITH_DES_CBC_SHA:
- case SSL_DH_RSA_WITH_DES_CBC_SHA:
- case SSL_DHE_DSS_WITH_DES_CBC_SHA:
- case SSL_DHE_RSA_WITH_DES_CBC_SHA:
- /* Disable IDEA: */
- case SSL_RSA_WITH_IDEA_CBC_SHA:
- case SSL_RSA_WITH_IDEA_CBC_MD5:
- break;
- default: /* enable everything else */
- allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
- break;
- }
- }
- err = SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers,
- allowed_ciphers_count);
- if(err != noErr) {
- failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- else {
- Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
- failf(data, "SSL: Failed to allocate memory for allowed ciphers");
- return CURLE_OUT_OF_MEMORY;
- }
- Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
-
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- /* We want to enable 1/n-1 when using a CBC cipher unless the user
- specifically doesn't want us doing that: */
- if(SSLSetSessionOption != NULL) {
- SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
- !data->set.ssl_enable_beast);
- SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart,
- data->set.ssl.falsestart); /* false start support */
- }
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
-
- /* Check if there's a cached ID we can/should use here! */
- if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
- &ssl_sessionid_len)) {
- /* we got a session id, use it! */
- err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
- if(err != noErr) {
- failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* Informational message */
- infof(data, "SSL re-using session ID\n");
- }
- /* If there isn't one, then let's make one up! This has to be done prior
- to starting the handshake. */
- else {
- CURLcode result;
- ssl_sessionid =
- aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE],
- data->set.ssl.verifypeer, data->set.ssl.verifyhost,
- conn->host.name, conn->remote_port);
- ssl_sessionid_len = strlen(ssl_sessionid);
-
- err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
- if(err != noErr) {
- failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
- if(result) {
- failf(data, "failed to store ssl session");
- return result;
- }
- }
-
- err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite);
- if(err != noErr) {
- failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* pass the raw socket into the SSL layers */
- /* We need to store the FD in a constant memory address, because
- * SSLSetConnection() will not copy that address. I've found that
- * conn->sock[sockindex] may change on its own. */
- connssl->ssl_sockfd = sockfd;
- err = SSLSetConnection(connssl->ssl_ctx, connssl);
- if(err != noErr) {
- failf(data, "SSL: SSLSetConnection() failed: %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
-}
-
-static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
-{
- char *sep_start, *sep_end, *cert_start, *cert_end;
- size_t i, j, err;
- size_t len;
- unsigned char *b64;
-
- /* Jump through the separators at the beginning of the certificate. */
- sep_start = strstr(in, "-----");
- if(sep_start == NULL)
- return 0;
- cert_start = strstr(sep_start + 1, "-----");
- if(cert_start == NULL)
- return -1;
-
- cert_start += 5;
-
- /* Find separator after the end of the certificate. */
- cert_end = strstr(cert_start, "-----");
- if(cert_end == NULL)
- return -1;
-
- sep_end = strstr(cert_end + 1, "-----");
- if(sep_end == NULL)
- return -1;
- sep_end += 5;
-
- len = cert_end - cert_start;
- b64 = malloc(len + 1);
- if(!b64)
- return -1;
-
- /* Create base64 string without linefeeds. */
- for(i = 0, j = 0; i < len; i++) {
- if(cert_start[i] != '\r' && cert_start[i] != '\n')
- b64[j++] = cert_start[i];
- }
- b64[j] = '\0';
-
- err = Curl_base64_decode((const char *)b64, out, outlen);
- free(b64);
- if(err) {
- free(*out);
- return -1;
- }
-
- return sep_end - in;
-}
-
-static int read_cert(const char *file, unsigned char **out, size_t *outlen)
-{
- int fd;
- ssize_t n, len = 0, cap = 512;
- unsigned char buf[cap], *data;
-
- fd = open(file, 0);
- if(fd < 0)
- return -1;
-
- data = malloc(cap);
- if(!data) {
- close(fd);
- return -1;
- }
-
- for(;;) {
- n = read(fd, buf, sizeof(buf));
- if(n < 0) {
- close(fd);
- free(data);
- return -1;
- }
- else if(n == 0) {
- close(fd);
- break;
- }
-
- if(len + n >= cap) {
- cap *= 2;
- data = realloc(data, cap);
- if(!data) {
- close(fd);
- return -1;
- }
- }
-
- memcpy(data + len, buf, n);
- len += n;
- }
- data[len] = '\0';
-
- *out = data;
- *outlen = len;
-
- return 0;
-}
-
-static int sslerr_to_curlerr(struct SessionHandle *data, int err)
-{
- switch(err) {
- case errSSLXCertChainInvalid:
- failf(data, "SSL certificate problem: Invalid certificate chain");
- return CURLE_SSL_CACERT;
- case errSSLUnknownRootCert:
- failf(data, "SSL certificate problem: Untrusted root certificate");
- return CURLE_SSL_CACERT;
- case errSSLNoRootCert:
- failf(data, "SSL certificate problem: No root certificate");
- return CURLE_SSL_CACERT;
- case errSSLCertExpired:
- failf(data, "SSL certificate problem: Certificate chain had an "
- "expired certificate");
- return CURLE_SSL_CACERT;
- case errSSLBadCert:
- failf(data, "SSL certificate problem: Couldn't understand the server "
- "certificate format");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLHostNameMismatch:
- failf(data, "SSL certificate peer hostname mismatch");
- return CURLE_PEER_FAILED_VERIFICATION;
- default:
- failf(data, "SSL unexpected certificate error %d", err);
- return CURLE_SSL_CACERT;
- }
-}
-
-static int append_cert_to_array(struct SessionHandle *data,
- unsigned char *buf, size_t buflen,
- CFMutableArrayRef array)
-{
- CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
- if(!certdata) {
- failf(data, "SSL: failed to allocate array for CA certificate");
- return CURLE_OUT_OF_MEMORY;
- }
-
- SecCertificateRef cacert =
- SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
- CFRelease(certdata);
- if(!cacert) {
- failf(data, "SSL: failed to create SecCertificate from CA certificate");
- return CURLE_SSL_CACERT;
- }
-
- /* Check if cacert is valid. */
- CFStringRef subject = CopyCertSubject(cacert);
- if(subject) {
- char subject_cbuf[128];
- memset(subject_cbuf, 0, 128);
- if(!CFStringGetCString(subject,
- subject_cbuf,
- 128,
- kCFStringEncodingUTF8)) {
- CFRelease(cacert);
- failf(data, "SSL: invalid CA certificate subject");
- return CURLE_SSL_CACERT;
- }
- CFRelease(subject);
- }
- else {
- CFRelease(cacert);
- failf(data, "SSL: invalid CA certificate");
- return CURLE_SSL_CACERT;
- }
-
- CFArrayAppendValue(array, cacert);
- CFRelease(cacert);
-
- return CURLE_OK;
-}
-
-static int verify_cert(const char *cafile, struct SessionHandle *data,
- SSLContextRef ctx)
-{
- int n = 0, rc;
- long res;
- unsigned char *certbuf, *der;
- size_t buflen, derlen, offset = 0;
-
- if(read_cert(cafile, &certbuf, &buflen) < 0) {
- failf(data, "SSL: failed to read or invalid CA certificate");
- return CURLE_SSL_CACERT;
- }
-
- /*
- * Certbuf now contains the contents of the certificate file, which can be
- * - a single DER certificate,
- * - a single PEM certificate or
- * - a bunch of PEM certificates (certificate bundle).
- *
- * Go through certbuf, and convert any PEM certificate in it into DER
- * format.
- */
- CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeArrayCallBacks);
- if(array == NULL) {
- free(certbuf);
- failf(data, "SSL: out of memory creating CA certificate array");
- return CURLE_OUT_OF_MEMORY;
- }
-
- while(offset < buflen) {
- n++;
-
- /*
- * Check if the certificate is in PEM format, and convert it to DER. If
- * this fails, we assume the certificate is in DER format.
- */
- res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
- if(res < 0) {
- free(certbuf);
- CFRelease(array);
- failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle",
- n, offset);
- return CURLE_SSL_CACERT;
- }
- offset += res;
-
- if(res == 0 && offset == 0) {
- /* This is not a PEM file, probably a certificate in DER format. */
- rc = append_cert_to_array(data, certbuf, buflen, array);
- free(certbuf);
- if(rc != CURLE_OK) {
- CFRelease(array);
- return rc;
- }
- break;
- }
- else if(res == 0) {
- /* No more certificates in the bundle. */
- free(certbuf);
- break;
- }
-
- rc = append_cert_to_array(data, der, derlen, array);
- free(der);
- if(rc != CURLE_OK) {
- free(certbuf);
- CFRelease(array);
- return rc;
- }
- }
-
- SecTrustRef trust;
- OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
- if(trust == NULL) {
- failf(data, "SSL: error getting certificate chain");
- CFRelease(array);
- return CURLE_OUT_OF_MEMORY;
- }
- else if(ret != noErr) {
- CFRelease(array);
- return sslerr_to_curlerr(data, ret);
- }
-
- ret = SecTrustSetAnchorCertificates(trust, array);
- if(ret != noErr) {
- CFRelease(trust);
- return sslerr_to_curlerr(data, ret);
- }
- ret = SecTrustSetAnchorCertificatesOnly(trust, true);
- if(ret != noErr) {
- CFRelease(trust);
- return sslerr_to_curlerr(data, ret);
- }
-
- SecTrustResultType trust_eval = 0;
- ret = SecTrustEvaluate(trust, &trust_eval);
- CFRelease(array);
- CFRelease(trust);
- if(ret != noErr) {
- return sslerr_to_curlerr(data, ret);
- }
-
- switch (trust_eval) {
- case kSecTrustResultUnspecified:
- case kSecTrustResultProceed:
- return CURLE_OK;
-
- case kSecTrustResultRecoverableTrustFailure:
- case kSecTrustResultDeny:
- default:
- failf(data, "SSL: certificate verification failed (result: %d)",
- trust_eval);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
-}
-
-static CURLcode
-darwinssl_connect_step2(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- OSStatus err;
- SSLCipherSuite cipher;
- SSLProtocol protocol = 0;
-
- DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
- || ssl_connect_2_reading == connssl->connecting_state
- || ssl_connect_2_writing == connssl->connecting_state);
-
- /* Here goes nothing: */
- err = SSLHandshake(connssl->ssl_ctx);
-
- if(err != noErr) {
- switch (err) {
- case errSSLWouldBlock: /* they're not done with us yet */
- connssl->connecting_state = connssl->ssl_direction ?
- ssl_connect_2_writing : ssl_connect_2_reading;
- return CURLE_OK;
-
- /* The below is errSSLServerAuthCompleted; it's not defined in
- Leopard's headers */
- case -9841:
- if(data->set.str[STRING_SSL_CAFILE]) {
- int res = verify_cert(data->set.str[STRING_SSL_CAFILE], data,
- connssl->ssl_ctx);
- if(res != CURLE_OK)
- return res;
- }
- /* the documentation says we need to call SSLHandshake() again */
- return darwinssl_connect_step2(conn, sockindex);
-
- /* These are all certificate problems with the server: */
- case errSSLXCertChainInvalid:
- failf(data, "SSL certificate problem: Invalid certificate chain");
- return CURLE_SSL_CACERT;
- case errSSLUnknownRootCert:
- failf(data, "SSL certificate problem: Untrusted root certificate");
- return CURLE_SSL_CACERT;
- case errSSLNoRootCert:
- failf(data, "SSL certificate problem: No root certificate");
- return CURLE_SSL_CACERT;
- case errSSLCertExpired:
- failf(data, "SSL certificate problem: Certificate chain had an "
- "expired certificate");
- return CURLE_SSL_CACERT;
- case errSSLBadCert:
- failf(data, "SSL certificate problem: Couldn't understand the server "
- "certificate format");
- return CURLE_SSL_CONNECT_ERROR;
-
- /* These are all certificate problems with the client: */
- case errSecAuthFailed:
- failf(data, "SSL authentication failed");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLPeerHandshakeFail:
- failf(data, "SSL peer handshake failed, the server most likely "
- "requires a client certificate to connect");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLPeerUnknownCA:
- failf(data, "SSL server rejected the client certificate due to "
- "the certificate being signed by an unknown certificate "
- "authority");
- return CURLE_SSL_CONNECT_ERROR;
-
- /* This error is raised if the server's cert didn't match the server's
- host name: */
- case errSSLHostNameMismatch:
- failf(data, "SSL certificate peer verification failed, the "
- "certificate did not match \"%s\"\n", conn->host.dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
-
- /* Generic handshake errors: */
- case errSSLConnectionRefused:
- failf(data, "Server dropped the connection during the SSL handshake");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLClosedAbort:
- failf(data, "Server aborted the SSL handshake");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLNegotiation:
- failf(data, "Could not negotiate an SSL cipher suite with the server");
- return CURLE_SSL_CONNECT_ERROR;
- /* Sometimes paramErr happens with buggy ciphers: */
- case paramErr: case errSSLInternal:
- failf(data, "Internal SSL engine error encountered during the "
- "SSL handshake");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLFatalAlert:
- failf(data, "Fatal SSL engine error encountered during the SSL "
- "handshake");
- return CURLE_SSL_CONNECT_ERROR;
- default:
- failf(data, "Unknown SSL protocol error in connection to %s:%d",
- conn->host.name, err);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- else {
- /* we have been connected fine, we're not waiting for anything else. */
- connssl->connecting_state = ssl_connect_3;
-
- /* Informational message */
- (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher);
- (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol);
- switch (protocol) {
- case kSSLProtocol2:
- infof(data, "SSL 2.0 connection using %s\n",
- SSLCipherNameForNumber(cipher));
- break;
- case kSSLProtocol3:
- infof(data, "SSL 3.0 connection using %s\n",
- SSLCipherNameForNumber(cipher));
- break;
- case kTLSProtocol1:
- infof(data, "TLS 1.0 connection using %s\n",
- TLSCipherNameForNumber(cipher));
- break;
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- case kTLSProtocol11:
- infof(data, "TLS 1.1 connection using %s\n",
- TLSCipherNameForNumber(cipher));
- break;
- case kTLSProtocol12:
- infof(data, "TLS 1.2 connection using %s\n",
- TLSCipherNameForNumber(cipher));
- break;
-#endif
- default:
- infof(data, "Unknown protocol connection\n");
- break;
- }
-
- return CURLE_OK;
- }
-}
-
-static CURLcode
-darwinssl_connect_step3(struct connectdata *conn,
- int sockindex)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- CFStringRef server_cert_summary;
- char server_cert_summary_c[128];
- CFArrayRef server_certs = NULL;
- SecCertificateRef server_cert;
- OSStatus err;
- CFIndex i, count;
- SecTrustRef trust = NULL;
-
- /* There is no step 3!
- * Well, okay, if verbose mode is on, let's print the details of the
- * server certificates. */
-#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
-#if CURL_BUILD_IOS
-#pragma unused(server_certs)
- err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
- /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
- a null trust, so be on guard for that: */
- if(err == noErr && trust) {
- count = SecTrustGetCertificateCount(trust);
- for(i = 0L ; i < count ; i++) {
- server_cert = SecTrustGetCertificateAtIndex(trust, i);
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
- }
- CFRelease(server_cert_summary);
- }
- CFRelease(trust);
- }
-#else
- /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
- The function SecTrustGetCertificateAtIndex() is officially present
- in Lion, but it is unfortunately also present in Snow Leopard as
- private API and doesn't work as expected. So we have to look for
- a different symbol to make sure this code is only executed under
- Lion or later. */
- if(SecTrustEvaluateAsync != NULL) {
-#pragma unused(server_certs)
- err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
- /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
- a null trust, so be on guard for that: */
- if(err == noErr && trust) {
- count = SecTrustGetCertificateCount(trust);
- for(i = 0L ; i < count ; i++) {
- server_cert = SecTrustGetCertificateAtIndex(trust, i);
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
- }
- CFRelease(server_cert_summary);
- }
- CFRelease(trust);
- }
- }
- else {
-#if CURL_SUPPORT_MAC_10_8
- err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
- /* Just in case SSLCopyPeerCertificates() returns null too... */
- if(err == noErr && server_certs) {
- count = CFArrayGetCount(server_certs);
- for(i = 0L ; i < count ; i++) {
- server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
- i);
-
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
- }
- CFRelease(server_cert_summary);
- }
- CFRelease(server_certs);
- }
-#endif /* CURL_SUPPORT_MAC_10_8 */
- }
-#endif /* CURL_BUILD_IOS */
-#else
-#pragma unused(trust)
- err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
- if(err == noErr) {
- count = CFArrayGetCount(server_certs);
- for(i = 0L ; i < count ; i++) {
- server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
- }
- CFRelease(server_cert_summary);
- }
- CFRelease(server_certs);
- }
-#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
-
- connssl->connecting_state = ssl_connect_done;
- return CURLE_OK;
-}
-
-static Curl_recv darwinssl_recv;
-static Curl_send darwinssl_send;
-
-static CURLcode
-darwinssl_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
-{
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
- int what;
-
- /* check if the connection has already been established */
- if(ssl_connection_complete == connssl->state) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- if(ssl_connect_1==connssl->connecting_state) {
- /* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- result = darwinssl_connect_step1(conn, sockindex);
- if(result)
- return result;
- }
-
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
-
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading ||
- connssl->connecting_state == ssl_connect_2_writing) {
-
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-
- what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* Run transaction, and return to the caller if it failed or if this
- * connection is done nonblocking and this loop would execute again. This
- * permits the owner of a multi handle to abort a connection attempt
- * before step2 has completed while ensuring that a client using select()
- * or epoll() will always have a valid fdset to wait on.
- */
- result = darwinssl_connect_step2(conn, sockindex);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
- return result;
-
- } /* repeat step2 until all transactions are done. */
-
-
- if(ssl_connect_3 == connssl->connecting_state) {
- result = darwinssl_connect_step3(conn, sockindex);
- if(result)
- return result;
- }
-
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = darwinssl_recv;
- conn->send[sockindex] = darwinssl_send;
- *done = TRUE;
- }
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-CURL_STATIC CURLcode
-Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- return darwinssl_connect_common(conn, sockindex, TRUE, done);
-}
-
-CURL_STATIC CURLcode
-Curl_darwinssl_connect(struct connectdata *conn,
- int sockindex)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = darwinssl_connect_common(conn, sockindex, FALSE, &done);
-
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-CURL_STATIC void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->ssl_ctx) {
- (void)SSLClose(connssl->ssl_ctx);
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext != NULL)
- CFRelease(connssl->ssl_ctx);
-#if CURL_SUPPORT_MAC_10_8
- else
- (void)SSLDisposeContext(connssl->ssl_ctx);
-#endif /* CURL_SUPPORT_MAC_10_8 */
-#else
- (void)SSLDisposeContext(connssl->ssl_ctx);
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
- connssl->ssl_ctx = NULL;
- }
- connssl->ssl_sockfd = 0;
-}
-
-CURL_STATIC int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- ssize_t nread;
- int what;
- int rc;
- char buf[120];
-
- if(!connssl->ssl_ctx)
- return 0;
-
- if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
- return 0;
-
- Curl_darwinssl_close(conn, sockindex);
-
- rc = 0;
-
- what = Curl_socket_ready(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
-
- for(;;) {
- if(what < 0) {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- rc = -1;
- break;
- }
-
- if(!what) { /* timeout */
- failf(data, "SSL shutdown timeout");
- break;
- }
-
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server. No way to SSL_Read now, so use read(). */
-
- nread = read(conn->sock[sockindex], buf, sizeof(buf));
-
- if(nread < 0) {
- failf(data, "read: %s", strerror(errno));
- rc = -1;
- }
-
- if(nread <= 0)
- break;
-
- what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
- }
-
- return rc;
-}
-
-CURL_STATIC void Curl_darwinssl_session_free(void *ptr)
-{
- /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
- cached session ID inside the Security framework. There is a private
- function that does this, but I don't want to have to explain to you why I
- got your application rejected from the App Store due to the use of a
- private API, so the best we can do is free up our own char array that we
- created way back in darwinssl_connect_step1... */
- Curl_safefree(ptr);
-}
-
-CURL_STATIC size_t Curl_darwinssl_version(char *buffer, size_t size)
-{
- return snprintf(buffer, size, "SecureTransport");
-}
-
-/*
- * This function uses SSLGetSessionState to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-CURL_STATIC int Curl_darwinssl_check_cxn(struct connectdata *conn)
-{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
- OSStatus err;
- SSLSessionState state;
-
- if(connssl->ssl_ctx) {
- err = SSLGetSessionState(connssl->ssl_ctx, &state);
- if(err == noErr)
- return state == kSSLConnected || state == kSSLHandshake;
- return -1;
- }
- return 0;
-}
-
-CURL_STATIC bool Curl_darwinssl_data_pending(const struct connectdata *conn,
- int connindex)
-{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- OSStatus err;
- size_t buffer;
-
- if(connssl->ssl_ctx) { /* SSL is in use */
- err = SSLGetBufferedReadSize(connssl->ssl_ctx, &buffer);
- if(err == noErr)
- return buffer > 0UL;
- return false;
- }
- else
- return false;
-}
-
-CURL_STATIC int Curl_darwinssl_random(unsigned char *entropy,
- size_t length)
-{
- /* arc4random_buf() isn't available on cats older than Lion, so let's
- do this manually for the benefit of the older cats. */
- size_t i;
- u_int32_t random_number = 0;
-
- for(i = 0 ; i < length ; i++) {
- if(i % sizeof(u_int32_t) == 0)
- random_number = arc4random();
- entropy[i] = random_number & 0xFF;
- random_number >>= 8;
- }
- i = random_number = 0;
- return 0;
-}
-
-CURL_STATIC void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
-{
- (void)md5len;
- (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum);
-}
-
-bool Curl_darwinssl_false_start(void) {
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- if(SSLSetSessionOption != NULL)
- return TRUE;
-#endif
- return FALSE;
-}
-
-static ssize_t darwinssl_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
-{
- /*struct SessionHandle *data = conn->data;*/
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- size_t processed = 0UL;
- OSStatus err;
-
- /* The SSLWrite() function works a little differently than expected. The
- fourth argument (processed) is currently documented in Apple's
- documentation as: "On return, the length, in bytes, of the data actually
- written."
-
- Now, one could interpret that as "written to the socket," but actually,
- it returns the amount of data that was written to a buffer internal to
- the SSLContextRef instead. So it's possible for SSLWrite() to return
- errSSLWouldBlock and a number of bytes "written" because those bytes were
- encrypted and written to a buffer, not to the socket.
-
- So if this happens, then we need to keep calling SSLWrite() over and
- over again with no new data until it quits returning errSSLWouldBlock. */
-
- /* Do we have buffered data to write from the last time we were called? */
- if(connssl->ssl_write_buffered_length) {
- /* Write the buffered data: */
- err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed);
- switch (err) {
- case noErr:
- /* processed is always going to be 0 because we didn't write to
- the buffer, so return how much was written to the socket */
- processed = connssl->ssl_write_buffered_length;
- connssl->ssl_write_buffered_length = 0UL;
- break;
- case errSSLWouldBlock: /* argh, try again */
- *curlcode = CURLE_AGAIN;
- return -1L;
- default:
- failf(conn->data, "SSLWrite() returned error %d", err);
- *curlcode = CURLE_SEND_ERROR;
- return -1L;
- }
- }
- else {
- /* We've got new data to write: */
- err = SSLWrite(connssl->ssl_ctx, mem, len, &processed);
- if(err != noErr) {
- switch (err) {
- case errSSLWouldBlock:
- /* Data was buffered but not sent, we have to tell the caller
- to try sending again, and remember how much was buffered */
- connssl->ssl_write_buffered_length = len;
- *curlcode = CURLE_AGAIN;
- return -1L;
- default:
- failf(conn->data, "SSLWrite() returned error %d", err);
- *curlcode = CURLE_SEND_ERROR;
- return -1L;
- }
- }
- }
- return (ssize_t)processed;
-}
-
-static ssize_t darwinssl_recv(struct connectdata *conn,
- int num,
- char *buf,
- size_t buffersize,
- CURLcode *curlcode)
-{
- /*struct SessionHandle *data = conn->data;*/
- struct ssl_connect_data *connssl = &conn->ssl[num];
- size_t processed = 0UL;
- OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed);
-
- if(err != noErr) {
- switch (err) {
- case errSSLWouldBlock: /* return how much we read (if anything) */
- if(processed)
- return (ssize_t)processed;
- *curlcode = CURLE_AGAIN;
- return -1L;
- break;
-
- /* errSSLClosedGraceful - server gracefully shut down the SSL session
- errSSLClosedNoNotify - server hung up on us instead of sending a
- closure alert notice, read() is returning 0
- Either way, inform the caller that the server disconnected. */
- case errSSLClosedGraceful:
- case errSSLClosedNoNotify:
- *curlcode = CURLE_OK;
- return -1L;
- break;
-
- default:
- failf(conn->data, "SSLRead() return error %d", err);
- *curlcode = CURLE_RECV_ERROR;
- return -1L;
- break;
- }
- }
- return (ssize_t)processed;
-}
-
-#endif /* USE_DARWINSSL */
diff --git a/libcurl/src/lib/vtls/darwinssl.h b/libcurl/src/lib/vtls/darwinssl.h
deleted file mode 100644
index f287eca..0000000
--- a/libcurl/src/lib/vtls/darwinssl.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef HEADER_CURL_DARWINSSL_H
-#define HEADER_CURL_DARWINSSL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#ifdef USE_DARWINSSL
-
-CURL_STATIC CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex);
-
-CURL_STATIC CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-/* close a SSL connection */
-CURL_STATIC void Curl_darwinssl_close(struct connectdata *conn, int sockindex);
-
-CURL_STATIC void Curl_darwinssl_session_free(void *ptr);
-CURL_STATIC size_t Curl_darwinssl_version(char *buffer, size_t size);
-CURL_STATIC int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC int Curl_darwinssl_check_cxn(struct connectdata *conn);
-CURL_STATIC bool Curl_darwinssl_data_pending(const struct connectdata *conn,
- int connindex);
-
-CURL_STATIC int Curl_darwinssl_random(unsigned char *entropy,
- size_t length);
-CURL_STATIC void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-bool Curl_darwinssl_false_start(void);
-
-/* Set the API backend definition to SecureTransport */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL
-
-/* API setup for SecureTransport */
-#define curlssl_init() (1)
-#define curlssl_cleanup() Curl_nop_stmt
-#define curlssl_connect Curl_darwinssl_connect
-#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking
-#define curlssl_session_free(x) Curl_darwinssl_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_darwinssl_close
-#define curlssl_shutdown(x,y) 0
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_darwinssl_version
-#define curlssl_check_cxn Curl_darwinssl_check_cxn
-#define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y)
-#define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z))
-#define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d)
-#define curlssl_false_start() Curl_darwinssl_false_start()
-
-#endif /* USE_DARWINSSL */
-#endif /* HEADER_CURL_DARWINSSL_H */
diff --git a/libcurl/src/lib/vtls/gskit.c b/libcurl/src/lib/vtls/gskit.c
deleted file mode 100644
index f683c76..0000000
--- a/libcurl/src/lib/vtls/gskit.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "../curl_setup.h"
-
-#ifdef USE_GSKIT
-
-#include <gskssl.h>
-#include <qsoasync.h>
-
-/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
-#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
-#define GSK_SSL_EXTN_SERVERNAME_REQUEST 230
-#endif
-
-#ifndef GSK_TLSV10_CIPHER_SPECS
-#define GSK_TLSV10_CIPHER_SPECS 236
-#endif
-
-#ifndef GSK_TLSV11_CIPHER_SPECS
-#define GSK_TLSV11_CIPHER_SPECS 237
-#endif
-
-#ifndef GSK_TLSV12_CIPHER_SPECS
-#define GSK_TLSV12_CIPHER_SPECS 238
-#endif
-
-#ifndef GSK_PROTOCOL_TLSV11
-#define GSK_PROTOCOL_TLSV11 437
-#endif
-
-#ifndef GSK_PROTOCOL_TLSV12
-#define GSK_PROTOCOL_TLSV12 438
-#endif
-
-#ifndef GSK_FALSE
-#define GSK_FALSE 0
-#endif
-
-#ifndef GSK_TRUE
-#define GSK_TRUE 1
-#endif
-
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "gskit.h"
-#include "vtls.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "strequal.h"
-#include "x509asn1.h"
-#include "curl_printf.h"
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-
-/* SSL version flags. */
-#define CURL_GSKPROTO_SSLV2 0
-#define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2)
-#define CURL_GSKPROTO_SSLV3 1
-#define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3)
-#define CURL_GSKPROTO_TLSV10 2
-#define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10)
-#define CURL_GSKPROTO_TLSV11 3
-#define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11)
-#define CURL_GSKPROTO_TLSV12 4
-#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
-#define CURL_GSKPROTO_LAST 5
-
-
-/* Supported ciphers. */
-typedef struct {
- const char *name; /* Cipher name. */
- const char *gsktoken; /* Corresponding token for GSKit String. */
- unsigned int versions; /* SSL version flags. */
-} gskit_cipher;
-
-static const gskit_cipher ciphertable[] = {
- { "null-md5", "01",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "null-sha", "02",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "exp-rc4-md5", "03",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
- { "rc4-md5", "04",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "rc4-sha", "05",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "exp-rc2-cbc-md5", "06",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
- { "exp-des-cbc-sha", "09",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK },
- { "des-cbc3-sha", "0A",
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
- { "aes128-sha", "2F",
- CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
- CURL_GSKPROTO_TLSV12_MASK },
- { "aes256-sha", "35",
- CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
- CURL_GSKPROTO_TLSV12_MASK },
- { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK },
- { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK },
- { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK },
- { "aes128-gcm-sha256",
- "9C", CURL_GSKPROTO_TLSV12_MASK },
- { "aes256-gcm-sha384",
- "9D", CURL_GSKPROTO_TLSV12_MASK },
- { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK },
- { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK },
- { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK },
- { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK },
- { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK },
- { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK },
- { (const char *) NULL, (const char *) NULL, 0 }
-};
-
-
-static bool is_separator(char c)
-{
- /* Return whether character is a cipher list separator. */
- switch (c) {
- case ' ':
- case '\t':
- case ':':
- case ',':
- case ';':
- return true;
- }
- return false;
-}
-
-
-static CURLcode gskit_status(struct SessionHandle *data, int rc,
- const char *procname, CURLcode defcode)
-{
- /* Process GSKit status and map it to a CURLcode. */
- switch (rc) {
- case GSK_OK:
- case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
- return CURLE_OK;
- case GSK_KEYRING_OPEN_ERROR:
- case GSK_OS400_ERROR_NO_ACCESS:
- return CURLE_SSL_CACERT_BADFILE;
- case GSK_INSUFFICIENT_STORAGE:
- return CURLE_OUT_OF_MEMORY;
- case GSK_ERROR_BAD_V2_CIPHER:
- case GSK_ERROR_BAD_V3_CIPHER:
- case GSK_ERROR_NO_CIPHERS:
- return CURLE_SSL_CIPHER;
- case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
- case GSK_ERROR_CERT_VALIDATION:
- return CURLE_PEER_FAILED_VERIFICATION;
- case GSK_OS400_ERROR_TIMED_OUT:
- return CURLE_OPERATION_TIMEDOUT;
- case GSK_WOULD_BLOCK:
- return CURLE_AGAIN;
- case GSK_OS400_ERROR_NOT_REGISTERED:
- break;
- case GSK_ERROR_IO:
- switch (errno) {
- case ENOMEM:
- return CURLE_OUT_OF_MEMORY;
- default:
- failf(data, "%s I/O error: %s", procname, strerror(errno));
- break;
- }
- break;
- default:
- failf(data, "%s: %s", procname, gsk_strerror(rc));
- break;
- }
- return defcode;
-}
-
-
-static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
- GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
-{
- int rc = gsk_attribute_set_enum(h, id, value);
-
- switch (rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
- break;
- case GSK_ATTRIBUTE_INVALID_ID:
- if(unsupported_ok)
- return CURLE_UNSUPPORTED_PROTOCOL;
- default:
- failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
- GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
-{
- int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
-
- switch (rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
- break;
- case GSK_ATTRIBUTE_INVALID_ID:
- if(unsupported_ok)
- return CURLE_UNSUPPORTED_PROTOCOL;
- default:
- failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_numeric(struct SessionHandle *data,
- gsk_handle h, GSK_NUM_ID id, int value)
-{
- int rc = gsk_attribute_set_numeric_value(h, id, value);
-
- switch (rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
- strerror(errno));
- break;
- default:
- failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_callback(struct SessionHandle *data,
- gsk_handle h, GSK_CALLBACK_ID id, void *info)
-{
- int rc = gsk_attribute_set_callback(h, id, info);
-
- switch (rc) {
- case GSK_OK:
- return CURLE_OK;
- case GSK_ERROR_IO:
- failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
- break;
- default:
- failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
- break;
- }
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-
-static CURLcode set_ciphers(struct SessionHandle *data,
- gsk_handle h, unsigned int *protoflags)
-{
- const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
- const char *clp;
- const gskit_cipher *ctp;
- int i;
- int l;
- bool unsupported;
- CURLcode result;
- struct {
- char *buf;
- char *ptr;
- } ciphers[CURL_GSKPROTO_LAST];
-
- /* Compile cipher list into GSKit-compatible cipher lists. */
-
- if(!cipherlist)
- return CURLE_OK;
- while(is_separator(*cipherlist)) /* Skip initial separators. */
- cipherlist++;
- if(!*cipherlist)
- return CURLE_OK;
-
- /* We allocate GSKit buffers of the same size as the input string: since
- GSKit tokens are always shorter than their cipher names, allocated buffers
- will always be large enough to accomodate the result. */
- l = strlen(cipherlist) + 1;
- memset((char *) ciphers, 0, sizeof ciphers);
- for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
- ciphers[i].buf = malloc(l);
- if(!ciphers[i].buf) {
- while(i--)
- free(ciphers[i].buf);
- return CURLE_OUT_OF_MEMORY;
- }
- ciphers[i].ptr = ciphers[i].buf;
- *ciphers[i].ptr = '\0';
- }
-
- /* Process each cipher in input string. */
- unsupported = FALSE;
- result = CURLE_OK;
- for(;;) {
- for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
- cipherlist++;
- l = cipherlist - clp;
- if(!l)
- break;
- /* Search the cipher in our table. */
- for(ctp = ciphertable; ctp->name; ctp++)
- if(strnequal(ctp->name, clp, l) && !ctp->name[l])
- break;
- if(!ctp->name) {
- failf(data, "Unknown cipher %.*s", l, clp);
- result = CURLE_SSL_CIPHER;
- }
- else {
- unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
- CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
- for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
- if(ctp->versions & (1 << i)) {
- strcpy(ciphers[i].ptr, ctp->gsktoken);
- ciphers[i].ptr += strlen(ctp->gsktoken);
- }
- }
- }
-
- /* Advance to next cipher name or end of string. */
- while(is_separator(*cipherlist))
- cipherlist++;
- }
-
- /* Disable protocols with empty cipher lists. */
- for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
- if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
- *protoflags &= ~(1 << i);
- ciphers[i].buf[0] = '\0';
- }
- }
-
- /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
- if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
- result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(unsupported) {
- failf(data, "TLSv1.1-only ciphers are not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
- if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
- result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(unsupported) {
- failf(data, "TLSv1.2-only ciphers are not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
-
- /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
- the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
- if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
- result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
- ciphers[CURL_GSKPROTO_TLSV10].ptr);
- }
- }
-
- /* Set-up other ciphers. */
- if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
- result = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
- if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
- result = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
- ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
-
- /* Clean-up. */
- for(i = 0; i < CURL_GSKPROTO_LAST; i++)
- free(ciphers[i].buf);
-
- return result;
-}
-
-
-CURL_STATIC int Curl_gskit_init(void)
-{
- /* No initialisation needed. */
-
- return 1;
-}
-
-
-CURL_STATIC void Curl_gskit_cleanup(void)
-{
- /* Nothing to do. */
-}
-
-
-static CURLcode init_environment(struct SessionHandle *data,
- gsk_handle *envir, const char *appid,
- const char *file, const char *label,
- const char *password)
-{
- int rc;
- CURLcode result;
- gsk_handle h;
-
- /* Creates the GSKit environment. */
-
- rc = gsk_environment_open(&h);
- switch (rc) {
- case GSK_OK:
- break;
- case GSK_INSUFFICIENT_STORAGE:
- return CURLE_OUT_OF_MEMORY;
- default:
- failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
- if(!result && appid)
- result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
- if(!result && file)
- result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
- if(!result && label)
- result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
- if(!result && password)
- result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
-
- if(!result) {
- /* Locate CAs, Client certificate and key according to our settings.
- Note: this call may be blocking for some tenths of seconds. */
- result = gskit_status(data, gsk_environment_init(h),
- "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
- if(!result) {
- *envir = h;
- return result;
- }
- }
- /* Error: rollback. */
- gsk_environment_close(&h);
- return result;
-}
-
-
-static void cancel_async_handshake(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- Qso_OverlappedIO_t cstat;
-
- if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
- QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
-}
-
-
-static void close_async_handshake(struct ssl_connect_data *connssl)
-{
- QsoDestroyIOCompletionPort(connssl->iocport);
- connssl->iocport = -1;
-}
-
-
-static void close_one(struct ssl_connect_data *conn,
- struct SessionHandle *data)
-{
- if(conn->handle) {
- gskit_status(data, gsk_secure_soc_close(&conn->handle),
- "gsk_secure_soc_close()", 0);
- conn->handle = (gsk_handle) NULL;
- }
- if(conn->iocport >= 0)
- close_async_handshake(conn);
-}
-
-
-static ssize_t gskit_send(struct connectdata *conn, int sockindex,
- const void *mem, size_t len, CURLcode *curlcode)
-{
- struct SessionHandle *data = conn->data;
- CURLcode cc;
- int written;
-
- cc = gskit_status(data,
- gsk_secure_soc_write(conn->ssl[sockindex].handle,
- (char *) mem, (int) len, &written),
- "gsk_secure_soc_write()", CURLE_SEND_ERROR);
- if(cc != CURLE_OK) {
- *curlcode = cc;
- written = -1;
- }
- return (ssize_t) written; /* number of bytes */
-}
-
-
-static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
- size_t buffersize, CURLcode *curlcode)
-{
- struct SessionHandle *data = conn->data;
- int buffsize;
- int nread;
- CURLcode cc;
-
- buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
- cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
- buf, buffsize, &nread),
- "gsk_secure_soc_read()", CURLE_RECV_ERROR);
- if(cc != CURLE_OK) {
- *curlcode = cc;
- nread = -1;
- }
- return (ssize_t) nread;
-}
-
-
-static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- gsk_handle envir;
- CURLcode result;
- int rc;
- char *keyringfile;
- char *keyringpwd;
- char *keyringlabel;
- char *sni;
- unsigned int protoflags;
- long timeout;
- Qso_OverlappedIO_t commarea;
-
- /* Create SSL environment, start (preferably asynchronous) handshake. */
-
- connssl->handle = (gsk_handle) NULL;
- connssl->iocport = -1;
-
- /* GSKit supports two ways of specifying an SSL context: either by
- * application identifier (that should have been defined at the system
- * level) or by keyring file, password and certificate label.
- * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
- * application identifier of the certificate label.
- * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
- * It is not possible to have different keyrings for the CAs and the
- * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
- * the keyring file.
- * If no key password is given and the keyring is the system keyring,
- * application identifier mode is tried first, as recommended in IBM doc.
- */
-
- keyringfile = data->set.str[STRING_SSL_CAFILE];
- keyringpwd = data->set.str[STRING_KEY_PASSWD];
- keyringlabel = data->set.str[STRING_CERT];
- envir = (gsk_handle) NULL;
-
- if(keyringlabel && *keyringlabel && !keyringpwd &&
- !strcmp(keyringfile, CURL_CA_BUNDLE)) {
- /* Try application identifier mode. */
- init_environment(data, &envir, keyringlabel, (const char *) NULL,
- (const char *) NULL, (const char *) NULL);
- }
-
- if(!envir) {
- /* Use keyring mode. */
- result = init_environment(data, &envir, (const char *) NULL,
- keyringfile, keyringlabel, keyringpwd);
- if(result)
- return result;
- }
-
- /* Create secure session. */
- result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
- "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
- gsk_environment_close(&envir);
- if(result)
- return result;
-
- /* Determine which SSL/TLS version should be enabled. */
- protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
- CURL_GSKPROTO_TLSV12_MASK;
- sni = conn->host.name;
- switch (data->set.ssl.version) {
- case CURL_SSLVERSION_SSLv2:
- protoflags = CURL_GSKPROTO_SSLV2_MASK;
- sni = (char *) NULL;
- break;
- case CURL_SSLVERSION_SSLv3:
- protoflags = CURL_GSKPROTO_SSLV3_MASK;
- sni = (char *) NULL;
- break;
- case CURL_SSLVERSION_TLSv1:
- protoflags = CURL_GSKPROTO_TLSV10_MASK |
- CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_0:
- protoflags = CURL_GSKPROTO_TLSV10_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_1:
- protoflags = CURL_GSKPROTO_TLSV11_MASK;
- break;
- case CURL_SSLVERSION_TLSv1_2:
- protoflags = CURL_GSKPROTO_TLSV12_MASK;
- break;
- }
-
- /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
- if(sni) {
- result = set_buffer(data, connssl->handle,
- GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL)
- result = CURLE_OK;
- }
-
- /* Set session parameters. */
- if(!result) {
- /* Compute the handshake timeout. Since GSKit granularity is 1 second,
- we round up the required value. */
- timeout = Curl_timeleft(data, NULL, TRUE);
- if(timeout < 0)
- result = CURLE_OPERATION_TIMEDOUT;
- else
- result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
- (timeout + 999) / 1000);
- }
- if(!result)
- result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
- if(!result)
- result = set_ciphers(data, connssl->handle, &protoflags);
- if(!protoflags) {
- failf(data, "No SSL protocol/cipher combination enabled");
- result = CURLE_SSL_CIPHER;
- }
- if(!result)
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
- (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
- GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
- if(!result)
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
- (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
- GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
- if(!result)
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
- (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
- GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
- if(!result) {
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
- (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
- GSK_TRUE: GSK_FALSE, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
- failf(data, "TLS 1.1 not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
- if(!result) {
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
- (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
- GSK_TRUE: GSK_FALSE, TRUE);
- if(result == CURLE_UNSUPPORTED_PROTOCOL) {
- result = CURLE_OK;
- if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
- failf(data, "TLS 1.2 not yet supported");
- result = CURLE_SSL_CIPHER;
- }
- }
- }
- if(!result)
- result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
- data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
- GSK_SERVER_AUTH_PASSTHRU, FALSE);
-
- if(!result) {
- /* Start handshake. Try asynchronous first. */
- memset(&commarea, 0, sizeof commarea);
- connssl->iocport = QsoCreateIOCompletionPort();
- if(connssl->iocport != -1) {
- result = gskit_status(data,
- gsk_secure_soc_startInit(connssl->handle,
- connssl->iocport,
- &commarea),
- "gsk_secure_soc_startInit()",
- CURLE_SSL_CONNECT_ERROR);
- if(!result) {
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
- }
- else
- close_async_handshake(connssl);
- }
- else if(errno != ENOBUFS)
- result = gskit_status(data, GSK_ERROR_IO,
- "QsoCreateIOCompletionPort()", 0);
- else {
- /* No more completion port available. Use synchronous IO. */
- result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
- "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
- if(!result) {
- connssl->connecting_state = ssl_connect_3;
- return CURLE_OK;
- }
- }
- }
-
- /* Error: rollback. */
- close_one(connssl, data);
- return result;
-}
-
-
-static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
- bool nonblocking)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- Qso_OverlappedIO_t cstat;
- long timeout_ms;
- struct timeval stmv;
- CURLcode result;
-
- /* Poll or wait for end of SSL asynchronous handshake. */
-
- for(;;) {
- timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
- if(timeout_ms < 0)
- timeout_ms = 0;
- stmv.tv_sec = timeout_ms / 1000;
- stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
- switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
- case 1: /* Operation complete. */
- break;
- case -1: /* An error occurred: handshake still in progress. */
- if(errno == EINTR) {
- if(nonblocking)
- return CURLE_OK;
- continue; /* Retry. */
- }
- if(errno != ETIME) {
- failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
- cancel_async_handshake(conn, sockindex);
- close_async_handshake(connssl);
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* FALL INTO... */
- case 0: /* Handshake in progress, timeout occurred. */
- if(nonblocking)
- return CURLE_OK;
- cancel_async_handshake(conn, sockindex);
- close_async_handshake(connssl);
- return CURLE_OPERATION_TIMEDOUT;
- }
- break;
- }
- result = gskit_status(data, cstat.returnValue, "SSL handshake",
- CURLE_SSL_CONNECT_ERROR);
- if(!result)
- connssl->connecting_state = ssl_connect_3;
- close_async_handshake(connssl);
- return result;
-}
-
-
-static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- const gsk_cert_data_elem *cdev;
- int cdec;
- const gsk_cert_data_elem *p;
- const char *cert = (const char *) NULL;
- const char *certend;
- const char *ptr;
- int i;
- CURLcode result;
-
- /* SSL handshake done: gather certificate info and verify host. */
-
- if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
- GSK_PARTNER_CERT_INFO,
- &cdev, &cdec),
- "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
- CURLE_OK) {
- infof(data, "Server certificate:\n");
- p = cdev;
- for(i = 0; i++ < cdec; p++)
- switch (p->cert_data_id) {
- case CERT_BODY_DER:
- cert = p->cert_data_p;
- certend = cert + cdev->cert_data_l;
- break;
- case CERT_DN_PRINTABLE:
- infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
- break;
- case CERT_ISSUER_DN_PRINTABLE:
- infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
- break;
- case CERT_VALID_FROM:
- infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
- break;
- case CERT_VALID_TO:
- infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
- break;
- }
- }
-
- /* Verify host. */
- result = Curl_verifyhost(conn, cert, certend);
- if(result)
- return result;
-
- /* The only place GSKit can get the whole CA chain is a validation
- callback where no user data pointer is available. Therefore it's not
- possible to copy this chain into our structures for CAINFO.
- However the server certificate may be available, thus we can return
- info about it. */
- if(data->set.ssl.certinfo) {
- result = Curl_ssl_init_certinfo(data, 1);
- if(result)
- return result;
-
- if(cert) {
- result = Curl_extract_certinfo(conn, 0, cert, certend);
- if(result)
- return result;
- }
- }
-
- /* Check pinned public key. */
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
- if(!result && ptr) {
- curl_X509certificate x509;
- curl_asn1Element *p;
-
- if(!cert)
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- Curl_parseX509(&x509, cert, certend);
- p = &x509.subjectPublicKeyInfo;
- result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header);
- if(result) {
- failf(data, "SSL: public key does not match pinned public key!");
- return result;
- }
- }
-
- connssl->connecting_state = ssl_connect_done;
- return CURLE_OK;
-}
-
-
-static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
- bool nonblocking, bool *done)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- long timeout_ms;
- Qso_OverlappedIO_t cstat;
- CURLcode result = CURLE_OK;
-
- *done = connssl->state == ssl_connection_complete;
- if(*done)
- return CURLE_OK;
-
- /* Step 1: create session, start handshake. */
- if(connssl->connecting_state == ssl_connect_1) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
- }
- else
- result = gskit_connect_step1(conn, sockindex);
- }
-
- /* Step 2: check if handshake is over. */
- if(!result && connssl->connecting_state == ssl_connect_2) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
- }
- else
- result = gskit_connect_step2(conn, sockindex, nonblocking);
- }
-
- /* Step 3: gather certificate info, verify host. */
- if(!result && connssl->connecting_state == ssl_connect_3)
- result = gskit_connect_step3(conn, sockindex);
-
- if(result)
- close_one(connssl, data);
- else if(connssl->connecting_state == ssl_connect_done) {
- connssl->state = ssl_connection_complete;
- connssl->connecting_state = ssl_connect_1;
- conn->recv[sockindex] = gskit_recv;
- conn->send[sockindex] = gskit_send;
- *done = TRUE;
- }
-
- return result;
-}
-
-
-CURL_STATIC CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- CURLcode result;
-
- result = gskit_connect_common(conn, sockindex, TRUE, done);
- if(*done || result)
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
- return result;
-}
-
-
-CURL_STATIC CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
-{
- CURLcode result;
- bool done;
-
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
- result = gskit_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-
-CURL_STATIC void Curl_gskit_close(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->use)
- close_one(connssl, data);
-}
-
-
-CURL_STATIC int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- ssize_t nread;
- int what;
- int rc;
- char buf[120];
-
- if(!connssl->handle)
- return 0;
-
- if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
- return 0;
-
- close_one(connssl, data);
- rc = 0;
- what = Curl_socket_ready(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
-
- for(;;) {
- if(what < 0) {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- rc = -1;
- break;
- }
-
- if(!what) { /* timeout */
- failf(data, "SSL shutdown timeout");
- break;
- }
-
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server. No way to gsk_secure_soc_read() now, so
- use read(). */
-
- nread = read(conn->sock[sockindex], buf, sizeof(buf));
-
- if(nread < 0) {
- failf(data, "read: %s", strerror(errno));
- rc = -1;
- }
-
- if(nread <= 0)
- break;
-
- what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
- }
-
- return rc;
-}
-
-
-CURL_STATIC size_t Curl_gskit_version(char *buffer, size_t size)
-{
- strncpy(buffer, "GSKit", size);
- return strlen(buffer);
-}
-
-
-CURL_STATIC int Curl_gskit_check_cxn(struct connectdata *cxn)
-{
- int err;
- int errlen;
-
- /* The only thing that can be tested here is at the socket level. */
-
- if(!cxn->ssl[FIRSTSOCKET].handle)
- return 0; /* connection has been closed */
-
- err = 0;
- errlen = sizeof err;
-
- if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
- (unsigned char *) &err, &errlen) ||
- errlen != sizeof err || err)
- return 0; /* connection has been closed */
-
- return -1; /* connection status unknown */
-}
-
-#endif /* USE_GSKIT */
diff --git a/libcurl/src/lib/vtls/gskit.h b/libcurl/src/lib/vtls/gskit.h
deleted file mode 100644
index 58e15b6..0000000
--- a/libcurl/src/lib/vtls/gskit.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef HEADER_CURL_GSKIT_H
-#define HEADER_CURL_GSKIT_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-/*
- * This header should only be needed to get included by vtls.c and gskit.c
- */
-
-#include "../urldata.h"
-
-#ifdef USE_GSKIT
-CURL_STATIC int Curl_gskit_init(void);
-CURL_STATIC void Curl_gskit_cleanup(void);
-CURL_STATIC CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
- int sockindex, bool *done);
-CURL_STATIC void Curl_gskit_close(struct connectdata *conn, int sockindex);
-CURL_STATIC int Curl_gskit_shutdown(struct connectdata *conn, int sockindex);
-
-CURL_STATIC size_t Curl_gskit_version(char *buffer, size_t size);
-CURL_STATIC int Curl_gskit_check_cxn(struct connectdata *cxn);
-
-/* Set the API backend definition to GSKit */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* API setup for GSKit */
-#define curlssl_init Curl_gskit_init
-#define curlssl_cleanup Curl_gskit_cleanup
-#define curlssl_connect Curl_gskit_connect
-#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking
-
-/* No session handling for GSKit */
-#define curlssl_session_free(x) Curl_nop_stmt
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_gskit_close
-#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y)
-#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN
-#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN
-#define curlssl_engines_list(x) NULL
-#define curlssl_version Curl_gskit_version
-#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x)
-#define curlssl_data_pending(x,y) 0
-#define curlssl_random(x,y,z) -1
-
-#endif /* USE_GSKIT */
-
-#endif /* HEADER_CURL_GSKIT_H */
diff --git a/libcurl/src/lib/vtls/gtls.c b/libcurl/src/lib/vtls/gtls.c
deleted file mode 100644
index 483c837..0000000
--- a/libcurl/src/lib/vtls/gtls.c
+++ /dev/null
@@ -1,1480 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- *
- * Note: don't use the GnuTLS' *_t variable type names in this source code,
- * since they were not present in 1.0.X.
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_GNUTLS
-
-#include <gnutls/abstract.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#ifdef USE_GNUTLS_NETTLE
-#include <gnutls/crypto.h>
-#include <nettle/md5.h>
-#else
-#include <gcrypt.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "inet_pton.h"
-#include "gtls.h"
-#include "vtls.h"
-#include "parsedate.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "rawstr.h"
-#include "warnless.h"
-#include "x509asn1.h"
-#include "curl_printf.h"
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/*
- Some hackish cast macros based on:
- http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
-*/
-#ifndef GNUTLS_POINTER_TO_INT_CAST
-#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
-#endif
-#ifndef GNUTLS_INT_TO_POINTER_CAST
-#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
-#endif
-
-/* Enable GnuTLS debugging by defining GTLSDEBUG */
-/*#define GTLSDEBUG */
-
-#ifdef GTLSDEBUG
-static void tls_log_func(int level, const char *str)
-{
- fprintf(stderr, "|<%d>| %s", level, str);
-}
-#endif
-static bool gtls_inited = FALSE;
-
-#if defined(GNUTLS_VERSION_NUMBER)
-# if (GNUTLS_VERSION_NUMBER >= 0x020c00)
-# undef gnutls_transport_set_lowat
-# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
-# define USE_GNUTLS_PRIORITY_SET_DIRECT 1
-# endif
-# if (GNUTLS_VERSION_NUMBER >= 0x020c03)
-# define GNUTLS_MAPS_WINSOCK_ERRORS 1
-# endif
-
-# if (GNUTLS_VERSION_NUMBER >= 0x030200)
-# define HAS_ALPN
-# endif
-
-# if (GNUTLS_VERSION_NUMBER >= 0x03020d)
-# define HAS_OCSP
-# endif
-
-# if (GNUTLS_VERSION_NUMBER >= 0x030306)
-# define HAS_CAPATH
-# endif
-#endif
-
-#ifdef HAS_OCSP
-# include <gnutls/ocsp.h>
-#endif
-
-/*
- * Custom push and pull callback functions used by GNU TLS to read and write
- * to the socket. These functions are simple wrappers to send() and recv()
- * (although here using the sread/swrite macros as defined by
- * curl_setup_once.h).
- * We use custom functions rather than the GNU TLS defaults because it allows
- * us to get specific about the fourth "flags" argument, and to use arbitrary
- * private data with gnutls_transport_set_ptr if we wish.
- *
- * When these custom push and pull callbacks fail, GNU TLS checks its own
- * session-specific error variable, and when not set also its own global
- * errno variable, in order to take appropriate action. GNU TLS does not
- * require that the transport is actually a socket. This implies that for
- * Windows builds these callbacks should ideally set the session-specific
- * error variable using function gnutls_transport_set_errno or as a last
- * resort global errno variable using gnutls_transport_set_global_errno,
- * with a transport agnostic error value. This implies that some winsock
- * error translation must take place in these callbacks.
- *
- * Paragraph above applies to GNU TLS versions older than 2.12.3, since
- * this version GNU TLS does its own internal winsock error translation
- * using system_errno() function.
- */
-
-#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
-# define gtls_EINTR 4
-# define gtls_EIO 5
-# define gtls_EAGAIN 11
-static int gtls_mapped_sockerrno(void)
-{
- switch(SOCKERRNO) {
- case WSAEWOULDBLOCK:
- return gtls_EAGAIN;
- case WSAEINTR:
- return gtls_EINTR;
- default:
- break;
- }
- return gtls_EIO;
-}
-#endif
-
-static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
-{
- ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
-#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
- if(ret < 0)
- gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
-#endif
- return ret;
-}
-
-static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
-{
- ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
-#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
- if(ret < 0)
- gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
-#endif
- return ret;
-}
-
-/* Curl_gtls_init()
- *
- * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
- * are not thread-safe and thus this function itself is not thread-safe and
- * must only be called from within curl_global_init() to keep the thread
- * situation under control!
- */
-CURL_STATIC int Curl_gtls_init(void)
-{
- int ret = 1;
- if(!gtls_inited) {
- ret = gnutls_global_init()?0:1;
-#ifdef GTLSDEBUG
- gnutls_global_set_log_function(tls_log_func);
- gnutls_global_set_log_level(2);
-#endif
- gtls_inited = TRUE;
- }
- return ret;
-}
-
-CURL_STATIC int Curl_gtls_cleanup(void)
-{
- if(gtls_inited) {
- gnutls_global_deinit();
- gtls_inited = FALSE;
- }
- return 1;
-}
-
-static void showtime(struct SessionHandle *data,
- const char *text,
- time_t stamp)
-{
- struct tm buffer;
- const struct tm *tm = &buffer;
- CURLcode result = Curl_gmtime(stamp, &buffer);
- if(result)
- return;
-
- snprintf(data->state.buffer,
- BUFSIZE,
- "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
- text,
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- infof(data, "%s\n", data->state.buffer);
-}
-
-static gnutls_datum_t load_file (const char *file)
-{
- FILE *f;
- gnutls_datum_t loaded_file = { NULL, 0 };
- long filelen;
- void *ptr;
-
- if(!(f = fopen(file, "r")))
- return loaded_file;
- if(fseek(f, 0, SEEK_END) != 0
- || (filelen = ftell(f)) < 0
- || fseek(f, 0, SEEK_SET) != 0
- || !(ptr = malloc((size_t)filelen)))
- goto out;
- if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
- free(ptr);
- goto out;
- }
-
- loaded_file.data = ptr;
- loaded_file.size = (unsigned int)filelen;
-out:
- fclose(f);
- return loaded_file;
-}
-
-static void unload_file(gnutls_datum_t data) {
- free(data.data);
-}
-
-
-/* this function does a SSL/TLS (re-)handshake */
-static CURLcode handshake(struct connectdata *conn,
- int sockindex,
- bool duringconnect,
- bool nonblocking)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- gnutls_session_t session = conn->ssl[sockindex].session;
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
- int rc;
- int what;
-
- for(;;) {
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, duringconnect);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
-
- curl_socket_t writefd = ssl_connect_2_writing==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-
- what = Curl_socket_ready(readfd, writefd,
- nonblocking?0:
- timeout_ms?timeout_ms:1000);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking)
- return CURLE_OK;
- else if(timeout_ms) {
- /* timeout */
- failf(data, "SSL connection timeout at %ld", timeout_ms);
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- rc = gnutls_handshake(session);
-
- if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
- connssl->connecting_state =
- gnutls_record_get_direction(session)?
- ssl_connect_2_writing:ssl_connect_2_reading;
- continue;
- }
- else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
- const char *strerr = NULL;
-
- if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
- int alert = gnutls_alert_get(session);
- strerr = gnutls_alert_get_name(alert);
- }
-
- if(strerr == NULL)
- strerr = gnutls_strerror(rc);
-
- failf(data, "gnutls_handshake() warning: %s", strerr);
- }
- else if(rc < 0) {
- const char *strerr = NULL;
-
- if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
- int alert = gnutls_alert_get(session);
- strerr = gnutls_alert_get_name(alert);
- }
-
- if(strerr == NULL)
- strerr = gnutls_strerror(rc);
-
- failf(data, "gnutls_handshake() failed: %s", strerr);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
- return CURLE_OK;
- }
-}
-
-static gnutls_x509_crt_fmt_t do_file_type(const char *type)
-{
- if(!type || !type[0])
- return GNUTLS_X509_FMT_PEM;
- if(Curl_raw_equal(type, "PEM"))
- return GNUTLS_X509_FMT_PEM;
- if(Curl_raw_equal(type, "DER"))
- return GNUTLS_X509_FMT_DER;
- return -1;
-}
-
-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
-
- 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_0) {
- 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(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]) ) !=
- GNUTLS_E_SUCCESS) {
- failf(data, "error reading X.509 key or certificate file");
- 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;
-}
-
-static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert,
- const char *pinnedpubkey)
-{
- /* Scratch */
- size_t len1 = 0, len2 = 0;
- unsigned char *buff1 = NULL;
-
- gnutls_pubkey_t key = NULL;
-
- /* Result is returned to caller */
- int ret = 0;
- CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
- /* if a path wasn't specified, don't pin */
- if(NULL == pinnedpubkey)
- return CURLE_OK;
-
- if(NULL == cert)
- return result;
-
- do {
- /* Begin Gyrations to get the public key */
- gnutls_pubkey_init(&key);
-
- ret = gnutls_pubkey_import_x509(key, cert, 0);
- if(ret < 0)
- break; /* failed */
-
- ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
- if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
- break; /* failed */
-
- buff1 = malloc(len1);
- if(NULL == buff1)
- break; /* failed */
-
- len2 = len1;
-
- ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
- if(ret < 0 || len1 != len2)
- break; /* failed */
-
- /* End Gyrations */
-
- /* The one good exit point */
- result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
- } while(0);
-
- if(NULL != key)
- gnutls_pubkey_deinit(key);
-
- Curl_safefree(buff1);
-
- return result;
-}
-
-static Curl_recv gtls_recv;
-static Curl_send gtls_send;
-
-static CURLcode
-gtls_connect_step3(struct connectdata *conn,
- int sockindex)
-{
- unsigned int cert_list_size;
- const gnutls_datum_t *chainp;
- unsigned int verify_status = 0;
- gnutls_x509_crt_t x509_cert, x509_issuer;
- gnutls_datum_t issuerp;
- char certbuf[256] = ""; /* big enough? */
- size_t size;
- unsigned int algo;
- unsigned int bits;
- time_t certclock;
- const char *ptr;
- struct SessionHandle *data = conn->data;
- gnutls_session_t session = conn->ssl[sockindex].session;
- int rc;
- bool incache;
- void *ssl_sessionid;
-#ifdef HAS_ALPN
- gnutls_datum_t proto;
-#endif
- CURLcode result = CURLE_OK;
-
- gnutls_protocol_t version = gnutls_protocol_get_version(session);
-
- /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
- ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
- gnutls_cipher_get(session),
- gnutls_mac_get(session));
-
- infof(data, "SSL connection using %s / %s\n",
- gnutls_protocol_get_name(version), ptr);
-
- /* This function will return the peer's raw certificate (chain) as sent by
- the peer. These certificates are in raw format (DER encoded for
- X.509). In case of a X.509 then a certificate list may be present. The
- first certificate in the list is the peer's certificate, following the
- issuer's certificate, then the issuer's issuer etc. */
-
- chainp = gnutls_certificate_get_peers(session, &cert_list_size);
- if(!chainp) {
- if(data->set.ssl.verifypeer ||
- data->set.ssl.verifyhost ||
- data->set.ssl.issuercert) {
-#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
- && data->set.ssl.username != NULL
- && !data->set.ssl.verifypeer
- && gnutls_cipher_get(session)) {
- /* no peer cert, but auth is ok if we have SRP user and cipher and no
- peer verify */
- }
- else {
-#endif
- failf(data, "failed to get server cert");
- return CURLE_PEER_FAILED_VERIFICATION;
-#ifdef USE_TLS_SRP
- }
-#endif
- }
- infof(data, "\t common name: WARNING couldn't obtain\n");
- }
-
- if(data->set.ssl.certinfo && chainp) {
- unsigned int i;
-
- result = Curl_ssl_init_certinfo(data, cert_list_size);
- if(result)
- return result;
-
- for(i = 0; i < cert_list_size; i++) {
- const char *beg = (const char *) chainp[i].data;
- const char *end = beg + chainp[i].size;
-
- result = Curl_extract_certinfo(conn, i, beg, end);
- if(result)
- return result;
- }
- }
-
- if(data->set.ssl.verifypeer) {
- /* This function will try to verify the peer's certificate and return its
- status (trusted, invalid etc.). The value of status should be one or
- more of the gnutls_certificate_status_t enumerated elements bitwise
- or'd. To avoid denial of service attacks some default upper limits
- regarding the certificate key size and chain size are set. To override
- them use gnutls_certificate_set_verify_limits(). */
-
- rc = gnutls_certificate_verify_peers2(session, &verify_status);
- if(rc < 0) {
- failf(data, "server cert verify failed: %d", rc);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* verify_status is a bitmask of gnutls_certificate_status bits */
- if(verify_status & GNUTLS_CERT_INVALID) {
- if(data->set.ssl.verifypeer) {
- failf(data, "server certificate verification failed. CAfile: %s "
- "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
- data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
- return CURLE_SSL_CACERT;
- }
- else
- infof(data, "\t server certificate verification FAILED\n");
- }
- else
- infof(data, "\t server certificate verification OK\n");
- }
- else
- infof(data, "\t server certificate verification SKIPPED\n");
-
-#ifdef HAS_OCSP
- if(data->set.ssl.verifystatus) {
- if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
- if(verify_status & GNUTLS_CERT_REVOKED)
- infof(data, "\t server certificate was REVOKED\n");
- else
- infof(data, "\t server certificate status verification FAILED\n");
-
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
- else
- infof(data, "\t server certificate status verification OK\n");
- }
- else
- infof(data, "\t server certificate status verification SKIPPED\n");
-#endif
-
- /* initialize an X.509 certificate structure. */
- gnutls_x509_crt_init(&x509_cert);
-
- if(chainp)
- /* convert the given DER or PEM encoded Certificate to the native
- gnutls_x509_crt_t format */
- gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
-
- if(data->set.ssl.issuercert) {
- gnutls_x509_crt_init(&x509_issuer);
- issuerp = load_file(data->set.ssl.issuercert);
- gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
- rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
- gnutls_x509_crt_deinit(x509_issuer);
- unload_file(issuerp);
- if(rc <= 0) {
- failf(data, "server certificate issuer check failed (IssuerCert: %s)",
- data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_SSL_ISSUER_ERROR;
- }
- infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
- data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
- }
-
- size=sizeof(certbuf);
- rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
- 0, /* the first and only one */
- FALSE,
- certbuf,
- &size);
- if(rc) {
- infof(data, "error fetching CN from cert:%s\n",
- gnutls_strerror(rc));
- }
-
- /* This function will check if the given certificate's subject matches the
- given hostname. This is a basic implementation of the matching described
- in RFC2818 (HTTPS), which takes into account wildcards, and the subject
- alternative name PKIX extension. Returns non zero on success, and zero on
- failure. */
- rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
-#if GNUTLS_VERSION_NUMBER < 0x030306
- /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
- addresses. */
- if(!rc) {
-#ifdef ENABLE_IPV6
- #define use_addr in6_addr
-#else
- #define use_addr in_addr
-#endif
- unsigned char addrbuf[sizeof(struct use_addr)];
- unsigned char certaddr[sizeof(struct use_addr)];
- size_t addrlen = 0, certaddrlen;
- int i;
- int ret = 0;
-
- if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0)
- addrlen = 4;
-#ifdef ENABLE_IPV6
- else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0)
- addrlen = 16;
-#endif
-
- if(addrlen) {
- for(i=0; ; i++) {
- certaddrlen = sizeof(certaddr);
- ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
- &certaddrlen, NULL);
- /* If this happens, it wasn't an IP address. */
- if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
- continue;
- if(ret < 0)
- break;
- if(ret != GNUTLS_SAN_IPADDRESS)
- continue;
- if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
- rc = 1;
- break;
- }
- }
- }
- }
-#endif
- if(!rc) {
- if(data->set.ssl.verifyhost) {
- failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certbuf, conn->host.dispname);
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\t common name: %s (does not match '%s')\n",
- certbuf, conn->host.dispname);
- }
- else
- infof(data, "\t common name: %s (matched)\n", certbuf);
-
- /* Check for time-based validity */
- certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
-
- if(certclock == (time_t)-1) {
- if(data->set.ssl.verifypeer) {
- failf(data, "server cert expiration date verify failed");
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else
- infof(data, "\t server certificate expiration date verify FAILED\n");
- }
- else {
- if(certclock < time(NULL)) {
- if(data->set.ssl.verifypeer) {
- failf(data, "server certificate expiration date has passed.");
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\t server certificate expiration date FAILED\n");
- }
- else
- infof(data, "\t server certificate expiration date OK\n");
- }
-
- certclock = gnutls_x509_crt_get_activation_time(x509_cert);
-
- if(certclock == (time_t)-1) {
- if(data->set.ssl.verifypeer) {
- failf(data, "server cert activation date verify failed");
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else
- infof(data, "\t server certificate activation date verify FAILED\n");
- }
- else {
- if(certclock > time(NULL)) {
- if(data->set.ssl.verifypeer) {
- failf(data, "server certificate not activated yet.");
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\t server certificate activation date FAILED\n");
- }
- else
- infof(data, "\t server certificate activation date OK\n");
- }
-
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
- if(ptr) {
- result = pkp_pin_peer_pubkey(x509_cert, ptr);
- if(result != CURLE_OK) {
- failf(data, "SSL: public key does not match pinned public key!");
- gnutls_x509_crt_deinit(x509_cert);
- return result;
- }
- }
-
- /* Show:
-
- - subject
- - start date
- - expire date
- - common name
- - issuer
-
- */
-
- /* public key algorithm's parameters */
- algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
- infof(data, "\t certificate public key: %s\n",
- gnutls_pk_algorithm_get_name(algo));
-
- /* version of the X.509 certificate. */
- infof(data, "\t certificate version: #%d\n",
- gnutls_x509_crt_get_version(x509_cert));
-
-
- size = sizeof(certbuf);
- gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
- infof(data, "\t subject: %s\n", certbuf);
-
- certclock = gnutls_x509_crt_get_activation_time(x509_cert);
- showtime(data, "start date", certclock);
-
- certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
- showtime(data, "expire date", certclock);
-
- size = sizeof(certbuf);
- gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
- infof(data, "\t issuer: %s\n", certbuf);
-
- gnutls_x509_crt_deinit(x509_cert);
-
- /* compression algorithm (if any) */
- ptr = gnutls_compression_get_name(gnutls_compression_get(session));
- /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
- infof(data, "\t compression: %s\n", ptr);
-
-#ifdef HAS_ALPN
- if(data->set.ssl_enable_alpn) {
- rc = gnutls_alpn_get_selected_protocol(session, &proto);
- if(rc == 0) {
- infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
- proto.data);
-
-#ifdef USE_NGHTTP2
- if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
- conn->negnpn = CURL_HTTP_VERSION_2_0;
- }
- else
-#endif
- if(proto.size == ALPN_HTTP_1_1_LENGTH &&
- !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
- conn->negnpn = CURL_HTTP_VERSION_1_1;
- }
- }
- else
- infof(data, "ALPN, server did not agree to a protocol\n");
- }
-#endif
-
- conn->ssl[sockindex].state = ssl_connection_complete;
- conn->recv[sockindex] = gtls_recv;
- conn->send[sockindex] = gtls_send;
-
- {
- /* we always unconditionally get the session id here, as even if we
- already got it from the cache and asked to use it in the connection, it
- might've been rejected and then a new one is in use now and we need to
- detect that. */
- void *connect_sessionid;
- size_t connect_idsize = 0;
-
- /* get the session ID data size */
- gnutls_session_get_data(session, NULL, &connect_idsize);
- connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
-
- if(connect_sessionid) {
- /* extract session ID to the allocated buffer */
- gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
-
- incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
- if(incache) {
- /* there was one before in the cache, so instead of risking that the
- previous one was rejected, we just kill that and store the new */
- Curl_ssl_delsessionid(conn, ssl_sessionid);
- }
-
- /* store this session id */
- result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
- if(result) {
- free(connect_sessionid);
- result = CURLE_OUT_OF_MEMORY;
- }
- }
- else
- result = CURLE_OUT_OF_MEMORY;
- }
-
- return result;
-}
-
-
-/*
- * This function is called after the TCP connect has completed. Setup the TLS
- * layer and do all necessary magic.
- */
-/* We use connssl->connecting_state to keep track of the connection status;
- there are three states: 'ssl_connect_1' (not started yet or complete),
- 'ssl_connect_2_reading' (waiting for data from server), and
- 'ssl_connect_2_writing' (waiting to be able to write).
- */
-static CURLcode
-gtls_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
-{
- int rc;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- /* Initiate the connection, if not already done */
- if(ssl_connect_1==connssl->connecting_state) {
- rc = gtls_connect_step1 (conn, sockindex);
- if(rc)
- return rc;
- }
-
- rc = handshake(conn, sockindex, TRUE, nonblocking);
- if(rc)
- /* handshake() sets its own error message with failf() */
- return rc;
-
- /* Finish connecting once the handshake is done */
- if(ssl_connect_1==connssl->connecting_state) {
- rc = gtls_connect_step3(conn, sockindex);
- if(rc)
- return rc;
- }
-
- *done = ssl_connect_1==connssl->connecting_state;
-
- return CURLE_OK;
-}
-
-CURL_STATIC CURLcode
-Curl_gtls_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- return gtls_connect_common(conn, sockindex, TRUE, done);
-}
-
-CURL_STATIC CURLcode
-Curl_gtls_connect(struct connectdata *conn,
- int sockindex)
-
-{
- CURLcode result;
- bool done = FALSE;
-
- result = gtls_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-static ssize_t gtls_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
-{
- ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
-
- if(rc < 0 ) {
- *curlcode = (rc == GNUTLS_E_AGAIN)
- ? CURLE_AGAIN
- : CURLE_SEND_ERROR;
-
- rc = -1;
- }
-
- return rc;
-}
-
-static void close_one(struct connectdata *conn,
- int idx)
-{
- if(conn->ssl[idx].session) {
- gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
- gnutls_deinit(conn->ssl[idx].session);
- conn->ssl[idx].session = NULL;
- }
- if(conn->ssl[idx].cred) {
- gnutls_certificate_free_credentials(conn->ssl[idx].cred);
- conn->ssl[idx].cred = NULL;
- }
-#ifdef USE_TLS_SRP
- if(conn->ssl[idx].srp_client_cred) {
- gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
- conn->ssl[idx].srp_client_cred = NULL;
- }
-#endif
-}
-
-CURL_STATIC void Curl_gtls_close(struct connectdata *conn, int sockindex)
-{
- close_one(conn, sockindex);
-}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-CURL_STATIC int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
-{
- ssize_t result;
- int retval = 0;
- struct SessionHandle *data = conn->data;
- int done = 0;
- char buf[120];
-
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
-
- if(conn->ssl[sockindex].session) {
- while(!done) {
- int what = Curl_socket_ready(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server */
- result = gnutls_record_recv(conn->ssl[sockindex].session,
- buf, sizeof(buf));
- switch(result) {
- case 0:
- /* This is the expected response. There was no data but only
- the close notify alert */
- done = 1;
- break;
- case GNUTLS_E_AGAIN:
- case GNUTLS_E_INTERRUPTED:
- infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
- break;
- default:
- retval = -1;
- done = 1;
- break;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- done = 1;
- break;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- retval = -1;
- done = 1;
- }
- }
- gnutls_deinit(conn->ssl[sockindex].session);
- }
- gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
-
-#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
- && data->set.ssl.username != NULL)
- gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
-#endif
-
- conn->ssl[sockindex].cred = NULL;
- conn->ssl[sockindex].session = NULL;
-
- return retval;
-}
-
-static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- CURLcode *curlcode)
-{
- ssize_t ret;
-
- ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
- if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
- *curlcode = CURLE_AGAIN;
- return -1;
- }
-
- if(ret == GNUTLS_E_REHANDSHAKE) {
- /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
- proper way" takes a whole lot of work. */
- CURLcode result = handshake(conn, num, FALSE, FALSE);
- if(result)
- /* handshake() writes error message on its own */
- *curlcode = result;
- else
- *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
- return -1;
- }
-
- if(ret < 0) {
- failf(conn->data, "GnuTLS recv error (%d): %s",
- (int)ret, gnutls_strerror((int)ret));
- *curlcode = CURLE_RECV_ERROR;
- return -1;
- }
-
- return ret;
-}
-
-CURL_STATIC void Curl_gtls_session_free(void *ptr)
-{
- free(ptr);
-}
-
-CURL_STATIC size_t Curl_gtls_version(char *buffer, size_t size)
-{
- return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
-}
-
-#ifndef USE_GNUTLS_NETTLE
-static int Curl_gtls_seed(struct SessionHandle *data)
-{
- /* we have the "SSL is seeded" boolean static to prevent multiple
- time-consuming seedings in vain */
- static bool ssl_seeded = FALSE;
-
- /* Quickly add a bit of entropy */
- gcry_fast_random_poll();
-
- if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
- data->set.str[STRING_SSL_EGDSOCKET]) {
-
- /* TODO: to a good job seeding the RNG
- This may involve the gcry_control function and these options:
- GCRYCTL_SET_RANDOM_SEED_FILE
- GCRYCTL_SET_RNDEGD_SOCKET
- */
- ssl_seeded = TRUE;
- }
- return 0;
-}
-#endif
-
-/* data might be NULL! */
-CURL_STATIC int Curl_gtls_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length)
-{
-#if defined(USE_GNUTLS_NETTLE)
- (void)data;
- gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
-#elif defined(USE_GNUTLS)
- if(data)
- Curl_gtls_seed(data); /* Initiate the seed if not already done */
- gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
-#endif
- return 0;
-}
-
-CURL_STATIC void Curl_gtls_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
-{
-#if defined(USE_GNUTLS_NETTLE)
- struct md5_ctx MD5pw;
- md5_init(&MD5pw);
- md5_update(&MD5pw, (unsigned int)tmplen, tmp);
- md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
-#elif defined(USE_GNUTLS)
- gcry_md_hd_t MD5pw;
- gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
- gcry_md_write(MD5pw, tmp, tmplen);
- memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len);
- gcry_md_close(MD5pw);
-#endif
-}
-
-bool Curl_gtls_cert_status_request(void)
-{
-#ifdef HAS_OCSP
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-#endif /* USE_GNUTLS */
diff --git a/libcurl/src/lib/vtls/gtls.h b/libcurl/src/lib/vtls/gtls.h
deleted file mode 100644
index dc98f79..0000000
--- a/libcurl/src/lib/vtls/gtls.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef HEADER_CURL_GTLS_H
-#define HEADER_CURL_GTLS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "../curl_setup.h"
-
-#ifdef USE_GNUTLS
-
-#include "urldata.h"
-
-CURL_STATIC int Curl_gtls_init(void);
-CURL_STATIC int Curl_gtls_cleanup(void);
-CURL_STATIC CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
- /* close a SSL connection */
-CURL_STATIC void Curl_gtls_close(struct connectdata *conn, int sockindex);
-
-CURL_STATIC void Curl_gtls_session_free(void *ptr);
-CURL_STATIC size_t Curl_gtls_version(char *buffer, size_t size);
-CURL_STATIC int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC int Curl_gtls_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length);
-CURL_STATIC void Curl_gtls_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-
-bool Curl_gtls_cert_status_request(void);
-
-/* Set the API backend definition to GnuTLS */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* API setup for GnuTLS */
-#define curlssl_init Curl_gtls_init
-#define curlssl_cleanup Curl_gtls_cleanup
-#define curlssl_connect Curl_gtls_connect
-#define curlssl_connect_nonblocking Curl_gtls_connect_nonblocking
-#define curlssl_session_free(x) Curl_gtls_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_gtls_close
-#define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_gtls_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
-#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z)
-#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d)
-#define curlssl_cert_status_request() Curl_gtls_cert_status_request()
-
-#endif /* USE_GNUTLS */
-#endif /* HEADER_CURL_GTLS_H */
diff --git a/libcurl/src/lib/vtls/nss.c b/libcurl/src/lib/vtls/nss.c
deleted file mode 100644
index 1c17612..0000000
--- a/libcurl/src/lib/vtls/nss.c
+++ /dev/null
@@ -1,2006 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all NSS-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_NSS
-
-#include "urldata.h"
-#include "sendf.h"
-#include "formdata.h" /* for the boundary function */
-#include "url.h" /* for the ssl config check function */
-#include "connect.h"
-#include "strequal.h"
-#include "select.h"
-#include "vtls.h"
-#include "llist.h"
-#include "curl_printf.h"
-#include "nssg.h"
-#include <nspr.h>
-#include <nss.h>
-#include <ssl.h>
-#include <sslerr.h>
-#include <secerr.h>
-#include <secmod.h>
-#include <sslproto.h>
-#include <prtypes.h>
-#include <pk11pub.h>
-#include <prio.h>
-#include <secitem.h>
-#include <secport.h>
-#include <certdb.h>
-#include <base64.h>
-#include <cert.h>
-#include <prerror.h>
-
-#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
-
-#if NSSVERNUM >= 0x030f00 /* 3.15.0 */
-#include <ocsp.h>
-#endif
-
-#include "rawstr.h"
-#include "warnless.h"
-#include "x509asn1.h"
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#define SSL_DIR "/etc/pki/nssdb"
-
-/* enough to fit the string "PEM Token #[0|1]" */
-#define SLOTSIZE 13
-
-PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
-
-PRLock * nss_initlock = NULL;
-PRLock * nss_crllock = NULL;
-struct curl_llist *nss_crl_list = NULL;
-NSSInitContext * nss_context = NULL;
-
-volatile int initialized = 0;
-
-typedef struct {
- const char *name;
- int num;
-} cipher_s;
-
-#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
- CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
- ptr->type = (_type); \
- ptr->pValue = (_val); \
- ptr->ulValueLen = (_len); \
-} WHILE_FALSE
-
-#define CERT_NewTempCertificate __CERT_NewTempCertificate
-
-#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
-static const cipher_s cipherlist[] = {
- /* SSL2 cipher suites */
- {"rc4", SSL_EN_RC4_128_WITH_MD5},
- {"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
- {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
- {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
- {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
- {"des", SSL_EN_DES_64_CBC_WITH_MD5},
- {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
- /* SSL3/TLS cipher suites */
- {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
- {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA},
- {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
- {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
- {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
- {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
- {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
- {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA},
- {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
- {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
- {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
- {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
- {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
- /* TLS 1.0: Exportable 56-bit Cipher Suites. */
- {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
- {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
- /* AES ciphers. */
- {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
- {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
- {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
- {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
- {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
- {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
- /* ECC ciphers. */
- {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA},
- {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
- {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
- {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
- {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA},
- {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
- {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
- {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
- {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA},
- {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA},
- {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
- {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
- {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA},
- {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
- {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
- {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
- {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
- {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA},
- {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA},
- {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
- {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
- {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
-#ifdef TLS_RSA_WITH_NULL_SHA256
- /* new HMAC-SHA256 cipher suites specified in RFC */
- {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256},
- {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256},
- {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256},
- {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
- {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
- {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
- {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
-#endif
-#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
- /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
- {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256},
- {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
- {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
- {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
- {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
-#endif
-};
-
-static const char* pem_library = "libnsspem.so";
-SECMODModule* mod = NULL;
-
-/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
-static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
-static PRIOMethods nspr_io_methods;
-
-static const char* nss_error_to_name(PRErrorCode code)
-{
- const char *name = PR_ErrorToName(code);
- if(name)
- return name;
-
- return "unknown error";
-}
-
-static void nss_print_error_message(struct SessionHandle *data, PRUint32 err)
-{
- failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
-}
-
-static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
- char *cipher_list)
-{
- unsigned int i;
- PRBool cipher_state[NUM_OF_CIPHERS];
- PRBool found;
- char *cipher;
-
- /* First disable all ciphers. This uses a different max value in case
- * NSS adds more ciphers later we don't want them available by
- * accident
- */
- for(i=0; i<SSL_NumImplementedCiphers; i++) {
- SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], PR_FALSE);
- }
-
- /* Set every entry in our list to false */
- for(i=0; i<NUM_OF_CIPHERS; i++) {
- cipher_state[i] = PR_FALSE;
- }
-
- cipher = cipher_list;
-
- while(cipher_list && (cipher_list[0])) {
- while((*cipher) && (ISSPACE(*cipher)))
- ++cipher;
-
- if((cipher_list = strchr(cipher, ','))) {
- *cipher_list++ = '\0';
- }
-
- found = PR_FALSE;
-
- for(i=0; i<NUM_OF_CIPHERS; i++) {
- if(Curl_raw_equal(cipher, cipherlist[i].name)) {
- cipher_state[i] = PR_TRUE;
- found = PR_TRUE;
- break;
- }
- }
-
- if(found == PR_FALSE) {
- failf(data, "Unknown cipher in list: %s", cipher);
- return SECFailure;
- }
-
- if(cipher_list) {
- cipher = cipher_list;
- }
- }
-
- /* Finally actually enable the selected ciphers */
- for(i=0; i<NUM_OF_CIPHERS; i++) {
- if(!cipher_state[i])
- continue;
-
- if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
- failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
- return SECFailure;
- }
- }
-
- return SECSuccess;
-}
-
-/*
- * Get the number of ciphers that are enabled. We use this to determine
- * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
- */
-static int num_enabled_ciphers(void)
-{
- PRInt32 policy = 0;
- int count = 0;
- unsigned int i;
-
- for(i=0; i<NUM_OF_CIPHERS; i++) {
- SSL_CipherPolicyGet(cipherlist[i].num, &policy);
- if(policy)
- count++;
- }
- return count;
-}
-
-/*
- * Determine whether the nickname passed in is a filename that needs to
- * be loaded as a PEM or a regular NSS nickname.
- *
- * returns 1 for a file
- * returns 0 for not a file (NSS nickname)
- */
-static int is_file(const char *filename)
-{
- struct_stat st;
-
- if(filename == NULL)
- return 0;
-
- if(stat(filename, &st) == 0)
- if(S_ISREG(st.st_mode))
- return 1;
-
- return 0;
-}
-
-/* Check if the given string is filename or nickname of a certificate. If the
- * given string is recognized as filename, return NULL. If the given string is
- * recognized as nickname, return a duplicated string. The returned string
- * should be later deallocated using free(). If the OOM failure occurs, we
- * return NULL, too.
- */
-static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
-{
- const char *str = data->set.str[cert_kind];
- const char *n;
-
- if(!is_file(str))
- /* no such file exists, use the string as nickname */
- return strdup(str);
-
- /* search the last slash; we require at least one slash in a file name */
- n = strrchr(str, '/');
- if(!n) {
- infof(data, "warning: certificate file name \"%s\" handled as nickname; "
- "please use \"./%s\" to force file name\n", str, str);
- return strdup(str);
- }
-
- /* we'll use the PEM reader to read the certificate from file */
- return NULL;
-}
-
-/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
- * the call succeeds, append the object handle to the list of objects so that
- * the object can be destroyed in Curl_nss_close(). */
-static CURLcode nss_create_object(struct ssl_connect_data *ssl,
- CK_OBJECT_CLASS obj_class,
- const char *filename, bool cacert)
-{
- PK11SlotInfo *slot;
- PK11GenericObject *obj;
- CK_BBOOL cktrue = CK_TRUE;
- CK_BBOOL ckfalse = CK_FALSE;
- CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
- int attr_cnt = 0;
- CURLcode result = (cacert)
- ? CURLE_SSL_CACERT_BADFILE
- : CURLE_SSL_CERTPROBLEM;
-
- const int slot_id = (cacert) ? 0 : 1;
- char *slot_name = aprintf("PEM Token #%d", slot_id);
- if(!slot_name)
- return CURLE_OUT_OF_MEMORY;
-
- slot = PK11_FindSlotByName(slot_name);
- free(slot_name);
- if(!slot)
- return result;
-
- PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
- PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
- PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
- strlen(filename) + 1);
-
- if(CKO_CERTIFICATE == obj_class) {
- CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
- PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
- }
-
- obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
- PK11_FreeSlot(slot);
- if(!obj)
- return result;
-
- if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
- PK11_DestroyGenericObject(obj);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(!cacert && CKO_CERTIFICATE == obj_class)
- /* store reference to a client certificate */
- ssl->obj_clicert = obj;
-
- return CURLE_OK;
-}
-
-/* Destroy the NSS object whose handle is given by ptr. This function is
- * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
- * NSS objects in Curl_nss_close() */
-static void nss_destroy_object(void *user, void *ptr)
-{
- PK11GenericObject *obj = (PK11GenericObject *)ptr;
- (void) user;
- PK11_DestroyGenericObject(obj);
-}
-
-/* same as nss_destroy_object() but for CRL items */
-static void nss_destroy_crl_item(void *user, void *ptr)
-{
- SECItem *crl_der = (SECItem *)ptr;
- (void) user;
- SECITEM_FreeItem(crl_der, PR_TRUE);
-}
-
-static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
- const char *filename, PRBool cacert)
-{
- CURLcode result = (cacert)
- ? CURLE_SSL_CACERT_BADFILE
- : CURLE_SSL_CERTPROBLEM;
-
- /* libnsspem.so leaks memory if the requested file does not exist. For more
- * details, go to <https://bugzilla.redhat.com/734760>. */
- if(is_file(filename))
- result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
-
- if(!result && !cacert) {
- /* we have successfully loaded a client certificate */
- CERTCertificate *cert;
- char *nickname = NULL;
- char *n = strrchr(filename, '/');
- if(n)
- n++;
-
- /* The following undocumented magic helps to avoid a SIGSEGV on call
- * of PK11_ReadRawAttribute() from SelectClientCert() when using an
- * immature version of libnsspem.so. For more details, go to
- * <https://bugzilla.redhat.com/733685>. */
- nickname = aprintf("PEM Token #1:%s", n);
- if(nickname) {
- cert = PK11_FindCertFromNickname(nickname, NULL);
- if(cert)
- CERT_DestroyCertificate(cert);
-
- free(nickname);
- }
- }
-
- return result;
-}
-
-/* add given CRL to cache if it is not already there */
-static CURLcode nss_cache_crl(SECItem *crl_der)
-{
- CERTCertDBHandle *db = CERT_GetDefaultCertDB();
- CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
- if(crl) {
- /* CRL already cached */
- SEC_DestroyCrl(crl);
- SECITEM_FreeItem(crl_der, PR_TRUE);
- return CURLE_OK;
- }
-
- /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
- PR_Lock(nss_crllock);
-
- /* store the CRL item so that we can free it in Curl_nss_cleanup() */
- if(!Curl_llist_insert_next(nss_crl_list, nss_crl_list->tail, crl_der)) {
- SECITEM_FreeItem(crl_der, PR_TRUE);
- PR_Unlock(nss_crllock);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
- /* unable to cache CRL */
- PR_Unlock(nss_crllock);
- return CURLE_SSL_CRL_BADFILE;
- }
-
- /* we need to clear session cache, so that the CRL could take effect */
- SSL_ClearSessionCache();
- PR_Unlock(nss_crllock);
- return CURLE_OK;
-}
-
-static CURLcode nss_load_crl(const char* crlfilename)
-{
- PRFileDesc *infile;
- PRFileInfo info;
- SECItem filedata = { 0, NULL, 0 };
- SECItem *crl_der = NULL;
- char *body;
-
- infile = PR_Open(crlfilename, PR_RDONLY, 0);
- if(!infile)
- return CURLE_SSL_CRL_BADFILE;
-
- if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
- goto fail;
-
- if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
- goto fail;
-
- if(info.size != PR_Read(infile, filedata.data, info.size))
- goto fail;
-
- crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
- if(!crl_der)
- goto fail;
-
- /* place a trailing zero right after the visible data */
- body = (char*)filedata.data;
- body[--filedata.len] = '\0';
-
- body = strstr(body, "-----BEGIN");
- if(body) {
- /* assume ASCII */
- char *trailer;
- char *begin = PORT_Strchr(body, '\n');
- if(!begin)
- begin = PORT_Strchr(body, '\r');
- if(!begin)
- goto fail;
-
- trailer = strstr(++begin, "-----END");
- if(!trailer)
- goto fail;
-
- /* retrieve DER from ASCII */
- *trailer = '\0';
- if(ATOB_ConvertAsciiToItem(crl_der, begin))
- goto fail;
-
- SECITEM_FreeItem(&filedata, PR_FALSE);
- }
- else
- /* assume DER */
- *crl_der = filedata;
-
- PR_Close(infile);
- return nss_cache_crl(crl_der);
-
-fail:
- PR_Close(infile);
- SECITEM_FreeItem(crl_der, PR_TRUE);
- SECITEM_FreeItem(&filedata, PR_FALSE);
- return CURLE_SSL_CRL_BADFILE;
-}
-
-static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
- char *key_file)
-{
- PK11SlotInfo *slot;
- SECStatus status;
- CURLcode result;
- struct ssl_connect_data *ssl = conn->ssl;
-
- (void)sockindex; /* unused */
-
- result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
- if(result) {
- PR_SetError(SEC_ERROR_BAD_KEY, 0);
- return result;
- }
-
- slot = PK11_FindSlotByName("PEM Token #1");
- if(!slot)
- return CURLE_SSL_CERTPROBLEM;
-
- /* This will force the token to be seen as re-inserted */
- SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
- PK11_IsPresent(slot);
-
- status = PK11_Authenticate(slot, PR_TRUE,
- conn->data->set.str[STRING_KEY_PASSWD]);
- PK11_FreeSlot(slot);
-
- return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
-}
-
-static int display_error(struct connectdata *conn, PRInt32 err,
- const char *filename)
-{
- switch(err) {
- case SEC_ERROR_BAD_PASSWORD:
- failf(conn->data, "Unable to load client key: Incorrect password");
- return 1;
- case SEC_ERROR_UNKNOWN_CERT:
- failf(conn->data, "Unable to load certificate %s", filename);
- return 1;
- default:
- break;
- }
- return 0; /* The caller will print a generic error */
-}
-
-static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
- char *cert_file, char *key_file)
-{
- struct SessionHandle *data = conn->data;
- CURLcode result;
-
- if(cert_file) {
- result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
- if(result) {
- const PRErrorCode err = PR_GetError();
- if(!display_error(conn, err, cert_file)) {
- const char *err_name = nss_error_to_name(err);
- failf(data, "unable to load client cert: %d (%s)", err, err_name);
- }
-
- return result;
- }
- }
-
- if(key_file || (is_file(cert_file))) {
- if(key_file)
- result = nss_load_key(conn, sockindex, key_file);
- else
- /* In case the cert file also has the key */
- result = nss_load_key(conn, sockindex, cert_file);
- if(result) {
- const PRErrorCode err = PR_GetError();
- if(!display_error(conn, err, key_file)) {
- const char *err_name = nss_error_to_name(err);
- failf(data, "unable to load client key: %d (%s)", err, err_name);
- }
-
- return result;
- }
- }
-
- return CURLE_OK;
-}
-
-static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
-{
- (void)slot; /* unused */
-
- if(retry || NULL == arg)
- return NULL;
- else
- return (char *)PORT_Strdup((char *)arg);
-}
-
-/* bypass the default SSL_AuthCertificate() hook in case we do not want to
- * verify peer */
-static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
- PRBool isServer)
-{
- struct connectdata *conn = (struct connectdata *)arg;
-
-#ifdef SSL_ENABLE_OCSP_STAPLING
- if(conn->data->set.ssl.verifystatus) {
- SECStatus cacheResult;
-
- const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
- if(!csa) {
- failf(conn->data, "Invalid OCSP response");
- return SECFailure;
- }
-
- if(csa->len == 0) {
- failf(conn->data, "No OCSP response received");
- return SECFailure;
- }
-
- cacheResult = CERT_CacheOCSPResponseFromSideChannel(
- CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd),
- PR_Now(), &csa->items[0], arg
- );
-
- if(cacheResult != SECSuccess) {
- failf(conn->data, "Invalid OCSP response");
- return cacheResult;
- }
- }
-#endif
-
- if(!conn->data->set.ssl.verifypeer) {
- infof(conn->data, "skipping SSL peer certificate verification\n");
- return SECSuccess;
- }
-
- return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
-}
-
-/**
- * Inform the application that the handshake is complete.
- */
-static void HandshakeCallback(PRFileDesc *sock, void *arg)
-{
- struct connectdata *conn = (struct connectdata*) arg;
- unsigned int buflenmax = 50;
- unsigned char buf[50];
- unsigned int buflen;
- SSLNextProtoState state;
-
- if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) {
- return;
- }
-
- if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
-
- switch(state) {
- case SSL_NEXT_PROTO_NO_SUPPORT:
- case SSL_NEXT_PROTO_NO_OVERLAP:
- infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n");
- return;
-#ifdef SSL_ENABLE_ALPN
- case SSL_NEXT_PROTO_SELECTED:
- infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf);
- break;
-#endif
- case SSL_NEXT_PROTO_NEGOTIATED:
- infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf);
- break;
- }
-
-#ifdef USE_NGHTTP2
- if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) {
- conn->negnpn = CURL_HTTP_VERSION_2_0;
- }
- else
-#endif
- if(buflen == ALPN_HTTP_1_1_LENGTH &&
- !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
- conn->negnpn = CURL_HTTP_VERSION_1_1;
- }
- }
-}
-
-static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
- PRBool *canFalseStart)
-{
- struct connectdata *conn = client_data;
- struct SessionHandle *data = conn->data;
-
- SSLChannelInfo channelInfo;
- SSLCipherSuiteInfo cipherInfo;
-
- SECStatus rv;
- PRBool negotiatedExtension;
-
- *canFalseStart = PR_FALSE;
-
- if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
- return SECFailure;
-
- if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
- sizeof(cipherInfo)) != SECSuccess)
- return SECFailure;
-
- /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
- * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
- */
- if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
- goto end;
-
- /* Only allow ECDHE key exchange algorithm.
- * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
- if(cipherInfo.keaType != ssl_kea_ecdh)
- goto end;
-
- /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
- * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
- * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
- if(cipherInfo.symCipher != ssl_calg_aes_gcm)
- goto end;
-
- /* Enforce ALPN or NPN to do False Start, as an indicator of server
- * compatibility. */
- rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
- &negotiatedExtension);
- if(rv != SECSuccess || !negotiatedExtension) {
- rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
- &negotiatedExtension);
- }
-
- if(rv != SECSuccess || !negotiatedExtension)
- goto end;
-
- *canFalseStart = PR_TRUE;
-
- infof(data, "Trying TLS False Start\n");
-
-end:
- return SECSuccess;
-}
-
-static void display_cert_info(struct SessionHandle *data,
- CERTCertificate *cert)
-{
- char *subject, *issuer, *common_name;
- PRExplodedTime printableTime;
- char timeString[256];
- PRTime notBefore, notAfter;
-
- subject = CERT_NameToAscii(&cert->subject);
- issuer = CERT_NameToAscii(&cert->issuer);
- common_name = CERT_GetCommonName(&cert->subject);
- infof(data, "\tsubject: %s\n", subject);
-
- CERT_GetCertTimes(cert, &notBefore, &notAfter);
- PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
- PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
- infof(data, "\tstart date: %s\n", timeString);
- PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
- PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
- infof(data, "\texpire date: %s\n", timeString);
- infof(data, "\tcommon name: %s\n", common_name);
- infof(data, "\tissuer: %s\n", issuer);
-
- PR_Free(subject);
- PR_Free(issuer);
- PR_Free(common_name);
-}
-
-static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
-{
- CURLcode result = CURLE_OK;
- SSLChannelInfo channel;
- SSLCipherSuiteInfo suite;
- CERTCertificate *cert;
- CERTCertificate *cert2;
- CERTCertificate *cert3;
- PRTime now;
- int i;
-
- if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
- SECSuccess && channel.length == sizeof channel &&
- channel.cipherSuite) {
- if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
- &suite, sizeof suite) == SECSuccess) {
- infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
- }
- }
-
- cert = SSL_PeerCertificate(sock);
- if(cert) {
- infof(conn->data, "Server certificate:\n");
-
- if(!conn->data->set.ssl.certinfo) {
- display_cert_info(conn->data, cert);
- CERT_DestroyCertificate(cert);
- }
- else {
- /* Count certificates in chain. */
- now = PR_Now();
- i = 1;
- if(!cert->isRoot) {
- cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
- while(cert2) {
- i++;
- if(cert2->isRoot) {
- CERT_DestroyCertificate(cert2);
- break;
- }
- cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
- CERT_DestroyCertificate(cert2);
- cert2 = cert3;
- }
- }
-
- result = Curl_ssl_init_certinfo(conn->data, i);
- if(!result) {
- for(i = 0; cert; cert = cert2) {
- result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
- (char *)cert->derCert.data +
- cert->derCert.len);
- if(result)
- break;
-
- if(cert->isRoot) {
- CERT_DestroyCertificate(cert);
- break;
- }
-
- cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
- CERT_DestroyCertificate(cert);
- }
- }
- }
- }
-
- return result;
-}
-
-static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
-{
- struct connectdata *conn = (struct connectdata *)arg;
- struct SessionHandle *data = conn->data;
- PRErrorCode err = PR_GetError();
- CERTCertificate *cert;
-
- /* remember the cert verification result */
- data->set.ssl.certverifyresult = err;
-
- if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost)
- /* we are asked not to verify the host name */
- return SECSuccess;
-
- /* print only info about the cert, the error is printed off the callback */
- cert = SSL_PeerCertificate(sock);
- if(cert) {
- infof(data, "Server certificate:\n");
- display_cert_info(data, cert);
- CERT_DestroyCertificate(cert);
- }
-
- return SECFailure;
-}
-
-/**
- *
- * Check that the Peer certificate's issuer certificate matches the one found
- * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
- * issuer check, so we provide comments that mimic the OpenSSL
- * X509_check_issued function (in x509v3/v3_purp.c)
- */
-static SECStatus check_issuer_cert(PRFileDesc *sock,
- char *issuer_nickname)
-{
- CERTCertificate *cert, *cert_issuer, *issuer;
- SECStatus res=SECSuccess;
- void *proto_win = NULL;
-
- /*
- PRArenaPool *tmpArena = NULL;
- CERTAuthKeyID *authorityKeyID = NULL;
- SECITEM *caname = NULL;
- */
-
- cert = SSL_PeerCertificate(sock);
- cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
-
- proto_win = SSL_RevealPinArg(sock);
- issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
-
- if((!cert_issuer) || (!issuer))
- res = SECFailure;
- else if(SECITEM_CompareItem(&cert_issuer->derCert,
- &issuer->derCert)!=SECEqual)
- res = SECFailure;
-
- CERT_DestroyCertificate(cert);
- CERT_DestroyCertificate(issuer);
- CERT_DestroyCertificate(cert_issuer);
- return res;
-}
-
-/**
- *
- * Callback to pick the SSL client certificate.
- */
-static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
- struct CERTDistNamesStr *caNames,
- struct CERTCertificateStr **pRetCert,
- struct SECKEYPrivateKeyStr **pRetKey)
-{
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
- struct SessionHandle *data = connssl->data;
- const char *nickname = connssl->client_nickname;
-
- if(connssl->obj_clicert) {
- /* use the cert/key provided by PEM reader */
- static const char pem_slotname[] = "PEM Token #1";
- SECItem cert_der = { 0, NULL, 0 };
- void *proto_win = SSL_RevealPinArg(sock);
- struct CERTCertificateStr *cert;
- struct SECKEYPrivateKeyStr *key;
-
- PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
- if(NULL == slot) {
- failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
- return SECFailure;
- }
-
- if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
- &cert_der) != SECSuccess) {
- failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
- PK11_FreeSlot(slot);
- return SECFailure;
- }
-
- cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
- SECITEM_FreeItem(&cert_der, PR_FALSE);
- if(NULL == cert) {
- failf(data, "NSS: client certificate from file not found");
- PK11_FreeSlot(slot);
- return SECFailure;
- }
-
- key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
- PK11_FreeSlot(slot);
- if(NULL == key) {
- failf(data, "NSS: private key from file not found");
- CERT_DestroyCertificate(cert);
- return SECFailure;
- }
-
- infof(data, "NSS: client certificate from file\n");
- display_cert_info(data, cert);
-
- *pRetCert = cert;
- *pRetKey = key;
- return SECSuccess;
- }
-
- /* use the default NSS hook */
- if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
- pRetCert, pRetKey)
- || NULL == *pRetCert) {
-
- if(NULL == nickname)
- failf(data, "NSS: client certificate not found (nickname not "
- "specified)");
- else
- failf(data, "NSS: client certificate not found: %s", nickname);
-
- return SECFailure;
- }
-
- /* get certificate nickname if any */
- nickname = (*pRetCert)->nickname;
- if(NULL == nickname)
- nickname = "[unknown]";
-
- if(NULL == *pRetKey) {
- failf(data, "NSS: private key not found for certificate: %s", nickname);
- return SECFailure;
- }
-
- infof(data, "NSS: using client certificate: %s\n", nickname);
- display_cert_info(data, *pRetCert);
- return SECSuccess;
-}
-
-/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
-static void nss_update_connecting_state(ssl_connect_state state, void *secret)
-{
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
- if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
- /* an unrelated error is passing by */
- return;
-
- switch(connssl->connecting_state) {
- case ssl_connect_2:
- case ssl_connect_2_reading:
- case ssl_connect_2_writing:
- break;
- default:
- /* we are not called from an SSL handshake */
- return;
- }
-
- /* update the state accordingly */
- connssl->connecting_state = state;
-}
-
-/* recv() wrapper we use to detect blocking direction during SSL handshake */
-static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- const PRRecvFN recv_fn = fd->lower->methods->recv;
- const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
- if(rv < 0)
- /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
- nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
- return rv;
-}
-
-/* send() wrapper we use to detect blocking direction during SSL handshake */
-static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- const PRSendFN send_fn = fd->lower->methods->send;
- const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
- if(rv < 0)
- /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
- nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
- return rv;
-}
-
-/* close() wrapper to avoid assertion failure due to fd->secret != NULL */
-static PRStatus nspr_io_close(PRFileDesc *fd)
-{
- const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
- fd->secret = NULL;
- return close_fn(fd);
-}
-
-/* data might be NULL */
-static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
-{
- NSSInitParameters initparams;
-
- if(nss_context != NULL)
- return CURLE_OK;
-
- memset((void *) &initparams, '\0', sizeof(initparams));
- initparams.length = sizeof(initparams);
-
- if(cert_dir) {
- char *certpath = aprintf("sql:%s", cert_dir);
- if(!certpath)
- return CURLE_OUT_OF_MEMORY;
-
- infof(data, "Initializing NSS with certpath: %s\n", certpath);
- nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
- NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
- free(certpath);
-
- if(nss_context != NULL)
- return CURLE_OK;
-
- infof(data, "Unable to initialize NSS database\n");
- }
-
- infof(data, "Initializing NSS with certpath: none\n");
- nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
- | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
- | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
- if(nss_context != NULL)
- return CURLE_OK;
-
- infof(data, "Unable to initialize NSS\n");
- return CURLE_SSL_CACERT_BADFILE;
-}
-
-/* data might be NULL */
-static CURLcode nss_init(struct SessionHandle *data)
-{
- char *cert_dir;
- struct_stat st;
- CURLcode result;
-
- if(initialized)
- return CURLE_OK;
-
- /* list of all CRL items we need to destroy in Curl_nss_cleanup() */
- nss_crl_list = Curl_llist_alloc(nss_destroy_crl_item);
- if(!nss_crl_list)
- return CURLE_OUT_OF_MEMORY;
-
- /* First we check if $SSL_DIR points to a valid dir */
- cert_dir = getenv("SSL_DIR");
- if(cert_dir) {
- if((stat(cert_dir, &st) != 0) ||
- (!S_ISDIR(st.st_mode))) {
- cert_dir = NULL;
- }
- }
-
- /* Now we check if the default location is a valid dir */
- if(!cert_dir) {
- if((stat(SSL_DIR, &st) == 0) &&
- (S_ISDIR(st.st_mode))) {
- cert_dir = (char *)SSL_DIR;
- }
- }
-
- if(nspr_io_identity == PR_INVALID_IO_LAYER) {
- /* allocate an identity for our own NSPR I/O layer */
- nspr_io_identity = PR_GetUniqueIdentity("libcurl");
- if(nspr_io_identity == PR_INVALID_IO_LAYER)
- return CURLE_OUT_OF_MEMORY;
-
- /* the default methods just call down to the lower I/O layer */
- memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods);
-
- /* override certain methods in the table by our wrappers */
- nspr_io_methods.recv = nspr_io_recv;
- nspr_io_methods.send = nspr_io_send;
- nspr_io_methods.close = nspr_io_close;
- }
-
- result = nss_init_core(data, cert_dir);
- if(result)
- return result;
-
- if(num_enabled_ciphers() == 0)
- NSS_SetDomesticPolicy();
-
- initialized = 1;
-
- return CURLE_OK;
-}
-
-/**
- * Global SSL init
- *
- * @retval 0 error initializing SSL
- * @retval 1 SSL initialized successfully
- */
-CURL_STATIC int Curl_nss_init(void)
-{
- /* curl_global_init() is not thread-safe so this test is ok */
- if(nss_initlock == NULL) {
- PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
- nss_initlock = PR_NewLock();
- nss_crllock = PR_NewLock();
- }
-
- /* We will actually initialize NSS later */
-
- return 1;
-}
-
-/* data might be NULL */
-CURL_STATIC CURLcode Curl_nss_force_init(struct SessionHandle *data)
-{
- CURLcode result;
- if(!nss_initlock) {
- if(data)
- failf(data, "unable to initialize NSS, curl_global_init() should have "
- "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
- return CURLE_FAILED_INIT;
- }
-
- PR_Lock(nss_initlock);
- result = nss_init(data);
- PR_Unlock(nss_initlock);
-
- return result;
-}
-
-/* Global cleanup */
-CURL_STATIC void Curl_nss_cleanup(void)
-{
- /* This function isn't required to be threadsafe and this is only done
- * as a safety feature.
- */
- PR_Lock(nss_initlock);
- if(initialized) {
- /* Free references to client certificates held in the SSL session cache.
- * Omitting this hampers destruction of the security module owning
- * the certificates. */
- SSL_ClearSessionCache();
-
- if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
- SECMOD_DestroyModule(mod);
- mod = NULL;
- }
- NSS_ShutdownContext(nss_context);
- nss_context = NULL;
- }
-
- /* destroy all CRL items */
- Curl_llist_destroy(nss_crl_list, NULL);
- nss_crl_list = NULL;
-
- PR_Unlock(nss_initlock);
-
- PR_DestroyLock(nss_initlock);
- PR_DestroyLock(nss_crllock);
- nss_initlock = NULL;
-
- initialized = 0;
-}
-
-/*
- * This function uses SSL_peek to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-CURL_STATIC int
-Curl_nss_check_cxn(struct connectdata *conn)
-{
- int rc;
- char buf;
-
- rc =
- PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
- PR_SecondsToInterval(1));
- if(rc > 0)
- return 1; /* connection still in place */
-
- if(rc == 0)
- return 0; /* connection has been closed */
-
- return -1; /* connection status unknown */
-}
-
-/*
- * This function is called when an SSL connection is closed.
- */
-CURL_STATIC void Curl_nss_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->handle) {
- /* NSS closes the socket we previously handed to it, so we must mark it
- as closed to avoid double close */
- fake_sclose(conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
-
- if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL))
- /* A server might require different authentication based on the
- * particular path being requested by the client. To support this
- * scenario, we must ensure that a connection will never reuse the
- * authentication data from a previous connection. */
- SSL_InvalidateSession(connssl->handle);
-
- free(connssl->client_nickname);
- connssl->client_nickname = NULL;
- /* destroy all NSS objects in order to avoid failure of NSS shutdown */
- Curl_llist_destroy(connssl->obj_list, NULL);
- connssl->obj_list = NULL;
- connssl->obj_clicert = NULL;
-
- PR_Close(connssl->handle);
- connssl->handle = NULL;
- }
-}
-
-/* return true if NSS can provide error code (and possibly msg) for the
- error */
-static bool is_nss_error(CURLcode err)
-{
- switch(err) {
- case CURLE_PEER_FAILED_VERIFICATION:
- case CURLE_SSL_CACERT:
- case CURLE_SSL_CERTPROBLEM:
- case CURLE_SSL_CONNECT_ERROR:
- case CURLE_SSL_ISSUER_ERROR:
- return true;
-
- default:
- return false;
- }
-}
-
-/* return true if the given error code is related to a client certificate */
-static bool is_cc_error(PRInt32 err)
-{
- switch(err) {
- case SSL_ERROR_BAD_CERT_ALERT:
- case SSL_ERROR_EXPIRED_CERT_ALERT:
- case SSL_ERROR_REVOKED_CERT_ALERT:
- return true;
-
- default:
- return false;
- }
-}
-
-static Curl_recv nss_recv;
-static Curl_send nss_send;
-
-static CURLcode nss_load_ca_certificates(struct connectdata *conn,
- int sockindex)
-{
- struct SessionHandle *data = conn->data;
- const char *cafile = data->set.ssl.CAfile;
- const char *capath = data->set.ssl.CApath;
-
- if(cafile) {
- CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
- if(result)
- return result;
- }
-
- if(capath) {
- struct_stat st;
- if(stat(capath, &st) == -1)
- return CURLE_SSL_CACERT_BADFILE;
-
- if(S_ISDIR(st.st_mode)) {
- PRDirEntry *entry;
- PRDir *dir = PR_OpenDir(capath);
- if(!dir)
- return CURLE_SSL_CACERT_BADFILE;
-
- while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
- char *fullpath = aprintf("%s/%s", capath, entry->name);
- if(!fullpath) {
- PR_CloseDir(dir);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
- /* This is purposefully tolerant of errors so non-PEM files can
- * be in the same directory */
- infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
-
- free(fullpath);
- }
-
- PR_CloseDir(dir);
- }
- else
- infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
- }
-
- infof(data, " CAfile: %s\n CApath: %s\n",
- cafile ? cafile : "none",
- capath ? capath : "none");
-
- return CURLE_OK;
-}
-
-static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct SessionHandle *data)
-{
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
-#ifdef SSL_LIBRARY_VERSION_TLS_1_2
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
-#elif defined SSL_LIBRARY_VERSION_TLS_1_1
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
-#else
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
-#endif
- return CURLE_OK;
-
- case CURL_SSLVERSION_SSLv2:
- sslver->min = SSL_LIBRARY_VERSION_2;
- sslver->max = SSL_LIBRARY_VERSION_2;
- return CURLE_OK;
-
- case CURL_SSLVERSION_SSLv3:
- sslver->min = SSL_LIBRARY_VERSION_3_0;
- sslver->max = SSL_LIBRARY_VERSION_3_0;
- return CURLE_OK;
-
- case CURL_SSLVERSION_TLSv1_0:
- sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
- return CURLE_OK;
-
- case CURL_SSLVERSION_TLSv1_1:
-#ifdef SSL_LIBRARY_VERSION_TLS_1_1
- sslver->min = SSL_LIBRARY_VERSION_TLS_1_1;
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
- return CURLE_OK;
-#endif
- break;
-
- case CURL_SSLVERSION_TLSv1_2:
-#ifdef SSL_LIBRARY_VERSION_TLS_1_2
- sslver->min = SSL_LIBRARY_VERSION_TLS_1_2;
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
- return CURLE_OK;
-#endif
- break;
- }
-
- failf(data, "TLS minor version cannot be set");
- return CURLE_SSL_CONNECT_ERROR;
-}
-
-static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
- struct SessionHandle *data,
- CURLcode curlerr)
-{
- PRErrorCode err = 0;
-
- if(is_nss_error(curlerr)) {
- /* read NSPR error code */
- err = PR_GetError();
- if(is_cc_error(err))
- curlerr = CURLE_SSL_CERTPROBLEM;
-
- /* print the error number and error string */
- infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
-
- /* print a human-readable message describing the error if available */
- nss_print_error_message(data, err);
- }
-
- /* cleanup on connection failure */
- Curl_llist_destroy(connssl->obj_list, NULL);
- connssl->obj_list = NULL;
-
- return curlerr;
-}
-
-/* Switch the SSL socket into non-blocking mode. */
-static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
- struct SessionHandle *data)
-{
- static PRSocketOptionData sock_opt;
- sock_opt.option = PR_SockOpt_Nonblocking;
- sock_opt.value.non_blocking = PR_TRUE;
-
- if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
- return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
-
- return CURLE_OK;
-}
-
-static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
-{
- PRFileDesc *model = NULL;
- PRFileDesc *nspr_io = NULL;
- PRFileDesc *nspr_io_stub = NULL;
- PRBool ssl_no_cache;
- PRBool ssl_cbc_random_iv;
- struct SessionHandle *data = conn->data;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- CURLcode result;
-
- SSLVersionRange sslver = {
- SSL_LIBRARY_VERSION_TLS_1_0, /* min */
- SSL_LIBRARY_VERSION_TLS_1_0 /* max */
- };
-
- connssl->data = data;
-
- /* list of all NSS objects we need to destroy in Curl_nss_close() */
- connssl->obj_list = Curl_llist_alloc(nss_destroy_object);
- if(!connssl->obj_list)
- return CURLE_OUT_OF_MEMORY;
-
- /* FIXME. NSS doesn't support multiple databases open at the same time. */
- PR_Lock(nss_initlock);
- result = nss_init(conn->data);
- if(result) {
- PR_Unlock(nss_initlock);
- goto error;
- }
-
- result = CURLE_SSL_CONNECT_ERROR;
-
- if(!mod) {
- char *configstring = aprintf("library=%s name=PEM", pem_library);
- if(!configstring) {
- PR_Unlock(nss_initlock);
- goto error;
- }
- mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
- free(configstring);
-
- if(!mod || !mod->loaded) {
- if(mod) {
- SECMOD_DestroyModule(mod);
- mod = NULL;
- }
- infof(data, "WARNING: failed to load NSS PEM library %s. Using "
- "OpenSSL PEM certificates will not work.\n", pem_library);
- }
- }
-
- PK11_SetPasswordFunc(nss_get_password);
- PR_Unlock(nss_initlock);
-
- model = PR_NewTCPSocket();
- if(!model)
- goto error;
- model = SSL_ImportFD(NULL, model);
-
- if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
- goto error;
- if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
- goto error;
- if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
- goto error;
-
- /* do not use SSL cache if disabled or we are not going to verify peer */
- ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ?
- PR_FALSE : PR_TRUE;
- if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
- goto error;
-
- /* enable/disable the requested SSL version(s) */
- if(nss_init_sslver(&sslver, data) != CURLE_OK)
- goto error;
- if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
- goto error;
-
- ssl_cbc_random_iv = !data->set.ssl_enable_beast;
-#ifdef SSL_CBC_RANDOM_IV
- /* unless the user explicitly asks to allow the protocol vulnerability, we
- use the work-around */
- if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
- infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
- ssl_cbc_random_iv);
-#else
- if(ssl_cbc_random_iv)
- infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
-#endif
-
- if(data->set.ssl.cipher_list) {
- if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
- result = CURLE_SSL_CIPHER;
- goto error;
- }
- }
-
- if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost)
- infof(data, "warning: ignoring value of ssl.verifyhost\n");
-
- /* bypass the default SSL_AuthCertificate() hook in case we do not want to
- * verify peer */
- if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
- goto error;
-
- data->set.ssl.certverifyresult=0; /* not checked yet */
- if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
- goto error;
-
- if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
- goto error;
-
- if(data->set.ssl.verifypeer) {
- const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
- if(rv) {
- result = rv;
- goto error;
- }
- }
-
- if(data->set.ssl.CRLfile) {
- const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile);
- if(rv) {
- result = rv;
- goto error;
- }
- infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile);
- }
-
- if(data->set.str[STRING_CERT]) {
- char *nickname = dup_nickname(data, STRING_CERT);
- if(nickname) {
- /* we are not going to use libnsspem.so to read the client cert */
- connssl->obj_clicert = NULL;
- }
- else {
- CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
- data->set.str[STRING_KEY]);
- if(rv) {
- /* failf() is already done in cert_stuff() */
- result = rv;
- goto error;
- }
- }
-
- /* store the nickname for SelectClientCert() called during handshake */
- connssl->client_nickname = nickname;
- }
- else
- connssl->client_nickname = NULL;
-
- if(SSL_GetClientAuthDataHook(model, SelectClientCert,
- (void *)connssl) != SECSuccess) {
- result = CURLE_SSL_CERTPROBLEM;
- goto error;
- }
-
- /* wrap OS file descriptor by NSPR's file descriptor abstraction */
- nspr_io = PR_ImportTCPSocket(sockfd);
- if(!nspr_io)
- goto error;
-
- /* create our own NSPR I/O layer */
- nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
- if(!nspr_io_stub) {
- PR_Close(nspr_io);
- goto error;
- }
-
- /* make the per-connection data accessible from NSPR I/O callbacks */
- nspr_io_stub->secret = (void *)connssl;
-
- /* push our new layer to the NSPR I/O stack */
- if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
- PR_Close(nspr_io);
- PR_Close(nspr_io_stub);
- goto error;
- }
-
- /* import our model socket onto the current I/O stack */
- connssl->handle = SSL_ImportFD(model, nspr_io);
- if(!connssl->handle) {
- PR_Close(nspr_io);
- goto error;
- }
-
- PR_Close(model); /* We don't need this any more */
- model = NULL;
-
- /* This is the password associated with the cert that we're using */
- if(data->set.str[STRING_KEY_PASSWD]) {
- SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
- }
-
-#ifdef SSL_ENABLE_OCSP_STAPLING
- if(data->set.ssl.verifystatus) {
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
- != SECSuccess)
- goto error;
- }
-#endif
-
-#ifdef SSL_ENABLE_NPN
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn
- ? PR_TRUE : PR_FALSE) != SECSuccess)
- goto error;
-#endif
-
-#ifdef SSL_ENABLE_ALPN
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_enable_alpn
- ? PR_TRUE : PR_FALSE) != SECSuccess)
- goto error;
-#endif
-
-#ifdef SSL_ENABLE_FALSE_START
- if(data->set.ssl.falsestart) {
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
- != SECSuccess)
- goto error;
-
- if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback,
- conn) != SECSuccess)
- goto error;
- }
-#endif
-
-#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
- if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) {
- int cur = 0;
- unsigned char protocols[128];
-
-#ifdef USE_NGHTTP2
- if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
- protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
- memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN);
- cur += NGHTTP2_PROTO_VERSION_ID_LEN;
- }
-#endif
- protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
- memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
- cur += ALPN_HTTP_1_1_LENGTH;
-
- if(SSL_SetNextProtoNego(connssl->handle, protocols, cur) != SECSuccess)
- goto error;
- }
-#endif
-
-
- /* Force handshake on next I/O */
- SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
-
- SSL_SetURL(connssl->handle, conn->host.name);
-
- return CURLE_OK;
-
-error:
- if(model)
- PR_Close(model);
-
- return nss_fail_connect(connssl, data, result);
-}
-
-static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- CURLcode result = CURLE_SSL_CONNECT_ERROR;
- PRUint32 timeout;
-
- /* check timeout situation */
- const long time_left = Curl_timeleft(data, NULL, TRUE);
- if(time_left < 0L) {
- failf(data, "timed out before SSL handshake");
- result = CURLE_OPERATION_TIMEDOUT;
- goto error;
- }
-
- /* Force the handshake now */
- timeout = PR_MillisecondsToInterval((PRUint32) time_left);
- if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
- if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
- /* blocking direction is updated by nss_update_connecting_state() */
- return CURLE_AGAIN;
- else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
- result = CURLE_PEER_FAILED_VERIFICATION;
- else if(conn->data->set.ssl.certverifyresult!=0)
- result = CURLE_SSL_CACERT;
- goto error;
- }
-
- result = display_conn_info(conn, connssl->handle);
- if(result)
- goto error;
-
- if(data->set.str[STRING_SSL_ISSUERCERT]) {
- SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT);
- if(nickname) {
- /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
- ret = check_issuer_cert(connssl->handle, nickname);
- free(nickname);
- }
-
- if(SECFailure == ret) {
- infof(data, "SSL certificate issuer check failed\n");
- result = CURLE_SSL_ISSUER_ERROR;
- goto error;
- }
- else {
- infof(data, "SSL certificate issuer check ok\n");
- }
- }
-
- return CURLE_OK;
-
-error:
- return nss_fail_connect(connssl, data, result);
-}
-
-static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
- bool *done)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- const bool blocking = (done == NULL);
- CURLcode result;
-
- if(connssl->state == ssl_connection_complete)
- return CURLE_OK;
-
- if(connssl->connecting_state == ssl_connect_1) {
- result = nss_setup_connect(conn, sockindex);
- if(result)
- /* we do not expect CURLE_AGAIN from nss_setup_connect() */
- return result;
-
- if(!blocking) {
- /* in non-blocking mode, set NSS non-blocking mode before handshake */
- result = nss_set_nonblock(connssl, data);
- if(result)
- return result;
- }
-
- connssl->connecting_state = ssl_connect_2;
- }
-
- result = nss_do_connect(conn, sockindex);
- switch(result) {
- case CURLE_OK:
- break;
- case CURLE_AGAIN:
- if(!blocking)
- /* CURLE_AGAIN in non-blocking mode is not an error */
- return CURLE_OK;
- /* fall through */
- default:
- return result;
- }
-
- if(blocking) {
- /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
- result = nss_set_nonblock(connssl, data);
- if(result)
- return result;
- }
- else
- /* signal completed SSL handshake */
- *done = TRUE;
-
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = nss_recv;
- conn->send[sockindex] = nss_send;
-
- /* ssl_connect_done is never used outside, go back to the initial state */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-CURL_STATIC CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
-{
- return nss_connect_common(conn, sockindex, /* blocking */ NULL);
-}
-
-CURL_STATIC CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
- int sockindex, bool *done)
-{
- return nss_connect_common(conn, sockindex, done);
-}
-
-static ssize_t nss_send(struct connectdata *conn, /* connection data */
- int sockindex, /* socketindex */
- const void *mem, /* send this data */
- size_t len, /* amount to write */
- CURLcode *curlcode)
-{
- ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0,
- PR_INTERVAL_NO_WAIT);
- if(rc < 0) {
- PRInt32 err = PR_GetError();
- if(err == PR_WOULD_BLOCK_ERROR)
- *curlcode = CURLE_AGAIN;
- else {
- /* print the error number and error string */
- const char *err_name = nss_error_to_name(err);
- infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
-
- /* print a human-readable message describing the error if available */
- nss_print_error_message(conn->data, err);
-
- *curlcode = (is_cc_error(err))
- ? CURLE_SSL_CERTPROBLEM
- : CURLE_SEND_ERROR;
- }
-
- return -1;
- }
-
- return rc; /* number of bytes */
-}
-
-static ssize_t nss_recv(struct connectdata * conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- CURLcode *curlcode)
-{
- ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0,
- PR_INTERVAL_NO_WAIT);
- if(nread < 0) {
- /* failed SSL read */
- PRInt32 err = PR_GetError();
-
- if(err == PR_WOULD_BLOCK_ERROR)
- *curlcode = CURLE_AGAIN;
- else {
- /* print the error number and error string */
- const char *err_name = nss_error_to_name(err);
- infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
-
- /* print a human-readable message describing the error if available */
- nss_print_error_message(conn->data, err);
-
- *curlcode = (is_cc_error(err))
- ? CURLE_SSL_CERTPROBLEM
- : CURLE_RECV_ERROR;
- }
-
- return -1;
- }
-
- return nread;
-}
-
-CURL_STATIC size_t Curl_nss_version(char *buffer, size_t size)
-{
- return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
-}
-
-/* data might be NULL */
-CURL_STATIC int Curl_nss_seed(struct SessionHandle *data)
-{
- /* make sure that NSS is initialized */
- return !!Curl_nss_force_init(data);
-}
-
-/* data might be NULL */
-CURL_STATIC int Curl_nss_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length)
-{
- Curl_nss_seed(data); /* Initiate the seed if not already done */
-
- if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
- /* signal a failure */
- return -1;
-
- return 0;
-}
-
-CURL_STATIC void Curl_nss_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
-{
- PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
- unsigned int MD5out;
-
- PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
- PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
- PK11_DestroyContext(MD5pw, PR_TRUE);
-}
-
-CURL_STATIC bool Curl_nss_cert_status_request(void)
-{
-#ifdef SSL_ENABLE_OCSP_STAPLING
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-CURL_STATIC bool Curl_nss_false_start(void) {
-#ifdef SSL_ENABLE_FALSE_START
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-
-#endif /* USE_NSS */
diff --git a/libcurl/src/lib/vtls/nssg.h b/libcurl/src/lib/vtls/nssg.h
deleted file mode 100644
index 7eba897..0000000
--- a/libcurl/src/lib/vtls/nssg.h
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef HEADER_CURL_NSSG_H
-#define HEADER_CURL_NSSG_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#ifdef USE_NSS
-/*
- * This header should only be needed to get included by vtls.c and nss.c
- */
-
-#include "urldata.h"
-
-CURL_STATIC CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-/* close a SSL connection */
-CURL_STATIC void Curl_nss_close(struct connectdata *conn, int sockindex);
-
-CURL_STATIC int Curl_nss_init(void);
-CURL_STATIC void Curl_nss_cleanup(void);
-
-CURL_STATIC size_t Curl_nss_version(char *buffer, size_t size);
-CURL_STATIC int Curl_nss_check_cxn(struct connectdata *cxn);
-CURL_STATIC int Curl_nss_seed(struct SessionHandle *data);
-
-/* initialize NSS library if not already */
-CURL_STATIC CURLcode Curl_nss_force_init(struct SessionHandle *data);
-
-CURL_STATIC int Curl_nss_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length);
-
-CURL_STATIC void Curl_nss_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-
-CURL_STATIC bool Curl_nss_cert_status_request(void);
-
-CURL_STATIC bool Curl_nss_false_start(void);
-
-/* Set the API backend definition to NSS */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_NSS
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* API setup for NSS */
-#define curlssl_init Curl_nss_init
-#define curlssl_cleanup Curl_nss_cleanup
-#define curlssl_connect Curl_nss_connect
-#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking
-
-/* NSS has its own session ID cache */
-#define curlssl_session_free(x) Curl_nop_stmt
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_nss_close
-/* NSS has no shutdown function provided and thus always fail */
-#define curlssl_shutdown(x,y) ((void)x, (void)y, 1)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_nss_version
-#define curlssl_check_cxn(x) Curl_nss_check_cxn(x)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
-#define curlssl_random(x,y,z) Curl_nss_random(x,y,z)
-#define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d)
-#define curlssl_cert_status_request() Curl_nss_cert_status_request()
-#define curlssl_false_start() Curl_nss_false_start()
-
-#endif /* USE_NSS */
-#endif /* HEADER_CURL_NSSG_H */
diff --git a/libcurl/src/lib/vtls/openssl.c b/libcurl/src/lib/vtls/openssl.c
deleted file mode 100644
index a5e6b98..0000000
--- a/libcurl/src/lib/vtls/openssl.c
+++ /dev/null
@@ -1,3226 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- */
-
-/*
- * The original SSLeay-using code for curl was written by Linas Vepstas and
- * Sampo Kellomaki 1998.
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_OPENSSL
-
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include "../urldata.h"
-#include "../sendf.h"
-#include "../formdata.h" /* for the boundary function */
-#include "../url.h" /* for the ssl config check function */
-#include "../inet_pton.h"
-#include "openssl.h"
-#include "../connect.h"
-#include "../slist.h"
-#include "../strequal.h"
-#include "../select.h"
-#include "vtls.h"
-#include "../rawstr.h"
-#include "../hostcheck.h"
-#include "../curl_printf.h"
-
-#include <openssl/ssl.h>
-#include <openssl/rand.h>
-#include <openssl/x509v3.h>
-#include <openssl/dsa.h>
-#include <openssl/dh.h>
-#include <openssl/err.h>
-#include <openssl/md5.h>
-#include <openssl/conf.h>
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-
-#ifdef HAVE_OPENSSL_PKCS12_H
-#include <openssl/pkcs12.h>
-#endif
-
-#ifndef HAVE_BORINGSSL
-#include <openssl/ocsp.h>
-#endif
-
-#include "warnless.h"
-#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#ifndef OPENSSL_VERSION_NUMBER
-#error "OPENSSL_VERSION_NUMBER not defined"
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
-#define HAVE_SSL_GET1_SESSION 1
-#else
-#undef HAVE_SSL_GET1_SESSION
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00904100L
-#define HAVE_USERDATA_IN_PWD_CALLBACK 1
-#else
-#undef HAVE_USERDATA_IN_PWD_CALLBACK
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00907001L && !defined(OPENSSL_IS_BORINGSSL)
-/* ENGINE_load_private_key() takes four arguments */
-#define HAVE_ENGINE_LOAD_FOUR_ARGS
-#include <openssl/ui.h>
-#else
-/* ENGINE_load_private_key() takes three arguments */
-#undef HAVE_ENGINE_LOAD_FOUR_ARGS
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && \
- defined(HAVE_OPENSSL_PKCS12_H) && \
- !defined(OPENSSL_IS_BORINGSSL)
-/* OpenSSL has PKCS 12 support, BoringSSL does not */
-#define HAVE_PKCS12_SUPPORT
-#else
-/* OpenSSL does not have PKCS12 support */
-#undef HAVE_PKCS12_SUPPORT
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00906001L
-#define HAVE_ERR_ERROR_STRING_N 1
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
-#define SSL_METHOD_QUAL const
-#else
-#define SSL_METHOD_QUAL
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-/* 0.9.6 didn't have X509_STORE_set_flags() */
-#define HAVE_X509_STORE_SET_FLAGS 1
-#else
-#define X509_STORE_set_flags(x,y) Curl_nop_stmt
-#endif
-
-#ifdef OPENSSL_IS_BORINGSSL
-/* BoringSSL has no ERR_remove_state() */
-#define ERR_remove_state(x)
-#elif (OPENSSL_VERSION_NUMBER >= 0x10000000L)
-#define HAVE_ERR_REMOVE_THREAD_STATE 1
-#endif
-
-#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \
- OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */
-#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */
-#define OPENSSL_NO_SSL2
-#endif
-
-#if defined(OPENSSL_IS_BORINGSSL)
-#define NO_RAND_SEED 1
-/* In BoringSSL OpenSSL_add_all_algorithms does nothing */
-#define OpenSSL_add_all_algorithms()
-/* BoringSSL does not have CONF_modules_load_file */
-#define CONF_modules_load_file(a,b,c)
-#endif
-
-/*
- * Number of bytes to read from the random number seed file. This must be
- * a finite value (because some entropy "files" like /dev/urandom have
- * an infinite length), but must be large enough to provide enough
- * entopy to properly seed OpenSSL's PRNG.
- */
-#define RAND_LOAD_LENGTH 1024
-
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
-static char global_passwd[64];
-#endif
-
-static int passwd_callback(char *buf, int num, int encrypting
-#ifdef HAVE_USERDATA_IN_PWD_CALLBACK
- /* This was introduced in 0.9.4, we can set this
- using SSL_CTX_set_default_passwd_cb_userdata()
- */
- , void *global_passwd
-#endif
- )
-{
- DEBUGASSERT(0 == encrypting);
-
- if(!encrypting) {
- int klen = curlx_uztosi(strlen((char *)global_passwd));
- if(num > klen) {
- memcpy(buf, global_passwd, klen+1);
- return klen;
- }
- }
- return 0;
-}
-
-/*
- * rand_enough() is a function that returns TRUE if we have seeded the random
- * engine properly. We use some preprocessor magic to provide a seed_enough()
- * macro to use, just to prevent a compiler warning on this function if we
- * pass in an argument that is never used.
- */
-
-#ifndef NO_RAND_SEED
-#ifdef HAVE_RAND_STATUS
-#define seed_enough(x) rand_enough()
-static bool rand_enough(void)
-{
- return (0 != RAND_status()) ? TRUE : FALSE;
-}
-#else
-#define seed_enough(x) rand_enough(x)
-static bool rand_enough(int nread)
-{
- /* this is a very silly decision to make */
- return (nread > 500) ? TRUE : FALSE;
-}
-#endif
-
-static int ossl_seed(struct SessionHandle *data)
-{
- char *buf = data->state.buffer; /* point to the big buffer */
- int nread=0;
-
- /* Q: should we add support for a random file name as a libcurl option?
- A: Yes, it is here */
-
-#ifndef RANDOM_FILE
- /* if RANDOM_FILE isn't defined, we only perform this if an option tells
- us to! */
- if(data->set.ssl.random_file)
-#define RANDOM_FILE "" /* doesn't matter won't be used */
-#endif
- {
- /* let the option override the define */
- nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
- data->set.str[STRING_SSL_RANDOM_FILE]:
- RANDOM_FILE),
- RAND_LOAD_LENGTH);
- if(seed_enough(nread))
- return nread;
- }
-
-#if defined(HAVE_RAND_EGD)
- /* only available in OpenSSL 0.9.5 and later */
- /* EGD_SOCKET is set at configure time or not at all */
-#ifndef EGD_SOCKET
- /* If we don't have the define set, we only do this if the egd-option
- is set */
- if(data->set.str[STRING_SSL_EGDSOCKET])
-#define EGD_SOCKET "" /* doesn't matter won't be used */
-#endif
- {
- /* If there's an option and a define, the option overrides the
- define */
- int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]?
- data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
- if(-1 != ret) {
- nread += ret;
- if(seed_enough(nread))
- return nread;
- }
- }
-#endif
-
- /* If we get here, it means we need to seed the PRNG using a "silly"
- approach! */
- do {
- unsigned char randb[64];
- int len = sizeof(randb);
- RAND_bytes(randb, len);
- RAND_add(randb, len, (len >> 1));
- } while(!RAND_status());
-
- /* generates a default path for the random seed file */
- buf[0]=0; /* blank it first */
- RAND_file_name(buf, BUFSIZE);
- if(buf[0]) {
- /* we got a file name to try */
- nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
- if(seed_enough(nread))
- return nread;
- }
-
- infof(data, "libcurl is now using a weak random seed!\n");
- return nread;
-}
-
-static void Curl_ossl_seed(struct SessionHandle *data)
-{
- /* we have the "SSL is seeded" boolean static to prevent multiple
- time-consuming seedings in vain */
- static bool ssl_seeded = FALSE;
-
- if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
- data->set.str[STRING_SSL_EGDSOCKET]) {
- ossl_seed(data);
- ssl_seeded = TRUE;
- }
-}
-#else
-/* BoringSSL needs no seeding */
-#define Curl_ossl_seed(x)
-#endif
-
-
-#ifndef SSL_FILETYPE_ENGINE
-#define SSL_FILETYPE_ENGINE 42
-#endif
-#ifndef SSL_FILETYPE_PKCS12
-#define SSL_FILETYPE_PKCS12 43
-#endif
-static int do_file_type(const char *type)
-{
- if(!type || !type[0])
- return SSL_FILETYPE_PEM;
- if(Curl_raw_equal(type, "PEM"))
- return SSL_FILETYPE_PEM;
- if(Curl_raw_equal(type, "DER"))
- return SSL_FILETYPE_ASN1;
- if(Curl_raw_equal(type, "ENG"))
- return SSL_FILETYPE_ENGINE;
- if(Curl_raw_equal(type, "P12"))
- return SSL_FILETYPE_PKCS12;
- return -1;
-}
-
-#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS)
-/*
- * Supply default password to the engine user interface conversation.
- * The password is passed by OpenSSL engine from ENGINE_load_private_key()
- * last argument to the ui and can be obtained by UI_get0_user_data(ui) here.
- */
-static int ssl_ui_reader(UI *ui, UI_STRING *uis)
-{
- const char *password;
- switch(UI_get_string_type(uis)) {
- case UIT_PROMPT:
- case UIT_VERIFY:
- password = (const char*)UI_get0_user_data(ui);
- if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
- UI_set_result(ui, uis, password);
- return 1;
- }
- default:
- break;
- }
- return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
-}
-
-/*
- * Suppress interactive request for a default password if available.
- */
-static int ssl_ui_writer(UI *ui, UI_STRING *uis)
-{
- switch(UI_get_string_type(uis)) {
- case UIT_PROMPT:
- case UIT_VERIFY:
- if(UI_get0_user_data(ui) &&
- (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
- return 1;
- }
- default:
- break;
- }
- return (UI_method_get_writer(UI_OpenSSL()))(ui, uis);
-}
-#endif
-
-static
-int cert_stuff(struct connectdata *conn,
- SSL_CTX* ctx,
- char *cert_file,
- const char *cert_type,
- char *key_file,
- const char *key_type)
-{
- struct SessionHandle *data = conn->data;
-
- int file_type = do_file_type(cert_type);
-
- if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
- SSL *ssl;
- X509 *x509;
- int cert_done = 0;
-
- if(data->set.str[STRING_KEY_PASSWD]) {
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
- /*
- * If password has been given, we store that in the global
- * area (*shudder*) for a while:
- */
- size_t len = strlen(data->set.str[STRING_KEY_PASSWD]);
- if(len < sizeof(global_passwd))
- memcpy(global_passwd, data->set.str[STRING_KEY_PASSWD], len+1);
- else
- global_passwd[0] = '\0';
-#else
- /*
- * We set the password in the callback userdata
- */
- SSL_CTX_set_default_passwd_cb_userdata(ctx,
- data->set.str[STRING_KEY_PASSWD]);
-#endif
- /* Set passwd callback: */
- SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
- }
-
-
- switch(file_type) {
- case SSL_FILETYPE_PEM:
- /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
- if(SSL_CTX_use_certificate_chain_file(ctx,
- cert_file) != 1) {
- failf(data,
- "could not load PEM client certificate, OpenSSL error %s, "
- "(no key found, wrong pass phrase, or wrong file format?)",
- ERR_error_string(ERR_get_error(), NULL) );
- return 0;
- }
- break;
-
- case SSL_FILETYPE_ASN1:
- /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
- we use the case above for PEM so this can only be performed with
- ASN1 files. */
- if(SSL_CTX_use_certificate_file(ctx,
- cert_file,
- file_type) != 1) {
- failf(data,
- "could not load ASN1 client certificate, OpenSSL error %s, "
- "(no key found, wrong pass phrase, or wrong file format?)",
- ERR_error_string(ERR_get_error(), NULL) );
- return 0;
- }
- break;
- case SSL_FILETYPE_ENGINE:
-#if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
- {
- if(data->state.engine) {
- const char *cmd_name = "LOAD_CERT_CTRL";
- struct {
- const char *cert_id;
- X509 *cert;
- } params;
-
- params.cert_id = cert_file;
- params.cert = NULL;
-
- /* Does the engine supports LOAD_CERT_CTRL ? */
- if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
- 0, (void *)cmd_name, NULL)) {
- failf(data, "ssl engine does not support loading certificates");
- return 0;
- }
-
- /* Load the certificate from the engine */
- if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
- 0, &params, NULL, 1)) {
- failf(data, "ssl engine cannot load client cert with id"
- " '%s' [%s]", cert_file,
- ERR_error_string(ERR_get_error(), NULL));
- return 0;
- }
-
- if(!params.cert) {
- failf(data, "ssl engine didn't initialized the certificate "
- "properly.");
- return 0;
- }
-
- if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
- failf(data, "unable to set client certificate");
- X509_free(params.cert);
- return 0;
- }
- X509_free(params.cert); /* we don't need the handle any more... */
- }
- else {
- failf(data, "crypto engine not set, can't load certificate");
- return 0;
- }
- }
- break;
-#else
- failf(data, "file type ENG for certificate not implemented");
- return 0;
-#endif
-
- case SSL_FILETYPE_PKCS12:
- {
-#ifdef HAVE_PKCS12_SUPPORT
- FILE *f;
- PKCS12 *p12;
- EVP_PKEY *pri;
- STACK_OF(X509) *ca = NULL;
- int i;
-
- f = fopen(cert_file, "rb");
- if(!f) {
- failf(data, "could not open PKCS12 file '%s'", cert_file);
- return 0;
- }
- p12 = d2i_PKCS12_fp(f, NULL);
- fclose(f);
-
- if(!p12) {
- failf(data, "error reading PKCS12 file '%s'", cert_file);
- return 0;
- }
-
- PKCS12_PBE_add();
-
- if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
- &ca)) {
- failf(data,
- "could not parse PKCS12 file, check password, OpenSSL error %s",
- ERR_error_string(ERR_get_error(), NULL) );
- PKCS12_free(p12);
- return 0;
- }
-
- PKCS12_free(p12);
-
- if(SSL_CTX_use_certificate(ctx, x509) != 1) {
- failf(data,
- "could not load PKCS12 client certificate, OpenSSL error %s",
- ERR_error_string(ERR_get_error(), NULL) );
- goto fail;
- }
-
- if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
- failf(data, "unable to use private key from PKCS12 file '%s'",
- cert_file);
- goto fail;
- }
-
- if(!SSL_CTX_check_private_key (ctx)) {
- failf(data, "private key from PKCS12 file '%s' "
- "does not match certificate in same file", cert_file);
- goto fail;
- }
- /* Set Certificate Verification chain */
- if(ca && sk_X509_num(ca)) {
- for(i = 0; i < sk_X509_num(ca); i++) {
- /*
- * Note that sk_X509_pop() is used below to make sure the cert is
- * removed from the stack properly before getting passed to
- * SSL_CTX_add_extra_chain_cert(). Previously we used
- * sk_X509_value() instead, but then we'd clean it in the subsequent
- * sk_X509_pop_free() call.
- */
- X509 *x = sk_X509_pop(ca);
- if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
- failf(data, "cannot add certificate to certificate chain");
- goto fail;
- }
- /* SSL_CTX_add_client_CA() seems to work with either sk_* function,
- * presumably because it duplicates what we pass to it.
- */
- if(!SSL_CTX_add_client_CA(ctx, x)) {
- failf(data, "cannot add certificate to client CA list");
- goto fail;
- }
- }
- }
-
- cert_done = 1;
- fail:
- EVP_PKEY_free(pri);
- X509_free(x509);
- sk_X509_pop_free(ca, X509_free);
-
- if(!cert_done)
- return 0; /* failure! */
- break;
-#else
- failf(data, "file type P12 for certificate not supported");
- return 0;
-#endif
- }
- default:
- failf(data, "not supported file type '%s' for certificate", cert_type);
- return 0;
- }
-
- file_type = do_file_type(key_type);
-
- switch(file_type) {
- case SSL_FILETYPE_PEM:
- if(cert_done)
- break;
- if(!key_file)
- /* cert & key can only be in PEM case in the same file */
- key_file=cert_file;
- case SSL_FILETYPE_ASN1:
- if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
- failf(data, "unable to set private key file: '%s' type %s",
- key_file, key_type?key_type:"PEM");
- return 0;
- }
- break;
- case SSL_FILETYPE_ENGINE:
-#ifdef HAVE_OPENSSL_ENGINE_H
- { /* XXXX still needs some work */
- EVP_PKEY *priv_key = NULL;
- if(data->state.engine) {
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
- UI_METHOD *ui_method =
- UI_create_method((char *)"cURL user interface");
- if(!ui_method) {
- failf(data, "unable do create OpenSSL user-interface method");
- return 0;
- }
- UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
- UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
- UI_method_set_reader(ui_method, ssl_ui_reader);
- UI_method_set_writer(ui_method, ssl_ui_writer);
-#endif
- /* the typecast below was added to please mingw32 */
- priv_key = (EVP_PKEY *)
- ENGINE_load_private_key(data->state.engine, key_file,
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
- ui_method,
-#endif
- data->set.str[STRING_KEY_PASSWD]);
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
- UI_destroy_method(ui_method);
-#endif
- if(!priv_key) {
- failf(data, "failed to load private key from crypto engine");
- return 0;
- }
- if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
- failf(data, "unable to set private key");
- EVP_PKEY_free(priv_key);
- return 0;
- }
- EVP_PKEY_free(priv_key); /* we don't need the handle any more... */
- }
- else {
- failf(data, "crypto engine not set, can't load private key");
- return 0;
- }
- }
- break;
-#else
- failf(data, "file type ENG for private key not supported");
- return 0;
-#endif
- case SSL_FILETYPE_PKCS12:
- if(!cert_done) {
- failf(data, "file type P12 for private key not supported");
- return 0;
- }
- break;
- default:
- failf(data, "not supported file type for private key");
- return 0;
- }
-
- ssl=SSL_new(ctx);
- if(!ssl) {
- failf(data, "unable to create an SSL structure");
- return 0;
- }
-
- x509=SSL_get_certificate(ssl);
-
- /* This version was provided by Evan Jordan and is supposed to not
- leak memory as the previous version: */
- if(x509) {
- EVP_PKEY *pktmp = X509_get_pubkey(x509);
- EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
- EVP_PKEY_free(pktmp);
- }
-
- SSL_free(ssl);
-
- /* If we are using DSA, we can copy the parameters from
- * the private key */
-
-
- /* Now we know that a key and cert have been set against
- * the SSL context */
- if(!SSL_CTX_check_private_key(ctx)) {
- failf(data, "Private key does not match the certificate public key");
- return 0;
- }
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
- /* erase it now */
- memset(global_passwd, 0, sizeof(global_passwd));
-#endif
- }
- return 1;
-}
-
-/* returns non-zero on failure */
-static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
-{
-#if 0
- return X509_NAME_oneline(a, buf, size);
-#else
- BIO *bio_out = BIO_new(BIO_s_mem());
- BUF_MEM *biomem;
- int rc;
-
- if(!bio_out)
- return 1; /* alloc failed! */
-
- rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
- BIO_get_mem_ptr(bio_out, &biomem);
-
- if((size_t)biomem->length < size)
- size = biomem->length;
- else
- size--; /* don't overwrite the buffer end */
-
- memcpy(buf, biomem->data, size);
- buf[size]=0;
-
- BIO_free(bio_out);
-
- return !rc;
-#endif
-}
-
-static
-int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
-{
- X509 *err_cert;
- char buf[256];
-
- err_cert=X509_STORE_CTX_get_current_cert(ctx);
- (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
- return ok;
-}
-
-/* Return error string for last OpenSSL error
- */
-static char *SSL_strerror(unsigned long error, char *buf, size_t size)
-{
-#ifdef HAVE_ERR_ERROR_STRING_N
- /* OpenSSL 0.9.6 and later has a function named
- ERRO_error_string_n() that takes the size of the buffer as a
- third argument */
- ERR_error_string_n(error, buf, size);
-#else
- (void) size;
- ERR_error_string(error, buf);
-#endif
- return buf;
-}
-
-/**
- * Global SSL init
- *
- * @retval 0 error initializing SSL
- * @retval 1 SSL initialized successfully
- */
-CURL_STATIC int Curl_ossl_init(void)
-{
-#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
- ENGINE_load_builtin_engines();
-#endif
-
- /* Lets get nice error messages */
- SSL_load_error_strings();
-
- /* Init the global ciphers and digests */
- if(!SSLeay_add_ssl_algorithms())
- return 0;
-
- OpenSSL_add_all_algorithms();
-
-
- /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately
- that function makes an exit() call on wrongly formatted config files
- which makes it hard to use in some situations. OPENSSL_config() itself
- calls CONF_modules_load_file() and we use that instead and we ignore
- its return code! */
-
- /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and
- 0.9.8e */
-#ifndef CONF_MFLAGS_DEFAULT_SECTION
-#define CONF_MFLAGS_DEFAULT_SECTION 0x0
-#endif
-
- CONF_modules_load_file(NULL, NULL,
- CONF_MFLAGS_DEFAULT_SECTION|
- CONF_MFLAGS_IGNORE_MISSING_FILE);
-
- return 1;
-}
-
-/* Global cleanup */
-CURL_STATIC void Curl_ossl_cleanup(void)
-{
- /* Free ciphers and digests lists */
- EVP_cleanup();
-
-#ifdef HAVE_ENGINE_CLEANUP
- /* Free engine list */
- ENGINE_cleanup();
-#endif
-
-#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
- /* Free OpenSSL ex_data table */
- CRYPTO_cleanup_all_ex_data();
-#endif
-
- /* Free OpenSSL error strings */
- ERR_free_strings();
-
- /* Free thread local error state, destroying hash upon zero refcount */
-#ifdef HAVE_ERR_REMOVE_THREAD_STATE
- ERR_remove_thread_state(NULL);
-#else
- ERR_remove_state(0);
-#endif
-}
-
-/*
- * This function uses SSL_peek to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-CURL_STATIC int Curl_ossl_check_cxn(struct connectdata *conn)
-{
- int rc;
- char buf;
-
- rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1);
- if(rc > 0)
- return 1; /* connection still in place */
-
- if(rc == 0)
- return 0; /* connection has been closed */
-
- return -1; /* connection status unknown */
-}
-
-/* Selects an OpenSSL crypto engine
- */
-CURL_STATIC CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
-{
-#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
- ENGINE *e;
-
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
- e = ENGINE_by_id(engine);
-#else
- /* avoid memory leak */
- for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
- const char *e_id = ENGINE_get_id(e);
- if(!strcmp(engine, e_id))
- break;
- }
-#endif
-
- if(!e) {
- failf(data, "SSL Engine '%s' not found", engine);
- return CURLE_SSL_ENGINE_NOTFOUND;
- }
-
- if(data->state.engine) {
- ENGINE_finish(data->state.engine);
- ENGINE_free(data->state.engine);
- data->state.engine = NULL;
- }
- if(!ENGINE_init(e)) {
- char buf[256];
-
- ENGINE_free(e);
- failf(data, "Failed to initialise SSL Engine '%s':\n%s",
- engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
- return CURLE_SSL_ENGINE_INITFAILED;
- }
- data->state.engine = e;
- return CURLE_OK;
-#else
- (void)engine;
- failf(data, "SSL Engine not supported");
- return CURLE_SSL_ENGINE_NOTFOUND;
-#endif
-}
-
-/* Sets engine as default for all SSL operations
- */
-CURL_STATIC CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
-{
-#ifdef HAVE_OPENSSL_ENGINE_H
- if(data->state.engine) {
- if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
- infof(data, "set default crypto engine '%s'\n",
- ENGINE_get_id(data->state.engine));
- }
- else {
- failf(data, "set default crypto engine '%s' failed",
- ENGINE_get_id(data->state.engine));
- return CURLE_SSL_ENGINE_SETFAILED;
- }
- }
-#else
- (void) data;
-#endif
- return CURLE_OK;
-}
-
-/* Return list of OpenSSL crypto engine names.
- */
-CURL_STATIC struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
-{
- struct curl_slist *list = NULL;
-#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
- struct curl_slist *beg;
- ENGINE *e;
-
- for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
- beg = curl_slist_append(list, ENGINE_get_id(e));
- if(!beg) {
- curl_slist_free_all(list);
- return NULL;
- }
- list = beg;
- }
-#endif
- (void) data;
- return list;
-}
-
-
-/*
- * This function is called when an SSL connection is closed.
- */
-CURL_STATIC void Curl_ossl_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->handle) {
- (void)SSL_shutdown(connssl->handle);
- SSL_set_connect_state(connssl->handle);
-
- SSL_free (connssl->handle);
- connssl->handle = NULL;
- }
- if(connssl->ctx) {
- SSL_CTX_free (connssl->ctx);
- connssl->ctx = NULL;
- }
-}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-CURL_STATIC int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
-{
- int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
- to be at least 120 bytes long. */
- unsigned long sslerror;
- ssize_t nread;
- int buffsize;
- int err;
- int done = 0;
-
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(connssl->handle);
-
- if(connssl->handle) {
- buffsize = (int)sizeof(buf);
- while(!done) {
- int what = Curl_socket_ready(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- ERR_clear_error();
-
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server */
- nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
- buffsize);
- err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
-
- switch(err) {
- case SSL_ERROR_NONE: /* this is not an error */
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- /* This is the expected response. There was no data but only
- the close notify alert */
- done = 1;
- break;
- case SSL_ERROR_WANT_READ:
- /* there's data pending, re-invoke SSL_read() */
- infof(data, "SSL_ERROR_WANT_READ\n");
- break;
- case SSL_ERROR_WANT_WRITE:
- /* SSL wants a write. Really odd. Let's bail out. */
- infof(data, "SSL_ERROR_WANT_WRITE\n");
- done = 1;
- break;
- default:
- /* openssl/ssl.h says "look at error stack/return value/errno" */
- sslerror = ERR_get_error();
- failf(conn->data, "SSL read: %s, errno %d",
- ERR_error_string(sslerror, buf),
- SOCKERRNO);
- done = 1;
- break;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- done = 1;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- retval = -1;
- done = 1;
- }
- } /* while()-loop for the select() */
-
- if(data->set.verbose) {
-#ifdef HAVE_SSL_GET_SHUTDOWN
- switch(SSL_get_shutdown(connssl->handle)) {
- case SSL_SENT_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
- break;
- case SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
- break;
- case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
- "SSL_RECEIVED__SHUTDOWN\n");
- break;
- }
-#endif
- }
-
- SSL_free (connssl->handle);
- connssl->handle = NULL;
- }
- return retval;
-}
-
-CURL_STATIC void Curl_ossl_session_free(void *ptr)
-{
- /* free the ID */
- SSL_SESSION_free(ptr);
-}
-
-/*
- * This function is called when the 'data' struct is going away. Close
- * down everything and free all resources!
- */
-CURL_STATIC void Curl_ossl_close_all(struct SessionHandle *data)
-{
-#ifdef HAVE_OPENSSL_ENGINE_H
- if(data->state.engine) {
- ENGINE_finish(data->state.engine);
- ENGINE_free(data->state.engine);
- data->state.engine = NULL;
- }
-#else
- (void)data;
-#endif
-}
-
-static int asn1_output(const ASN1_UTCTIME *tm,
- char *buf,
- size_t sizeofbuf)
-{
- const char *asn1_string;
- int gmt=FALSE;
- int i;
- int year=0, month=0, day=0, hour=0, minute=0, second=0;
-
- i=tm->length;
- asn1_string=(const char *)tm->data;
-
- if(i < 10)
- return 1;
- if(asn1_string[i-1] == 'Z')
- gmt=TRUE;
- for(i=0; i<10; i++)
- if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
- return 2;
-
- year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
- if(year < 50)
- year+=100;
-
- month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
- if((month > 12) || (month < 1))
- return 3;
-
- day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
- hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
- minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
-
- if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
- (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
- second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
-
- snprintf(buf, sizeofbuf,
- "%04d-%02d-%02d %02d:%02d:%02d %s",
- year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
-
- return 0;
-}
-
-/* ====================================================== */
-
-
-/* Quote from RFC2818 section 3.1 "Server Identity"
-
- If a subjectAltName extension of type dNSName is present, that MUST
- be used as the identity. Otherwise, the (most specific) Common Name
- field in the Subject field of the certificate MUST be used. Although
- the use of the Common Name is existing practice, it is deprecated and
- Certification Authorities are encouraged to use the dNSName instead.
-
- Matching is performed using the matching rules specified by
- [RFC2459]. If more than one identity of a given type is present in
- the certificate (e.g., more than one dNSName name, a match in any one
- of the set is considered acceptable.) Names may contain the wildcard
- character * which is considered to match any single domain name
- component or component fragment. E.g., *.a.com matches foo.a.com but
- not bar.foo.a.com. f*.com matches foo.com but not bar.com.
-
- In some cases, the URI is specified as an IP address rather than a
- hostname. In this case, the iPAddress subjectAltName must be present
- in the certificate and must exactly match the IP in the URI.
-
-*/
-static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
-{
- int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
- means mismatch */
- int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
- size_t addrlen = 0;
- struct SessionHandle *data = conn->data;
- STACK_OF(GENERAL_NAME) *altnames;
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
- CURLcode result = CURLE_OK;
-
-#ifdef ENABLE_IPV6
- if(conn->bits.ipv6_ip &&
- Curl_inet_pton(AF_INET6, conn->host.name, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in6_addr);
- }
- else
-#endif
- if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in_addr);
- }
-
- /* get a "list" of alternative names */
- altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
-
- if(altnames) {
- int numalts;
- int i;
-
- /* get amount of alternatives, RFC2459 claims there MUST be at least
- one, but we don't depend on it... */
- numalts = sk_GENERAL_NAME_num(altnames);
-
- /* loop through all alternatives while none has matched */
- for(i=0; (i<numalts) && (matched != 1); i++) {
- /* get a handle to alternative name number i */
- const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
-
- /* only check alternatives of the same type the target is */
- if(check->type == target) {
- /* get data and length */
- const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
- size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
-
- switch(target) {
- case GEN_DNS: /* name/pattern comparison */
- /* The OpenSSL man page explicitly says: "In general it cannot be
- assumed that the data returned by ASN1_STRING_data() is null
- terminated or does not contain embedded nulls." But also that
- "The actual format of the data will depend on the actual string
- type itself: for example for and IA5String the data will be ASCII"
-
- Gisle researched the OpenSSL sources:
- "I checked the 0.9.6 and 0.9.8 sources before my patch and
- it always 0-terminates an IA5String."
- */
- if((altlen == strlen(altptr)) &&
- /* if this isn't true, there was an embedded zero in the name
- string and we cannot match it. */
- Curl_cert_hostcheck(altptr, conn->host.name))
- matched = 1;
- else
- matched = 0;
- break;
-
- case GEN_IPADD: /* IP address comparison */
- /* compare alternative IP address if the data chunk is the same size
- our server IP address is */
- if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
- matched = 1;
- else
- matched = 0;
- break;
- }
- }
- }
- GENERAL_NAMES_free(altnames);
- }
-
- if(matched == 1)
- /* an alternative name matched the server hostname */
- infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
- else if(matched == 0) {
- /* an alternative name field existed, but didn't match and then
- we MUST fail */
- infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
- failf(data, "SSL: no alternative certificate subject name matches "
- "target host name '%s'", conn->host.dispname);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- else {
- /* we have to look to the last occurrence of a commonName in the
- distinguished one to get the most significant one. */
- int j, i=-1;
-
-/* The following is done because of a bug in 0.9.6b */
-
- unsigned char *nulstr = (unsigned char *)"";
- unsigned char *peer_CN = nulstr;
-
- X509_NAME *name = X509_get_subject_name(server_cert);
- if(name)
- while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
- i=j;
-
- /* we have the name entry and we will now convert this to a string
- that we can use for comparison. Doing this we support BMPstring,
- UTF8 etc. */
-
- if(i>=0) {
- ASN1_STRING *tmp =
- X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
-
- /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
- is already UTF-8 encoded. We check for this case and copy the raw
- string manually to avoid the problem. This code can be made
- conditional in the future when OpenSSL has been fixed. Work-around
- brought by Alexis S. L. Carvalho. */
- if(tmp) {
- if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
- j = ASN1_STRING_length(tmp);
- if(j >= 0) {
- peer_CN = OPENSSL_malloc(j+1);
- if(peer_CN) {
- memcpy(peer_CN, ASN1_STRING_data(tmp), j);
- peer_CN[j] = '\0';
- }
- }
- }
- else /* not a UTF8 name */
- j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
-
- if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) {
- /* there was a terminating zero before the end of string, this
- cannot match and we return failure! */
- failf(data, "SSL: illegal cert name field");
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- }
- }
-
- if(peer_CN == nulstr)
- peer_CN = NULL;
- else {
- /* convert peer_CN from UTF8 */
- CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
- /* Curl_convert_from_utf8 calls failf if unsuccessful */
- if(rc) {
- OPENSSL_free(peer_CN);
- return rc;
- }
- }
-
- if(result)
- /* error already detected, pass through */
- ;
- else if(!peer_CN) {
- failf(data,
- "SSL: unable to obtain common name from peer certificate");
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
- failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", peer_CN, conn->host.dispname);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- else {
- infof(data, "\t common name: %s (matched)\n", peer_CN);
- }
- if(peer_CN)
- OPENSSL_free(peer_CN);
- }
-
- return result;
-}
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_IS_BORINGSSL)
-static CURLcode verifystatus(struct connectdata *conn,
- struct ssl_connect_data *connssl)
-{
- int i, ocsp_status;
- const unsigned char *p;
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
-
- OCSP_RESPONSE *rsp = NULL;
- OCSP_BASICRESP *br = NULL;
- X509_STORE *st = NULL;
- STACK_OF(X509) *ch = NULL;
-
- long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p);
-
- if(!p) {
- failf(data, "No OCSP response received");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
-
- rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
- if(!rsp) {
- failf(data, "Invalid OCSP response");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
-
- ocsp_status = OCSP_response_status(rsp);
- if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
- failf(data, "Invalid OCSP response status: %s (%d)",
- OCSP_response_status_str(ocsp_status), ocsp_status);
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
-
- br = OCSP_response_get1_basic(rsp);
- if(!br) {
- failf(data, "Invalid OCSP response");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
-
- ch = SSL_get_peer_cert_chain(connssl->handle);
- st = SSL_CTX_get_cert_store(connssl->ctx);
-
-#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
- defined(LIBRESSL_VERSION_NUMBER))
- /* The authorized responder cert in the OCSP response MUST be signed by the
- peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
- no problem, but if it's an intermediate cert OpenSSL has a bug where it
- expects this issuer to be present in the chain embedded in the OCSP
- response. So we add it if necessary. */
-
- /* First make sure the peer cert chain includes both a peer and an issuer,
- and the OCSP response contains a responder cert. */
- if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
- X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);
-
- /* Find issuer of responder cert and add it to the OCSP response chain */
- for(i = 0; i < sk_X509_num(ch); i++) {
- X509 *issuer = sk_X509_value(ch, i);
- if(X509_check_issued(issuer, responder) == X509_V_OK) {
- if(!OCSP_basic_add1_cert(br, issuer)) {
- failf(data, "Could not add issuer cert to OCSP response");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
- }
- }
- }
-#endif
-
- if(OCSP_basic_verify(br, ch, st, 0) <= 0) {
- failf(data, "OCSP response verification failed");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
-
- for(i = 0; i < OCSP_resp_count(br); i++) {
- int cert_status, crl_reason;
- OCSP_SINGLERESP *single = NULL;
-
- ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
-
- if(!(single = OCSP_resp_get0(br, i)))
- continue;
-
- cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
- &thisupd, &nextupd);
-
- if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
- failf(data, "OCSP response has expired");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
-
- infof(data, "SSL certificate status: %s (%d)\n",
- OCSP_cert_status_str(cert_status), cert_status);
-
- switch(cert_status) {
- case V_OCSP_CERTSTATUS_GOOD:
- break;
-
- case V_OCSP_CERTSTATUS_REVOKED:
- result = CURLE_SSL_INVALIDCERTSTATUS;
-
- failf(data, "SSL certificate revocation reason: %s (%d)",
- OCSP_crl_reason_str(crl_reason), crl_reason);
- goto end;
-
- case V_OCSP_CERTSTATUS_UNKNOWN:
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
- }
-
-end:
- if(br) OCSP_BASICRESP_free(br);
- OCSP_RESPONSE_free(rsp);
-
- return result;
-}
-#endif
-
-#endif /* USE_OPENSSL */
-
-/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
- and thus this cannot be done there. */
-#ifdef SSL_CTRL_SET_MSG_CALLBACK
-
-static const char *ssl_msg_type(int ssl_ver, int msg)
-{
-#ifdef SSL2_VERSION_MAJOR
- if(ssl_ver == SSL2_VERSION_MAJOR) {
- switch (msg) {
- case SSL2_MT_ERROR:
- return "Error";
- case SSL2_MT_CLIENT_HELLO:
- return "Client hello";
- case SSL2_MT_CLIENT_MASTER_KEY:
- return "Client key";
- case SSL2_MT_CLIENT_FINISHED:
- return "Client finished";
- case SSL2_MT_SERVER_HELLO:
- return "Server hello";
- case SSL2_MT_SERVER_VERIFY:
- return "Server verify";
- case SSL2_MT_SERVER_FINISHED:
- return "Server finished";
- case SSL2_MT_REQUEST_CERTIFICATE:
- return "Request CERT";
- case SSL2_MT_CLIENT_CERTIFICATE:
- return "Client CERT";
- }
- }
- else
-#endif
- if(ssl_ver == SSL3_VERSION_MAJOR) {
- switch (msg) {
- case SSL3_MT_HELLO_REQUEST:
- return "Hello request";
- case SSL3_MT_CLIENT_HELLO:
- return "Client hello";
- case SSL3_MT_SERVER_HELLO:
- return "Server hello";
- case SSL3_MT_CERTIFICATE:
- return "CERT";
- case SSL3_MT_SERVER_KEY_EXCHANGE:
- return "Server key exchange";
- case SSL3_MT_CLIENT_KEY_EXCHANGE:
- return "Client key exchange";
- case SSL3_MT_CERTIFICATE_REQUEST:
- return "Request CERT";
- case SSL3_MT_SERVER_DONE:
- return "Server finished";
- case SSL3_MT_CERTIFICATE_VERIFY:
- return "CERT verify";
- case SSL3_MT_FINISHED:
- return "Finished";
- }
- }
- return "Unknown";
-}
-
-static const char *tls_rt_type(int type)
-{
- return (
- type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
- type == SSL3_RT_ALERT ? "TLS alert, " :
- type == SSL3_RT_HANDSHAKE ? "TLS handshake, " :
- type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " :
- "TLS Unknown, ");
-}
-
-
-/*
- * Our callback from the SSL/TLS layers.
- */
-static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
- const void *buf, size_t len, const SSL *ssl,
- struct connectdata *conn)
-{
- struct SessionHandle *data;
- const char *msg_name, *tls_rt_name;
- char ssl_buf[1024];
- char unknown[32];
- int msg_type, txt_len;
- const char *verstr;
-
- if(!conn || !conn->data || !conn->data->set.fdebug ||
- (direction != 0 && direction != 1))
- return;
-
- data = conn->data;
-
- switch(ssl_ver) {
-#ifdef SSL2_VERSION_MAJOR /* removed in recent versions */
- case SSL2_VERSION_MAJOR:
- verstr = "SSLv2";
- break;
-#endif
-#ifdef SSL3_VERSION
- case SSL3_VERSION:
- verstr = "SSLv3";
- break;
-#endif
- case TLS1_VERSION:
- verstr = "TLSv1.0";
- break;
-#ifdef TLS1_1_VERSION
- case TLS1_1_VERSION:
- verstr = "TLSv1.1";
- break;
-#endif
-#ifdef TLS1_2_VERSION
- case TLS1_2_VERSION:
- verstr = "TLSv1.2";
- break;
-#endif
- default:
- snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver);
- verstr = unknown;
- break;
- }
-
- ssl_ver >>= 8; /* check the upper 8 bits only below */
-
- /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
- * always pass-up content-type as 0. But the interesting message-type
- * is at 'buf[0]'.
- */
- if(ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
- tls_rt_name = tls_rt_type(content_type);
- else
- tls_rt_name = "";
-
- msg_type = *(char*)buf;
- msg_name = ssl_msg_type(ssl_ver, msg_type);
-
- txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s, %s%s (%d):\n",
- verstr, tls_rt_name, msg_name, msg_type);
- Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
-
- Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
- CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
- (void) ssl;
-}
-#endif
-
-#ifdef USE_OPENSSL
-/* ====================================================== */
-
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-# define use_sni(x) sni = (x)
-#else
-# define use_sni(x) Curl_nop_stmt
-#endif
-
-/* Check for OpenSSL 1.0.2 which has ALPN support. */
-#undef HAS_ALPN
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
- && !defined(OPENSSL_NO_TLSEXT)
-# define HAS_ALPN 1
-#endif
-
-/* Check for OpenSSL 1.0.1 which has NPN support. */
-#undef HAS_NPN
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L \
- && !defined(OPENSSL_NO_TLSEXT) \
- && !defined(OPENSSL_NO_NEXTPROTONEG)
-# define HAS_NPN 1
-#endif
-
-#ifdef HAS_NPN
-
-/*
- * in is a list of lenght prefixed strings. this function has to select
- * the protocol we want to use from the list and write its string into out.
- */
-
-static int
-select_next_protocol(unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen,
- const char *key, unsigned int keylen)
-{
- unsigned int i;
- for(i = 0; i + keylen <= inlen; i += in[i] + 1) {
- if(memcmp(&in[i + 1], key, keylen) == 0) {
- *out = (unsigned char *) &in[i + 1];
- *outlen = in[i];
- return 0;
- }
- }
- return -1;
-}
-
-static int
-select_next_proto_cb(SSL *ssl,
- unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen,
- void *arg)
-{
- struct connectdata *conn = (struct connectdata*) arg;
-
- (void)ssl;
-
-#ifdef USE_NGHTTP2
- if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 &&
- !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
- infof(conn->data, "NPN, negotiated HTTP2 (%s)\n",
- NGHTTP2_PROTO_VERSION_ID);
- conn->negnpn = CURL_HTTP_VERSION_2_0;
- return SSL_TLSEXT_ERR_OK;
- }
-#endif
-
- if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1,
- ALPN_HTTP_1_1_LENGTH)) {
- infof(conn->data, "NPN, negotiated HTTP1.1\n");
- conn->negnpn = CURL_HTTP_VERSION_1_1;
- return SSL_TLSEXT_ERR_OK;
- }
-
- infof(conn->data, "NPN, no overlap, use HTTP1.1\n");
- *out = (unsigned char *)ALPN_HTTP_1_1;
- *outlen = ALPN_HTTP_1_1_LENGTH;
- conn->negnpn = CURL_HTTP_VERSION_1_1;
-
- return SSL_TLSEXT_ERR_OK;
-}
-#endif /* HAS_NPN */
-
-static const char *
-get_ssl_version_txt(SSL *ssl)
-{
- if(!ssl)
- return "";
-
- switch(SSL_version(ssl)) {
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- case TLS1_2_VERSION:
- return "TLSv1.2";
- case TLS1_1_VERSION:
- return "TLSv1.1";
-#endif
- case TLS1_VERSION:
- return "TLSv1.0";
- case SSL3_VERSION:
- return "SSLv3";
- case SSL2_VERSION:
- return "SSLv2";
- }
- return "unknown";
-}
-
-static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
-{
- CURLcode result = CURLE_OK;
- char *ciphers;
- struct SessionHandle *data = conn->data;
- SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
- void *ssl_sessionid = NULL;
- X509_LOOKUP *lookup = NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- long ctx_options;
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- bool sni;
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
-#endif
-
- DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
-
- /* Make funny stuff to get random input */
- Curl_ossl_seed(data);
-
- data->set.ssl.certverifyresult = !X509_V_OK;
-
- /* check to see if we've been told to use an explicit SSL/TLS version */
-
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- /* it will be handled later with the context options */
- req_method = SSLv23_client_method();
- use_sni(TRUE);
- break;
- case CURL_SSLVERSION_SSLv2:
-#ifdef OPENSSL_NO_SSL2
- failf(data, "OpenSSL was built without SSLv2 support");
- return CURLE_NOT_BUILT_IN;
-#else
-#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
- return CURLE_SSL_CONNECT_ERROR;
-#endif
- req_method = SSLv2_client_method();
- use_sni(FALSE);
- break;
-#endif
- case CURL_SSLVERSION_SSLv3:
-#ifdef OPENSSL_NO_SSL3_METHOD
- failf(data, "OpenSSL was built without SSLv3 support");
- return CURLE_NOT_BUILT_IN;
-#else
-#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
- return CURLE_SSL_CONNECT_ERROR;
-#endif
- req_method = SSLv3_client_method();
- use_sni(FALSE);
- break;
-#endif
- }
-
- if(connssl->ctx)
- SSL_CTX_free(connssl->ctx);
- connssl->ctx = SSL_CTX_new(req_method);
-
- if(!connssl->ctx) {
- failf(data, "SSL: couldn't create a context: %s",
- ERR_error_string(ERR_peek_error(), NULL));
- return CURLE_OUT_OF_MEMORY;
- }
-
-#ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS);
-#endif
-
-#ifdef SSL_CTRL_SET_MSG_CALLBACK
- if(data->set.fdebug && data->set.verbose) {
- /* the SSL trace callback is only used for verbose logging so we only
- inform about failures of setting it */
- if(!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
- (void (*)(void))ssl_tls_trace)) {
- infof(data, "SSL: couldn't set callback!\n");
- }
- else if(!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0,
- conn)) {
- infof(data, "SSL: couldn't set callback argument!\n");
- }
- }
-#endif
-
- /* OpenSSL contains code to work-around lots of bugs and flaws in various
- SSL-implementations. SSL_CTX_set_options() is used to enabled those
- work-arounds. The man page for this option states that SSL_OP_ALL enables
- all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
- enable the bug workaround options if compatibility with somewhat broken
- implementations is desired."
-
- The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
- disable "rfc4507bis session ticket support". rfc4507bis was later turned
- into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077
-
- The enabled extension concerns the session management. I wonder how often
- libcurl stops a connection and then resumes a TLS session. also, sending
- the session data is some overhead. .I suggest that you just use your
- proposed patch (which explicitly disables TICKET).
-
- If someone writes an application with libcurl and openssl who wants to
- enable the feature, one can do this in the SSL callback.
-
- SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper
- interoperability with web server Netscape Enterprise Server 2.0.1 which
- was released back in 1996.
-
- Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has
- become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate
- CVE-2010-4180 when using previous OpenSSL versions we no longer enable
- this option regardless of OpenSSL version and SSL_OP_ALL definition.
-
- OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability
- (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
- SSL_OP_ALL that _disables_ that work-around despite the fact that
- SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to
- keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit
- must not be set.
- */
-
- ctx_options = SSL_OP_ALL;
-
-#ifdef SSL_OP_NO_TICKET
- ctx_options |= SSL_OP_NO_TICKET;
-#endif
-
-#ifdef SSL_OP_NO_COMPRESSION
- ctx_options |= SSL_OP_NO_COMPRESSION;
-#endif
-
-#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
- /* mitigate CVE-2010-4180 */
- ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
-#endif
-
-#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
- /* unless the user explicitly ask to allow the protocol vulnerability we
- use the work-around */
- if(!conn->data->set.ssl_enable_beast)
- ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
-#endif
-
- switch(data->set.ssl.version) {
- case CURL_SSLVERSION_SSLv3:
-#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
- infof(data, "Set version TLSv1.x for SRP authorisation\n");
- }
-#endif
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_TLSv1;
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-#endif
- break;
-
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
- break;
-
- case CURL_SSLVERSION_TLSv1_0:
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-#endif
- break;
-
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- case CURL_SSLVERSION_TLSv1_1:
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
- break;
-
- case CURL_SSLVERSION_TLSv1_2:
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
- ctx_options |= SSL_OP_NO_TLSv1_1;
- break;
-#endif
-
-#ifndef OPENSSL_NO_SSL2
- case CURL_SSLVERSION_SSLv2:
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-#endif
- break;
-#endif
-
- default:
- failf(data, "Unsupported SSL protocol version");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- SSL_CTX_set_options(connssl->ctx, ctx_options);
-
-#ifdef HAS_NPN
- if(data->set.ssl_enable_npn)
- SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
-#endif
-
-#ifdef HAS_ALPN
- if(data->set.ssl_enable_alpn) {
- int cur = 0;
- unsigned char protocols[128];
-
-#ifdef USE_NGHTTP2
- if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
- protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
-
- memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN);
- cur += NGHTTP2_PROTO_VERSION_ID_LEN;
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
- }
-#endif
-
- protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
- memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
- cur += ALPN_HTTP_1_1_LENGTH;
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
-
- /* expects length prefixed preference ordered list of protocols in wire
- * format
- */
- SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur);
- }
-#endif
-
- if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
- if(!cert_stuff(conn,
- connssl->ctx,
- data->set.str[STRING_CERT],
- data->set.str[STRING_CERT_TYPE],
- data->set.str[STRING_KEY],
- data->set.str[STRING_KEY_TYPE])) {
- /* failf() is already done in cert_stuff() */
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- ciphers = data->set.str[STRING_SSL_CIPHER_LIST];
- if(!ciphers)
- ciphers = (char *)DEFAULT_CIPHER_SELECTION;
- if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) {
- failf(data, "failed setting cipher list: %s", ciphers);
- return CURLE_SSL_CIPHER;
- }
- infof(data, "Cipher selection: %s\n", ciphers);
-
-#ifdef USE_TLS_SRP
- if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
- infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
-
- if(!SSL_CTX_set_srp_username(connssl->ctx, data->set.ssl.username)) {
- failf(data, "Unable to set SRP user name");
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) {
- failf(data, "failed setting SRP password");
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- if(!data->set.str[STRING_SSL_CIPHER_LIST]) {
- infof(data, "Setting cipher list SRP\n");
-
- if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) {
- failf(data, "failed setting SRP cipher list");
- return CURLE_SSL_CIPHER;
- }
- }
- }
-#endif
- if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) {
- /* tell SSL where to find CA certificates that are used to verify
- the servers certificate. */
- if(!SSL_CTX_load_verify_locations(connssl->ctx,
- data->set.str[STRING_SSL_CAFILE],
- data->set.str[STRING_SSL_CAPATH])) {
- if(data->set.ssl.verifypeer) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:\n"
- " CAfile: %s\n CApath: %s",
- data->set.str[STRING_SSL_CAFILE]?
- data->set.str[STRING_SSL_CAFILE]: "none",
- data->set.str[STRING_SSL_CAPATH]?
- data->set.str[STRING_SSL_CAPATH] : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- /* Just continue with a warning if no strict certificate verification
- is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
- }
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:\n");
- }
- infof(data,
- " CAfile: %s\n"
- " CApath: %s\n",
- data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
- "none",
- data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
- "none");
- }
-
- if(data->set.str[STRING_SSL_CRLFILE]) {
- /* tell SSL where to find CRL file that is used to check certificate
- * revocation */
- lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
- X509_LOOKUP_file());
- if(!lookup ||
- (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE],
- X509_FILETYPE_PEM)) ) {
- failf(data, "error loading CRL file: %s",
- data->set.str[STRING_SSL_CRLFILE]);
- return CURLE_SSL_CRL_BADFILE;
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully load CRL file:\n");
- X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
- X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
- }
- infof(data,
- " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ?
- data->set.str[STRING_SSL_CRLFILE]: "none");
- }
-
- /* SSL always tries to verify the peer, this only says whether it should
- * fail to connect if the verification fails, or if it should continue
- * anyway. In the latter case the result of the verification is checked with
- * SSL_get_verify_result() below. */
- SSL_CTX_set_verify(connssl->ctx,
- data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
- cert_verify_callback);
-
- /* give application a chance to interfere with SSL set up. */
- if(data->set.ssl.fsslctx) {
- result = (*data->set.ssl.fsslctx)(data, connssl->ctx,
- data->set.ssl.fsslctxp);
- if(result) {
- failf(data, "error signaled by ssl ctx callback");
- return result;
- }
- }
-
- /* Lets make an SSL structure */
- if(connssl->handle)
- SSL_free(connssl->handle);
- connssl->handle = SSL_new(connssl->ctx);
- if(!connssl->handle) {
- failf(data, "SSL: couldn't create a context (handle)!");
- return CURLE_OUT_OF_MEMORY;
- }
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_IS_BORINGSSL)
- if(data->set.ssl.verifystatus)
- SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
-#endif
-
- SSL_set_connect_state(connssl->handle);
-
- connssl->server_cert = 0x0;
-
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- 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 &&
- !SSL_set_tlsext_host_name(connssl->handle, conn->host.name))
- infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension\n");
-#endif
-
- /* Check if there's a cached ID we can/should use here! */
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
- /* we got a session id, use it! */
- if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
- failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* Informational message */
- infof (data, "SSL re-using session ID\n");
- }
-
- /* pass the raw socket into the SSL layers */
- if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
- failf(data, "SSL: SSL_set_fd failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- connssl->connecting_state = ssl_connect_2;
-
- return CURLE_OK;
-}
-
-static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
-{
- struct SessionHandle *data = conn->data;
- int err;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
- || ssl_connect_2_reading == connssl->connecting_state
- || ssl_connect_2_writing == connssl->connecting_state);
-
- ERR_clear_error();
-
- err = SSL_connect(connssl->handle);
-
- /* 1 is fine
- 0 is "not successful but was shut down controlled"
- <0 is "handshake was not successful, because a fatal error occurred" */
- if(1 != err) {
- int detail = SSL_get_error(connssl->handle, err);
-
- if(SSL_ERROR_WANT_READ == detail) {
- connssl->connecting_state = ssl_connect_2_reading;
- return CURLE_OK;
- }
- else if(SSL_ERROR_WANT_WRITE == detail) {
- connssl->connecting_state = ssl_connect_2_writing;
- return CURLE_OK;
- }
- else {
- /* untreated error */
- unsigned long errdetail;
- char error_buffer[256]; /* OpenSSL documents that this must be at least
- 256 bytes long. */
- CURLcode result;
- const char *cert_problem = NULL;
- long lerr;
-
- connssl->connecting_state = ssl_connect_2; /* the connection failed,
- we're not waiting for
- anything else. */
-
- errdetail = ERR_get_error(); /* Gets the earliest error code from the
- thread's error queue and removes the
- entry. */
-
- switch(errdetail) {
- case 0x1407E086:
- /* 1407E086:
- SSL routines:
- SSL2_SET_CERTIFICATE:
- certificate verify failed */
- /* fall-through */
- case 0x14090086:
- /* 14090086:
- SSL routines:
- SSL3_GET_SERVER_CERTIFICATE:
- certificate verify failed */
- result = CURLE_SSL_CACERT;
-
- lerr = SSL_get_verify_result(connssl->handle);
- if(lerr != X509_V_OK) {
- snprintf(error_buffer, sizeof(error_buffer),
- "SSL certificate problem: %s",
- X509_verify_cert_error_string(lerr));
- }
- else
- cert_problem = "SSL certificate problem, verify that the CA cert is"
- " OK.";
-
- break;
- default:
- result = CURLE_SSL_CONNECT_ERROR;
- SSL_strerror(errdetail, error_buffer, sizeof(error_buffer));
- break;
- }
-
- /* detail is already set to the SSL error above */
-
- /* If we e.g. use SSLv2 request-method and the server doesn't like us
- * (RST connection etc.), OpenSSL gives no explanation whatsoever and
- * the SO_ERROR is also lost.
- */
- if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
- failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
- conn->host.name, conn->remote_port);
- return result;
- }
-
- /* Could be a CERT problem */
- failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
-
- return result;
- }
- }
- else {
- /* we have been connected fine, we're not waiting for anything else. */
- connssl->connecting_state = ssl_connect_3;
-
- /* Informational message */
- infof(data, "SSL connection using %s / %s\n",
- get_ssl_version_txt(connssl->handle),
- SSL_get_cipher(connssl->handle));
-
-#ifdef HAS_ALPN
- /* Sets data and len to negotiated protocol, len is 0 if no protocol was
- * negotiated
- */
- if(data->set.ssl_enable_alpn) {
- const unsigned char* neg_protocol;
- unsigned int len;
- SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
- if(len != 0) {
- infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
-
-#ifdef USE_NGHTTP2
- if(len == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) {
- conn->negnpn = CURL_HTTP_VERSION_2_0;
- }
- else
-#endif
- if(len == ALPN_HTTP_1_1_LENGTH &&
- !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) {
- conn->negnpn = CURL_HTTP_VERSION_1_1;
- }
- }
- else
- infof(data, "ALPN, server did not agree to a protocol\n");
- }
-#endif
-
- return CURLE_OK;
- }
-}
-
-static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
-{
- int i, ilen;
-
- if((ilen = (int)len) < 0)
- return 1; /* buffer too big */
-
- i = i2t_ASN1_OBJECT(buf, ilen, a);
-
- if(i >= ilen)
- return 1; /* buffer too small */
-
- return 0;
-}
-
-static void pubkey_show(struct SessionHandle *data,
- int num,
- const char *type,
- const char *name,
- unsigned char *raw,
- int len)
-{
- size_t left;
- int i;
- char namebuf[32];
- char *buffer;
-
- left = len*3 + 1;
- buffer = malloc(left);
- if(buffer) {
- char *ptr=buffer;
- snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
- for(i=0; i< len; i++) {
- snprintf(ptr, left, "%02x:", raw[i]);
- ptr += 3;
- left -= 3;
- }
- infof(data, " %s: %s\n", namebuf, buffer);
- Curl_ssl_push_certinfo(data, num, namebuf, buffer);
- free(buffer);
- }
-}
-
-#define print_pubkey_BN(_type, _name, _num) \
-do { \
- if(pubkey->pkey._type->_name) { \
- int len = BN_num_bytes(pubkey->pkey._type->_name); \
- if(len < CERTBUFFERSIZE) { \
- BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \
- bufp[len] = 0; \
- pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \
- } \
- } \
-} WHILE_FALSE
-
-static int X509V3_ext(struct SessionHandle *data,
- int certnum,
- STACK_OF(X509_EXTENSION) *exts)
-{
- int i;
- size_t j;
-
- if(sk_X509_EXTENSION_num(exts) <= 0)
- /* no extensions, bail out */
- return 1;
-
- for(i=0; i<sk_X509_EXTENSION_num(exts); i++) {
- ASN1_OBJECT *obj;
- X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
- BUF_MEM *biomem;
- char buf[512];
- char *ptr=buf;
- char namebuf[128];
- BIO *bio_out = BIO_new(BIO_s_mem());
-
- if(!bio_out)
- return 1;
-
- obj = X509_EXTENSION_get_object(ext);
-
- asn1_object_dump(obj, namebuf, sizeof(namebuf));
-
- infof(data, "%s: %s\n", namebuf,
- X509_EXTENSION_get_critical(ext)?"(critical)":"");
-
- if(!X509V3_EXT_print(bio_out, ext, 0, 0))
- ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
-
- BIO_get_mem_ptr(bio_out, &biomem);
-
- /* biomem->length bytes at biomem->data, this little loop here is only
- done for the infof() call, we send the "raw" data to the certinfo
- function */
- for(j=0; j<(size_t)biomem->length; j++) {
- const char *sep="";
- if(biomem->data[j] == '\n') {
- sep=", ";
- j++; /* skip the newline */
- };
- while((j<(size_t)biomem->length) && (biomem->data[j] == ' '))
- j++;
- if(j<(size_t)biomem->length)
- ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
- biomem->data[j]);
- }
- infof(data, " %s\n", buf);
-
- Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
-
- BIO_free(bio_out);
-
- }
- return 0; /* all is fine */
-}
-
-
-static void X509_signature(struct SessionHandle *data,
- int numcert,
- ASN1_STRING *sig)
-{
- char buf[1024];
- char *ptr = buf;
- int i;
-
- for(i=0; i<sig->length; i++)
- ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
-
- infof(data, " Signature: %s\n", buf);
- Curl_ssl_push_certinfo(data, numcert, "Signature", buf);
-}
-
-static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
-{
- BIO *bio_out = BIO_new(BIO_s_mem());
- BUF_MEM *biomem;
-
- /* this outputs the cert in this 64 column wide style with newlines and
- -----BEGIN CERTIFICATE----- texts and more */
- PEM_write_bio_X509(bio_out, x);
-
- BIO_get_mem_ptr(bio_out, &biomem);
-
- Curl_ssl_push_certinfo_len(data, numcert,
- "Cert", biomem->data, biomem->length);
-
- BIO_free(bio_out);
-}
-
-/*
- * This size was previously 512 which has been reported "too small" without
- * any specifics, so it was enlarged to allow more data to get shown uncut.
- * The "perfect" size is yet to figure out.
- */
-#define CERTBUFFERSIZE 8192
-
-static CURLcode get_cert_chain(struct connectdata *conn,
- struct ssl_connect_data *connssl)
-
-{
- CURLcode result;
- STACK_OF(X509) *sk;
- int i;
- char *bufp;
- struct SessionHandle *data = conn->data;
- int numcerts;
-
- bufp = malloc(CERTBUFFERSIZE);
- if(!bufp)
- return CURLE_OUT_OF_MEMORY;
-
- sk = SSL_get_peer_cert_chain(connssl->handle);
- if(!sk) {
- free(bufp);
- return CURLE_OUT_OF_MEMORY;
- }
-
- numcerts = sk_X509_num(sk);
-
- result = Curl_ssl_init_certinfo(data, numcerts);
- if(result) {
- free(bufp);
- return result;
- }
-
- infof(data, "--- Certificate chain\n");
- for(i=0; i<numcerts; i++) {
- long value;
- ASN1_INTEGER *num;
- ASN1_TIME *certdate;
-
- /* get the certs in "importance order" */
-#if 0
- X509 *x = sk_X509_value(sk, numcerts - i - 1);
-#else
- X509 *x = sk_X509_value(sk, i);
-#endif
-
- X509_CINF *cinf;
- EVP_PKEY *pubkey=NULL;
- int j;
- char *ptr;
-
- (void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE);
- infof(data, "%2d Subject: %s\n", i, bufp);
- Curl_ssl_push_certinfo(data, i, "Subject", bufp);
-
- (void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE);
- infof(data, " Issuer: %s\n", bufp);
- Curl_ssl_push_certinfo(data, i, "Issuer", bufp);
-
- value = X509_get_version(x);
- infof(data, " Version: %lu (0x%lx)\n", value+1, value);
- snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
- Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */
-
- num=X509_get_serialNumber(x);
- {
- int left = CERTBUFFERSIZE;
-
- ptr = bufp;
- if(num->type == V_ASN1_NEG_INTEGER) {
- *ptr++='-';
- left--;
- }
-
- for(j=0; (j<num->length) && (left>=3); j++) {
- snprintf(ptr, left, "%02x", num->data[j]);
- ptr += 2;
- left -= 2;
- }
- if(num->length)
- infof(data, " Serial Number: %s\n", bufp);
- else
- bufp[0]=0;
- }
- if(bufp[0])
- Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */
-
- cinf = x->cert_info;
-
- j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE);
- if(!j) {
- infof(data, " Signature Algorithm: %s\n", bufp);
- Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp);
- }
-
- certdate = X509_get_notBefore(x);
- asn1_output(certdate, bufp, CERTBUFFERSIZE);
- infof(data, " Start date: %s\n", bufp);
- Curl_ssl_push_certinfo(data, i, "Start date", bufp);
-
- certdate = X509_get_notAfter(x);
- asn1_output(certdate, bufp, CERTBUFFERSIZE);
- infof(data, " Expire date: %s\n", bufp);
- Curl_ssl_push_certinfo(data, i, "Expire date", bufp);
-
- j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE);
- if(!j) {
- infof(data, " Public Key Algorithm: %s\n", bufp);
- Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp);
- }
-
- pubkey = X509_get_pubkey(x);
- if(!pubkey)
- infof(data, " Unable to load public key\n");
- else {
- switch(pubkey->type) {
- case EVP_PKEY_RSA:
- infof(data, " RSA Public Key (%d bits)\n",
- BN_num_bits(pubkey->pkey.rsa->n));
- snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n));
- Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp);
-
- print_pubkey_BN(rsa, n, i);
- print_pubkey_BN(rsa, e, i);
- print_pubkey_BN(rsa, d, i);
- print_pubkey_BN(rsa, p, i);
- print_pubkey_BN(rsa, q, i);
- print_pubkey_BN(rsa, dmp1, i);
- print_pubkey_BN(rsa, dmq1, i);
- print_pubkey_BN(rsa, iqmp, i);
- break;
- case EVP_PKEY_DSA:
- print_pubkey_BN(dsa, p, i);
- print_pubkey_BN(dsa, q, i);
- print_pubkey_BN(dsa, g, i);
- print_pubkey_BN(dsa, priv_key, i);
- print_pubkey_BN(dsa, pub_key, i);
- break;
- case EVP_PKEY_DH:
- print_pubkey_BN(dh, p, i);
- print_pubkey_BN(dh, g, i);
- print_pubkey_BN(dh, priv_key, i);
- print_pubkey_BN(dh, pub_key, i);
- break;
-#if 0
- case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
- /* left TODO */
- break;
-#endif
- }
- EVP_PKEY_free(pubkey);
- }
-
- X509V3_ext(data, i, cinf->extensions);
-
- X509_signature(data, i, x->signature);
-
- dumpcert(data, x, i);
- }
-
- free(bufp);
-
- return CURLE_OK;
-}
-
-/*
- * Heavily modified from:
- * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
- */
-static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey)
-{
- /* Scratch */
- int len1 = 0, len2 = 0;
- unsigned char *buff1 = NULL, *temp = NULL;
-
- /* Result is returned to caller */
- CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
- /* if a path wasn't specified, don't pin */
- if(!pinnedpubkey)
- return CURLE_OK;
-
- if(!cert)
- return result;
-
- do {
- /* Begin Gyrations to get the subjectPublicKeyInfo */
- /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
-
- /* https://groups.google.com/group/mailing.openssl.users/browse_thread
- /thread/d61858dae102c6c7 */
- len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
- if(len1 < 1)
- break; /* failed */
-
- /* https://www.openssl.org/docs/crypto/buffer.html */
- buff1 = temp = OPENSSL_malloc(len1);
- if(!buff1)
- break; /* failed */
-
- /* https://www.openssl.org/docs/crypto/d2i_X509.html */
- len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);
-
- /*
- * These checks are verifying we got back the same values as when we
- * sized the buffer. It's pretty weak since they should always be the
- * same. But it gives us something to test.
- */
- if((len1 != len2) || !temp || ((temp - buff1) != len1))
- break; /* failed */
-
- /* End Gyrations */
-
- /* The one good exit point */
- result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
- } while(0);
-
- /* https://www.openssl.org/docs/crypto/buffer.html */
- if(buff1)
- OPENSSL_free(buff1);
-
- return result;
-}
-
-/*
- * Get the server cert, verify it and show it etc, only call failf() if the
- * 'strict' argument is TRUE as otherwise all this is for informational
- * purposes only!
- *
- * We check certificates to authenticate the server; otherwise we risk
- * man-in-the-middle attack.
- */
-static CURLcode servercert(struct connectdata *conn,
- struct ssl_connect_data *connssl,
- bool strict)
-{
- CURLcode result = CURLE_OK;
- int rc;
- long lerr;
- ASN1_TIME *certdate;
- struct SessionHandle *data = conn->data;
- X509 *issuer;
- FILE *fp;
- char *buffer = data->state.buffer;
- const char *ptr;
-
- if(data->set.ssl.certinfo)
- /* we've been asked to gather certificate info! */
- (void)get_cert_chain(conn, connssl);
-
- connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
- if(!connssl->server_cert) {
- if(strict)
- failf(data, "SSL: couldn't get peer certificate!");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
-
- infof(data, "Server certificate:\n");
-
- rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
- buffer, BUFSIZE);
- infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);
-
- certdate = X509_get_notBefore(connssl->server_cert);
- asn1_output(certdate, buffer, BUFSIZE);
- infof(data, "\t start date: %s\n", buffer);
-
- certdate = X509_get_notAfter(connssl->server_cert);
- asn1_output(certdate, buffer, BUFSIZE);
- infof(data, "\t expire date: %s\n", buffer);
-
- if(data->set.ssl.verifyhost) {
- result = verifyhost(conn, connssl->server_cert);
- if(result) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- return result;
- }
- }
-
- rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
- buffer, BUFSIZE);
- if(rc) {
- if(strict)
- failf(data, "SSL: couldn't get X509-issuer name!");
- result = CURLE_SSL_CONNECT_ERROR;
- }
- else {
- infof(data, "\t issuer: %s\n", buffer);
-
- /* We could do all sorts of certificate verification stuff here before
- deallocating the certificate. */
-
- /* e.g. match issuer name with provided issuer certificate */
- if(data->set.str[STRING_SSL_ISSUERCERT]) {
- fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], "r");
- if(!fp) {
- if(strict)
- failf(data, "SSL: Unable to open issuer cert (%s)",
- data->set.str[STRING_SSL_ISSUERCERT]);
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- return CURLE_SSL_ISSUER_ERROR;
- }
-
- issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL);
- if(!issuer) {
- if(strict)
- failf(data, "SSL: Unable to read issuer cert (%s)",
- data->set.str[STRING_SSL_ISSUERCERT]);
- X509_free(connssl->server_cert);
- X509_free(issuer);
- fclose(fp);
- return CURLE_SSL_ISSUER_ERROR;
- }
-
- fclose(fp);
-
- if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) {
- if(strict)
- failf(data, "SSL: Certificate issuer check failed (%s)",
- data->set.str[STRING_SSL_ISSUERCERT]);
- X509_free(connssl->server_cert);
- X509_free(issuer);
- connssl->server_cert = NULL;
- return CURLE_SSL_ISSUER_ERROR;
- }
-
- infof(data, "\t SSL certificate issuer check ok (%s)\n",
- data->set.str[STRING_SSL_ISSUERCERT]);
- X509_free(issuer);
- }
-
- lerr = data->set.ssl.certverifyresult =
- SSL_get_verify_result(connssl->handle);
-
- if(data->set.ssl.certverifyresult != X509_V_OK) {
- if(data->set.ssl.verifypeer) {
- /* We probably never reach this, because SSL_connect() will fail
- and we return earlier if verifypeer is set? */
- if(strict)
- failf(data, "SSL certificate verify result: %s (%ld)",
- X509_verify_cert_error_string(lerr), lerr);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- else
- infof(data, "\t SSL certificate verify result: %s (%ld),"
- " continuing anyway.\n",
- X509_verify_cert_error_string(lerr), lerr);
- }
- else
- infof(data, "\t SSL certificate verify ok.\n");
- }
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_IS_BORINGSSL)
- if(data->set.ssl.verifystatus) {
- result = verifystatus(conn, connssl);
- if(result) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- return result;
- }
- }
-#endif
-
- if(!strict)
- /* when not strict, we don't bother about the verify cert problems */
- result = CURLE_OK;
-
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
- if(!result && ptr) {
- result = pkp_pin_peer_pubkey(connssl->server_cert, ptr);
- if(result)
- failf(data, "SSL: public key does not match pinned public key!");
- }
-
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- connssl->connecting_state = ssl_connect_done;
-
- return result;
-}
-
-static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
-{
- CURLcode result = CURLE_OK;
- void *old_ssl_sessionid = NULL;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- bool incache;
- SSL_SESSION *our_ssl_sessionid;
-
- DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-
-#ifdef HAVE_SSL_GET1_SESSION
- our_ssl_sessionid = SSL_get1_session(connssl->handle);
-
- /* SSL_get1_session() will increment the reference
- count and the session will stay in memory until explicitly freed with
- SSL_SESSION_free(3), regardless of its state.
- This function was introduced in openssl 0.9.5a. */
-#else
- our_ssl_sessionid = SSL_get_session(connssl->handle);
-
- /* if SSL_get1_session() is unavailable, use SSL_get_session().
- This is an inferior option because the session can be flushed
- at any time by openssl. It is included only so curl compiles
- under versions of openssl < 0.9.5a.
-
- WARNING: How curl behaves if it's session is flushed is
- untested.
- */
-#endif
-
- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
- if(incache) {
- if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing\n");
- Curl_ssl_delsessionid(conn, old_ssl_sessionid);
- incache = FALSE;
- }
- }
-
- if(!incache) {
- result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */);
- if(result) {
- failf(data, "failed to store ssl session");
- return result;
- }
- }
-#ifdef HAVE_SSL_GET1_SESSION
- else {
- /* Session was incache, so refcount already incremented earlier.
- * Avoid further increments with each SSL_get1_session() call.
- * This does not free the session as refcount remains > 0
- */
- SSL_SESSION_free(our_ssl_sessionid);
- }
-#endif
-
- /*
- * We check certificates to authenticate the server; otherwise we risk
- * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
- * verify the peer ignore faults and failures from the server cert
- * operations.
- */
-
- result = servercert(conn, connssl,
- (data->set.ssl.verifypeer || data->set.ssl.verifyhost));
-
- if(!result)
- connssl->connecting_state = ssl_connect_done;
-
- return result;
-}
-
-static Curl_recv ossl_recv;
-static Curl_send ossl_send;
-
-static CURLcode ossl_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
-{
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
- int what;
-
- /* check if the connection has already been established */
- if(ssl_connection_complete == connssl->state) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- result = ossl_connect_step1(conn, sockindex);
- if(result)
- return result;
- }
-
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
-
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading ||
- connssl->connecting_state == ssl_connect_2_writing) {
-
- curl_socket_t writefd = ssl_connect_2_writing==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-
- what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* Run transaction, and return to the caller if it failed or if this
- * connection is done nonblocking and this loop would execute again. This
- * permits the owner of a multi handle to abort a connection attempt
- * before step2 has completed while ensuring that a client using select()
- * or epoll() will always have a valid fdset to wait on.
- */
- result = ossl_connect_step2(conn, sockindex);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
- return result;
-
- } /* repeat step2 until all transactions are done. */
-
- if(ssl_connect_3 == connssl->connecting_state) {
- result = ossl_connect_step3(conn, sockindex);
- if(result)
- return result;
- }
-
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = ossl_recv;
- conn->send[sockindex] = ossl_send;
- *done = TRUE;
- }
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-CURL_STATIC CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- return ossl_connect_common(conn, sockindex, TRUE, done);
-}
-
-CURL_STATIC CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = ossl_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-CURL_STATIC bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex)
-{
- if(conn->ssl[connindex].handle)
- /* SSL is in use */
- return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
- else
- return FALSE;
-}
-
-static ssize_t ossl_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
-{
- /* SSL_write() is said to return 'int' while write() and send() returns
- 'size_t' */
- int err;
- char error_buffer[120]; /* OpenSSL documents that this must be at least 120
- bytes long. */
- unsigned long sslerror;
- int memlen;
- int rc;
-
- ERR_clear_error();
-
- memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
-
- if(rc <= 0) {
- err = SSL_get_error(conn->ssl[sockindex].handle, rc);
-
- switch(err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* The operation did not complete; the same TLS/SSL I/O function
- should be called again later. This is basically an EWOULDBLOCK
- equivalent. */
- *curlcode = CURLE_AGAIN;
- return -1;
- case SSL_ERROR_SYSCALL:
- failf(conn->data, "SSL_write() returned SYSCALL, errno = %d",
- SOCKERRNO);
- *curlcode = CURLE_SEND_ERROR;
- return -1;
- case SSL_ERROR_SSL:
- /* A failure in the SSL library occurred, usually a protocol error.
- The OpenSSL error queue contains more information on the error. */
- sslerror = ERR_get_error();
- failf(conn->data, "SSL_write() error: %s",
- ERR_error_string(sslerror, error_buffer));
- *curlcode = CURLE_SEND_ERROR;
- return -1;
- }
- /* a true error */
- failf(conn->data, "SSL_write() return error %d", err);
- *curlcode = CURLE_SEND_ERROR;
- return -1;
- }
- *curlcode = CURLE_OK;
- return (ssize_t)rc; /* number of bytes */
-}
-
-static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- CURLcode *curlcode)
-{
- char error_buffer[120]; /* OpenSSL documents that this must be at
- least 120 bytes long. */
- unsigned long sslerror;
- ssize_t nread;
- int buffsize;
-
- ERR_clear_error();
-
- buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
- if(nread <= 0) {
- /* failed SSL_read */
- int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
-
- switch(err) {
- case SSL_ERROR_NONE: /* this is not an error */
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- break;
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_read() */
- *curlcode = CURLE_AGAIN;
- return -1;
- default:
- /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
- value/errno" */
- /* https://www.openssl.org/docs/crypto/ERR_get_error.html */
- sslerror = ERR_get_error();
- if((nread < 0) || sslerror) {
- /* If the return code was negative or there actually is an error in the
- queue */
- failf(conn->data, "SSL read: %s, errno %d",
- ERR_error_string(sslerror, error_buffer),
- SOCKERRNO);
- *curlcode = CURLE_RECV_ERROR;
- return -1;
- }
- }
- }
- return nread;
-}
-
-CURL_STATIC size_t Curl_ossl_version(char *buffer, size_t size)
-{
-#ifdef YASSL_VERSION
- /* yassl provides an OpenSSL API compatibility layer so it looks identical
- to OpenSSL in all other aspects */
- return snprintf(buffer, size, "yassl/%s", YASSL_VERSION);
-#else /* YASSL_VERSION */
-#ifdef OPENSSL_IS_BORINGSSL
- return snprintf(buffer, size, "BoringSSL");
-#else /* OPENSSL_IS_BORINGSSL */
-
-#if(OPENSSL_VERSION_NUMBER >= 0x905000)
- {
- char sub[3];
- unsigned long ssleay_value;
- sub[2]='\0';
- sub[1]='\0';
- ssleay_value=SSLeay();
- if(ssleay_value < 0x906000) {
- ssleay_value=SSLEAY_VERSION_NUMBER;
- sub[0]='\0';
- }
- else {
- if(ssleay_value&0xff0) {
- int minor_ver = (ssleay_value >> 4) & 0xff;
- if(minor_ver > 26) {
- /* handle extended version introduced for 0.9.8za */
- sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
- sub[0] = 'z';
- }
- else {
- sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1);
- }
- }
- else
- sub[0]='\0';
- }
-
- return snprintf(buffer, size, "%s/%lx.%lx.%lx%s",
-#ifdef LIBRESSL_VERSION_NUMBER
- "LibreSSL"
-#else
- "OpenSSL"
-#endif
- , (ssleay_value>>28)&0xf,
- (ssleay_value>>20)&0xff,
- (ssleay_value>>12)&0xff,
- sub);
- }
-
-#else /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */
-
-#if(OPENSSL_VERSION_NUMBER >= 0x900000)
- return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx",
- (OPENSSL_VERSION_NUMBER>>28)&0xff,
- (OPENSSL_VERSION_NUMBER>>20)&0xff,
- (OPENSSL_VERSION_NUMBER>>12)&0xf);
-
-#else /* (OPENSSL_VERSION_NUMBER >= 0x900000) */
- {
- char sub[2];
- sub[1]='\0';
- if(OPENSSL_VERSION_NUMBER&0x0f) {
- sub[0]=(OPENSSL_VERSION_NUMBER&0x0f) + 'a' -1;
- }
- else
- sub[0]='\0';
-
- return snprintf(buffer, size, "SSL/%x.%x.%x%s",
- (OPENSSL_VERSION_NUMBER>>12)&0xff,
- (OPENSSL_VERSION_NUMBER>>8)&0xf,
- (OPENSSL_VERSION_NUMBER>>4)&0xf, sub);
- }
-#endif /* (OPENSSL_VERSION_NUMBER >= 0x900000) */
-#endif /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */
-
-#endif /* OPENSSL_IS_BORINGSSL */
-#endif /* YASSL_VERSION */
-}
-
-/* can be called with data == NULL */
-CURL_STATIC int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
- size_t length)
-{
- if(data) {
- Curl_ossl_seed(data); /* Initiate the seed if not already done */
- }
- RAND_bytes(entropy, curlx_uztosi(length));
- return 0; /* 0 as in no problem */
-}
-
-CURL_STATIC void Curl_ossl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum /* output */,
- size_t unused)
-{
- MD5_CTX MD5pw;
- (void)unused;
- MD5_Init(&MD5pw);
- MD5_Update(&MD5pw, tmp, tmplen);
- MD5_Final(md5sum, &MD5pw);
-}
-
-bool Curl_ossl_cert_status_request(void)
-{
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_IS_BORINGSSL)
- return TRUE;
-#else
- return FALSE;
-#endif
-}
-#endif /* USE_OPENSSL */
diff --git a/libcurl/src/lib/vtls/openssl.h b/libcurl/src/lib/vtls/openssl.h
deleted file mode 100644
index bfa3bc0..0000000
--- a/libcurl/src/lib/vtls/openssl.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef HEADER_CURL_SSLUSE_H
-#define HEADER_CURL_SSLUSE_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "../curl_setup.h"
-
-#ifdef USE_OPENSSL
-/*
- * This header should only be needed to get included by vtls.c and openssl.c
- */
-
-#include "urldata.h"
-
-CURL_STATIC CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-/* close a SSL connection */
-CURL_STATIC void Curl_ossl_close(struct connectdata *conn, int sockindex);
-
-/* tell OpenSSL to close down all open information regarding connections (and
- thus session ID caching etc) */
-CURL_STATIC void Curl_ossl_close_all(struct SessionHandle *data);
-
-/* Sets an OpenSSL engine */
-CURL_STATIC CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine);
-
-/* function provided for the generic SSL-layer, called when a session id
- should be freed */
-CURL_STATIC void Curl_ossl_session_free(void *ptr);
-
-/* Sets engine as default for all SSL operations */
-CURL_STATIC CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data);
-
-/* Build list of OpenSSL engines */
-CURL_STATIC struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
-
-CURL_STATIC int Curl_ossl_init(void);
-CURL_STATIC void Curl_ossl_cleanup(void);
-
-CURL_STATIC size_t Curl_ossl_version(char *buffer, size_t size);
-CURL_STATIC int Curl_ossl_check_cxn(struct connectdata *cxn);
-CURL_STATIC int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC bool Curl_ossl_data_pending(const struct connectdata *conn,
- int connindex);
-
-/* return 0 if a find random is filled in */
-CURL_STATIC int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
- size_t length);
-CURL_STATIC void Curl_ossl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum /* output */,
- size_t unused);
-
-bool Curl_ossl_cert_status_request(void);
-
-/* Set the API backend definition to OpenSSL */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* this backend suppots CURLOPT_SSL_CTX_* */
-#define have_curlssl_ssl_ctx 1
-
-/* API setup for OpenSSL */
-#define curlssl_init Curl_ossl_init
-#define curlssl_cleanup Curl_ossl_cleanup
-#define curlssl_connect Curl_ossl_connect
-#define curlssl_connect_nonblocking Curl_ossl_connect_nonblocking
-#define curlssl_session_free(x) Curl_ossl_session_free(x)
-#define curlssl_close_all Curl_ossl_close_all
-#define curlssl_close Curl_ossl_close
-#define curlssl_shutdown(x,y) Curl_ossl_shutdown(x,y)
-#define curlssl_set_engine(x,y) Curl_ossl_set_engine(x,y)
-#define curlssl_set_engine_default(x) Curl_ossl_set_engine_default(x)
-#define curlssl_engines_list(x) Curl_ossl_engines_list(x)
-#define curlssl_version Curl_ossl_version
-#define curlssl_check_cxn Curl_ossl_check_cxn
-#define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
-#define curlssl_random(x,y,z) Curl_ossl_random(x,y,z)
-#define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d)
-#define curlssl_cert_status_request() Curl_ossl_cert_status_request()
-
-#define DEFAULT_CIPHER_SELECTION \
- "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
-
-#endif /* USE_OPENSSL */
-#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/libcurl/src/lib/vtls/polarssl.c b/libcurl/src/lib/vtls/polarssl.c
deleted file mode 100644
index 8deef27..0000000
--- a/libcurl/src/lib/vtls/polarssl.c
+++ /dev/null
@@ -1,753 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- *
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_POLARSSL
-
-#include <polarssl/net.h>
-#include <polarssl/ssl.h>
-#include <polarssl/certs.h>
-#include <polarssl/x509.h>
-#include <polarssl/version.h>
-
-#if POLARSSL_VERSION_NUMBER < 0x01030000
-#error too old PolarSSL
-#endif
-
-#include <polarssl/error.h>
-#include <polarssl/entropy.h>
-#include <polarssl/ctr_drbg.h>
-
-#include "urldata.h"
-#include "sendf.h"
-#include "inet_pton.h"
-#include "polarssl.h"
-#include "vtls.h"
-#include "parsedate.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "rawstr.h"
-#include "polarssl_threadlock.h"
-#include "curl_printf.h"
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* apply threading? */
-#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
-#define THREADING_SUPPORT
-#endif
-
-#if defined(THREADING_SUPPORT)
-static entropy_context entropy;
-
-static int entropy_init_initialized = 0;
-
-/* start of entropy_init_mutex() */
-static void entropy_init_mutex(entropy_context *ctx)
-{
- /* lock 0 = entropy_init_mutex() */
- polarsslthreadlock_lock_function(0);
- if(entropy_init_initialized == 0) {
- entropy_init(ctx);
- entropy_init_initialized = 1;
- }
- polarsslthreadlock_unlock_function(0);
-}
-/* end of entropy_init_mutex() */
-
-/* start of entropy_func_mutex() */
-static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
-{
- int ret;
- /* lock 1 = entropy_func_mutex() */
- polarsslthreadlock_lock_function(1);
- ret = entropy_func(data, output, len);
- polarsslthreadlock_unlock_function(1);
-
- return ret;
-}
-/* end of entropy_func_mutex() */
-
-#endif /* THREADING_SUPPORT */
-
-/* Define this to enable lots of debugging for PolarSSL */
-#undef POLARSSL_DEBUG
-
-#ifdef POLARSSL_DEBUG
-static void polarssl_debug(void *context, int level, const char *line)
-{
- struct SessionHandle *data = NULL;
-
- if(!context)
- return;
-
- data = (struct SessionHandle *)context;
-
- infof(data, "%s", line);
- (void) level;
-}
-#else
-#endif
-
-/* ALPN for http2? */
-#ifdef POLARSSL_SSL_ALPN
-# define HAS_ALPN
-#endif
-
-static Curl_recv polarssl_recv;
-static Curl_send polarssl_send;
-
-
-static CURLcode
-polarssl_connect_step1(struct connectdata *conn,
- int sockindex)
-{
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data* connssl = &conn->ssl[sockindex];
-
- bool sni = TRUE; /* default is SNI enabled */
- int ret = -1;
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
- void *old_session = NULL;
- size_t old_session_size = 0;
- char errorbuf[128];
- errorbuf[0]=0;
-
- /* PolarSSL only supports SSLv3 and TLSv1 */
- if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
- failf(data, "PolarSSL does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
- sni = FALSE; /* SSLv3 has no SNI */
-
-#ifdef THREADING_SUPPORT
- entropy_init_mutex(&entropy);
-
- if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy,
- connssl->ssn.id, connssl->ssn.length)) != 0) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
- -ret, errorbuf);
- }
-#else
- entropy_init(&connssl->entropy);
-
- if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy,
- connssl->ssn.id, connssl->ssn.length)) != 0) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
- -ret, errorbuf);
- }
-#endif /* THREADING_SUPPORT */
-
- /* Load the trusted CA */
- memset(&connssl->cacert, 0, sizeof(x509_crt));
-
- if(data->set.str[STRING_SSL_CAFILE]) {
- ret = x509_crt_parse_file(&connssl->cacert,
- data->set.str[STRING_SSL_CAFILE]);
-
- if(ret<0) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_SSL_CAFILE], -ret, errorbuf);
-
- if(data->set.ssl.verifypeer)
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
-
- if(data->set.str[STRING_SSL_CAPATH]) {
- ret = x509_crt_parse_path(&connssl->cacert,
- data->set.str[STRING_SSL_CAPATH]);
-
- if(ret<0) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_SSL_CAPATH], -ret, errorbuf);
-
- if(data->set.ssl.verifypeer)
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
-
- /* Load the client certificate */
- memset(&connssl->clicert, 0, sizeof(x509_crt));
-
- if(data->set.str[STRING_CERT]) {
- ret = x509_crt_parse_file(&connssl->clicert,
- data->set.str[STRING_CERT]);
-
- if(ret) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_CERT], -ret, errorbuf);
-
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- /* Load the client private key */
- if(data->set.str[STRING_KEY]) {
- pk_context pk;
- pk_init(&pk);
- ret = pk_parse_keyfile(&pk, data->set.str[STRING_KEY],
- data->set.str[STRING_KEY_PASSWD]);
- if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA))
- ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
- if(ret == 0)
- rsa_copy(&connssl->rsa, pk_rsa(pk));
- else
- rsa_free(&connssl->rsa);
- pk_free(&pk);
-
- if(ret) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_KEY], -ret, errorbuf);
-
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- /* Load the CRL */
- memset(&connssl->crl, 0, sizeof(x509_crl));
-
- if(data->set.str[STRING_SSL_CRLFILE]) {
- ret = x509_crl_parse_file(&connssl->crl,
- data->set.str[STRING_SSL_CRLFILE]);
-
- if(ret) {
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s",
- data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
-
- return CURLE_SSL_CRL_BADFILE;
- }
- }
-
- infof(data, "PolarSSL: Connecting to %s:%d\n",
- conn->host.name, conn->remote_port);
-
- if(ssl_init(&connssl->ssl)) {
- failf(data, "PolarSSL: ssl_init failed");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_1);
- break;
- case CURL_SSLVERSION_SSLv3:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_0);
- ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_0);
- infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n");
- break;
- case CURL_SSLVERSION_TLSv1_0:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_1);
- ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_1);
- infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.0\n");
- break;
- case CURL_SSLVERSION_TLSv1_1:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_2);
- ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_2);
- infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.1\n");
- break;
- case CURL_SSLVERSION_TLSv1_2:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_3);
- ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
- SSL_MINOR_VERSION_3);
- infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n");
- break;
- }
-
- ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT);
- ssl_set_authmode(&connssl->ssl, SSL_VERIFY_OPTIONAL);
-
- ssl_set_rng(&connssl->ssl, ctr_drbg_random,
- &connssl->ctr_drbg);
- ssl_set_bio(&connssl->ssl,
- net_recv, &conn->sock[sockindex],
- net_send, &conn->sock[sockindex]);
-
- ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites());
- if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) {
- memcpy(&connssl->ssn, old_session, old_session_size);
- infof(data, "PolarSSL re-using session\n");
- }
-
- ssl_set_session(&connssl->ssl,
- &connssl->ssn);
-
- ssl_set_ca_chain(&connssl->ssl,
- &connssl->cacert,
- &connssl->crl,
- conn->host.name);
-
- ssl_set_own_cert_rsa(&connssl->ssl,
- &connssl->clicert, &connssl->rsa);
-
- if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) &&
-#ifdef ENABLE_IPV6
- !Curl_inet_pton(AF_INET6, conn->host.name, &addr) &&
-#endif
- sni && ssl_set_hostname(&connssl->ssl, conn->host.name)) {
- infof(data, "WARNING: failed to configure "
- "server name indication (SNI) TLS extension\n");
- }
-
-#ifdef HAS_ALPN
- if(data->set.ssl_enable_alpn) {
- static const char* protocols[3];
- int cur = 0;
-
-#ifdef USE_NGHTTP2
- if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
- protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
- }
-#endif
-
- protocols[cur++] = ALPN_HTTP_1_1;
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
-
- protocols[cur] = NULL;
-
- ssl_set_alpn_protocols(&connssl->ssl, protocols);
- }
-#endif
-
-#ifdef POLARSSL_DEBUG
- ssl_set_dbg(&connssl->ssl, polarssl_debug, data);
-#endif
-
- connssl->connecting_state = ssl_connect_2;
-
- return CURLE_OK;
-}
-
-static CURLcode
-polarssl_connect_step2(struct connectdata *conn,
- int sockindex)
-{
- int ret;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data* connssl = &conn->ssl[sockindex];
- char buffer[1024];
-
- char errorbuf[128];
- errorbuf[0] = 0;
-
- conn->recv[sockindex] = polarssl_recv;
- conn->send[sockindex] = polarssl_send;
-
- ret = ssl_handshake(&connssl->ssl);
-
- switch(ret) {
- case 0:
- break;
-
- case POLARSSL_ERR_NET_WANT_READ:
- connssl->connecting_state = ssl_connect_2_reading;
- return CURLE_OK;
-
- case POLARSSL_ERR_NET_WANT_WRITE:
- connssl->connecting_state = ssl_connect_2_writing;
- return CURLE_OK;
-
- default:
-#ifdef POLARSSL_ERROR_C
- error_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* POLARSSL_ERROR_C */
- failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s",
- -ret, errorbuf);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
- ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) );
-
- ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl);
-
- if(ret && data->set.ssl.verifypeer) {
- if(ret & BADCERT_EXPIRED)
- failf(data, "Cert verify failed: BADCERT_EXPIRED");
-
- if(ret & BADCERT_REVOKED) {
- failf(data, "Cert verify failed: BADCERT_REVOKED");
- return CURLE_SSL_CACERT;
- }
-
- if(ret & BADCERT_CN_MISMATCH)
- failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
-
- if(ret & BADCERT_NOT_TRUSTED)
- failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
-
- return CURLE_PEER_FAILED_VERIFICATION;
- }
-
- if(ssl_get_peer_cert(&(connssl->ssl))) {
- /* If the session was resumed, there will be no peer certs */
- memset(buffer, 0, sizeof(buffer));
-
- if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ",
- ssl_get_peer_cert(&(connssl->ssl))) != -1)
- infof(data, "Dumping cert info:\n%s\n", buffer);
- }
-
-#ifdef HAS_ALPN
- if(data->set.ssl_enable_alpn) {
- const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl);
-
- if(next_protocol != NULL) {
- infof(data, "ALPN, server accepted to use %s\n", next_protocol);
-
-#ifdef USE_NGHTTP2
- if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
- conn->negnpn = CURL_HTTP_VERSION_2_0;
- }
- else
-#endif
- if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) {
- conn->negnpn = CURL_HTTP_VERSION_1_1;
- }
- }
- else
- infof(data, "ALPN, server did not agree to a protocol\n");
- }
-#endif
-
- connssl->connecting_state = ssl_connect_3;
- infof(data, "SSL connected\n");
-
- return CURLE_OK;
-}
-
-static CURLcode
-polarssl_connect_step3(struct connectdata *conn,
- int sockindex)
-{
- CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- void *old_ssl_sessionid = NULL;
- ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn;
- bool incache;
-
- DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-
- /* Save the current session data for possible re-use */
- incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
- if(incache) {
- if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing\n");
- Curl_ssl_delsessionid(conn, old_ssl_sessionid);
- incache = FALSE;
- }
- }
-
- if(!incache) {
- void *new_session = malloc(sizeof(ssl_session));
-
- if(new_session) {
- memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session));
-
- result = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session));
- }
- else
- result = CURLE_OUT_OF_MEMORY;
-
- if(result) {
- failf(data, "failed to store ssl session");
- return result;
- }
- }
-
- connssl->connecting_state = ssl_connect_done;
-
- return CURLE_OK;
-}
-
-static ssize_t polarssl_send(struct connectdata *conn,
- int sockindex,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
-{
- int ret = -1;
-
- ret = ssl_write(&conn->ssl[sockindex].ssl,
- (unsigned char *)mem, len);
-
- if(ret < 0) {
- *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ?
- CURLE_AGAIN : CURLE_SEND_ERROR;
- ret = -1;
- }
-
- return ret;
-}
-
-CURL_STATIC void Curl_polarssl_close(struct connectdata *conn, int sockindex)
-{
- rsa_free(&conn->ssl[sockindex].rsa);
- x509_crt_free(&conn->ssl[sockindex].clicert);
- x509_crt_free(&conn->ssl[sockindex].cacert);
- x509_crl_free(&conn->ssl[sockindex].crl);
- ssl_free(&conn->ssl[sockindex].ssl);
-}
-
-static ssize_t polarssl_recv(struct connectdata *conn,
- int num,
- char *buf,
- size_t buffersize,
- CURLcode *curlcode)
-{
- int ret = -1;
- ssize_t len = -1;
-
- memset(buf, 0, buffersize);
- ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize);
-
- if(ret <= 0) {
- if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
- return 0;
-
- *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ?
- CURLE_AGAIN : CURLE_RECV_ERROR;
- return -1;
- }
-
- len = ret;
-
- return len;
-}
-
-CURL_STATIC void Curl_polarssl_session_free(void *ptr)
-{
- free(ptr);
-}
-
-/* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and
- higher) will be mbed TLS branded.. */
-
-CURL_STATIC size_t Curl_polarssl_version(char *buffer, size_t size)
-{
- unsigned int version = version_get_number();
- return snprintf(buffer, size, "%s/%d.%d.%d",
- version >= 0x01030A00?"mbedTLS":"PolarSSL",
- version>>24, (version>>16)&0xff, (version>>8)&0xff);
-}
-
-static CURLcode
-polarssl_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
-{
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
- int what;
-
- /* check if the connection has already been established */
- if(ssl_connection_complete == connssl->state) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- result = polarssl_connect_step1(conn, sockindex);
- if(result)
- return result;
- }
-
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
-
- /* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading ||
- connssl->connecting_state == ssl_connect_2_writing) {
-
- curl_socket_t writefd = ssl_connect_2_writing==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-
- what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* Run transaction, and return to the caller if it failed or if
- * this connection is part of a multi handle and this loop would
- * execute again. This permits the owner of a multi handle to
- * abort a connection attempt before step2 has completed while
- * ensuring that a client using select() or epoll() will always
- * have a valid fdset to wait on.
- */
- result = polarssl_connect_step2(conn, sockindex);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
- return result;
-
- } /* repeat step2 until all transactions are done. */
-
- if(ssl_connect_3 == connssl->connecting_state) {
- result = polarssl_connect_step3(conn, sockindex);
- if(result)
- return result;
- }
-
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = polarssl_recv;
- conn->send[sockindex] = polarssl_send;
- *done = TRUE;
- }
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-CURL_STATIC CURLcode
-Curl_polarssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- return polarssl_connect_common(conn, sockindex, TRUE, done);
-}
-
-
-CURL_STATIC CURLcode
-Curl_polarssl_connect(struct connectdata *conn,
- int sockindex)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = polarssl_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-/*
- * return 0 error initializing SSL
- * return 1 SSL initialized successfully
- */
-int polarssl_init(void)
-{
- return polarsslthreadlock_thread_setup();
-}
-
-void polarssl_cleanup(void)
-{
- (void)polarsslthreadlock_thread_cleanup();
-}
-
-#endif /* USE_POLARSSL */
diff --git a/libcurl/src/lib/vtls/polarssl.h b/libcurl/src/lib/vtls/polarssl.h
deleted file mode 100644
index 98c2e5c..0000000
--- a/libcurl/src/lib/vtls/polarssl.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef HEADER_CURL_POLARSSL_H
-#define HEADER_CURL_POLARSSL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#ifdef USE_POLARSSL
-
-/* Called on first use PolarSSL, setup threading if supported */
-int polarssl_init(void);
-void polarssl_cleanup(void);
-
-
-CURL_STATIC CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex);
-
-CURL_STATIC CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
- /* close a SSL connection */
-CURL_STATIC void Curl_polarssl_close(struct connectdata *conn, int sockindex);
-
-CURL_STATIC void Curl_polarssl_session_free(void *ptr);
-CURL_STATIC size_t Curl_polarssl_version(char *buffer, size_t size);
-CURL_STATIC int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
-
-/* Set the API backend definition to PolarSSL */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_POLARSSL
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* API setup for PolarSSL */
-#define curlssl_init() polarssl_init()
-#define curlssl_cleanup() polarssl_cleanup()
-#define curlssl_connect Curl_polarssl_connect
-#define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking
-#define curlssl_session_free(x) Curl_polarssl_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_polarssl_close
-#define curlssl_shutdown(x,y) 0
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_polarssl_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
-
-/* This might cause libcurl to use a weeker random!
- TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that
-*/
-#define curlssl_random(x,y,z) ((void)x, (void)y, (void)z, CURLE_NOT_BUILT_IN)
-
-#endif /* USE_POLARSSL */
-#endif /* HEADER_CURL_POLARSSL_H */
diff --git a/libcurl/src/lib/vtls/polarssl_threadlock.c b/libcurl/src/lib/vtls/polarssl_threadlock.c
deleted file mode 100644
index 8a8d3ea..0000000
--- a/libcurl/src/lib/vtls/polarssl_threadlock.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#if defined(USE_POLARSSL) && \
- (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32))
-
-#if defined(USE_THREADS_POSIX)
-# ifdef HAVE_PTHREAD_H
-# include <pthread.h>
-# endif
-#elif defined(USE_THREADS_WIN32)
-# ifdef HAVE_PROCESS_H
-# include <process.h>
-# endif
-#endif
-
-#include "polarssl_threadlock.h"
-#include "curl_printf.h"
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* number of thread locks */
-#define NUMT 2
-
-/* This array will store all of the mutexes available to PolarSSL. */
-static POLARSSL_MUTEX_T *mutex_buf = NULL;
-
-int polarsslthreadlock_thread_setup(void)
-{
- int i;
- int ret;
-
- mutex_buf = malloc(NUMT * sizeof(POLARSSL_MUTEX_T));
- if(!mutex_buf)
- return 0; /* error, no number of threads defined */
-
-#ifdef HAVE_PTHREAD_H
- for(i = 0; i < NUMT; i++) {
- ret = pthread_mutex_init(&mutex_buf[i], NULL);
- if(ret)
- return 0; /* pthread_mutex_init failed */
- }
-#elif defined(HAVE_PROCESS_H)
- for(i = 0; i < NUMT; i++) {
- mutex_buf[i] = CreateMutex(0, FALSE, 0);
- if(mutex_buf[i] == 0)
- return 0; /* CreateMutex failed */
- }
-#endif /* HAVE_PTHREAD_H */
-
- return 1; /* OK */
-}
-
-int polarsslthreadlock_thread_cleanup(void)
-{
- int i;
- int ret;
-
- if(!mutex_buf)
- return 0; /* error, no threads locks defined */
-
-#ifdef HAVE_PTHREAD_H
- for(i = 0; i < NUMT; i++) {
- ret = pthread_mutex_destroy(&mutex_buf[i]);
- if(ret)
- return 0; /* pthread_mutex_destroy failed */
- }
-#elif defined(HAVE_PROCESS_H)
- for(i = 0; i < NUMT; i++) {
- ret = CloseHandle(mutex_buf[i]);
- if(!ret)
- return 0; /* CloseHandle failed */
- }
-#endif /* HAVE_PTHREAD_H */
- free(mutex_buf);
- mutex_buf = NULL;
-
- return 1; /* OK */
-}
-
-int polarsslthreadlock_lock_function(int n)
-{
- int ret;
-#ifdef HAVE_PTHREAD_H
- if(n < NUMT) {
- ret = pthread_mutex_lock(&mutex_buf[n]);
- if(ret) {
- DEBUGF(fprintf(stderr,
- "Error: polarsslthreadlock_lock_function failed\n"));
- return 0; /* pthread_mutex_lock failed */
- }
- }
-#elif defined(HAVE_PROCESS_H)
- if(n < NUMT) {
- ret = (WaitForSingleObject(mutex_buf[n], INFINITE)==WAIT_FAILED?1:0);
- if(ret) {
- DEBUGF(fprintf(stderr,
- "Error: polarsslthreadlock_lock_function failed\n"));
- return 0; /* pthread_mutex_lock failed */
- }
- }
-#endif /* HAVE_PTHREAD_H */
- return 1; /* OK */
-}
-
-int polarsslthreadlock_unlock_function(int n)
-{
- int ret;
-#ifdef HAVE_PTHREAD_H
- if(n < NUMT) {
- ret = pthread_mutex_unlock(&mutex_buf[n]);
- if(ret) {
- DEBUGF(fprintf(stderr,
- "Error: polarsslthreadlock_unlock_function failed\n"));
- return 0; /* pthread_mutex_unlock failed */
- }
- }
-#elif defined(HAVE_PROCESS_H)
- if(n < NUMT) {
- ret = ReleaseMutex(mutex_buf[n]);
- if(!ret) {
- DEBUGF(fprintf(stderr,
- "Error: polarsslthreadlock_unlock_function failed\n"));
- return 0; /* pthread_mutex_lock failed */
- }
- }
-#endif /* HAVE_PTHREAD_H */
- return 1; /* OK */
-}
-
-#endif /* USE_POLARSSL */
diff --git a/libcurl/src/lib/vtls/polarssl_threadlock.h b/libcurl/src/lib/vtls/polarssl_threadlock.h
deleted file mode 100644
index b67b3f9..0000000
--- a/libcurl/src/lib/vtls/polarssl_threadlock.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H
-#define HEADER_CURL_POLARSSL_THREADLOCK_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "curl_setup.h"
-
-#ifdef USE_POLARSSL
-
-#if defined(USE_THREADS_POSIX)
-# define POLARSSL_MUTEX_T pthread_mutex_t
-#elif defined(USE_THREADS_WIN32)
-# define POLARSSL_MUTEX_T HANDLE
-#endif
-
-#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
-
-int polarsslthreadlock_thread_setup(void);
-int polarsslthreadlock_thread_cleanup(void);
-int polarsslthreadlock_lock_function(int n);
-int polarsslthreadlock_unlock_function(int n);
-
-#else
-
-#define polarsslthreadlock_thread_setup() 1
-#define polarsslthreadlock_thread_cleanup() 1
-#define polarsslthreadlock_lock_function(x) 1
-#define polarsslthreadlock_unlock_function(x) 1
-
-#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
-
-#endif /* USE_POLARSSL */
-
-#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */
diff --git a/libcurl/src/lib/vtls/schannel.c b/libcurl/src/lib/vtls/schannel.c
deleted file mode 100644
index 00f6b81..0000000
--- a/libcurl/src/lib/vtls/schannel.c
+++ /dev/null
@@ -1,1364 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2012 - 2014, Marc Hoersken, <info@marc-hoersken.de>
- * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/*
- * Source file for all SChannel-specific code for the TLS/SSL layer. No code
- * but vtls.c should ever call or use these functions.
- *
- */
-
-/*
- * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
- * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- *
- * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * Thanks for code and inspiration!
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_SCHANNEL
-
-#ifndef USE_WINDOWS_SSPI
-# error "Can't compile SCHANNEL support without SSPI."
-#endif
-
-#include "../curl_sspi.h"
-#include "schannel.h"
-#include "vtls.h"
-#include "../sendf.h"
-#include "../connect.h" /* for the connect timeout */
-#include "../strerror.h"
-#include "../select.h" /* for the socket readyness */
-#include "../inet_pton.h" /* for IP addr SNI check */
-#include "../curl_multibyte.h"
-#include "../warnless.h"
-#include "../curl_printf.h"
-#include "../curl_memory.h"
-/* The last #include file should be: */
-#include "../memdebug.h"
-
-/* Uncomment to force verbose output
- * #define infof(x, y, ...) printf(y, __VA_ARGS__)
- * #define failf(x, y, ...) printf(y, __VA_ARGS__)
- */
-
-static Curl_recv schannel_recv;
-static Curl_send schannel_send;
-
-#ifdef _WIN32_WCE
-static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
-#endif
-
-static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
- void *BufDataPtr, unsigned long BufByteSize)
-{
- buffer->cbBuffer = BufByteSize;
- buffer->BufferType = BufType;
- buffer->pvBuffer = BufDataPtr;
-}
-
-static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
- unsigned long NumArrElem)
-{
- desc->ulVersion = SECBUFFER_VERSION;
- desc->pBuffers = BufArr;
- desc->cBuffers = NumArrElem;
-}
-
-static CURLcode
-schannel_connect_step1(struct connectdata *conn, int sockindex)
-{
- ssize_t written = -1;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- SecBuffer outbuf;
- SecBufferDesc outbuf_desc;
- SCHANNEL_CRED schannel_cred;
- SECURITY_STATUS sspi_status = SEC_E_OK;
- struct curl_schannel_cred *old_cred = NULL;
- struct in_addr addr;
-#ifdef ENABLE_IPV6
- struct in6_addr addr6;
-#endif
- TCHAR *host_name;
- CURLcode result;
-
- infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
- conn->host.name, conn->remote_port);
-
- /* check for an existing re-usable credential handle */
- if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
- connssl->cred = old_cred;
- infof(data, "schannel: re-using existing credential handle\n");
- }
- else {
- /* setup Schannel API options */
- memset(&schannel_cred, 0, sizeof(schannel_cred));
- schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-
- if(data->set.ssl.verifypeer) {
-#ifdef _WIN32_WCE
- /* certificate validation on CE doesn't seem to work right; we'll
- do it following a more manual process. */
- schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
- SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-#else
- schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
- SCH_CRED_REVOCATION_CHECK_CHAIN;
-#endif
- infof(data, "schannel: checking server certificate revocation\n");
- }
- else {
- schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
- SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE;
- infof(data, "schannel: disable server certificate revocation checks\n");
- }
-
- if(!data->set.ssl.verifyhost) {
- schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
- infof(data, "schannel: verifyhost setting prevents Schannel from "
- "comparing the supplied target name with the subject "
- "names in server certificates. Also disables SNI.\n");
- }
-
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
- SP_PROT_TLS1_1_CLIENT |
- SP_PROT_TLS1_2_CLIENT;
- break;
- case CURL_SSLVERSION_TLSv1_0:
- schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT;
- break;
- case CURL_SSLVERSION_TLSv1_1:
- schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT;
- break;
- case CURL_SSLVERSION_TLSv1_2:
- schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
- break;
- case CURL_SSLVERSION_SSLv3:
- schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
- break;
- case CURL_SSLVERSION_SSLv2:
- schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
- break;
- }
-
- /* allocate memory for the re-usable credential handle */
- connssl->cred = (struct curl_schannel_cred *)
- malloc(sizeof(struct curl_schannel_cred));
- if(!connssl->cred) {
- failf(data, "schannel: unable to allocate memory");
- return CURLE_OUT_OF_MEMORY;
- }
- memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
-
- /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
- sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
- SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
- &connssl->cred->cred_handle, &connssl->cred->time_stamp);
-
- if(sspi_status != SEC_E_OK) {
- if(sspi_status == SEC_E_WRONG_PRINCIPAL)
- failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- else
- failf(data, "schannel: AcquireCredentialsHandle failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- Curl_safefree(connssl->cred);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- /* Warn if SNI is disabled due to use of an IP address */
- if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
-#ifdef ENABLE_IPV6
- || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
-#endif
- ) {
- infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
- }
-
- /* setup output buffer */
- InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
- InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
-
- /* setup request flags */
- connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_STREAM;
-
- /* allocate memory for the security context handle */
- connssl->ctxt = (struct curl_schannel_ctxt *)
- malloc(sizeof(struct curl_schannel_ctxt));
- if(!connssl->ctxt) {
- failf(data, "schannel: unable to allocate memory");
- return CURLE_OUT_OF_MEMORY;
- }
- memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
-
- host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
- if(!host_name)
- return CURLE_OUT_OF_MEMORY;
-
- /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
-
- sspi_status = s_pSecFn->InitializeSecurityContext(
- &connssl->cred->cred_handle, NULL, host_name,
- connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle,
- &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
-
- Curl_unicodefree(host_name);
-
- if(sspi_status != SEC_I_CONTINUE_NEEDED) {
- if(sspi_status == SEC_E_WRONG_PRINCIPAL)
- failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- else
- failf(data, "schannel: initial InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- Curl_safefree(connssl->ctxt);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- infof(data, "schannel: sending initial handshake data: "
- "sending %lu bytes...\n", outbuf.cbBuffer);
-
- /* send initial handshake data which is now stored in output buffer */
- result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
- outbuf.cbBuffer, &written);
- s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
- if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
- failf(data, "schannel: failed to send initial handshake data: "
- "sent %zd of %lu bytes", written, outbuf.cbBuffer);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- infof(data, "schannel: sent initial handshake data: "
- "sent %zd bytes\n", written);
-
- /* continue to second handshake step */
- connssl->connecting_state = ssl_connect_2;
-
- return CURLE_OK;
-}
-
-static CURLcode
-schannel_connect_step2(struct connectdata *conn, int sockindex)
-{
- int i;
- ssize_t nread = -1, written = -1;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- unsigned char *reallocated_buffer;
- size_t reallocated_length;
- SecBuffer outbuf[2];
- SecBufferDesc outbuf_desc;
- SecBuffer inbuf[2];
- SecBufferDesc inbuf_desc;
- SECURITY_STATUS sspi_status = SEC_E_OK;
- TCHAR *host_name;
- CURLcode result;
- bool doread;
-
- doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
-
- infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
- conn->host.name, conn->remote_port);
-
- if(!connssl->cred || !connssl->ctxt)
- return CURLE_SSL_CONNECT_ERROR;
-
- /* buffer to store previously received and encrypted data */
- if(connssl->encdata_buffer == NULL) {
- connssl->encdata_offset = 0;
- connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
- connssl->encdata_buffer = malloc(connssl->encdata_length);
- if(connssl->encdata_buffer == NULL) {
- failf(data, "schannel: unable to allocate memory");
- return CURLE_OUT_OF_MEMORY;
- }
- }
-
- /* if we need a bigger buffer to read a full message, increase buffer now */
- if(connssl->encdata_length - connssl->encdata_offset <
- CURL_SCHANNEL_BUFFER_FREE_SIZE) {
- /* increase internal encrypted data buffer */
- reallocated_length = connssl->encdata_offset +
- CURL_SCHANNEL_BUFFER_FREE_SIZE;
- reallocated_buffer = realloc(connssl->encdata_buffer,
- reallocated_length);
-
- if(reallocated_buffer == NULL) {
- failf(data, "schannel: unable to re-allocate memory");
- return CURLE_OUT_OF_MEMORY;
- }
- else {
- connssl->encdata_buffer = reallocated_buffer;
- connssl->encdata_length = reallocated_length;
- }
- }
-
- for(;;) {
- if(doread) {
- /* read encrypted handshake data from socket */
- result = Curl_read_plain(conn->sock[sockindex],
- (char *) (connssl->encdata_buffer +
- connssl->encdata_offset),
- connssl->encdata_length -
- connssl->encdata_offset,
- &nread);
- if(result == CURLE_AGAIN) {
- if(connssl->connecting_state != ssl_connect_2_writing)
- connssl->connecting_state = ssl_connect_2_reading;
- infof(data, "schannel: failed to receive handshake, "
- "need more data\n");
- return CURLE_OK;
- }
- else if((result != CURLE_OK) || (nread == 0)) {
- failf(data, "schannel: failed to receive handshake, "
- "SSL/TLS connection failed");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* increase encrypted data buffer offset */
- connssl->encdata_offset += nread;
- }
-
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
-
- /* setup input buffers */
- InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
- curlx_uztoul(connssl->encdata_offset));
- InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
- InitSecBufferDesc(&inbuf_desc, inbuf, 2);
-
- /* setup output buffers */
- InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
- InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
- InitSecBufferDesc(&outbuf_desc, outbuf, 2);
-
- if(inbuf[0].pvBuffer == NULL) {
- failf(data, "schannel: unable to allocate memory");
- return CURLE_OUT_OF_MEMORY;
- }
-
- /* copy received handshake data into input buffer */
- memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
- connssl->encdata_offset);
-
- host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
- if(!host_name)
- return CURLE_OUT_OF_MEMORY;
-
- /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
-
- sspi_status = s_pSecFn->InitializeSecurityContext(
- &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
- host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
- &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
-
- Curl_unicodefree(host_name);
-
- /* free buffer for received handshake data */
- Curl_safefree(inbuf[0].pvBuffer);
-
- /* check if the handshake was incomplete */
- if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- connssl->connecting_state = ssl_connect_2_reading;
- infof(data, "schannel: received incomplete message, need more data\n");
- return CURLE_OK;
- }
-
- /* check if the handshake needs to be continued */
- if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
- for(i = 0; i < 2; i++) {
- /* search for handshake tokens that need to be send */
- if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
- infof(data, "schannel: sending next handshake data: "
- "sending %lu bytes...\n", outbuf[i].cbBuffer);
-
- /* send handshake token to server */
- result = Curl_write_plain(conn, conn->sock[sockindex],
- outbuf[i].pvBuffer, outbuf[i].cbBuffer,
- &written);
- if((result != CURLE_OK) ||
- (outbuf[i].cbBuffer != (size_t) written)) {
- failf(data, "schannel: failed to send next handshake data: "
- "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- /* free obsolete buffer */
- if(outbuf[i].pvBuffer != NULL) {
- s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
- }
- }
- }
- else {
- if(sspi_status == SEC_E_WRONG_PRINCIPAL)
- failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- else
- failf(data, "schannel: next InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* check if there was additional remaining encrypted data */
- if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
- infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
- /*
- There are two cases where we could be getting extra data here:
- 1) If we're renegotiating a connection and the handshake is already
- complete (from the server perspective), it can encrypted app data
- (not handshake data) in an extra buffer at this point.
- 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
- connection and this extra data is part of the handshake.
- We should process the data immediately; waiting for the socket to
- be ready may fail since the server is done sending handshake data.
- */
- /* check if the remaining data is less than the total amount
- and therefore begins after the already processed data */
- if(connssl->encdata_offset > inbuf[1].cbBuffer) {
- memmove(connssl->encdata_buffer,
- (connssl->encdata_buffer + connssl->encdata_offset) -
- inbuf[1].cbBuffer, inbuf[1].cbBuffer);
- connssl->encdata_offset = inbuf[1].cbBuffer;
- if(sspi_status == SEC_I_CONTINUE_NEEDED) {
- doread = FALSE;
- continue;
- }
- }
- }
- else {
- connssl->encdata_offset = 0;
- }
- break;
- }
-
- /* check if the handshake needs to be continued */
- if(sspi_status == SEC_I_CONTINUE_NEEDED) {
- connssl->connecting_state = ssl_connect_2_reading;
- return CURLE_OK;
- }
-
- /* check if the handshake is complete */
- if(sspi_status == SEC_E_OK) {
- connssl->connecting_state = ssl_connect_3;
- infof(data, "schannel: SSL/TLS handshake complete\n");
- }
-
-#ifdef _WIN32_WCE
- /* Windows CE doesn't do any server certificate validation.
- We have to do it manually. */
- if(data->set.ssl.verifypeer)
- return verify_certificate(conn, sockindex);
-#endif
-
- return CURLE_OK;
-}
-
-static CURLcode
-schannel_connect_step3(struct connectdata *conn, int sockindex)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct curl_schannel_cred *old_cred = NULL;
- bool incache;
-
- DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-
- infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
- conn->host.name, conn->remote_port);
-
- if(!connssl->cred)
- return CURLE_SSL_CONNECT_ERROR;
-
- /* check if the required context attributes are met */
- if(connssl->ret_flags != connssl->req_flags) {
- if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
- failf(data, "schannel: failed to setup sequence detection");
- if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
- failf(data, "schannel: failed to setup replay detection");
- if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
- failf(data, "schannel: failed to setup confidentiality");
- if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
- failf(data, "schannel: failed to setup memory allocation");
- if(!(connssl->ret_flags & ISC_RET_STREAM))
- failf(data, "schannel: failed to setup stream orientation");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* increment the reference counter of the credential/session handle */
- if(connssl->cred && connssl->ctxt) {
- connssl->cred->refcount++;
- infof(data, "schannel: incremented credential handle refcount = %d\n",
- connssl->cred->refcount);
- }
-
- /* save the current session data for possible re-use */
- incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
- if(incache) {
- if(old_cred != connssl->cred) {
- infof(data, "schannel: old credential handle is stale, removing\n");
- Curl_ssl_delsessionid(conn, (void *)old_cred);
- incache = FALSE;
- }
- }
-
- if(!incache) {
- result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
- sizeof(struct curl_schannel_cred));
- if(result) {
- failf(data, "schannel: failed to store credential handle");
- return result;
- }
- else {
- connssl->cred->cached = TRUE;
- infof(data, "schannel: stored credential handle in session cache\n");
- }
- }
-
- connssl->connecting_state = ssl_connect_done;
-
- return CURLE_OK;
-}
-
-static CURLcode
-schannel_connect_common(struct connectdata *conn, int sockindex,
- bool nonblocking, bool *done)
-{
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
- int what;
-
- /* check if the connection has already been established */
- if(ssl_connection_complete == connssl->state) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- if(ssl_connect_1 == connssl->connecting_state) {
- /* check out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL/TLS connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- result = schannel_connect_step1(conn, sockindex);
- if(result)
- return result;
- }
-
- while(ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
-
- /* check out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL/TLS connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- /* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
-
- curl_socket_t writefd = ssl_connect_2_writing ==
- connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading ==
- connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
-
- what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL/TLS connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* Run transaction, and return to the caller if it failed or if
- * this connection is part of a multi handle and this loop would
- * execute again. This permits the owner of a multi handle to
- * abort a connection attempt before step2 has completed while
- * ensuring that a client using select() or epoll() will always
- * have a valid fdset to wait on.
- */
- result = schannel_connect_step2(conn, sockindex);
- if(result || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
- return result;
-
- } /* repeat step2 until all transactions are done. */
-
- if(ssl_connect_3 == connssl->connecting_state) {
- result = schannel_connect_step3(conn, sockindex);
- if(result)
- return result;
- }
-
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = schannel_recv;
- conn->send[sockindex] = schannel_send;
- *done = TRUE;
- }
- else
- *done = FALSE;
-
- /* reset our connection state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-static ssize_t
-schannel_send(struct connectdata *conn, int sockindex,
- const void *buf, size_t len, CURLcode *err)
-{
- ssize_t written = -1;
- size_t data_len = 0;
- unsigned char *data = NULL;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- SecBuffer outbuf[4];
- SecBufferDesc outbuf_desc;
- SECURITY_STATUS sspi_status = SEC_E_OK;
- CURLcode result;
-
- /* check if the maximum stream sizes were queried */
- if(connssl->stream_sizes.cbMaximumMessage == 0) {
- sspi_status = s_pSecFn->QueryContextAttributes(
- &connssl->ctxt->ctxt_handle,
- SECPKG_ATTR_STREAM_SIZES,
- &connssl->stream_sizes);
- if(sspi_status != SEC_E_OK) {
- *err = CURLE_SEND_ERROR;
- return -1;
- }
- }
-
- /* check if the buffer is longer than the maximum message length */
- if(len > connssl->stream_sizes.cbMaximumMessage) {
- *err = CURLE_SEND_ERROR;
- return -1;
- }
-
- /* calculate the complete message length and allocate a buffer for it */
- data_len = connssl->stream_sizes.cbHeader + len +
- connssl->stream_sizes.cbTrailer;
- data = (unsigned char *) malloc(data_len);
- if(data == NULL) {
- *err = CURLE_OUT_OF_MEMORY;
- return -1;
- }
-
- /* setup output buffers (header, data, trailer, empty) */
- InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
- data, connssl->stream_sizes.cbHeader);
- InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
- data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
- InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
- data + connssl->stream_sizes.cbHeader + len,
- connssl->stream_sizes.cbTrailer);
- InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
- InitSecBufferDesc(&outbuf_desc, outbuf, 4);
-
- /* copy data into output buffer */
- memcpy(outbuf[1].pvBuffer, buf, len);
-
- /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
- sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
- &outbuf_desc, 0);
-
- /* check if the message was encrypted */
- if(sspi_status == SEC_E_OK) {
- written = 0;
-
- /* send the encrypted message including header, data and trailer */
- len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
-
- /*
- It's important to send the full message which includes the header,
- encrypted payload, and trailer. Until the client receives all the
- data a coherent message has not been delivered and the client
- can't read any of it.
-
- If we wanted to buffer the unwritten encrypted bytes, we would
- tell the client that all data it has requested to be sent has been
- sent. The unwritten encrypted bytes would be the first bytes to
- send on the next invocation.
- Here's the catch with this - if we tell the client that all the
- bytes have been sent, will the client call this method again to
- send the buffered data? Looking at who calls this function, it
- seems the answer is NO.
- */
-
- /* send entire message or fail */
- while(len > (size_t)written) {
- ssize_t this_write;
- long timeleft;
- int what;
-
- this_write = 0;
-
- timeleft = Curl_timeleft(conn->data, NULL, FALSE);
- if(timeleft < 0) {
- /* we already got the timeout */
- failf(conn->data, "schannel: timed out sending data "
- "(bytes sent: %zd)", written);
- *err = CURLE_OPERATION_TIMEDOUT;
- written = -1;
- break;
- }
-
- what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex],
- timeleft);
- if(what < 0) {
- /* fatal error */
- failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- *err = CURLE_SEND_ERROR;
- written = -1;
- break;
- }
- else if(0 == what) {
- failf(conn->data, "schannel: timed out sending data "
- "(bytes sent: %zd)", written);
- *err = CURLE_OPERATION_TIMEDOUT;
- written = -1;
- break;
- }
- /* socket is writable */
-
- result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
- len - written, &this_write);
- if(result == CURLE_AGAIN)
- continue;
- else if(result != CURLE_OK) {
- *err = result;
- written = -1;
- break;
- }
-
- written += this_write;
- }
- }
- else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
- *err = CURLE_OUT_OF_MEMORY;
- }
- else{
- *err = CURLE_SEND_ERROR;
- }
-
- Curl_safefree(data);
-
- if(len == (size_t)written)
- /* Encrypted message including header, data and trailer entirely sent.
- The return value is the number of unencrypted bytes that were sent. */
- written = outbuf[1].cbBuffer;
-
- return written;
-}
-
-static ssize_t
-schannel_recv(struct connectdata *conn, int sockindex,
- char *buf, size_t len, CURLcode *err)
-{
- size_t size = 0;
- ssize_t nread = 0, ret = -1;
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- unsigned char *reallocated_buffer;
- size_t reallocated_length;
- bool done = FALSE;
- SecBuffer inbuf[4];
- SecBufferDesc inbuf_desc;
- SECURITY_STATUS sspi_status = SEC_E_OK;
-
- infof(data, "schannel: client wants to read %zu bytes\n", len);
- *err = CURLE_OK;
-
- /* buffer to store previously received and decrypted data */
- if(connssl->decdata_buffer == NULL) {
- connssl->decdata_offset = 0;
- connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
- connssl->decdata_buffer = malloc(connssl->decdata_length);
- if(connssl->decdata_buffer == NULL) {
- failf(data, "schannel: unable to allocate memory");
- *err = CURLE_OUT_OF_MEMORY;
- return -1;
- }
- }
-
- /* increase buffer in order to fit the requested amount of data */
- if(connssl->encdata_length - connssl->encdata_offset <
- CURL_SCHANNEL_BUFFER_FREE_SIZE || connssl->encdata_length < len) {
- /* increase internal encrypted data buffer */
- reallocated_length = connssl->encdata_offset +
- CURL_SCHANNEL_BUFFER_FREE_SIZE;
- /* make sure that the requested amount of data fits */
- if(reallocated_length < len) {
- reallocated_length = len;
- }
- reallocated_buffer = realloc(connssl->encdata_buffer,
- reallocated_length);
-
- if(reallocated_buffer == NULL) {
- failf(data, "schannel: unable to re-allocate memory");
- *err = CURLE_OUT_OF_MEMORY;
- return -1;
- }
- else {
- connssl->encdata_buffer = reallocated_buffer;
- connssl->encdata_length = reallocated_length;
- }
- }
-
- /* read encrypted data from socket */
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
- size = connssl->encdata_length - connssl->encdata_offset;
- if(size > 0) {
- *err = Curl_read_plain(conn->sock[sockindex],
- (char *) (connssl->encdata_buffer + connssl->encdata_offset),
- size, &nread);
- /* check for received data */
- if(*err != CURLE_OK)
- ret = -1;
- else {
- if(nread > 0)
- /* increase encrypted data buffer offset */
- connssl->encdata_offset += nread;
- ret = nread;
- }
- infof(data, "schannel: encrypted data got %zd\n", ret);
- }
-
- infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
-
- /* check if we still have some data in our buffers */
- while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
- connssl->decdata_offset < len) {
- /* prepare data buffer for DecryptMessage call */
- InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
- curlx_uztoul(connssl->encdata_offset));
-
- /* we need 3 more empty input buffers for possible output */
- InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
- InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
- InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
-
- InitSecBufferDesc(&inbuf_desc, inbuf, 4);
-
- /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
- sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
- &inbuf_desc, 0, NULL);
-
- /* check if we need more data */
- if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- infof(data, "schannel: failed to decrypt data, need more data\n");
- *err = CURLE_AGAIN;
- return -1;
- }
-
- /* check if everything went fine (server may want to renegotiate
- or shutdown the connection context) */
- if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
- sspi_status == SEC_I_CONTEXT_EXPIRED) {
- /* check for successfully decrypted data, even before actual
- renegotiation or shutdown of the connection context */
- if(inbuf[1].BufferType == SECBUFFER_DATA) {
- infof(data, "schannel: decrypted data length: %lu\n",
- inbuf[1].cbBuffer);
-
- /* increase buffer in order to fit the received amount of data */
- size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
- inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
- if(connssl->decdata_length - connssl->decdata_offset < size ||
- connssl->decdata_length < len) {
- /* increase internal decrypted data buffer */
- reallocated_length = connssl->decdata_offset + size;
- /* make sure that the requested amount of data fits */
- if(reallocated_length < len) {
- reallocated_length = len;
- }
- reallocated_buffer = realloc(connssl->decdata_buffer,
- reallocated_length);
-
- if(reallocated_buffer == NULL) {
- failf(data, "schannel: unable to re-allocate memory");
- *err = CURLE_OUT_OF_MEMORY;
- return -1;
- }
- else {
- connssl->decdata_buffer = reallocated_buffer;
- connssl->decdata_length = reallocated_length;
- }
- }
-
- /* copy decrypted data to internal buffer */
- size = inbuf[1].cbBuffer;
- if(size > 0) {
- memcpy(connssl->decdata_buffer + connssl->decdata_offset,
- inbuf[1].pvBuffer, size);
- connssl->decdata_offset += size;
- }
-
- infof(data, "schannel: decrypted data added: %zu\n", size);
- infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
- connssl->decdata_offset, connssl->decdata_length);
- }
-
- /* check for remaining encrypted data */
- if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
- infof(data, "schannel: encrypted data length: %lu\n",
- inbuf[3].cbBuffer);
-
- /* check if the remaining data is less than the total amount
- * and therefore begins after the already processed data
- */
- if(connssl->encdata_offset > inbuf[3].cbBuffer) {
- /* move remaining encrypted data forward to the beginning of
- buffer */
- memmove(connssl->encdata_buffer,
- (connssl->encdata_buffer + connssl->encdata_offset) -
- inbuf[3].cbBuffer, inbuf[3].cbBuffer);
- connssl->encdata_offset = inbuf[3].cbBuffer;
- }
-
- infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
- }
- else{
- /* reset encrypted buffer offset, because there is no data remaining */
- connssl->encdata_offset = 0;
- }
- }
-
- /* check if server wants to renegotiate the connection context */
- if(sspi_status == SEC_I_RENEGOTIATE) {
- infof(data, "schannel: remote party requests SSL/TLS renegotiation\n");
-
- /* begin renegotiation */
- infof(data, "schannel: renegotiating SSL/TLS connection\n");
- connssl->state = ssl_connection_negotiating;
- connssl->connecting_state = ssl_connect_2_writing;
- result = schannel_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- *err = result;
- else {
- infof(data, "schannel: SSL/TLS connection renegotiated\n");
- /* now retry receiving data */
- return schannel_recv(conn, sockindex, buf, len, err);
- }
- }
- }
-
- infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
- connssl->decdata_offset, connssl->decdata_length);
-
- /* copy requested decrypted data to supplied buffer */
- size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
- if(size > 0) {
- memcpy(buf, connssl->decdata_buffer, size);
- ret = size;
-
- /* move remaining decrypted data forward to the beginning of buffer */
- memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
- connssl->decdata_offset - size);
- connssl->decdata_offset -= size;
-
- infof(data, "schannel: decrypted data returned %zd\n", size);
- infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
- connssl->decdata_offset, connssl->decdata_length);
- }
- else
- ret = 0;
-
- /* check if the server closed the connection */
- if(ret <= 0 && ( /* special check for Windows 2000 Professional */
- sspi_status == SEC_I_CONTEXT_EXPIRED || (sspi_status == SEC_E_OK &&
- connssl->encdata_offset > 0 && connssl->encdata_buffer[0] == 0x15))) {
- infof(data, "schannel: server closed the connection\n");
- *err = CURLE_OK;
- return 0;
- }
-
- /* check if something went wrong and we need to return an error */
- if(ret < 0 && sspi_status != SEC_E_OK) {
- infof(data, "schannel: failed to read data from server: %s\n",
- Curl_sspi_strerror(conn, sspi_status));
- *err = CURLE_RECV_ERROR;
- return -1;
- }
-
- return ret;
-}
-
-CURL_STATIC CURLcode
-Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
- bool *done)
-{
- return schannel_connect_common(conn, sockindex, TRUE, done);
-}
-
-CURL_STATIC CURLcode
-Curl_schannel_connect(struct connectdata *conn, int sockindex)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = schannel_connect_common(conn, sockindex, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-CURL_STATIC bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
-{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- if(connssl->use) /* SSL/TLS is in use */
- return (connssl->encdata_offset > 0 ||
- connssl->decdata_offset > 0 ) ? TRUE : FALSE;
- else
- return FALSE;
-}
-
-CURL_STATIC void Curl_schannel_close(struct connectdata *conn, int sockindex)
-{
- if(conn->ssl[sockindex].use)
- /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
- Curl_ssl_shutdown(conn, sockindex);
-}
-
-CURL_STATIC int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
-{
- /* See http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
- * Shutting Down an Schannel Connection
- */
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
- conn->host.name, conn->remote_port);
-
- if(connssl->cred && connssl->ctxt) {
- SecBufferDesc BuffDesc;
- SecBuffer Buffer;
- SECURITY_STATUS sspi_status;
- SecBuffer outbuf;
- SecBufferDesc outbuf_desc;
- CURLcode result;
- TCHAR *host_name;
- DWORD dwshut = SCHANNEL_SHUTDOWN;
-
- InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
- InitSecBufferDesc(&BuffDesc, &Buffer, 1);
-
- sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
- &BuffDesc);
-
- if(sspi_status != SEC_E_OK)
- failf(data, "schannel: ApplyControlToken failure: %s",
- Curl_sspi_strerror(conn, sspi_status));
-
- host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
- if(!host_name)
- return CURLE_OUT_OF_MEMORY;
-
- /* setup output buffer */
- InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
- InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
-
- sspi_status = s_pSecFn->InitializeSecurityContext(
- &connssl->cred->cred_handle,
- &connssl->ctxt->ctxt_handle,
- host_name,
- connssl->req_flags,
- 0,
- 0,
- NULL,
- 0,
- &connssl->ctxt->ctxt_handle,
- &outbuf_desc,
- &connssl->ret_flags,
- &connssl->ctxt->time_stamp);
-
- Curl_unicodefree(host_name);
-
- if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
- /* send close message which is in output buffer */
- ssize_t written;
- result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
- outbuf.cbBuffer, &written);
-
- s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
- if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
- infof(data, "schannel: failed to send close msg: %s"
- " (bytes written: %zd)\n", curl_easy_strerror(result), written);
- }
- }
- }
-
- /* free SSPI Schannel API security context handle */
- if(connssl->ctxt) {
- infof(data, "schannel: clear security context handle\n");
- s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
- Curl_safefree(connssl->ctxt);
- }
-
- /* free SSPI Schannel API credential handle */
- if(connssl->cred) {
- /* decrement the reference counter of the credential/session handle */
- if(connssl->cred->refcount > 0) {
- connssl->cred->refcount--;
- infof(data, "schannel: decremented credential handle refcount = %d\n",
- connssl->cred->refcount);
- }
-
- /* if the handle was not cached and the refcount is zero */
- if(!connssl->cred->cached && connssl->cred->refcount == 0) {
- infof(data, "schannel: clear credential handle\n");
- s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle);
- Curl_safefree(connssl->cred);
- }
- }
-
- /* free internal buffer for received encrypted data */
- if(connssl->encdata_buffer != NULL) {
- Curl_safefree(connssl->encdata_buffer);
- connssl->encdata_length = 0;
- connssl->encdata_offset = 0;
- }
-
- /* free internal buffer for received decrypted data */
- if(connssl->decdata_buffer != NULL) {
- Curl_safefree(connssl->decdata_buffer);
- connssl->decdata_length = 0;
- connssl->decdata_offset = 0;
- }
-
- return CURLE_OK;
-}
-
-CURL_STATIC void Curl_schannel_session_free(void *ptr)
-{
- struct curl_schannel_cred *cred = ptr;
-
- if(cred && cred->cached) {
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- Curl_safefree(cred);
- }
- else {
- cred->cached = FALSE;
- }
- }
-}
-
-CURL_STATIC int Curl_schannel_init(void)
-{
- return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
-}
-
-CURL_STATIC void Curl_schannel_cleanup(void)
-{
- Curl_sspi_global_cleanup();
-}
-
-CURL_STATIC size_t Curl_schannel_version(char *buffer, size_t size)
-{
- size = snprintf(buffer, size, "WinSSL");
-
- return size;
-}
-
-CURL_STATIC int Curl_schannel_random(unsigned char *entropy, size_t length)
-{
- HCRYPTPROV hCryptProv = 0;
-
- if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
- return 1;
-
- if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
- CryptReleaseContext(hCryptProv, 0UL);
- return 1;
- }
-
- CryptReleaseContext(hCryptProv, 0UL);
- return 0;
-}
-
-#ifdef _WIN32_WCE
-static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
-{
- SECURITY_STATUS status;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- CURLcode result = CURLE_OK;
- CERT_CONTEXT *pCertContextServer = NULL;
- const CERT_CHAIN_CONTEXT *pChainContext = NULL;
-
- status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &pCertContextServer);
-
- if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
- failf(data, "schannel: Failed to read remote certificate context: %s",
- Curl_sspi_strerror(conn, status));
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
-
- if(result == CURLE_OK) {
- CERT_CHAIN_PARA ChainPara;
- memset(&ChainPara, 0, sizeof(ChainPara));
- ChainPara.cbSize = sizeof(ChainPara);
-
- if(!CertGetCertificateChain(NULL,
- pCertContextServer,
- NULL,
- pCertContextServer->hCertStore,
- &ChainPara,
- 0,
- NULL,
- &pChainContext)) {
- failf(data, "schannel: CertGetCertificateChain failed: %s",
- Curl_sspi_strerror(conn, GetLastError()));
- pChainContext = NULL;
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
-
- if(result == CURLE_OK) {
- CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
- DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED|
- CERT_TRUST_REVOCATION_STATUS_UNKNOWN);
- dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
- if(dwTrustErrorMask) {
- if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_PARTIAL_CHAIN");
- if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_UNTRUSTED_ROOT");
- if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
- failf(data, "schannel: CertGetCertificateChain trust error"
- " CERT_TRUST_IS_NOT_TIME_VALID");
- failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
- dwTrustErrorMask);
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- }
- }
-
- if(result == CURLE_OK) {
- if(data->set.ssl.verifyhost) {
- TCHAR cert_hostname_buff[128];
- xcharp_u hostname;
- xcharp_u cert_hostname;
- DWORD len;
-
- cert_hostname.const_tchar_ptr = cert_hostname_buff;
- hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name);
-
- len = CertGetNameString(pCertContextServer,
- CERT_NAME_DNS_TYPE,
- 0,
- NULL,
- cert_hostname.tchar_ptr,
- 128);
- if(len > 0 && *cert_hostname.tchar_ptr == '*') {
- /* this is a wildcard cert. try matching the last len - 1 chars */
- int hostname_len = strlen(conn->host.name);
- cert_hostname.tchar_ptr++;
- if(_tcsicmp(cert_hostname.const_tchar_ptr,
- hostname.const_tchar_ptr + hostname_len - len + 2) != 0)
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr,
- cert_hostname.const_tchar_ptr) != 0) {
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- if(result == CURLE_PEER_FAILED_VERIFICATION) {
- char *_cert_hostname;
- _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr);
- failf(data, "schannel: CertGetNameString() certificate hostname "
- "(%s) did not match connection (%s)",
- _cert_hostname, conn->host.name);
- Curl_unicodefree(_cert_hostname);
- }
- Curl_unicodefree(hostname.tchar_ptr);
- }
- }
-
- if(pChainContext)
- CertFreeCertificateChain(pChainContext);
-
- if(pCertContextServer)
- CertFreeCertificateContext(pCertContextServer);
-
- return result;
-}
-#endif /* _WIN32_WCE */
-
-#endif /* USE_SCHANNEL */
diff --git a/libcurl/src/lib/vtls/schannel.h b/libcurl/src/lib/vtls/schannel.h
deleted file mode 100644
index e48dd97..0000000
--- a/libcurl/src/lib/vtls/schannel.h
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifndef HEADER_CURL_SCHANNEL_H
-#define HEADER_CURL_SCHANNEL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#ifdef USE_SCHANNEL
-
-#include "../urldata.h"
-
-#ifndef UNISP_NAME_A
-#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
-#endif
-
-#ifndef UNISP_NAME_W
-#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
-#endif
-
-#ifndef UNISP_NAME
-#ifdef UNICODE
-#define UNISP_NAME UNISP_NAME_W
-#else
-#define UNISP_NAME UNISP_NAME_A
-#endif
-#endif
-
-#ifndef SP_PROT_SSL2_CLIENT
-#define SP_PROT_SSL2_CLIENT 0x00000008
-#endif
-
-#ifndef SP_PROT_SSL3_CLIENT
-#define SP_PROT_SSL3_CLIENT 0x00000008
-#endif
-
-#ifndef SP_PROT_TLS1_CLIENT
-#define SP_PROT_TLS1_CLIENT 0x00000080
-#endif
-
-#ifndef SP_PROT_TLS1_0_CLIENT
-#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
-#endif
-
-#ifndef SP_PROT_TLS1_1_CLIENT
-#define SP_PROT_TLS1_1_CLIENT 0x00000200
-#endif
-
-#ifndef SP_PROT_TLS1_2_CLIENT
-#define SP_PROT_TLS1_2_CLIENT 0x00000800
-#endif
-
-#ifndef SECBUFFER_ALERT
-#define SECBUFFER_ALERT 17
-#endif
-
-#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
-#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
-
-
-CURL_STATIC CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
-
-CURL_STATIC CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-CURL_STATIC bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
-CURL_STATIC void Curl_schannel_close(struct connectdata *conn, int sockindex);
-CURL_STATIC int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC void Curl_schannel_session_free(void *ptr);
-
-CURL_STATIC int Curl_schannel_init(void);
-CURL_STATIC void Curl_schannel_cleanup(void);
-CURL_STATIC size_t Curl_schannel_version(char *buffer, size_t size);
-
-CURL_STATIC int Curl_schannel_random(unsigned char *entropy, size_t length);
-
-/* Set the API backend definition to Schannel */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL
-
-/* API setup for Schannel */
-#define curlssl_init Curl_schannel_init
-#define curlssl_cleanup Curl_schannel_cleanup
-#define curlssl_connect Curl_schannel_connect
-#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking
-#define curlssl_session_free Curl_schannel_session_free
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_schannel_close
-#define curlssl_shutdown Curl_schannel_shutdown
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_schannel_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending Curl_schannel_data_pending
-#define curlssl_random(x,y,z) ((void)x, Curl_schannel_random(y,z))
-
-#endif /* USE_SCHANNEL */
-#endif /* HEADER_CURL_SCHANNEL_H */
diff --git a/libcurl/src/lib/vtls/vtls.c b/libcurl/src/lib/vtls/vtls.c
deleted file mode 100644
index b7f7059..0000000
--- a/libcurl/src/lib/vtls/vtls.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-/* This file is for implementing all "generic" SSL functions that all libcurl
- internals should use. It is then responsible for calling the proper
- "backend" function.
-
- SSL-functions in libcurl should call functions in this source file, and not
- to any specific SSL-layer.
-
- Curl_ssl_ - prefix for generic ones
- Curl_ossl_ - prefix for OpenSSL ones
- Curl_gtls_ - prefix for GnuTLS ones
- Curl_nss_ - prefix for NSS ones
- Curl_gskit_ - prefix for GSKit ones
- Curl_polarssl_ - prefix for PolarSSL ones
- Curl_cyassl_ - prefix for CyaSSL ones
- Curl_schannel_ - prefix for Schannel SSPI ones
- Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones
-
- Note that this source code uses curlssl_* functions, and they are all
- defines/macros #defined by the lib-specific header files.
-
- "SSL/TLS Strong Encryption: An Introduction"
- http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
-*/
-
-#include "../curl_setup.h"
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#include "../urldata.h"
-
-#include "vtls.h" /* generic SSL protos etc */
-#include "../slist.h"
-#include "../sendf.h"
-#include "../rawstr.h"
-#include "../url.h"
-#include "../progress.h"
-#include "../share.h"
-#include "../timeval.h"
-#include "../curl_md5.h"
-#include "../warnless.h"
-#include "../curl_base64.h"
-#include "../curl_printf.h"
-
-/* The last #include files should be: */
-#include "../curl_memory.h"
-#include "../memdebug.h"
-
-/* convenience macro to check if this handle is using a shared SSL session */
-#define SSLSESSION_SHARED(data) (data->share && \
- (data->share->specifier & \
- (1<<CURL_LOCK_DATA_SSL_SESSION)))
-
-static bool safe_strequal(char* str1, char* str2)
-{
- if(str1 && str2)
- /* both pointers point to something then compare them */
- return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE;
- else
- /* if both pointers are NULL then treat them as equal */
- return (!str1 && !str2) ? TRUE : FALSE;
-}
-
-CURL_STATIC bool
-Curl_ssl_config_matches(struct ssl_config_data* data,
- struct ssl_config_data* needle)
-{
- if((data->version == needle->version) &&
- (data->verifypeer == needle->verifypeer) &&
- (data->verifyhost == needle->verifyhost) &&
- safe_strequal(data->CApath, needle->CApath) &&
- safe_strequal(data->CAfile, needle->CAfile) &&
- safe_strequal(data->random_file, needle->random_file) &&
- safe_strequal(data->egdsocket, needle->egdsocket) &&
- safe_strequal(data->cipher_list, needle->cipher_list))
- return TRUE;
-
- return FALSE;
-}
-
-CURL_STATIC bool
-Curl_clone_ssl_config(struct ssl_config_data *source,
- struct ssl_config_data *dest)
-{
- dest->sessionid = source->sessionid;
- dest->verifyhost = source->verifyhost;
- dest->verifypeer = source->verifypeer;
- dest->version = source->version;
-
- if(source->CAfile) {
- dest->CAfile = strdup(source->CAfile);
- if(!dest->CAfile)
- return FALSE;
- }
- else
- dest->CAfile = NULL;
-
- if(source->CApath) {
- dest->CApath = strdup(source->CApath);
- if(!dest->CApath)
- return FALSE;
- }
- else
- dest->CApath = NULL;
-
- if(source->cipher_list) {
- dest->cipher_list = strdup(source->cipher_list);
- if(!dest->cipher_list)
- return FALSE;
- }
- else
- dest->cipher_list = NULL;
-
- if(source->egdsocket) {
- dest->egdsocket = strdup(source->egdsocket);
- if(!dest->egdsocket)
- return FALSE;
- }
- else
- dest->egdsocket = NULL;
-
- if(source->random_file) {
- dest->random_file = strdup(source->random_file);
- if(!dest->random_file)
- return FALSE;
- }
- else
- dest->random_file = NULL;
-
- return TRUE;
-}
-
-CURL_STATIC void Curl_free_ssl_config(struct ssl_config_data* sslc)
-{
- Curl_safefree(sslc->CAfile);
- Curl_safefree(sslc->CApath);
- Curl_safefree(sslc->cipher_list);
- Curl_safefree(sslc->egdsocket);
- Curl_safefree(sslc->random_file);
-}
-
-
-/*
- * Curl_rand() returns a random unsigned integer, 32bit.
- *
- * This non-SSL function is put here only because this file is the only one
- * with knowledge of what the underlying SSL libraries provide in terms of
- * randomizers.
- *
- * NOTE: 'data' may be passed in as NULL when coming from external API without
- * easy handle!
- *
- */
-
-CURL_STATIC unsigned int Curl_rand(struct SessionHandle *data)
-{
- unsigned int r = 0;
- static unsigned int randseed;
- static bool seeded = FALSE;
-
-#ifdef CURLDEBUG
- char *force_entropy = getenv("CURL_ENTROPY");
- if(force_entropy) {
- if(!seeded) {
- size_t elen = strlen(force_entropy);
- size_t clen = sizeof(randseed);
- size_t min = elen < clen ? elen : clen;
- memcpy((char *)&randseed, force_entropy, min);
- seeded = TRUE;
- }
- else
- randseed++;
- return randseed;
- }
-#endif
-
- /* data may be NULL! */
- if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r)))
- return r;
-
- /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we
- instead perform a "best effort" */
-
-#ifdef RANDOM_FILE
- if(!seeded) {
- /* if there's a random file to read a seed from, use it */
- int fd = open(RANDOM_FILE, O_RDONLY);
- if(fd > -1) {
- /* read random data into the randseed variable */
- ssize_t nread = read(fd, &randseed, sizeof(randseed));
- if(nread == sizeof(randseed))
- seeded = TRUE;
- close(fd);
- }
- }
-#endif
-
- if(!seeded) {
- struct timeval now = curlx_tvnow();
- infof(data, "WARNING: Using weak random seed\n");
- randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
- randseed = randseed * 1103515245 + 12345;
- randseed = randseed * 1103515245 + 12345;
- randseed = randseed * 1103515245 + 12345;
- seeded = TRUE;
- }
-
- /* Return an unsigned 32-bit pseudo-random number. */
- r = randseed = randseed * 1103515245 + 12345;
- return (r << 16) | ((r >> 16) & 0xFFFF);
-}
-
-CURL_STATIC int Curl_ssl_backend(void)
-{
- return (int)CURL_SSL_BACKEND;
-}
-
-#ifdef USE_SSL
-
-/* "global" init done? */
-static bool init_ssl=FALSE;
-
-/**
- * Global SSL init
- *
- * @retval 0 error initializing SSL
- * @retval 1 SSL initialized successfully
- */
-CURL_STATIC int Curl_ssl_init(void)
-{
- /* make sure this is only done once */
- if(init_ssl)
- return 1;
- init_ssl = TRUE; /* never again */
-
- return curlssl_init();
-}
-
-
-/* Global cleanup */
-CURL_STATIC void Curl_ssl_cleanup(void)
-{
- if(init_ssl) {
- /* only cleanup if we did a previous init */
- curlssl_cleanup();
- init_ssl = FALSE;
- }
-}
-
-static bool ssl_prefs_check(struct SessionHandle *data)
-{
- /* check for CURLOPT_SSLVERSION invalid parameter value */
- if((data->set.ssl.version < 0)
- || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) {
- failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
- return FALSE;
- }
- return TRUE;
-}
-
-CURL_STATIC CURLcode
-Curl_ssl_connect(struct connectdata *conn, int sockindex)
-{
- CURLcode result;
-
- if(!ssl_prefs_check(conn->data))
- return CURLE_SSL_CONNECT_ERROR;
-
- /* mark this is being ssl-enabled from here on. */
- conn->ssl[sockindex].use = TRUE;
- conn->ssl[sockindex].state = ssl_connection_negotiating;
-
- result = curlssl_connect(conn, sockindex);
-
- if(!result)
- Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
-
- return result;
-}
-
-CURL_STATIC CURLcode
-Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
- bool *done)
-{
- CURLcode result;
-
- if(!ssl_prefs_check(conn->data))
- return CURLE_SSL_CONNECT_ERROR;
-
- /* mark this is being ssl requested from here on. */
- conn->ssl[sockindex].use = TRUE;
-#ifdef curlssl_connect_nonblocking
- result = curlssl_connect_nonblocking(conn, sockindex, done);
-#else
- *done = TRUE; /* fallback to BLOCKING */
- result = curlssl_connect(conn, sockindex);
-#endif /* non-blocking connect support */
- if(!result && *done)
- Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
- return result;
-}
-
-/*
- * Check if there's a session ID for the given connection in the cache, and if
- * there's one suitable, it is provided. Returns TRUE when no entry matched.
- */
-CURL_STATIC bool Curl_ssl_getsessionid(struct connectdata *conn,
- void **ssl_sessionid,
- size_t *idsize) /* set 0 if unknown */
-{
- struct curl_ssl_session *check;
- struct SessionHandle *data = conn->data;
- size_t i;
- long *general_age;
- bool no_match = TRUE;
-
- *ssl_sessionid = NULL;
-
- if(!conn->ssl_config.sessionid)
- /* session ID re-use is disabled */
- return TRUE;
-
- /* Lock if shared */
- if(SSLSESSION_SHARED(data)) {
- Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
- general_age = &data->share->sessionage;
- }
- else
- general_age = &data->state.sessionage;
-
- for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
- check = &data->state.session[i];
- if(!check->sessionid)
- /* not session ID means blank entry */
- continue;
- if(Curl_raw_equal(conn->host.name, check->name) &&
- (conn->remote_port == check->remote_port) &&
- Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
- /* yes, we have a session ID! */
- (*general_age)++; /* increase general age */
- check->age = *general_age; /* set this as used in this age */
- *ssl_sessionid = check->sessionid;
- if(idsize)
- *idsize = check->idsize;
- no_match = FALSE;
- break;
- }
- }
-
- /* Unlock */
- if(SSLSESSION_SHARED(data))
- Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-
- return no_match;
-}
-
-/*
- * Kill a single session ID entry in the cache.
- */
-CURL_STATIC void Curl_ssl_kill_session(struct curl_ssl_session *session)
-{
- if(session->sessionid) {
- /* defensive check */
-
- /* free the ID the SSL-layer specific way */
- curlssl_session_free(session->sessionid);
-
- session->sessionid = NULL;
- session->age = 0; /* fresh */
-
- Curl_free_ssl_config(&session->ssl_config);
-
- Curl_safefree(session->name);
- }
-}
-
-/*
- * Delete the given session ID from the cache.
- */
-CURL_STATIC void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
-{
- size_t i;
- struct SessionHandle *data=conn->data;
-
- if(SSLSESSION_SHARED(data))
- Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
-
- for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
- struct curl_ssl_session *check = &data->state.session[i];
-
- if(check->sessionid == ssl_sessionid) {
- Curl_ssl_kill_session(check);
- break;
- }
- }
-
- if(SSLSESSION_SHARED(data))
- Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-}
-
-/*
- * Store session id in the session cache. The ID passed on to this function
- * must already have been extracted and allocated the proper way for the SSL
- * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
- * later on.
- */
-CURL_STATIC CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
- void *ssl_sessionid,
- size_t idsize)
-{
- size_t i;
- struct SessionHandle *data=conn->data; /* the mother of all structs */
- struct curl_ssl_session *store = &data->state.session[0];
- long oldest_age=data->state.session[0].age; /* zero if unused */
- char *clone_host;
- long *general_age;
-
- /* Even though session ID re-use might be disabled, that only disables USING
- IT. We still store it here in case the re-using is again enabled for an
- upcoming transfer */
-
- clone_host = strdup(conn->host.name);
- if(!clone_host)
- return CURLE_OUT_OF_MEMORY; /* bail out */
-
- /* Now we should add the session ID and the host name to the cache, (remove
- the oldest if necessary) */
-
- /* If using shared SSL session, lock! */
- if(SSLSESSION_SHARED(data)) {
- Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
- general_age = &data->share->sessionage;
- }
- else {
- general_age = &data->state.sessionage;
- }
-
- /* find an empty slot for us, or find the oldest */
- for(i = 1; (i < data->set.ssl.max_ssl_sessions) &&
- data->state.session[i].sessionid; i++) {
- if(data->state.session[i].age < oldest_age) {
- oldest_age = data->state.session[i].age;
- store = &data->state.session[i];
- }
- }
- if(i == data->set.ssl.max_ssl_sessions)
- /* cache is full, we must "kill" the oldest entry! */
- Curl_ssl_kill_session(store);
- else
- store = &data->state.session[i]; /* use this slot */
-
- /* now init the session struct wisely */
- store->sessionid = ssl_sessionid;
- store->idsize = idsize;
- store->age = *general_age; /* set current age */
- /* free it if there's one already present */
- free(store->name);
- store->name = clone_host; /* clone host name */
- store->remote_port = conn->remote_port; /* port number */
-
-
- /* Unlock */
- if(SSLSESSION_SHARED(data))
- Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-
- if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
- store->sessionid = NULL; /* let caller free sessionid */
- free(clone_host);
- return CURLE_OUT_OF_MEMORY;
- }
-
- return CURLE_OK;
-}
-
-
-CURL_STATIC void Curl_ssl_close_all(struct SessionHandle *data)
-{
- size_t i;
- /* kill the session ID cache if not shared */
- if(data->state.session && !SSLSESSION_SHARED(data)) {
- for(i = 0; i < data->set.ssl.max_ssl_sessions; i++)
- /* the single-killer function handles empty table slots */
- Curl_ssl_kill_session(&data->state.session[i]);
-
- /* free the cache data */
- Curl_safefree(data->state.session);
- }
-
- curlssl_close_all(data);
-}
-
-CURL_STATIC void Curl_ssl_close(struct connectdata *conn, int sockindex)
-{
- DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
- curlssl_close(conn, sockindex);
-}
-
-CURL_STATIC CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
-{
- if(curlssl_shutdown(conn, sockindex))
- return CURLE_SSL_SHUTDOWN_FAILED;
-
- conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
- conn->ssl[sockindex].state = ssl_connection_none;
-
- conn->recv[sockindex] = Curl_recv_plain;
- conn->send[sockindex] = Curl_send_plain;
-
- return CURLE_OK;
-}
-
-/* Selects an SSL crypto engine
- */
-CURL_STATIC CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
-{
- return curlssl_set_engine(data, engine);
-}
-
-/* Selects the default SSL crypto engine
- */
-CURL_STATIC CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
-{
- return curlssl_set_engine_default(data);
-}
-
-/* Return list of OpenSSL crypto engine names. */
-CURL_STATIC struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
-{
- return curlssl_engines_list(data);
-}
-
-/*
- * This sets up a session ID cache to the specified size. Make sure this code
- * is agnostic to what underlying SSL technology we use.
- */
-CURL_STATIC CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount)
-{
- struct curl_ssl_session *session;
-
- if(data->state.session)
- /* this is just a precaution to prevent multiple inits */
- return CURLE_OK;
-
- session = calloc(amount, sizeof(struct curl_ssl_session));
- if(!session)
- return CURLE_OUT_OF_MEMORY;
-
- /* store the info in the SSL section */
- data->set.ssl.max_ssl_sessions = amount;
- data->state.session = session;
- data->state.sessionage = 1; /* this is brand new */
- return CURLE_OK;
-}
-
-CURL_STATIC size_t Curl_ssl_version(char *buffer, size_t size)
-{
- return curlssl_version(buffer, size);
-}
-
-/*
- * This function tries to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-CURL_STATIC int Curl_ssl_check_cxn(struct connectdata *conn)
-{
- return curlssl_check_cxn(conn);
-}
-
-CURL_STATIC bool Curl_ssl_data_pending(const struct connectdata *conn,
- int connindex)
-{
- return curlssl_data_pending(conn, connindex);
-}
-
-CURL_STATIC void Curl_ssl_free_certinfo(struct SessionHandle *data)
-{
- int i;
- struct curl_certinfo *ci = &data->info.certs;
-
- if(ci->num_of_certs) {
- /* free all individual lists used */
- for(i=0; i<ci->num_of_certs; i++) {
- curl_slist_free_all(ci->certinfo[i]);
- ci->certinfo[i] = NULL;
- }
-
- free(ci->certinfo); /* free the actual array too */
- ci->certinfo = NULL;
- ci->num_of_certs = 0;
- }
-}
-
-CURL_STATIC CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num)
-{
- struct curl_certinfo *ci = &data->info.certs;
- struct curl_slist **table;
-
- /* Free any previous certificate information structures */
- Curl_ssl_free_certinfo(data);
-
- /* Allocate the required certificate information structures */
- table = calloc((size_t) num, sizeof(struct curl_slist *));
- if(!table)
- return CURLE_OUT_OF_MEMORY;
-
- ci->num_of_certs = num;
- ci->certinfo = table;
-
- return CURLE_OK;
-}
-
-/*
- * 'value' is NOT a zero terminated string
- */
-CURL_STATIC CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data,
- int certnum,
- const char *label,
- const char *value,
- size_t valuelen)
-{
- struct curl_certinfo * ci = &data->info.certs;
- char * output;
- struct curl_slist * nl;
- CURLcode result = CURLE_OK;
- size_t labellen = strlen(label);
- size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
-
- output = malloc(outlen);
- if(!output)
- return CURLE_OUT_OF_MEMORY;
-
- /* sprintf the label and colon */
- snprintf(output, outlen, "%s:", label);
-
- /* memcpy the value (it might not be zero terminated) */
- memcpy(&output[labellen+1], value, valuelen);
-
- /* zero terminate the output */
- output[labellen + 1 + valuelen] = 0;
-
- nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
- if(!nl) {
- free(output);
- curl_slist_free_all(ci->certinfo[certnum]);
- result = CURLE_OUT_OF_MEMORY;
- }
-
- ci->certinfo[certnum] = nl;
- return result;
-}
-
-/*
- * This is a convenience function for push_certinfo_len that takes a zero
- * terminated value.
- */
-CURL_STATIC CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data,
- int certnum,
- const char *label,
- const char *value)
-{
- size_t valuelen = strlen(value);
-
- return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
-}
-
-CURL_STATIC int Curl_ssl_random(struct SessionHandle *data,
- unsigned char *entropy,
- size_t length)
-{
- return curlssl_random(data, entropy, length);
-}
-
-/*
- * Public key pem to der conversion
- */
-
-static CURLcode pubkey_pem_to_der(const char *pem,
- unsigned char **der, size_t *der_len)
-{
- char *stripped_pem, *begin_pos, *end_pos;
- size_t pem_count, stripped_pem_count = 0, pem_len;
- CURLcode result;
-
- /* if no pem, exit. */
- if(!pem)
- return CURLE_BAD_CONTENT_ENCODING;
-
- begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
- if(!begin_pos)
- return CURLE_BAD_CONTENT_ENCODING;
-
- pem_count = begin_pos - pem;
- /* Invalid if not at beginning AND not directly following \n */
- if(0 != pem_count && '\n' != pem[pem_count - 1])
- return CURLE_BAD_CONTENT_ENCODING;
-
- /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
- pem_count += 26;
-
- /* Invalid if not directly following \n */
- end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
- if(!end_pos)
- return CURLE_BAD_CONTENT_ENCODING;
-
- pem_len = end_pos - pem;
-
- stripped_pem = malloc(pem_len - pem_count + 1);
- if(!stripped_pem)
- return CURLE_OUT_OF_MEMORY;
-
- /*
- * Here we loop through the pem array one character at a time between the
- * correct indices, and place each character that is not '\n' or '\r'
- * into the stripped_pem array, which should represent the raw base64 string
- */
- while(pem_count < pem_len) {
- if('\n' != pem[pem_count] && '\r' != pem[pem_count])
- stripped_pem[stripped_pem_count++] = pem[pem_count];
- ++pem_count;
- }
- /* Place the null terminator in the correct place */
- stripped_pem[stripped_pem_count] = '\0';
-
- result = Curl_base64_decode(stripped_pem, der, der_len);
-
- Curl_safefree(stripped_pem);
-
- return result;
-}
-
-/*
- * Generic pinned public key check.
- */
-
-CURL_STATIC CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
- const unsigned char *pubkey, size_t pubkeylen)
-{
- FILE *fp;
- unsigned char *buf = NULL, *pem_ptr = NULL;
- long filesize;
- size_t size, pem_len;
- CURLcode pem_read;
- CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
- /* if a path wasn't specified, don't pin */
- if(!pinnedpubkey)
- return CURLE_OK;
- if(!pubkey || !pubkeylen)
- return result;
- fp = fopen(pinnedpubkey, "rb");
- if(!fp)
- return result;
-
- do {
- /* Determine the file's size */
- if(fseek(fp, 0, SEEK_END))
- break;
- filesize = ftell(fp);
- if(fseek(fp, 0, SEEK_SET))
- break;
- if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
- break;
-
- /*
- * if the size of our certificate is bigger than the file
- * size then it can't match
- */
- size = curlx_sotouz((curl_off_t) filesize);
- if(pubkeylen > size)
- break;
-
- /*
- * Allocate buffer for the pinned key
- * With 1 additional byte for null terminator in case of PEM key
- */
- buf = malloc(size + 1);
- if(!buf)
- break;
-
- /* Returns number of elements read, which should be 1 */
- if((int) fread(buf, size, 1, fp) != 1)
- break;
-
- /* If the sizes are the same, it can't be base64 encoded, must be der */
- if(pubkeylen == size) {
- if(!memcmp(pubkey, buf, pubkeylen))
- result = CURLE_OK;
- break;
- }
-
- /*
- * Otherwise we will assume it's PEM and try to decode it
- * after placing null terminator
- */
- buf[size] = '\0';
- pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
- /* if it wasn't read successfully, exit */
- if(pem_read)
- break;
-
- /*
- * if the size of our certificate doesn't match the size of
- * the decoded file, they can't be the same, otherwise compare
- */
- if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
- result = CURLE_OK;
- } while(0);
-
- Curl_safefree(buf);
- Curl_safefree(pem_ptr);
- fclose(fp);
-
- return result;
-}
-
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-CURL_STATIC CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
-{
-#ifdef curlssl_md5sum
- curlssl_md5sum(tmp, tmplen, md5sum, md5len);
-#else
- MD5_context *MD5pw;
-
- (void) md5len;
-
- MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
- if(!MD5pw)
- return CURLE_OUT_OF_MEMORY;
- Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen));
- Curl_MD5_final(MD5pw, md5sum);
-#endif
- return CURLE_OK;
-}
-#endif
-
-/*
- * Check whether the SSL backend supports the status_request extension.
- */
-CURL_STATIC bool Curl_ssl_cert_status_request(void)
-{
-#ifdef curlssl_cert_status_request
- return curlssl_cert_status_request();
-#else
- return FALSE;
-#endif
-}
-
-/*
- * Check whether the SSL backend supports false start.
- */
-CURL_STATIC bool Curl_ssl_false_start(void)
-{
-#ifdef curlssl_false_start
- return curlssl_false_start();
-#else
- return FALSE;
-#endif
-}
-
-#endif /* USE_SSL */
diff --git a/libcurl/src/lib/vtls/vtls.h b/libcurl/src/lib/vtls/vtls.h
deleted file mode 100644
index cc2503f..0000000
--- a/libcurl/src/lib/vtls/vtls.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef HEADER_CURL_VTLS_H
-#define HEADER_CURL_VTLS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#include "openssl.h" /* OpenSSL versions */
-#include "gtls.h" /* GnuTLS versions */
-#include "nssg.h" /* NSS versions */
-#include "gskit.h" /* Global Secure ToolKit versions */
-#include "polarssl.h" /* PolarSSL versions */
-#include "axtls.h" /* axTLS versions */
-#include "cyassl.h" /* CyaSSL versions */
-#include "schannel.h" /* Schannel SSPI version */
-#include "darwinssl.h" /* SecureTransport (Darwin) version */
-
-#ifndef MAX_PINNED_PUBKEY_SIZE
-#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
-#endif
-
-#ifndef MD5_DIGEST_LENGTH
-#define MD5_DIGEST_LENGTH 16 /* fixed size */
-#endif
-
-/* see http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
-#define ALPN_HTTP_1_1_LENGTH 8
-#define ALPN_HTTP_1_1 "http/1.1"
-
-CURL_STATIC bool Curl_ssl_config_matches(struct ssl_config_data* data,
- struct ssl_config_data* needle);
-CURL_STATIC bool Curl_clone_ssl_config(struct ssl_config_data* source,
- struct ssl_config_data* dest);
-CURL_STATIC void Curl_free_ssl_config(struct ssl_config_data* sslc);
-
-CURL_STATIC unsigned int Curl_rand(struct SessionHandle *);
-
-CURL_STATIC int Curl_ssl_backend(void);
-
-#ifdef USE_SSL
-CURL_STATIC int Curl_ssl_init(void);
-CURL_STATIC void Curl_ssl_cleanup(void);
-CURL_STATIC CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-/* tell the SSL stuff to close down all open information regarding
- connections (and thus session ID caching etc) */
-CURL_STATIC void Curl_ssl_close_all(struct SessionHandle *data);
-CURL_STATIC void Curl_ssl_close(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
-CURL_STATIC CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
-/* Sets engine as default for all SSL operations */
-CURL_STATIC CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
-CURL_STATIC struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
-
-/* init the SSL session ID cache */
-CURL_STATIC CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t);
-CURL_STATIC size_t Curl_ssl_version(char *buffer, size_t size);
-CURL_STATIC bool Curl_ssl_data_pending(const struct connectdata *conn,
- int connindex);
-CURL_STATIC int Curl_ssl_check_cxn(struct connectdata *conn);
-
-/* Certificate information list handling. */
-
-CURL_STATIC void Curl_ssl_free_certinfo(struct SessionHandle *data);
-CURL_STATIC CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num);
-CURL_STATIC CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum,
- const char * label, const char * value,
- size_t valuelen);
-CURL_STATIC CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum,
- const char * label, const char * value);
-
-/* Functions to be used by SSL library adaptation functions */
-
-/* extract a session ID */
-CURL_STATIC bool Curl_ssl_getsessionid(struct connectdata *conn,
- void **ssl_sessionid,
- size_t *idsize) /* set 0 if unknown */;
-/* add a new session ID */
-CURL_STATIC CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
- void *ssl_sessionid,
- size_t idsize);
-/* Kill a single session ID entry in the cache */
-CURL_STATIC void Curl_ssl_kill_session(struct curl_ssl_session *session);
-/* delete a session from the cache */
-CURL_STATIC void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
-
-/* get N random bytes into the buffer, return 0 if a find random is filled
- in */
-CURL_STATIC int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer,
- size_t length);
-CURL_STATIC CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-/* Check pinned public key. */
-CURL_STATIC CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
- const unsigned char *pubkey, size_t pubkeylen);
-
-CURL_STATIC bool Curl_ssl_cert_status_request(void);
-
-CURL_STATIC bool Curl_ssl_false_start(void);
-
-#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
-
-#else
-/* Set the API backend definition to none */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_NONE
-
-/* When SSL support is not present, just define away these function calls */
-#define Curl_ssl_init() 1
-#define Curl_ssl_cleanup() Curl_nop_stmt
-#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN
-#define Curl_ssl_close_all(x) Curl_nop_stmt
-#define Curl_ssl_close(x,y) Curl_nop_stmt
-#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN
-#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
-#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
-#define Curl_ssl_engines_list(x) NULL
-#define Curl_ssl_send(a,b,c,d,e) -1
-#define Curl_ssl_recv(a,b,c,d,e) -1
-#define Curl_ssl_initsessions(x,y) CURLE_OK
-#define Curl_ssl_version(x,y) 0
-#define Curl_ssl_data_pending(x,y) 0
-#define Curl_ssl_check_cxn(x) 0
-#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
-#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN
-#define Curl_ssl_kill_session(x) Curl_nop_stmt
-#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
-#define Curl_ssl_cert_status_request() FALSE
-#define Curl_ssl_false_start() FALSE
-#endif
-
-#endif /* HEADER_CURL_VTLS_H */