Externals: Add libcurl.

This commit is contained in:
Pierre Bourdon
2016-06-17 02:28:34 +02:00
parent fe51de23f1
commit c4f5c471bb
291 changed files with 122838 additions and 1 deletions

690
Externals/curl/lib/vtls/axtls.c vendored Normal file
View File

@ -0,0 +1,690 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>.
* Copyright (C) 2010 - 2016, 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 https://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"
#include <unistd.h>
/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"
/* Global axTLS init, called from Curl_ssl_init() */
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;
}
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.
*/
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.
*/
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 */
usleep(10000);
}
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;
}
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)
*/
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
*/
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 */
}
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. */
}
size_t Curl_axtls_version(char *buffer, size_t size)
{
return snprintf(buffer, size, "axTLS/%s", ssl_version());
}
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 */

71
Externals/curl/lib/vtls/axtls.h vendored Normal file
View File

@ -0,0 +1,71 @@
#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 https://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"
int Curl_axtls_init(void);
int Curl_axtls_cleanup(void);
CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_axtls_connect_nonblocking(
struct connectdata *conn,
int sockindex,
bool *done);
/* close a SSL connection */
void Curl_axtls_close(struct connectdata *conn, int sockindex);
void Curl_axtls_session_free(void *ptr);
size_t Curl_axtls_version(char *buffer, size_t size);
int Curl_axtls_shutdown(struct connectdata *conn, int sockindex);
int Curl_axtls_check_cxn(struct connectdata *conn);
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 */

902
Externals/curl/lib/vtls/cyassl.c vendored Normal file
View File

@ -0,0 +1,902 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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. https://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 "vtls.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "rawstr.h"
#include "x509asn1.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>
#include <cyassl/ctaocrypt/sha256.h>
#include "cyassl.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
/* To determine what functions are available we rely on one or both of:
- the user's options.h generated by CyaSSL/wolfSSL
- the symbols detected by curl's configure
Since they are markedly different from one another, and one or the other may
not be available, we do some checking below to bring things in sync. */
/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
#ifndef HAVE_ALPN
#ifdef HAVE_WOLFSSL_USEALPN
#define HAVE_ALPN
#endif
#endif
/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
options.h, but is only seen in >= 3.6.6 since that's when they started
disabling SSLv3 by default. */
#ifndef WOLFSSL_ALLOW_SSLV3
#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \
defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
#define WOLFSSL_ALLOW_SSLV3
#endif
#endif
/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC
supported curve extension in options.h. Note ECC is enabled separately. */
#ifndef HAVE_SUPPORTED_CURVES
#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \
defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE)
#define HAVE_SUPPORTED_CURVES
#endif
#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:
#ifdef WOLFSSL_ALLOW_SSLV3
req_method = SSLv3_client_method();
use_sni(FALSE);
#else
failf(data, "No support for SSLv3");
return CURLE_NOT_BUILT_IN;
#endif
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
#ifdef HAVE_SUPPORTED_CURVES
/* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically:
https://github.com/wolfSSL/wolfssl/issues/366
The supported curves below are those also supported by OpenSSL 1.0.2 and
in the same order. */
CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */
CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */
CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */
#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;
}
#ifdef HAVE_ALPN
if(conn->bits.tls_enable_alpn) {
char protocols[128];
*protocols = '\0';
/* wolfSSL's ALPN protocol name list format is a comma separated string of
protocols in descending order of preference, eg: "h2,http/1.1" */
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
}
#endif
strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
if(wolfSSL_UseALPN(conssl->handle, protocols,
(unsigned)strlen(protocols),
WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
return CURLE_SSL_CONNECT_ERROR;
}
}
#endif /* HAVE_ALPN */
/* 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;
}
}
if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
#ifdef KEEP_PEER_CERT
X509 *x509;
const char *x509_der;
int x509_der_len;
curl_X509certificate x509_parsed;
curl_asn1Element *pubkey;
CURLcode result;
x509 = SSL_get_peer_certificate(conssl->handle);
if(!x509) {
failf(data, "SSL: failed retrieving server certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len);
if(!x509_der) {
failf(data, "SSL: failed retrieving ASN.1 server certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
memset(&x509_parsed, 0, sizeof x509_parsed);
Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len);
pubkey = &x509_parsed.subjectPublicKeyInfo;
if(!pubkey->header || pubkey->end <= pubkey->header) {
failf(data, "SSL: failed retrieving public key from server certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
result = Curl_pin_peer_pubkey(data,
data->set.str[STRING_SSL_PINNEDPUBLICKEY],
(const unsigned char *)pubkey->header,
(size_t)(pubkey->end - pubkey->header));
if(result) {
failf(data, "SSL: public key does not match pinned public key!");
return result;
}
#else
failf(data, "Library lacks pinning support built-in");
return CURLE_NOT_BUILT_IN;
#endif
}
#ifdef HAVE_ALPN
if(conn->bits.tls_enable_alpn) {
int rc;
char *protocol = NULL;
unsigned short protocol_len = 0;
rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
if(rc == SSL_SUCCESS) {
infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
protocol);
if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
conn->negnpn = CURL_HTTP_VERSION_1_1;
#ifdef USE_NGHTTP2
else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
!memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN))
conn->negnpn = CURL_HTTP_VERSION_2;
#endif
else
infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
protocol);
}
else if(rc == SSL_ALPN_NOT_FOUND)
infof(data, "ALPN, server did not agree to a protocol\n");
else {
failf(data, "ALPN, failure getting protocol, error %d", rc);
return CURLE_SSL_CONNECT_ERROR;
}
}
#endif /* HAVE_ALPN */
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;
}
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;
}
void Curl_cyassl_session_free(void *ptr)
{
(void)ptr;
/* CyaSSL reuses sessions on own, no free */
}
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
}
int Curl_cyassl_init(void)
{
return (CyaSSL_Init() == SSL_SUCCESS);
}
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)
*/
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;
}
CURLcode
Curl_cyassl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done)
{
return cyassl_connect_common(conn, sockindex, TRUE, done);
}
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;
}
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;
}
void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum /* output */,
size_t unused)
{
Sha256 SHA256pw;
(void)unused;
InitSha256(&SHA256pw);
Sha256Update(&SHA256pw, tmp, (word32)tmplen);
Sha256Final(&SHA256pw, sha256sum);
}
#endif

92
Externals/curl/lib/vtls/cyassl.h vendored Normal file
View File

@ -0,0 +1,92 @@
#ifndef HEADER_CURL_CYASSL_H
#define HEADER_CURL_CYASSL_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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
/* KEEP_PEER_CERT is a product of the presence of build time symbol
OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
in wolfSSL's settings.h, and the latter two are build time symbols in
options.h. */
#ifndef KEEP_PEER_CERT
#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
(defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
#define KEEP_PEER_CERT
#endif
#endif
CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex);
bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex);
int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex);
/* close a SSL connection */
void Curl_cyassl_close(struct connectdata *conn, int sockindex);
void Curl_cyassl_session_free(void *ptr);
size_t Curl_cyassl_version(char *buffer, size_t size);
int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex);
int Curl_cyassl_init(void);
CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
int Curl_cyassl_random(struct SessionHandle *data,
unsigned char *entropy,
size_t length);
void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t unused);
/* 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
#ifdef KEEP_PEER_CERT
/* this backend supports CURLOPT_PINNEDPUBLICKEY */
#define have_curlssl_pinnedpubkey 1
#endif
/* 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)
#define curlssl_sha256sum(a,b,c,d) Curl_cyassl_sha256sum(a,b,c,d)
#endif /* USE_CYASSL */
#endif /* HEADER_CURL_CYASSL_H */

2490
Externals/curl/lib/vtls/darwinssl.c vendored Normal file

File diff suppressed because it is too large Load Diff

76
Externals/curl/lib/vtls/darwinssl.h vendored Normal file
View File

@ -0,0 +1,76 @@
#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 https://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
CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
/* close a SSL connection */
void Curl_darwinssl_close(struct connectdata *conn, int sockindex);
void Curl_darwinssl_session_free(void *ptr);
size_t Curl_darwinssl_version(char *buffer, size_t size);
int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex);
int Curl_darwinssl_check_cxn(struct connectdata *conn);
bool Curl_darwinssl_data_pending(const struct connectdata *conn,
int connindex);
int Curl_darwinssl_random(unsigned char *entropy,
size_t length);
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 */

1069
Externals/curl/lib/vtls/gskit.c vendored Normal file

File diff suppressed because it is too large Load Diff

71
Externals/curl/lib/vtls/gskit.h vendored Normal file
View File

@ -0,0 +1,71 @@
#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 https://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
int Curl_gskit_init(void);
void Curl_gskit_cleanup(void);
CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
int sockindex, bool *done);
void Curl_gskit_close(struct connectdata *conn, int sockindex);
int Curl_gskit_shutdown(struct connectdata *conn, int sockindex);
size_t Curl_gskit_version(char *buffer, size_t size);
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 */

1627
Externals/curl/lib/vtls/gtls.c vendored Normal file

File diff suppressed because it is too large Load Diff

91
Externals/curl/lib/vtls/gtls.h vendored Normal file
View File

@ -0,0 +1,91 @@
#ifndef HEADER_CURL_GTLS_H
#define HEADER_CURL_GTLS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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"
int Curl_gtls_init(void);
int Curl_gtls_cleanup(void);
CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
/* close a SSL connection */
void Curl_gtls_close(struct connectdata *conn, int sockindex);
void Curl_gtls_session_free(void *ptr);
size_t Curl_gtls_version(char *buffer, size_t size);
int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
int Curl_gtls_random(struct SessionHandle *data,
unsigned char *entropy,
size_t length);
void Curl_gtls_md5sum(unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *md5sum, /* output */
size_t md5len);
void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t sha256len);
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
/* this backend supports CURLOPT_PINNEDPUBLICKEY */
#define have_curlssl_pinnedpubkey 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_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d)
#define curlssl_cert_status_request() Curl_gtls_cert_status_request()
#endif /* USE_GNUTLS */
#endif /* HEADER_CURL_GTLS_H */

866
Externals/curl/lib/vtls/mbedtls.c vendored Normal file
View File

@ -0,0 +1,866 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
* Copyright (C) 2012 - 2016, 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 https://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 mbedTLS-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_MBEDTLS
#include <mbedtls/net.h>
#include <mbedtls/ssl.h>
#include <mbedtls/certs.h>
#include <mbedtls/x509.h>
#include <mbedtls/version.h>
#include <mbedtls/error.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/sha256.h>
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "mbedtls.h"
#include "vtls.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "rawstr.h"
#include "polarssl_threadlock.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
/* apply threading? */
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
#define THREADING_SUPPORT
#endif
#if defined(THREADING_SUPPORT)
static mbedtls_entropy_context entropy;
static int entropy_init_initialized = 0;
/* start of entropy_init_mutex() */
static void entropy_init_mutex(mbedtls_entropy_context *ctx)
{
/* lock 0 = entropy_init_mutex() */
Curl_polarsslthreadlock_lock_function(0);
if(entropy_init_initialized == 0) {
mbedtls_entropy_init(ctx);
entropy_init_initialized = 1;
}
Curl_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() */
Curl_polarsslthreadlock_lock_function(1);
ret = mbedtls_entropy_func(data, output, len);
Curl_polarsslthreadlock_unlock_function(1);
return ret;
}
/* end of entropy_func_mutex() */
#endif /* THREADING_SUPPORT */
/* Define this to enable lots of debugging for mbedTLS */
#undef MBEDTLS_DEBUG
#ifdef MBEDTLS_DEBUG
static void mbed_debug(void *context, int level, const char *f_name,
int line_nb, 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 USE_NGHTTP2
# undef HAS_ALPN
# ifdef MBEDTLS_SSL_ALPN
# define HAS_ALPN
# endif
#endif
/*
* profile
*/
const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
{
/* Hashes from SHA-1 and above */
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
0xFFFFFFF, /* Any PK alg */
0xFFFFFFF, /* Any curve */
1024, /* RSA min key len */
};
/* See https://tls.mbed.org/discussions/generic/
howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
*/
#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
static Curl_recv mbed_recv;
static Curl_send mbed_send;
static CURLcode
mbed_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;
char errorbuf[128];
errorbuf[0]=0;
/* mbedTLS only supports SSLv3 and TLSv1 */
if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
failf(data, "mbedTLS 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);
mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex,
&entropy, NULL, 0);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
-ret, errorbuf);
}
#else
mbedtls_entropy_init(&connssl->entropy);
mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func,
&connssl->entropy, NULL, 0);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
-ret, errorbuf);
}
#endif /* THREADING_SUPPORT */
/* Load the trusted CA */
mbedtls_x509_crt_init(&connssl->cacert);
if(data->set.str[STRING_SSL_CAFILE]) {
ret = mbedtls_x509_crt_parse_file(&connssl->cacert,
data->set.str[STRING_SSL_CAFILE]);
if(ret<0) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading ca cert file %s - mbedTLS: (-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 = mbedtls_x509_crt_parse_path(&connssl->cacert,
data->set.str[STRING_SSL_CAPATH]);
if(ret<0) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading ca cert path %s - mbedTLS: (-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 */
mbedtls_x509_crt_init(&connssl->clicert);
if(data->set.str[STRING_CERT]) {
ret = mbedtls_x509_crt_parse_file(&connssl->clicert,
data->set.str[STRING_CERT]);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
data->set.str[STRING_CERT], -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
}
/* Load the client private key */
mbedtls_pk_init(&connssl->pk);
if(data->set.str[STRING_KEY]) {
ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY],
data->set.str[STRING_KEY_PASSWD]);
if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
data->set.str[STRING_KEY], -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
}
/* Load the CRL */
mbedtls_x509_crl_init(&connssl->crl);
if(data->set.str[STRING_SSL_CRLFILE]) {
ret = mbedtls_x509_crl_parse_file(&connssl->crl,
data->set.str[STRING_SSL_CRLFILE]);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
return CURLE_SSL_CRL_BADFILE;
}
}
infof(data, "mbedTLS: Connecting to %s:%d\n",
conn->host.name, conn->remote_port);
mbedtls_ssl_config_init(&connssl->config);
mbedtls_ssl_init(&connssl->ssl);
if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) {
failf(data, "mbedTLS: ssl_init failed");
return CURLE_SSL_CONNECT_ERROR;
}
ret = mbedtls_ssl_config_defaults(&connssl->config,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if(ret) {
failf(data, "mbedTLS: ssl_config failed");
return CURLE_SSL_CONNECT_ERROR;
}
/* new profile with RSA min key len = 1024 ... */
mbedtls_ssl_conf_cert_profile(&connssl->config,
&mbedtls_x509_crt_profile_fr);
switch(data->set.ssl.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_1);
infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
break;
case CURL_SSLVERSION_SSLv3:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_0);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_0);
infof(data, "mbedTLS: Set SSL version to SSLv3\n");
break;
case CURL_SSLVERSION_TLSv1_0:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_1);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_1);
infof(data, "mbedTLS: Set SSL version to TLS 1.0\n");
break;
case CURL_SSLVERSION_TLSv1_1:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_2);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_2);
infof(data, "mbedTLS: Set SSL version to TLS 1.1\n");
break;
case CURL_SSLVERSION_TLSv1_2:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_3);
infof(data, "mbedTLS: Set SSL version to TLS 1.2\n");
break;
default:
failf(data, "mbedTLS: Unsupported SSL protocol version");
return CURLE_SSL_CONNECT_ERROR;
}
mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random,
&connssl->ctr_drbg);
mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex],
mbedtls_net_send,
mbedtls_net_recv,
NULL /* rev_timeout() */);
mbedtls_ssl_conf_ciphersuites(&connssl->config,
mbedtls_ssl_list_ciphersuites());
if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
if(ret) {
failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
infof(data, "mbedTLS re-using session\n");
}
mbedtls_ssl_conf_ca_chain(&connssl->config,
&connssl->cacert,
&connssl->crl);
if(data->set.str[STRING_KEY]) {
mbedtls_ssl_conf_own_cert(&connssl->config,
&connssl->clicert, &connssl->pk);
}
if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) {
/* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
the name to set in the SNI extension. So even if curl connects to a
host specified as an IP address, this function must be used. */
failf(data, "couldn't set hostname in mbedTLS");
return CURLE_SSL_CONNECT_ERROR;
}
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
const char **p = &connssl->protocols[0];
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2)
*p++ = NGHTTP2_PROTO_VERSION_ID;
#endif
*p++ = ALPN_HTTP_1_1;
*p = NULL;
/* this function doesn't clone the protocols array, which is why we need
to keep it around */
if(mbedtls_ssl_conf_alpn_protocols(&connssl->config,
&connssl->protocols[0])) {
failf(data, "Failed setting ALPN protocols");
return CURLE_SSL_CONNECT_ERROR;
}
for(p = &connssl->protocols[0]; *p; ++p)
infof(data, "ALPN, offering %s\n", *p);
}
#endif
#ifdef MBEDTLS_DEBUG
mbedtls_ssl_conf_dbg(&connssl->config, mbedtls_debug, data);
#endif
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
static CURLcode
mbed_connect_step2(struct connectdata *conn,
int sockindex)
{
int ret;
struct SessionHandle *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
const mbedtls_x509_crt *peercert;
#ifdef HAS_ALPN
const char* next_protocol;
#endif
char errorbuf[128];
errorbuf[0] = 0;
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
ret = mbedtls_ssl_handshake(&connssl->ssl);
if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
else if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
#endif /* MBEDTLS_ERROR_C */
failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
-ret, errorbuf);
return CURLE_SSL_CONNECT_ERROR;
}
infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
);
ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
if(ret && data->set.ssl.verifypeer) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
failf(data, "Cert verify failed: BADCERT_REVOKED");
return CURLE_SSL_CACERT;
}
if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
return CURLE_PEER_FAILED_VERIFICATION;
}
peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl);
if(peercert && data->set.verbose) {
const size_t bufsize = 16384;
char *buffer = malloc(bufsize);
if(!buffer)
return CURLE_OUT_OF_MEMORY;
if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
infof(data, "Dumping cert info:\n%s\n", buffer);
else
infof(data, "Unable to dump certificate information.\n");
free(buffer);
}
if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
int size;
CURLcode result;
mbedtls_x509_crt *p;
unsigned char pubkey[PUB_DER_MAX_BYTES];
if(!peercert || !peercert->raw.p || !peercert->raw.len) {
failf(data, "Failed due to missing peer certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
p = calloc(1, sizeof(*p));
if(!p)
return CURLE_OUT_OF_MEMORY;
mbedtls_x509_crt_init(p);
/* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
needs a non-const key, for now.
https://github.com/ARMmbed/mbedtls/issues/396 */
if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
failf(data, "Failed copying peer certificate");
mbedtls_x509_crt_free(p);
free(p);
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
if(size <= 0) {
failf(data, "Failed copying public key from peer certificate");
mbedtls_x509_crt_free(p);
free(p);
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
/* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
result = Curl_pin_peer_pubkey(data,
data->set.str[STRING_SSL_PINNEDPUBLICKEY],
&pubkey[PUB_DER_MAX_BYTES - size], size);
if(result) {
mbedtls_x509_crt_free(p);
free(p);
return result;
}
mbedtls_x509_crt_free(p);
free(p);
}
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl);
if(next_protocol) {
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) &&
!next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
!next_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
connssl->connecting_state = ssl_connect_3;
infof(data, "SSL connected\n");
return CURLE_OK;
}
static CURLcode
mbed_connect_step3(struct connectdata *conn,
int sockindex)
{
CURLcode retcode = CURLE_OK;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct SessionHandle *data = conn->data;
void *old_ssl_sessionid = NULL;
mbedtls_ssl_session *our_ssl_sessionid;
int ret;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
return CURLE_OUT_OF_MEMORY;
mbedtls_ssl_session_init(our_ssl_sessionid);
ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid);
if(ret) {
failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
/* If there's already a matching session in the cache, delete it */
if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(conn, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
if(retcode) {
free(our_ssl_sessionid);
failf(data, "failed to store ssl session");
return retcode;
}
connssl->connecting_state = ssl_connect_done;
return CURLE_OK;
}
static ssize_t mbed_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len,
CURLcode *curlcode)
{
int ret = -1;
ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl,
(unsigned char *)mem, len);
if(ret < 0) {
*curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
CURLE_AGAIN : CURLE_SEND_ERROR;
ret = -1;
}
return ret;
}
void Curl_mbedtls_close_all(struct SessionHandle *data)
{
(void)data;
}
void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
{
mbedtls_pk_free(&conn->ssl[sockindex].pk);
mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert);
mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert);
mbedtls_x509_crl_free(&conn->ssl[sockindex].crl);
mbedtls_ssl_config_free(&conn->ssl[sockindex].config);
mbedtls_ssl_free(&conn->ssl[sockindex].ssl);
mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg);
#ifndef THREADING_SUPPORT
mbedtls_entropy_free(&conn->ssl[sockindex].entropy);
#endif /* THREADING_SUPPORT */
}
static ssize_t mbed_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 = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf,
buffersize);
if(ret <= 0) {
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
return 0;
*curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
CURLE_AGAIN : CURLE_RECV_ERROR;
return -1;
}
len = ret;
return len;
}
void Curl_mbedtls_session_free(void *ptr)
{
mbedtls_ssl_session_free(ptr);
free(ptr);
}
size_t Curl_mbedtls_version(char *buffer, size_t size)
{
unsigned int version = mbedtls_version_get_number();
return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
(version>>16)&0xff, (version>>8)&0xff);
}
static CURLcode
mbed_connect_common(struct connectdata *conn,
int sockindex,
bool nonblocking,
bool *done)
{
CURLcode retcode;
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;
}
retcode = mbed_connect_step1(conn, sockindex);
if(retcode)
return retcode;
}
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.
*/
retcode = mbed_connect_step2(conn, sockindex);
if(retcode || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
ssl_connect_2_writing == connssl->connecting_state)))
return retcode;
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3==connssl->connecting_state) {
retcode = mbed_connect_step3(conn, sockindex);
if(retcode)
return retcode;
}
if(ssl_connect_done==connssl->connecting_state) {
connssl->state = ssl_connection_complete;
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
*done = TRUE;
}
else
*done = FALSE;
/* Reset our connect state machine */
connssl->connecting_state = ssl_connect_1;
return CURLE_OK;
}
CURLcode
Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done)
{
return mbed_connect_common(conn, sockindex, TRUE, done);
}
CURLcode
Curl_mbedtls_connect(struct connectdata *conn,
int sockindex)
{
CURLcode retcode;
bool done = FALSE;
retcode = mbed_connect_common(conn, sockindex, FALSE, &done);
if(retcode)
return retcode;
DEBUGASSERT(done);
return CURLE_OK;
}
/*
* return 0 error initializing SSL
* return 1 SSL initialized successfully
*/
int Curl_mbedtls_init(void)
{
return Curl_polarsslthreadlock_thread_setup();
}
void Curl_mbedtls_cleanup(void)
{
(void)Curl_polarsslthreadlock_thread_cleanup();
}
int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex)
{
mbedtls_ssl_context *ssl =
(mbedtls_ssl_context *)&conn->ssl[sockindex].ssl;
return ssl->in_msglen != 0;
}
#endif /* USE_MBEDTLS */

80
Externals/curl/lib/vtls/mbedtls.h vendored Normal file
View File

@ -0,0 +1,80 @@
#ifndef HEADER_CURL_MBEDTLS_H
#define HEADER_CURL_MBEDTLS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* 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 https://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_MBEDTLS
#include <mbedtls/sha256.h>
/* Called on first use mbedTLS, setup threading if supported */
int Curl_mbedtls_init(void);
void Curl_mbedtls_cleanup(void);
int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex);
CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
/* tell mbedTLS to close down all open information regarding connections (and
thus session ID caching etc) */
void Curl_mbedtls_close_all(struct SessionHandle *data);
/* close a SSL connection */
void Curl_mbedtls_close(struct connectdata *conn, int sockindex);
void Curl_mbedtls_session_free(void *ptr);
size_t Curl_mbedtls_version(char *buffer, size_t size);
int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex);
/* this backends supports CURLOPT_PINNEDPUBLICKEY */
#define have_curlssl_pinnedpubkey 1
/* API setup for mbedTLS */
#define curlssl_init() Curl_mbedtls_init()
#define curlssl_cleanup() Curl_mbedtls_cleanup()
#define curlssl_connect Curl_mbedtls_connect
#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking
#define curlssl_session_free(x) Curl_mbedtls_session_free(x)
#define curlssl_close_all Curl_mbedtls_close_all
#define curlssl_close Curl_mbedtls_close
#define curlssl_shutdown(x,y) 0
#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
#define curlssl_version Curl_mbedtls_version
#define curlssl_check_cxn(x) (x=x, -1)
#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y)
#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS
#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,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) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN)
#endif /* USE_MBEDTLS */
#endif /* HEADER_CURL_MBEDTLS_H */

2081
Externals/curl/lib/vtls/nss.c vendored Normal file

File diff suppressed because it is too large Load Diff

105
Externals/curl/lib/vtls/nssg.h vendored Normal file
View File

@ -0,0 +1,105 @@
#ifndef HEADER_CURL_NSSG_H
#define HEADER_CURL_NSSG_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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"
CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
/* close a SSL connection */
void Curl_nss_close(struct connectdata *conn, int sockindex);
int Curl_nss_init(void);
void Curl_nss_cleanup(void);
size_t Curl_nss_version(char *buffer, size_t size);
int Curl_nss_check_cxn(struct connectdata *cxn);
int Curl_nss_seed(struct SessionHandle *data);
/* initialize NSS library if not already */
CURLcode Curl_nss_force_init(struct SessionHandle *data);
int Curl_nss_random(struct SessionHandle *data,
unsigned char *entropy,
size_t length);
void Curl_nss_md5sum(unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *md5sum, /* output */
size_t md5len);
void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum, /* output */
size_t sha256len);
bool Curl_nss_cert_status_request(void);
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
/* this backends supports CURLOPT_PINNEDPUBLICKEY */
#define have_curlssl_pinnedpubkey 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_sha256sum(a,b,c,d) Curl_nss_sha256sum(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 */

3188
Externals/curl/lib/vtls/openssl.c vendored Normal file

File diff suppressed because it is too large Load Diff

123
Externals/curl/lib/vtls/openssl.h vendored Normal file
View File

@ -0,0 +1,123 @@
#ifndef HEADER_CURL_SSLUSE_H
#define HEADER_CURL_SSLUSE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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"
CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
/* close a SSL connection */
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) */
void Curl_ossl_close_all(struct SessionHandle *data);
/* Sets an OpenSSL engine */
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 */
void Curl_ossl_session_free(void *ptr);
/* Sets engine as default for all SSL operations */
CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data);
/* Build list of OpenSSL engines */
struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
int Curl_ossl_init(void);
void Curl_ossl_cleanup(void);
size_t Curl_ossl_version(char *buffer, size_t size);
int Curl_ossl_check_cxn(struct connectdata *cxn);
int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
bool Curl_ossl_data_pending(const struct connectdata *conn,
int connindex);
/* return 0 if a find random is filled in */
int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
size_t length);
void Curl_ossl_md5sum(unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *md5sum /* output */,
size_t unused);
void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum /* 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 supports CURLOPT_SSL_CTX_* */
#define have_curlssl_ssl_ctx 1
/* this backend supports CURLOPT_PINNEDPUBLICKEY */
#define have_curlssl_pinnedpubkey 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)
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
#define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d)
#endif
#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 */

814
Externals/curl/lib/vtls/polarssl.c vendored Normal file
View File

@ -0,0 +1,814 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* 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 https://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>
#include <polarssl/sha256.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"
/* See https://tls.mbed.org/discussions/generic/
howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
*/
#define RSA_PUB_DER_MAX_BYTES (38 + 2 * POLARSSL_MPI_MAX_SIZE)
#define ECP_PUB_DER_MAX_BYTES (30 + 2 * POLARSSL_ECP_MAX_BYTES)
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
/* 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() */
Curl_polarsslthreadlock_lock_function(0);
if(entropy_init_initialized == 0) {
entropy_init(ctx);
entropy_init_initialized = 1;
}
Curl_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() */
Curl_polarsslthreadlock_lock_function(1);
ret = entropy_func(data, output, len);
Curl_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;
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,
NULL, 0)) != 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,
NULL, 0)) != 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, NULL)) {
ret = ssl_set_session(&connssl->ssl, old_session);
if(ret) {
failf(data, "ssl_set_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
infof(data, "PolarSSL re-using session\n");
}
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(ssl_set_hostname(&connssl->ssl, conn->host.name)) {
/* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name
to set in the SNI extension. So even if curl connects to a host
specified as an IP address, this function must be used. */
failf(data, "couldn't set hostname in PolarSSL");
return CURLE_SSL_CONNECT_ERROR;
}
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
static const char* protocols[3];
int cur = 0;
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
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);
}
/* adapted from mbedtls.c */
if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
int size;
CURLcode result;
x509_crt *p;
unsigned char pubkey[PUB_DER_MAX_BYTES];
const x509_crt *peercert;
peercert = ssl_get_peer_cert(&connssl->ssl);
if(!peercert || !peercert->raw.p || !peercert->raw.len) {
failf(data, "Failed due to missing peer certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
p = calloc(1, sizeof(*p));
if(!p)
return CURLE_OUT_OF_MEMORY;
x509_crt_init(p);
/* Make a copy of our const peercert because pk_write_pubkey_der
needs a non-const key, for now.
https://github.com/ARMmbed/mbedtls/issues/396 */
if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
failf(data, "Failed copying peer certificate");
x509_crt_free(p);
free(p);
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
if(size <= 0) {
failf(data, "Failed copying public key from peer certificate");
x509_crt_free(p);
free(p);
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
}
/* pk_write_pubkey_der writes data at the end of the buffer. */
result = Curl_pin_peer_pubkey(data,
data->set.str[STRING_SSL_PINNEDPUBLICKEY],
&pubkey[PUB_DER_MAX_BYTES - size], size);
if(result) {
x509_crt_free(p);
free(p);
return result;
}
x509_crt_free(p);
free(p);
}
#ifdef HAS_ALPN
if(conn->bits.tls_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;
}
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 retcode = 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;
int ret;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
our_ssl_sessionid = malloc(sizeof(ssl_session));
if(!our_ssl_sessionid)
return CURLE_OUT_OF_MEMORY;
ssl_session_init(our_ssl_sessionid);
ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid);
if(ret) {
failf(data, "ssl_get_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
/* If there's already a matching session in the cache, delete it */
if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(conn, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
if(retcode) {
free(our_ssl_sessionid);
failf(data, "failed to store ssl session");
return retcode;
}
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;
}
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;
}
void Curl_polarssl_session_free(void *ptr)
{
ssl_session_free(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.. */
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;
}
CURLcode
Curl_polarssl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done)
{
return polarssl_connect_common(conn, sockindex, TRUE, done);
}
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 Curl_polarssl_init(void)
{
return Curl_polarsslthreadlock_thread_setup();
}
void Curl_polarssl_cleanup(void)
{
(void)Curl_polarsslthreadlock_thread_cleanup();
}
#endif /* USE_POLARSSL */

81
Externals/curl/lib/vtls/polarssl.h vendored Normal file
View File

@ -0,0 +1,81 @@
#ifndef HEADER_CURL_POLARSSL_H
#define HEADER_CURL_POLARSSL_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* 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 https://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
#include <polarssl/sha256.h>
/* Called on first use PolarSSL, setup threading if supported */
int Curl_polarssl_init(void);
void Curl_polarssl_cleanup(void);
CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
/* close a SSL connection */
void Curl_polarssl_close(struct connectdata *conn, int sockindex);
void Curl_polarssl_session_free(void *ptr);
size_t Curl_polarssl_version(char *buffer, size_t size);
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
/* this backends supports CURLOPT_PINNEDPUBLICKEY */
#define have_curlssl_pinnedpubkey 1
/* API setup for PolarSSL */
#define curlssl_init() Curl_polarssl_init()
#define curlssl_cleanup() Curl_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)
#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,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 */

View File

@ -0,0 +1,153 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* 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 https://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_MBEDTLS)) && \
(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 Curl_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 Curl_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 Curl_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 Curl_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 || USE_MBEDTLS */

View File

@ -0,0 +1,53 @@
#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H
#define HEADER_CURL_POLARSSL_THREADLOCK_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* 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 https://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_MBEDTLS)
#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 Curl_polarsslthreadlock_thread_setup(void);
int Curl_polarsslthreadlock_thread_cleanup(void);
int Curl_polarsslthreadlock_lock_function(int n);
int Curl_polarsslthreadlock_unlock_function(int n);
#else
#define Curl_polarsslthreadlock_thread_setup() 1
#define Curl_polarsslthreadlock_thread_cleanup() 1
#define Curl_polarsslthreadlock_lock_function(x) 1
#define Curl_polarsslthreadlock_unlock_function(x) 1
#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
#endif /* USE_POLARSSL */
#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */

1623
Externals/curl/lib/vtls/schannel.c vendored Normal file

File diff suppressed because it is too large Load Diff

118
Externals/curl/lib/vtls/schannel.h vendored Normal file
View File

@ -0,0 +1,118 @@
#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 https://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
/* Both schannel buffer sizes must be > 0 */
#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
void Curl_schannel_close(struct connectdata *conn, int sockindex);
int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
void Curl_schannel_session_free(void *ptr);
int Curl_schannel_init(void);
void Curl_schannel_cleanup(void);
size_t Curl_schannel_version(char *buffer, size_t size);
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 */

993
Externals/curl/lib/vtls/vtls.c vendored Normal file
View File

@ -0,0 +1,993 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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"
https://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;
}
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;
}
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;
}
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!
*
*/
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);
}
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
*/
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 */
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;
}
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;
}
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.
*/
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->bits.conn_to_host && !check->conn_to_host) ||
(conn->bits.conn_to_host && check->conn_to_host &&
Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) &&
((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
(conn->bits.conn_to_port && check->conn_to_port != -1 &&
conn->conn_to_port == check->conn_to_port)) &&
(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.
*/
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);
Curl_safefree(session->conn_to_host);
}
}
/*
* Delete the given session ID from the cache.
*/
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.
*/
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;
char *clone_conn_to_host;
int conn_to_port;
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 */
if(conn->bits.conn_to_host) {
clone_conn_to_host = strdup(conn->conn_to_host.name);
if(!clone_conn_to_host) {
free(clone_host);
return CURLE_OUT_OF_MEMORY; /* bail out */
}
}
else
clone_conn_to_host = NULL;
if(conn->bits.conn_to_port)
conn_to_port = conn->conn_to_port;
else
conn_to_port = -1;
/* 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);
free(store->conn_to_host);
store->name = clone_host; /* clone host name */
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
store->conn_to_port = conn_to_port; /* connect to port number */
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);
free(clone_conn_to_host);
return CURLE_OUT_OF_MEMORY;
}
return CURLE_OK;
}
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);
}
void Curl_ssl_close(struct connectdata *conn, int sockindex)
{
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
curlssl_close(conn, sockindex);
}
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
*/
CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
{
return curlssl_set_engine(data, engine);
}
/* Selects the default SSL crypto engine
*/
CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
{
return curlssl_set_engine_default(data);
}
/* Return list of OpenSSL crypto engine names. */
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.
*/
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;
}
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
*/
int Curl_ssl_check_cxn(struct connectdata *conn)
{
return curlssl_check_cxn(conn);
}
bool Curl_ssl_data_pending(const struct connectdata *conn,
int connindex)
{
return curlssl_data_pending(conn, connindex);
}
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;
}
}
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
*/
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.
*/
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);
}
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.
*/
CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data,
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;
#ifdef curlssl_sha256sum
CURLcode encode;
size_t encodedlen, pinkeylen;
char *encoded, *pinkeycopy, *begin_pos, *end_pos;
unsigned char *sha256sumdigest = NULL;
#endif
/* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
return CURLE_OK;
if(!pubkey || !pubkeylen)
return result;
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
#ifdef curlssl_sha256sum
/* compute sha256sum of public key */
sha256sumdigest = malloc(SHA256_DIGEST_LENGTH);
if(!sha256sumdigest)
return CURLE_OUT_OF_MEMORY;
curlssl_sha256sum(pubkey, pubkeylen,
sha256sumdigest, SHA256_DIGEST_LENGTH);
encode = Curl_base64_encode(data, (char *)sha256sumdigest,
SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
Curl_safefree(sha256sumdigest);
if(encode)
return encode;
infof(data, "\t public key hash: sha256//%s\n", encoded);
/* it starts with sha256//, copy so we can modify it */
pinkeylen = strlen(pinnedpubkey) + 1;
pinkeycopy = malloc(pinkeylen);
if(!pinkeycopy) {
Curl_safefree(encoded);
return CURLE_OUT_OF_MEMORY;
}
memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
/* point begin_pos to the copy, and start extracting keys */
begin_pos = pinkeycopy;
do {
end_pos = strstr(begin_pos, ";sha256//");
/*
* if there is an end_pos, null terminate,
* otherwise it'll go to the end of the original string
*/
if(end_pos)
end_pos[0] = '\0';
/* compare base64 sha256 digests, 8 is the length of "sha256//" */
if(encodedlen == strlen(begin_pos + 8) &&
!memcmp(encoded, begin_pos + 8, encodedlen)) {
result = CURLE_OK;
break;
}
/*
* change back the null-terminator we changed earlier,
* and look for next begin
*/
if(end_pos) {
end_pos[0] = ';';
begin_pos = strstr(end_pos, "sha256//");
}
} while(end_pos && begin_pos);
Curl_safefree(encoded);
Curl_safefree(pinkeycopy);
#else
/* without sha256 support, this cannot match */
(void)data;
#endif
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
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.
*/
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.
*/
bool Curl_ssl_false_start(void)
{
#ifdef curlssl_false_start
return curlssl_false_start();
#else
return FALSE;
#endif
}
#endif /* USE_SSL */

159
Externals/curl/lib/vtls/vtls.h vendored Normal file
View File

@ -0,0 +1,159 @@
#ifndef HEADER_CURL_VTLS_H
#define HEADER_CURL_VTLS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, 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 https://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 */
#include "mbedtls.h" /* mbedTLS versions */
#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
#ifndef SHA256_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH 32 /* fixed size */
#endif
/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
#define ALPN_HTTP_1_1_LENGTH 8
#define ALPN_HTTP_1_1 "http/1.1"
bool Curl_ssl_config_matches(struct ssl_config_data* data,
struct ssl_config_data* needle);
bool Curl_clone_ssl_config(struct ssl_config_data* source,
struct ssl_config_data* dest);
void Curl_free_ssl_config(struct ssl_config_data* sslc);
unsigned int Curl_rand(struct SessionHandle *);
int Curl_ssl_backend(void);
#ifdef USE_SSL
int Curl_ssl_init(void);
void Curl_ssl_cleanup(void);
CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
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) */
void Curl_ssl_close_all(struct SessionHandle *data);
void Curl_ssl_close(struct connectdata *conn, int sockindex);
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
/* Sets engine as default for all SSL operations */
CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
/* init the SSL session ID cache */
CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t);
size_t Curl_ssl_version(char *buffer, size_t size);
bool Curl_ssl_data_pending(const struct connectdata *conn,
int connindex);
int Curl_ssl_check_cxn(struct connectdata *conn);
/* Certificate information list handling. */
void Curl_ssl_free_certinfo(struct SessionHandle *data);
CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num);
CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum,
const char * label, const char * value,
size_t valuelen);
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 */
bool Curl_ssl_getsessionid(struct connectdata *conn,
void **ssl_sessionid,
size_t *idsize); /* set 0 if unknown */
/* add a new session ID */
CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
void *ssl_sessionid,
size_t idsize);
/* Kill a single session ID entry in the cache */
void Curl_ssl_kill_session(struct curl_ssl_session *session);
/* delete a session from the cache */
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 */
int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer,
size_t length);
CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *md5sum, /* output */
size_t md5len);
/* Check pinned public key. */
CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data,
const char *pinnedpubkey,
const unsigned char *pubkey, size_t pubkeylen);
bool Curl_ssl_cert_status_request(void);
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 */