Skip to content

Commit

Permalink
vtls: prepare the SSL backends for encapsulated private data
Browse files Browse the repository at this point in the history
At the moment, cURL's SSL backend needs to be configured at build time.
As such, it is totally okay for them to hard-code their backend-specific
data in the ssl_connect_data struct.

In preparation for making the SSL backend a runtime option, let's make
the access of said private data a bit more abstract so that it can be
adjusted later in an easy manner.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
dscho authored and bagder committed Aug 28, 2017
1 parent 20c6cf7 commit d65e6cc
Show file tree
Hide file tree
Showing 10 changed files with 762 additions and 712 deletions.
70 changes: 39 additions & 31 deletions lib/vtls/axtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#include "curl_memory.h"
#include "memdebug.h"

#define BACKEND connssl

static CURLcode map_error_to_curl(int axtls_err)
{
switch(axtls_err) {
Expand Down Expand Up @@ -104,13 +106,13 @@ 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(BACKEND->ssl) {
ssl_free(BACKEND->ssl);
BACKEND->ssl = NULL;
}
if(connssl->ssl_ctx) {
ssl_ctx_free(connssl->ssl_ctx);
connssl->ssl_ctx = NULL;
if(BACKEND->ssl_ctx) {
ssl_ctx_free(BACKEND->ssl_ctx);
BACKEND->ssl_ctx = NULL;
}
}

Expand All @@ -121,6 +123,7 @@ static void free_ssl_structs(struct ssl_connect_data *connssl)
*/
static CURLcode connect_prep(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
SSL_CTX *ssl_ctx;
SSL *ssl = NULL;
Expand All @@ -135,7 +138,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
SSL_SERVER_VERIFY_LATER |
SSL_CONNECT_IN_PARTS;

if(conn->ssl[sockindex].state == ssl_connection_complete)
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
return CURLE_OK;
Expand Down Expand Up @@ -169,8 +172,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}

conn->ssl[sockindex].ssl_ctx = ssl_ctx;
conn->ssl[sockindex].ssl = NULL;
BACKEND->ssl_ctx = ssl_ctx;
BACKEND->ssl = NULL;

/* Load the trusted CA cert bundle file */
if(SSL_CONN_CONFIG(CAfile)) {
Expand Down Expand Up @@ -265,7 +268,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
if(!ssl)
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL);

conn->ssl[sockindex].ssl = ssl;
BACKEND->ssl = ssl;
return CURLE_OK;
}

Expand All @@ -275,7 +278,7 @@ static void Curl_axtls_close(struct connectdata *conn, int sockindex)

infof(conn->data, " Curl_axtls_close\n");

/* line from openssl.c: (void)SSL_shutdown(connssl->ssl);
/* line from openssl.c: (void)SSL_shutdown(BACKEND->ssl);
axTLS compat layer does nothing for SSL_shutdown */

/* The following line is from openssl.c. There seems to be no axTLS
Expand All @@ -292,7 +295,8 @@ static void Curl_axtls_close(struct connectdata *conn, int sockindex)
static CURLcode connect_finish(struct connectdata *conn, int sockindex)
{
struct Curl_easy *data = conn->data;
SSL *ssl = conn->ssl[sockindex].ssl;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SSL *ssl = BACKEND->ssl;
const char *peer_CN;
uint32_t dns_altname_index;
const char *dns_altname;
Expand Down Expand Up @@ -387,7 +391,7 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
}

/* General housekeeping */
conn->ssl[sockindex].state = ssl_connection_complete;
connssl->state = ssl_connection_complete;
conn->recv[sockindex] = axtls_recv;
conn->send[sockindex] = axtls_send;

Expand All @@ -412,30 +416,31 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn,
int sockindex, bool *done)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
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) {
if(connssl->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;
connssl->connecting_state = ssl_connect_2;
}

if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
if(connssl->connecting_state == ssl_connect_2) {
/* Check to make sure handshake was ok. */
if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
if(ssl_handshake_status(BACKEND->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);
ssl_fcn_return = ssl_read(BACKEND->ssl, NULL);
if(ssl_fcn_return < 0) {
Curl_axtls_close(conn, sockindex);
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
Expand All @@ -445,26 +450,26 @@ static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn,
}
}
infof(conn->data, "handshake completed successfully\n");
conn->ssl[sockindex].connecting_state = ssl_connect_3;
connssl->connecting_state = ssl_connect_3;
}

if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
if(connssl->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;
connssl->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;
connssl->state = ssl_connection_none;
connssl->connecting_state = ssl_connect_1;
/* Return value perhaps not strictly correct, but distinguishes the issue.*/
return CURLE_BAD_FUNCTION_ARGUMENT;
}
Expand All @@ -479,7 +484,8 @@ static CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data;
CURLcode conn_step = connect_prep(conn, sockindex);
int ssl_fcn_return;
SSL *ssl = conn->ssl[sockindex].ssl;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SSL *ssl = BACKEND->ssl;
long timeout_ms;

if(conn_step != CURLE_OK) {
Expand Down Expand Up @@ -525,8 +531,9 @@ static ssize_t axtls_send(struct connectdata *conn,
size_t len,
CURLcode *err)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
/* ssl_write() returns 'int' while write() and send() returns 'size_t' */
int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
int rc = ssl_write(BACKEND->ssl, mem, (int)len);

infof(conn->data, " axtls_send\n");

Expand Down Expand Up @@ -563,17 +570,17 @@ static int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)

/* 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);
(void)SSL_shutdown(BACKEND->ssl);
*/

if(connssl->ssl) {
if(BACKEND->ssl) {
int what = SOCKET_READABLE(conn->sock[sockindex], 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);
nread = (ssize_t)ssl_read(BACKEND->ssl, &buf);

if(nread < SSL_OK) {
failf(data, "close notify alert not received during shutdown");
Expand Down Expand Up @@ -609,7 +616,7 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */

*err = CURLE_OK;
if(connssl) {
ret = ssl_read(connssl->ssl, &read_buf);
ret = ssl_read(BACKEND->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. */
Expand Down Expand Up @@ -644,7 +651,8 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
*/
static int Curl_axtls_check_cxn(struct connectdata *conn)
{
/* openssl.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
/* 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? */

Expand Down Expand Up @@ -685,7 +693,7 @@ static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
(void)info;
return connssl->ssl;
return BACKEND->ssl;
}

const struct Curl_ssl Curl_ssl_axtls = {
Expand Down

0 comments on commit d65e6cc

Please sign in to comment.