mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Externals: Add libcurl.
This commit is contained in:
690
Externals/curl/lib/vtls/axtls.c
vendored
Normal file
690
Externals/curl/lib/vtls/axtls.c
vendored
Normal 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
71
Externals/curl/lib/vtls/axtls.h
vendored
Normal 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
902
Externals/curl/lib/vtls/cyassl.c
vendored
Normal 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
92
Externals/curl/lib/vtls/cyassl.h
vendored
Normal 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
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
76
Externals/curl/lib/vtls/darwinssl.h
vendored
Normal 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
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
71
Externals/curl/lib/vtls/gskit.h
vendored
Normal 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
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
91
Externals/curl/lib/vtls/gtls.h
vendored
Normal 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
866
Externals/curl/lib/vtls/mbedtls.c
vendored
Normal 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
80
Externals/curl/lib/vtls/mbedtls.h
vendored
Normal 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
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
105
Externals/curl/lib/vtls/nssg.h
vendored
Normal 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
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
123
Externals/curl/lib/vtls/openssl.h
vendored
Normal 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
814
Externals/curl/lib/vtls/polarssl.c
vendored
Normal 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
81
Externals/curl/lib/vtls/polarssl.h
vendored
Normal 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 */
|
153
Externals/curl/lib/vtls/polarssl_threadlock.c
vendored
Normal file
153
Externals/curl/lib/vtls/polarssl_threadlock.c
vendored
Normal 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 */
|
53
Externals/curl/lib/vtls/polarssl_threadlock.h
vendored
Normal file
53
Externals/curl/lib/vtls/polarssl_threadlock.h
vendored
Normal 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
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
118
Externals/curl/lib/vtls/schannel.h
vendored
Normal 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
993
Externals/curl/lib/vtls/vtls.c
vendored
Normal 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
159
Externals/curl/lib/vtls/vtls.h
vendored
Normal 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 */
|
Reference in New Issue
Block a user