Imported Upstream version 7.59.0
[platform/upstream/curl.git] / lib / vtls / mbedtls.c
index 07239bf..28251a3 100644 (file)
 #include "curl_memory.h"
 #include "memdebug.h"
 
+struct ssl_backend_data {
+  mbedtls_ctr_drbg_context ctr_drbg;
+  mbedtls_entropy_context entropy;
+  mbedtls_ssl_context ssl;
+  int server_fd;
+  mbedtls_x509_crt cacert;
+  mbedtls_x509_crt clicert;
+  mbedtls_x509_crl crl;
+  mbedtls_pk_context pk;
+  mbedtls_ssl_config config;
+  const char *protocols[3];
+};
+
+#define BACKEND connssl->backend
+
 /* 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 mbedtls_entropy_context ts_entropy;
 
 static int entropy_init_initialized = 0;
 
@@ -131,7 +146,7 @@ static void mbed_debug(void *context, int level, const char *f_name,
 /*
  *  profile
  */
-const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
+static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
 {
   /* Hashes from SHA-1 and above */
   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
@@ -157,6 +172,71 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
 static Curl_recv mbed_recv;
 static Curl_send mbed_send;
 
+static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
+{
+  switch(version) {
+    case CURL_SSLVERSION_TLSv1_0:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_1:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_2:
+      *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+      return CURLE_OK;
+    case CURL_SSLVERSION_TLSv1_3:
+      break;
+  }
+  return CURLE_SSL_CONNECT_ERROR;
+}
+
+static CURLcode
+set_ssl_version_min_max(struct connectdata *conn, int sockindex)
+{
+  struct Curl_easy *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
+  int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
+  long ssl_version = SSL_CONN_CONFIG(version);
+  long ssl_version_max = SSL_CONN_CONFIG(version_max);
+  CURLcode result = CURLE_OK;
+
+  switch(ssl_version) {
+    case CURL_SSLVERSION_DEFAULT:
+    case CURL_SSLVERSION_TLSv1:
+      ssl_version = CURL_SSLVERSION_TLSv1_0;
+      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+      break;
+  }
+
+  switch(ssl_version_max) {
+    case CURL_SSLVERSION_MAX_NONE:
+      ssl_version_max = ssl_version << 16;
+      break;
+    case CURL_SSLVERSION_MAX_DEFAULT:
+      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+      break;
+  }
+
+  result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
+  if(result) {
+    failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+    return result;
+  }
+  result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
+  if(result) {
+    failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+    return result;
+  }
+
+  mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                               mbedtls_ver_min);
+  mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                               mbedtls_ver_max);
+
+  return result;
+}
+
 static CURLcode
 mbed_connect_step1(struct connectdata *conn,
                    int sockindex)
@@ -173,7 +253,7 @@ mbed_connect_step1(struct connectdata *conn,
   const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
   int ret = -1;
   char errorbuf[128];
-  errorbuf[0]=0;
+  errorbuf[0] = 0;
 
   /* mbedTLS only supports SSLv3 and TLSv1 */
   if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
@@ -182,11 +262,11 @@ mbed_connect_step1(struct connectdata *conn,
   }
 
 #ifdef THREADING_SUPPORT
-  entropy_init_mutex(&entropy);
-  mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+  entropy_init_mutex(&ts_entropy);
+  mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg);
 
-  ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex,
-                              &entropy, NULL, 0);
+  ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex,
+                              &ts_entropy, NULL, 0);
   if(ret) {
 #ifdef MBEDTLS_ERROR_C
     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -195,11 +275,11 @@ mbed_connect_step1(struct connectdata *conn,
           -ret, errorbuf);
   }
 #else
-  mbedtls_entropy_init(&connssl->entropy);
-  mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+  mbedtls_entropy_init(&BACKEND->entropy);
+  mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg);
 
-  ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func,
-                              &connssl->entropy, NULL, 0);
+  ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func,
+                              &BACKEND->entropy, NULL, 0);
   if(ret) {
 #ifdef MBEDTLS_ERROR_C
     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -210,10 +290,10 @@ mbed_connect_step1(struct connectdata *conn,
 #endif /* THREADING_SUPPORT */
 
   /* Load the trusted CA */
-  mbedtls_x509_crt_init(&connssl->cacert);
+  mbedtls_x509_crt_init(&BACKEND->cacert);
 
   if(ssl_cafile) {
-    ret = mbedtls_x509_crt_parse_file(&connssl->cacert, ssl_cafile);
+    ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile);
 
     if(ret<0) {
 #ifdef MBEDTLS_ERROR_C
@@ -228,7 +308,7 @@ mbed_connect_step1(struct connectdata *conn,
   }
 
   if(ssl_capath) {
-    ret = mbedtls_x509_crt_parse_path(&connssl->cacert, ssl_capath);
+    ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath);
 
     if(ret<0) {
 #ifdef MBEDTLS_ERROR_C
@@ -243,10 +323,10 @@ mbed_connect_step1(struct connectdata *conn,
   }
 
   /* Load the client certificate */
-  mbedtls_x509_crt_init(&connssl->clicert);
+  mbedtls_x509_crt_init(&BACKEND->clicert);
 
   if(ssl_cert) {
-    ret = mbedtls_x509_crt_parse_file(&connssl->clicert, ssl_cert);
+    ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert);
 
     if(ret) {
 #ifdef MBEDTLS_ERROR_C
@@ -260,12 +340,12 @@ mbed_connect_step1(struct connectdata *conn,
   }
 
   /* Load the client private key */
-  mbedtls_pk_init(&connssl->pk);
+  mbedtls_pk_init(&BACKEND->pk);
 
   if(SSL_SET_OPTION(key)) {
-    ret = mbedtls_pk_parse_keyfile(&connssl->pk, SSL_SET_OPTION(key),
+    ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key),
                                    SSL_SET_OPTION(key_passwd));
-    if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
+    if(ret == 0 && !mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA))
       ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
 
     if(ret) {
@@ -280,10 +360,10 @@ mbed_connect_step1(struct connectdata *conn,
   }
 
   /* Load the CRL */
-  mbedtls_x509_crl_init(&connssl->crl);
+  mbedtls_x509_crl_init(&BACKEND->crl);
 
   if(ssl_crlfile) {
-    ret = mbedtls_x509_crl_parse_file(&connssl->crl, ssl_crlfile);
+    ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile);
 
     if(ret) {
 #ifdef MBEDTLS_ERROR_C
@@ -298,14 +378,14 @@ mbed_connect_step1(struct connectdata *conn,
 
   infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
 
-  mbedtls_ssl_config_init(&connssl->config);
+  mbedtls_ssl_config_init(&BACKEND->config);
 
-  mbedtls_ssl_init(&connssl->ssl);
-  if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) {
+  mbedtls_ssl_init(&BACKEND->ssl);
+  if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) {
     failf(data, "mbedTLS: ssl_init failed");
     return CURLE_SSL_CONNECT_ERROR;
   }
-  ret = mbedtls_ssl_config_defaults(&connssl->config,
+  ret = mbedtls_ssl_config_defaults(&BACKEND->config,
                                     MBEDTLS_SSL_IS_CLIENT,
                                     MBEDTLS_SSL_TRANSPORT_STREAM,
                                     MBEDTLS_SSL_PRESET_DEFAULT);
@@ -315,76 +395,67 @@ mbed_connect_step1(struct connectdata *conn,
   }
 
   /* new profile with RSA min key len = 1024 ... */
-  mbedtls_ssl_conf_cert_profile(&connssl->config,
+  mbedtls_ssl_conf_cert_profile(&BACKEND->config,
                                 &mbedtls_x509_crt_profile_fr);
 
   switch(SSL_CONN_CONFIG(version)) {
   case CURL_SSLVERSION_DEFAULT:
   case CURL_SSLVERSION_TLSv1:
-    mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+    mbedtls_ssl_conf_min_version(&BACKEND->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_conf_min_version(&BACKEND->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_conf_max_version(&BACKEND->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;
   case CURL_SSLVERSION_TLSv1_3:
-    failf(data, "mbedTLS: TLS 1.3 is not yet supported");
-    return CURLE_SSL_CONNECT_ERROR;
+    {
+      CURLcode result = set_ssl_version_min_max(conn, sockindex);
+      if(result != CURLE_OK)
+        return result;
+      break;
+    }
   default:
     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
     return CURLE_SSL_CONNECT_ERROR;
   }
 
-  mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+  mbedtls_ssl_conf_authmode(&BACKEND->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_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random,
+                       &BACKEND->ctr_drbg);
+  mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex],
                       mbedtls_net_send,
                       mbedtls_net_recv,
                       NULL /*  rev_timeout() */);
 
-  mbedtls_ssl_conf_ciphersuites(&connssl->config,
+  mbedtls_ssl_conf_ciphersuites(&BACKEND->config,
                                 mbedtls_ssl_list_ciphersuites());
 
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+  mbedtls_ssl_conf_renegotiation(&BACKEND->config,
+                                 MBEDTLS_SSL_RENEGOTIATION_ENABLED);
+#endif
+
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-  mbedtls_ssl_conf_session_tickets(&connssl->config,
+  mbedtls_ssl_conf_session_tickets(&BACKEND->config,
                                    MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
 #endif
 
   /* Check if there's a cached ID we can/should use here! */
-  if(data->set.general_ssl.sessionid) {
+  if(SSL_SET_OPTION(primary.sessionid)) {
     void *old_session = NULL;
 
     Curl_ssl_sessionid_lock(conn);
     if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
-      ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
+      ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session);
       if(ret) {
         Curl_ssl_sessionid_unlock(conn);
         failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
@@ -395,15 +466,15 @@ mbed_connect_step1(struct connectdata *conn,
     Curl_ssl_sessionid_unlock(conn);
   }
 
-  mbedtls_ssl_conf_ca_chain(&connssl->config,
-                            &connssl->cacert,
-                            &connssl->crl);
+  mbedtls_ssl_conf_ca_chain(&BACKEND->config,
+                            &BACKEND->cacert,
+                            &BACKEND->crl);
 
   if(SSL_SET_OPTION(key)) {
-    mbedtls_ssl_conf_own_cert(&connssl->config,
-                              &connssl->clicert, &connssl->pk);
+    mbedtls_ssl_conf_own_cert(&BACKEND->config,
+                              &BACKEND->clicert, &BACKEND->pk);
   }
-  if(mbedtls_ssl_set_hostname(&connssl->ssl, hostname)) {
+  if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) {
     /* 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. */
@@ -413,7 +484,7 @@ mbed_connect_step1(struct connectdata *conn,
 
 #ifdef HAS_ALPN
   if(conn->bits.tls_enable_alpn) {
-    const char **p = &connssl->protocols[0];
+    const char **p = &BACKEND->protocols[0];
 #ifdef USE_NGHTTP2
     if(data->set.httpversion >= CURL_HTTP_VERSION_2)
       *p++ = NGHTTP2_PROTO_VERSION_ID;
@@ -422,19 +493,19 @@ mbed_connect_step1(struct connectdata *conn,
     *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])) {
+    if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config,
+                                       &BACKEND->protocols[0])) {
       failf(data, "Failed setting ALPN protocols");
       return CURLE_SSL_CONNECT_ERROR;
     }
-    for(p = &connssl->protocols[0]; *p; ++p)
+    for(p = &BACKEND->protocols[0]; *p; ++p)
       infof(data, "ALPN, offering %s\n", *p);
   }
 #endif
 
 #ifdef MBEDTLS_DEBUG
   /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
-  mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data);
+  mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data);
   /* - 0 No debug
    * - 1 Error
    * - 2 State change
@@ -444,6 +515,16 @@ mbed_connect_step1(struct connectdata *conn,
   mbedtls_debug_set_threshold(4);
 #endif
 
+  /* give application a chance to interfere with mbedTLS set up. */
+  if(data->set.ssl.fsslctx) {
+    ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config,
+                                   data->set.ssl.fsslctxp);
+    if(ret) {
+      failf(data, "error signaled by ssl ctx callback");
+      return ret;
+    }
+  }
+
   connssl->connecting_state = ssl_connect_2;
 
   return CURLE_OK;
@@ -471,7 +552,7 @@ mbed_connect_step2(struct connectdata *conn,
   conn->recv[sockindex] = mbed_recv;
   conn->send[sockindex] = mbed_send;
 
-  ret = mbedtls_ssl_handshake(&connssl->ssl);
+  ret = mbedtls_ssl_handshake(&BACKEND->ssl);
 
   if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
     connssl->connecting_state = ssl_connect_2_reading;
@@ -491,10 +572,10 @@ mbed_connect_step2(struct connectdata *conn,
   }
 
   infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
-        mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
+        mbedtls_ssl_get_ciphersuite(&BACKEND->ssl)
     );
 
-  ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+  ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl);
 
   if(ret && SSL_CONN_CONFIG(verifypeer)) {
     if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
@@ -514,7 +595,7 @@ mbed_connect_step2(struct connectdata *conn,
     return CURLE_PEER_FAILED_VERIFICATION;
   }
 
-  peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl);
+  peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl);
 
   if(peercert && data->set.verbose) {
     const size_t bufsize = 16384;
@@ -584,7 +665,7 @@ mbed_connect_step2(struct connectdata *conn,
 
 #ifdef HAS_ALPN
   if(conn->bits.tls_enable_alpn) {
-    next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl);
+    next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl);
 
     if(next_protocol) {
       infof(data, "ALPN, server accepted to use %s\n", next_protocol);
@@ -623,7 +704,7 @@ mbed_connect_step3(struct connectdata *conn,
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
-  if(data->set.general_ssl.sessionid) {
+  if(SSL_SET_OPTION(primary.sessionid)) {
     int ret;
     mbedtls_ssl_session *our_ssl_sessionid;
     void *old_ssl_sessionid = NULL;
@@ -634,8 +715,9 @@ mbed_connect_step3(struct connectdata *conn,
 
     mbedtls_ssl_session_init(our_ssl_sessionid);
 
-    ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+    ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
     if(ret) {
+      free(our_ssl_sessionid);
       failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
       return CURLE_SSL_CONNECT_ERROR;
     }
@@ -663,9 +745,10 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex,
                          const void *mem, size_t len,
                          CURLcode *curlcode)
 {
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   int ret = -1;
 
-  ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl,
+  ret = mbedtls_ssl_write(&BACKEND->ssl,
                           (unsigned char *)mem, len);
 
   if(ret < 0) {
@@ -677,22 +760,23 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex,
   return ret;
 }
 
-void Curl_mbedtls_close_all(struct Curl_easy *data)
+static void Curl_mbedtls_close_all(struct Curl_easy *data)
 {
   (void)data;
 }
 
-void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
+static 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);
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  mbedtls_pk_free(&BACKEND->pk);
+  mbedtls_x509_crt_free(&BACKEND->clicert);
+  mbedtls_x509_crt_free(&BACKEND->cacert);
+  mbedtls_x509_crl_free(&BACKEND->crl);
+  mbedtls_ssl_config_free(&BACKEND->config);
+  mbedtls_ssl_free(&BACKEND->ssl);
+  mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg);
 #ifndef THREADING_SUPPORT
-  mbedtls_entropy_free(&conn->ssl[sockindex].entropy);
+  mbedtls_entropy_free(&BACKEND->entropy);
 #endif /* THREADING_SUPPORT */
 }
 
@@ -700,11 +784,12 @@ static ssize_t mbed_recv(struct connectdata *conn, int num,
                          char *buf, size_t buffersize,
                          CURLcode *curlcode)
 {
+  struct ssl_connect_data *connssl = &conn->ssl[num];
   int ret = -1;
   ssize_t len = -1;
 
   memset(buf, 0, buffersize);
-  ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf,
+  ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf,
                          buffersize);
 
   if(ret <= 0) {
@@ -721,21 +806,21 @@ static ssize_t mbed_recv(struct connectdata *conn, int num,
   return len;
 }
 
-void Curl_mbedtls_session_free(void *ptr)
+static void Curl_mbedtls_session_free(void *ptr)
 {
   mbedtls_ssl_session_free(ptr);
   free(ptr);
 }
 
-size_t Curl_mbedtls_version(char *buffer, size_t size)
+static 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);
 }
 
-CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
-                             size_t length)
+static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
+                                    unsigned char *entropy, size_t length)
 {
 #if defined(MBEDTLS_CTR_DRBG_C)
   int ret = -1;
@@ -744,7 +829,7 @@ CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
   mbedtls_ctr_drbg_context ctr_drbg;
   mbedtls_entropy_init(&ctr_entropy);
   mbedtls_ctr_drbg_init(&ctr_drbg);
-  errorbuf[0]=0;
+  errorbuf[0] = 0;
 
   ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
                               &ctr_entropy, NULL, 0);
@@ -802,7 +887,7 @@ mbed_connect_common(struct connectdata *conn,
     return CURLE_OK;
   }
 
-  if(ssl_connect_1==connssl->connecting_state) {
+  if(ssl_connect_1 == connssl->connecting_state) {
     /* Find out how much more time we're allowed */
     timeout_ms = Curl_timeleft(data, NULL, TRUE);
 
@@ -833,9 +918,9 @@ mbed_connect_common(struct connectdata *conn,
     if(connssl->connecting_state == ssl_connect_2_reading
        || connssl->connecting_state == ssl_connect_2_writing) {
 
-      curl_socket_t writefd = 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==
+      curl_socket_t readfd = ssl_connect_2_reading ==
         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
 
       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -875,13 +960,13 @@ mbed_connect_common(struct connectdata *conn,
 
   } /* repeat step2 until all transactions are done. */
 
-  if(ssl_connect_3==connssl->connecting_state) {
+  if(ssl_connect_3 == connssl->connecting_state) {
     retcode = mbed_connect_step3(conn, sockindex);
     if(retcode)
       return retcode;
   }
 
-  if(ssl_connect_done==connssl->connecting_state) {
+  if(ssl_connect_done == connssl->connecting_state) {
     connssl->state = ssl_connection_complete;
     conn->recv[sockindex] = mbed_recv;
     conn->send[sockindex] = mbed_send;
@@ -896,18 +981,14 @@ mbed_connect_common(struct connectdata *conn,
   return CURLE_OK;
 }
 
-CURLcode
-Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
-                                 int sockindex,
-                                 bool *done)
+static 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)
+static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex)
 {
   CURLcode retcode;
   bool done = FALSE;
@@ -925,19 +1006,70 @@ Curl_mbedtls_connect(struct connectdata *conn,
  * return 0 error initializing SSL
  * return 1 SSL initialized successfully
  */
-int Curl_mbedtls_init(void)
+static int Curl_mbedtls_init(void)
 {
   return Curl_polarsslthreadlock_thread_setup();
 }
 
-void Curl_mbedtls_cleanup(void)
+static void Curl_mbedtls_cleanup(void)
 {
   (void)Curl_polarsslthreadlock_thread_cleanup();
 }
 
-int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex)
+static bool Curl_mbedtls_data_pending(const struct connectdata *conn,
+                                      int sockindex)
+{
+  const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0;
+}
+
+static void Curl_mbedtls_sha256sum(const unsigned char *input,
+                                    size_t inputlen,
+                                    unsigned char *sha256sum,
+                                    size_t sha256len UNUSED_PARAM)
+{
+  (void)sha256len;
+  mbedtls_sha256(input, inputlen, sha256sum, 0);
+}
+
+static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
+                                        CURLINFO info UNUSED_PARAM)
 {
-  return mbedtls_ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0;
+  (void)info;
+  return &BACKEND->ssl;
 }
 
+const struct Curl_ssl Curl_ssl_mbedtls = {
+  { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
+
+  1, /* have_ca_path */
+  0, /* have_certinfo */
+  1, /* have_pinnedpubkey */
+  1, /* have_ssl_ctx */
+  0, /* support_https_proxy */
+
+  sizeof(struct ssl_backend_data),
+
+  Curl_mbedtls_init,                /* init */
+  Curl_mbedtls_cleanup,             /* cleanup */
+  Curl_mbedtls_version,             /* version */
+  Curl_none_check_cxn,              /* check_cxn */
+  Curl_none_shutdown,               /* shutdown */
+  Curl_mbedtls_data_pending,        /* data_pending */
+  Curl_mbedtls_random,              /* random */
+  Curl_none_cert_status_request,    /* cert_status_request */
+  Curl_mbedtls_connect,             /* connect */
+  Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */
+  Curl_mbedtls_get_internals,       /* get_internals */
+  Curl_mbedtls_close,               /* close_one */
+  Curl_mbedtls_close_all,           /* close_all */
+  Curl_mbedtls_session_free,        /* session_free */
+  Curl_none_set_engine,             /* set_engine */
+  Curl_none_set_engine_default,     /* set_engine_default */
+  Curl_none_engines_list,           /* engines_list */
+  Curl_none_false_start,            /* false_start */
+  Curl_none_md5sum,                 /* md5sum */
+  Curl_mbedtls_sha256sum            /* sha256sum */
+};
+
 #endif /* USE_MBEDTLS */