Unverified Commit d65e6cc4 authored by Johannes Schindelin's avatar Johannes Schindelin Committed by Daniel Stenberg
Browse files

vtls: prepare the SSL backends for encapsulated private data



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: default avatarJohannes Schindelin <johannes.schindelin@gmx.de>
parent 20c6cf7e
Loading
Loading
Loading
Loading
+39 −31
Original line number Diff line number Diff line
@@ -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) {
@@ -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;
  }
}

@@ -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;
@@ -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;
@@ -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)) {
@@ -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;
}

@@ -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
@@ -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;
@@ -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;

@@ -412,6 +416,7 @@ 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;
@@ -419,23 +424,23 @@ static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn,
 *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. */
@@ -445,10 +450,10 @@ 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);
@@ -456,15 +461,15 @@ static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn,
    }

    /* 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;
}
@@ -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) {
@@ -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");

@@ -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");
@@ -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.  */
@@ -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? */

@@ -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 = {
+63 −58
Original line number Diff line number Diff line
@@ -122,6 +122,8 @@ and that's a problem since options.h hasn't been included yet. */
#endif
#endif

#define BACKEND connssl

static Curl_recv cyassl_recv;
static Curl_send cyassl_send;

@@ -148,7 +150,7 @@ cyassl_connect_step1(struct connectdata *conn,
  char error_buffer[CYASSL_MAX_ERROR_SZ];
  char *ciphers;
  struct Curl_easy *data = conn->data;
  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
  SSL_METHOD* req_method = NULL;
  curl_socket_t sockfd = conn->sock[sockindex];
#ifdef HAVE_SNI
@@ -158,7 +160,7 @@ cyassl_connect_step1(struct connectdata *conn,
#define use_sni(x)  Curl_nop_stmt
#endif

  if(conssl->state == ssl_connection_complete)
  if(connssl->state == ssl_connection_complete)
    return CURLE_OK;

  if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
@@ -217,11 +219,11 @@ cyassl_connect_step1(struct connectdata *conn,
    return CURLE_OUT_OF_MEMORY;
  }

  if(conssl->ctx)
    SSL_CTX_free(conssl->ctx);
  conssl->ctx = SSL_CTX_new(req_method);
  if(BACKEND->ctx)
    SSL_CTX_free(BACKEND->ctx);
  BACKEND->ctx = SSL_CTX_new(req_method);

  if(!conssl->ctx) {
  if(!BACKEND->ctx) {
    failf(data, "SSL: couldn't create a context!");
    return CURLE_OUT_OF_MEMORY;
  }
@@ -237,9 +239,9 @@ cyassl_connect_step1(struct connectdata *conn,
    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)) {
    if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)) {
      failf(data, "SSL: couldn't set the minimum protocol version");
      return CURLE_SSL_CONNECT_ERROR;
    }
@@ -249,7 +251,7 @@ cyassl_connect_step1(struct connectdata *conn,

  ciphers = SSL_CONN_CONFIG(cipher_list);
  if(ciphers) {
    if(!SSL_CTX_set_cipher_list(conssl->ctx, ciphers)) {
    if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
      failf(data, "failed setting cipher list: %s", ciphers);
      return CURLE_SSL_CIPHER;
    }
@@ -259,7 +261,7 @@ cyassl_connect_step1(struct connectdata *conn,
#ifndef NO_FILESYSTEM
  /* load trusted cacert */
  if(SSL_CONN_CONFIG(CAfile)) {
    if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
    if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx,
                                      SSL_CONN_CONFIG(CAfile),
                                      SSL_CONN_CONFIG(CApath))) {
      if(SSL_CONN_CONFIG(verifypeer)) {
@@ -296,7 +298,7 @@ cyassl_connect_step1(struct connectdata *conn,
  if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
    int file_type = do_file_type(SSL_SET_OPTION(cert_type));

    if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert),
    if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert),
                                     file_type) != 1) {
      failf(data, "unable to use client certificate (no key or wrong pass"
            " phrase?)");
@@ -304,7 +306,7 @@ cyassl_connect_step1(struct connectdata *conn,
    }

    file_type = do_file_type(SSL_SET_OPTION(key_type));
    if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key),
    if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
                                    file_type) != 1) {
      failf(data, "unable to set private key");
      return CURLE_SSL_CONNECT_ERROR;
@@ -316,7 +318,7 @@ cyassl_connect_step1(struct connectdata *conn,
   * 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,
  SSL_CTX_set_verify(BACKEND->ctx,
                     SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
                                                 SSL_VERIFY_NONE,
                     NULL);
@@ -335,7 +337,7 @@ cyassl_connect_step1(struct connectdata *conn,
#ifdef ENABLE_IPV6
       (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
#endif
       (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname,
       (CyaSSL_CTX_UseSNI(BACKEND->ctx, CYASSL_SNI_HOST_NAME, hostname,
                          (unsigned short)hostname_len) != 1)) {
      infof(data, "WARNING: failed to configure server name indication (SNI) "
            "TLS extension\n");
@@ -348,15 +350,15 @@ cyassl_connect_step1(struct connectdata *conn,
     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 */
  CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x17); /* secp256r1 */
  CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x19); /* secp521r1 */
  CyaSSL_CTX_UseSupportedCurve(BACKEND->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,
    result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
                                      data->set.ssl.fsslctxp);
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
@@ -374,10 +376,10 @@ cyassl_connect_step1(struct connectdata *conn,
#endif

  /* Let's make an SSL structure */
  if(conssl->handle)
    SSL_free(conssl->handle);
  conssl->handle = SSL_new(conssl->ctx);
  if(!conssl->handle) {
  if(BACKEND->handle)
    SSL_free(BACKEND->handle);
  BACKEND->handle = SSL_new(BACKEND->ctx);
  if(!BACKEND->handle) {
    failf(data, "SSL: couldn't create a context (handle)!");
    return CURLE_OUT_OF_MEMORY;
  }
@@ -400,7 +402,7 @@ cyassl_connect_step1(struct connectdata *conn,
    strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
    infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);

    if(wolfSSL_UseALPN(conssl->handle, protocols,
    if(wolfSSL_UseALPN(BACKEND->handle, protocols,
                       (unsigned)strlen(protocols),
                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
      failf(data, "SSL: failed setting ALPN protocols");
@@ -416,10 +418,10 @@ cyassl_connect_step1(struct connectdata *conn,
    Curl_ssl_sessionid_lock(conn);
    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
      /* we got a session id, use it! */
      if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
      if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
        Curl_ssl_sessionid_unlock(conn);
        failf(data, "SSL: SSL_set_session failed: %s",
              ERR_error_string(SSL_get_error(conssl->handle, 0),
              ERR_error_string(SSL_get_error(BACKEND->handle, 0),
              error_buffer));
        return CURLE_SSL_CONNECT_ERROR;
      }
@@ -430,12 +432,12 @@ cyassl_connect_step1(struct connectdata *conn,
  }

  /* pass the raw socket into the SSL layer */
  if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
  if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) {
    failf(data, "SSL: SSL_set_fd failed");
    return CURLE_SSL_CONNECT_ERROR;
  }

  conssl->connecting_state = ssl_connect_2;
  connssl->connecting_state = ssl_connect_2;
  return CURLE_OK;
}

@@ -446,7 +448,7 @@ cyassl_connect_step2(struct connectdata *conn,
{
  int ret = -1;
  struct Curl_easy *data = conn->data;
  struct ssl_connect_data* conssl = &conn->ssl[sockindex];
  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
    conn->host.name;
  const char * const dispname = SSL_IS_PROXY() ?
@@ -460,22 +462,22 @@ cyassl_connect_step2(struct connectdata *conn,

  /* Enable RFC2818 checks */
  if(SSL_CONN_CONFIG(verifyhost)) {
    ret = CyaSSL_check_domain_name(conssl->handle, hostname);
    ret = CyaSSL_check_domain_name(BACKEND->handle, hostname);
    if(ret == SSL_FAILURE)
      return CURLE_OUT_OF_MEMORY;
  }

  ret = SSL_connect(conssl->handle);
  ret = SSL_connect(BACKEND->handle);
  if(ret != 1) {
    char error_buffer[CYASSL_MAX_ERROR_SZ];
    int  detail = SSL_get_error(conssl->handle, ret);
    int  detail = SSL_get_error(BACKEND->handle, ret);

    if(SSL_ERROR_WANT_READ == detail) {
      conssl->connecting_state = ssl_connect_2_reading;
      connssl->connecting_state = ssl_connect_2_reading;
      return CURLE_OK;
    }
    else if(SSL_ERROR_WANT_WRITE == detail) {
      conssl->connecting_state = ssl_connect_2_writing;
      connssl->connecting_state = ssl_connect_2_writing;
      return CURLE_OK;
    }
    /* There is no easy way to override only the CN matching.
@@ -536,7 +538,7 @@ cyassl_connect_step2(struct connectdata *conn,
    curl_asn1Element *pubkey;
    CURLcode result;

    x509 = SSL_get_peer_certificate(conssl->handle);
    x509 = SSL_get_peer_certificate(BACKEND->handle);
    if(!x509) {
      failf(data, "SSL: failed retrieving server certificate");
      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
@@ -578,7 +580,7 @@ cyassl_connect_step2(struct connectdata *conn,
    char *protocol = NULL;
    unsigned short protocol_len = 0;

    rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
    rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len);

    if(rc == SSL_SUCCESS) {
      infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
@@ -607,11 +609,11 @@ cyassl_connect_step2(struct connectdata *conn,
  }
#endif /* HAVE_ALPN */

  conssl->connecting_state = ssl_connect_3;
  connssl->connecting_state = ssl_connect_3;
#if (LIBCYASSL_VERSION_HEX >= 0x03009010)
  infof(data, "SSL connection using %s / %s\n",
        wolfSSL_get_version(conssl->handle),
        wolfSSL_get_cipher_name(conssl->handle));
        wolfSSL_get_version(BACKEND->handle),
        wolfSSL_get_cipher_name(BACKEND->handle));
#else
  infof(data, "SSL connected\n");
#endif
@@ -635,7 +637,7 @@ cyassl_connect_step3(struct connectdata *conn,
    SSL_SESSION *our_ssl_sessionid;
    void *old_ssl_sessionid = NULL;

    our_ssl_sessionid = SSL_get_session(connssl->handle);
    our_ssl_sessionid = SSL_get_session(BACKEND->handle);

    Curl_ssl_sessionid_lock(conn);
    incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
@@ -672,12 +674,13 @@ static ssize_t cyassl_send(struct connectdata *conn,
                           size_t len,
                           CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  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);
  int  rc     = SSL_write(BACKEND->handle, mem, memlen);

  if(rc < 0) {
    int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
    int err = SSL_get_error(BACKEND->handle, rc);

    switch(err) {
    case SSL_ERROR_WANT_READ:
@@ -698,16 +701,16 @@ static ssize_t cyassl_send(struct connectdata *conn,

static void Curl_cyassl_close(struct connectdata *conn, int sockindex)
{
  struct ssl_connect_data *conssl = &conn->ssl[sockindex];
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];

  if(conssl->handle) {
    (void)SSL_shutdown(conssl->handle);
    SSL_free(conssl->handle);
    conssl->handle = NULL;
  if(BACKEND->handle) {
    (void)SSL_shutdown(BACKEND->handle);
    SSL_free(BACKEND->handle);
    BACKEND->handle = NULL;
  }
  if(conssl->ctx) {
    SSL_CTX_free(conssl->ctx);
    conssl->ctx = NULL;
  if(BACKEND->ctx) {
    SSL_CTX_free(BACKEND->ctx);
    BACKEND->ctx = NULL;
  }
}

@@ -717,12 +720,13 @@ static ssize_t cyassl_recv(struct connectdata *conn,
                           size_t buffersize,
                           CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = &conn->ssl[num];
  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);
  int  nread    = SSL_read(BACKEND->handle, buf, buffsize);

  if(nread < 0) {
    int err = SSL_get_error(conn->ssl[num].handle, nread);
    int err = SSL_get_error(BACKEND->handle, nread);

    switch(err) {
    case SSL_ERROR_ZERO_RETURN: /* no more data */
@@ -774,8 +778,9 @@ static int Curl_cyassl_init(void)
static bool Curl_cyassl_data_pending(const struct connectdata* conn,
                                     int connindex)
{
  if(conn->ssl[connindex].handle)   /* SSL is in use */
    return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
  const struct ssl_connect_data *connssl = &conn->ssl[connindex];
  if(BACKEND->handle)   /* SSL is in use */
    return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE;
  else
    return FALSE;
}
@@ -790,9 +795,9 @@ static int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
  int retval = 0;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];

  if(connssl->handle) {
    SSL_free(connssl->handle);
    connssl->handle = NULL;
  if(BACKEND->handle) {
    SSL_free(BACKEND->handle);
    BACKEND->handle = NULL;
  }
  return retval;
}
@@ -963,7 +968,7 @@ static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
                                       CURLINFO info UNUSED_PARAM)
{
  (void)info;
  return connssl->handle;
  return BACKEND->handle;
}

const struct Curl_ssl Curl_ssl_cyassl = {
+85 −83

File changed.

Preview size limit exceeded, changes collapsed.

+64 −59

File changed.

Preview size limit exceeded, changes collapsed.

+52 −44
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ static bool gtls_inited = FALSE;
# include <gnutls/ocsp.h>
#endif

#define BACKEND connssl

/*
 * Custom push and pull callback functions used by GNU TLS to read and write
 * to the socket.  These functions are simple wrappers to send() and recv()
@@ -276,7 +278,7 @@ static CURLcode handshake(struct connectdata *conn,
{
  struct Curl_easy *data = conn->data;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  gnutls_session_t session = conn->ssl[sockindex].session;
  gnutls_session_t session = BACKEND->session;
  curl_socket_t sockfd = conn->sock[sockindex];
  time_t timeout_ms;
  int rc;
@@ -474,6 +476,7 @@ gtls_connect_step1(struct connectdata *conn,
                   int sockindex)
{
  struct Curl_easy *data = conn->data;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  unsigned int init_flags;
  gnutls_session_t session;
  int rc;
@@ -509,7 +512,7 @@ gtls_connect_step1(struct connectdata *conn,
  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
    conn->host.name;

  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;
@@ -525,7 +528,7 @@ gtls_connect_step1(struct connectdata *conn,
    sni = FALSE; /* SSLv3 has no SNI */

  /* allocate a cred struct */
  rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
  rc = gnutls_certificate_allocate_credentials(&BACKEND->cred);
  if(rc != GNUTLS_E_SUCCESS) {
    failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
    return CURLE_SSL_CONNECT_ERROR;
@@ -536,15 +539,14 @@ gtls_connect_step1(struct connectdata *conn,
    infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));

    rc = gnutls_srp_allocate_client_credentials(
           &conn->ssl[sockindex].srp_client_cred);
           &BACKEND->srp_client_cred);
    if(rc != GNUTLS_E_SUCCESS) {
      failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
            gnutls_strerror(rc));
      return CURLE_OUT_OF_MEMORY;
    }

    rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
                                           srp_client_cred,
    rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred,
                                           SSL_SET_OPTION(username),
                                           SSL_SET_OPTION(password));
    if(rc != GNUTLS_E_SUCCESS) {
@@ -557,10 +559,10 @@ gtls_connect_step1(struct connectdata *conn,

  if(SSL_CONN_CONFIG(CAfile)) {
    /* set the trusted CA cert bundle file */
    gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
    gnutls_certificate_set_verify_flags(BACKEND->cred,
                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

    rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
    rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred,
                                                SSL_CONN_CONFIG(CAfile),
                                                GNUTLS_X509_FMT_PEM);
    if(rc < 0) {
@@ -577,7 +579,7 @@ gtls_connect_step1(struct connectdata *conn,
#ifdef HAS_CAPATH
  if(SSL_CONN_CONFIG(CApath)) {
    /* set the trusted CA cert directory */
    rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
    rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred,
                                               SSL_CONN_CONFIG(CApath),
                                               GNUTLS_X509_FMT_PEM);
    if(rc < 0) {
@@ -596,13 +598,13 @@ gtls_connect_step1(struct connectdata *conn,
  /* use system ca certificate store as fallback */
  if(SSL_CONN_CONFIG(verifypeer) &&
     !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
    gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
    gnutls_certificate_set_x509_system_trust(BACKEND->cred);
  }
#endif

  if(SSL_SET_OPTION(CRLfile)) {
    /* set the CRL list file */
    rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
    rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred,
                                              SSL_SET_OPTION(CRLfile),
                                              GNUTLS_X509_FMT_PEM);
    if(rc < 0) {
@@ -623,14 +625,14 @@ gtls_connect_step1(struct connectdata *conn,
  init_flags |= GNUTLS_NO_TICKETS;
#endif

  rc = gnutls_init(&conn->ssl[sockindex].session, init_flags);
  rc = gnutls_init(&BACKEND->session, init_flags);
  if(rc != GNUTLS_E_SUCCESS) {
    failf(data, "gnutls_init() failed: %d", rc);
    return CURLE_SSL_CONNECT_ERROR;
  }

  /* convenient assign */
  session = conn->ssl[sockindex].session;
  session = BACKEND->session;

  if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
@@ -787,7 +789,7 @@ gtls_connect_step1(struct connectdata *conn,
        GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
        GNUTLS_PKCS_USE_PBES2_AES_256;
      rc = gnutls_certificate_set_x509_key_file2(
           conn->ssl[sockindex].cred,
           BACKEND->cred,
           SSL_SET_OPTION(cert),
           SSL_SET_OPTION(key) ?
           SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
@@ -807,7 +809,7 @@ gtls_connect_step1(struct connectdata *conn,
    }
    else {
      if(gnutls_certificate_set_x509_key_file(
           conn->ssl[sockindex].cred,
           BACKEND->cred,
           SSL_SET_OPTION(cert),
           SSL_SET_OPTION(key) ?
           SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
@@ -823,7 +825,7 @@ gtls_connect_step1(struct connectdata *conn,
  /* put the credentials to the current session */
  if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
    rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
                                conn->ssl[sockindex].srp_client_cred);
                                BACKEND->srp_client_cred);
    if(rc != GNUTLS_E_SUCCESS) {
      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
      return CURLE_SSL_CONNECT_ERROR;
@@ -833,7 +835,7 @@ gtls_connect_step1(struct connectdata *conn,
#endif
  {
    rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
                                conn->ssl[sockindex].cred);
                                BACKEND->cred);
    if(rc != GNUTLS_E_SUCCESS) {
      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
      return CURLE_SSL_CONNECT_ERROR;
@@ -966,7 +968,8 @@ gtls_connect_step3(struct connectdata *conn,
  time_t certclock;
  const char *ptr;
  struct Curl_easy *data = conn->data;
  gnutls_session_t session = conn->ssl[sockindex].session;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  gnutls_session_t session = BACKEND->session;
  int rc;
#ifdef HAS_ALPN
  gnutls_datum_t proto;
@@ -1516,13 +1519,15 @@ static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex)
static bool Curl_gtls_data_pending(const struct connectdata *conn,
                                   int connindex)
{
  const struct ssl_connect_data *connssl = &conn->ssl[connindex];
  bool res = FALSE;
  if(conn->ssl[connindex].session &&
     0 != gnutls_record_check_pending(conn->ssl[connindex].session))
  if(BACKEND->session &&
     0 != gnutls_record_check_pending(BACKEND->session))
    res = TRUE;

  if(conn->proxy_ssl[connindex].session &&
     0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session))
  connssl = &conn->proxy_ssl[connindex];
  if(BACKEND->session &&
     0 != gnutls_record_check_pending(BACKEND->session))
    res = TRUE;

  return res;
@@ -1534,7 +1539,8 @@ static ssize_t gtls_send(struct connectdata *conn,
                         size_t len,
                         CURLcode *curlcode)
{
  ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  ssize_t rc = gnutls_record_send(BACKEND->session, mem, len);

  if(rc < 0) {
    *curlcode = (rc == GNUTLS_E_AGAIN)
@@ -1547,21 +1553,21 @@ static ssize_t gtls_send(struct connectdata *conn,
  return rc;
}

static void close_one(struct ssl_connect_data *ssl)
static void close_one(struct ssl_connect_data *connssl)
{
  if(ssl->session) {
    gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
    gnutls_deinit(ssl->session);
    ssl->session = NULL;
  if(BACKEND->session) {
    gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR);
    gnutls_deinit(BACKEND->session);
    BACKEND->session = NULL;
  }
  if(ssl->cred) {
    gnutls_certificate_free_credentials(ssl->cred);
    ssl->cred = NULL;
  if(BACKEND->cred) {
    gnutls_certificate_free_credentials(BACKEND->cred);
    BACKEND->cred = NULL;
  }
#ifdef USE_TLS_SRP
  if(ssl->srp_client_cred) {
    gnutls_srp_free_client_credentials(ssl->srp_client_cred);
    ssl->srp_client_cred = NULL;
  if(BACKEND->srp_client_cred) {
    gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
    BACKEND->srp_client_cred = NULL;
  }
#endif
}
@@ -1578,6 +1584,7 @@ static void Curl_gtls_close(struct connectdata *conn, int sockindex)
 */
static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
{
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  ssize_t result;
  int retval = 0;
  struct Curl_easy *data = conn->data;
@@ -1590,16 +1597,16 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
     we do not send one. Let's hope other servers do the same... */

  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
      gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
      gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR);

  if(conn->ssl[sockindex].session) {
  if(BACKEND->session) {
    while(!done) {
      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 */
        result = gnutls_record_recv(conn->ssl[sockindex].session,
        result = gnutls_record_recv(BACKEND->session,
                                    buf, sizeof(buf));
        switch(result) {
        case 0:
@@ -1630,18 +1637,18 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
        done = 1;
      }
    }
    gnutls_deinit(conn->ssl[sockindex].session);
    gnutls_deinit(BACKEND->session);
  }
  gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
  gnutls_certificate_free_credentials(BACKEND->cred);

#ifdef USE_TLS_SRP
  if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
     && SSL_SET_OPTION(username) != NULL)
    gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
    gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
#endif

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

  return retval;
}
@@ -1652,9 +1659,10 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
                         size_t buffersize,        /* max amount to read */
                         CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = &conn->ssl[num];
  ssize_t ret;

  ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
  ret = gnutls_record_recv(BACKEND->session, buf, buffersize);
  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
    *curlcode = CURLE_AGAIN;
    return -1;
@@ -1786,7 +1794,7 @@ static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
                                     CURLINFO info UNUSED_PARAM)
{
  (void)info;
  return connssl->session;
  return BACKEND->session;
}

const struct Curl_ssl Curl_ssl_gnutls = {
Loading