| 1 | /*************************************************************************** | 
| 2 |  *                                  _   _ ____  _ | 
| 3 |  *  Project                     ___| | | |  _ \| | | 
| 4 |  *                             / __| | | | |_) | | | 
| 5 |  *                            | (__| |_| |  _ <| |___ | 
| 6 |  *                             \___|\___/|_| \_\_____| | 
| 7 |  * | 
| 8 |  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. | 
| 9 |  * Copyright (C) Hoi-Ho Chan, <hoiho.chan@gmail.com> | 
| 10 |  * | 
| 11 |  * This software is licensed as described in the file COPYING, which | 
| 12 |  * you should have received as part of this distribution. The terms | 
| 13 |  * are also available at https://curl.se/docs/copyright.html. | 
| 14 |  * | 
| 15 |  * You may opt to use, copy, modify, merge, publish, distribute and/or sell | 
| 16 |  * copies of the Software, and permit persons to whom the Software is | 
| 17 |  * furnished to do so, under the terms of the COPYING file. | 
| 18 |  * | 
| 19 |  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | 
| 20 |  * KIND, either express or implied. | 
| 21 |  * | 
| 22 |  * SPDX-License-Identifier: curl | 
| 23 |  * | 
| 24 |  ***************************************************************************/ | 
| 25 |  | 
| 26 | /* | 
| 27 |  * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code | 
| 28 |  * but vtls.c should ever call or use these functions. | 
| 29 |  * | 
| 30 |  */ | 
| 31 |  | 
| 32 | #include "curl_setup.h" | 
| 33 |  | 
| 34 | #ifdef USE_MBEDTLS | 
| 35 |  | 
| 36 | /* Define this to enable lots of debugging for mbedTLS */ | 
| 37 | /* #define MBEDTLS_DEBUG */ | 
| 38 |  | 
| 39 | #include <mbedtls/version.h> | 
| 40 | #if MBEDTLS_VERSION_NUMBER >= 0x02040000 | 
| 41 | #include <mbedtls/net_sockets.h> | 
| 42 | #else | 
| 43 | #include <mbedtls/net.h> | 
| 44 | #endif | 
| 45 | #include <mbedtls/ssl.h> | 
| 46 | #include <mbedtls/x509.h> | 
| 47 |  | 
| 48 | #include <mbedtls/error.h> | 
| 49 | #include <mbedtls/entropy.h> | 
| 50 | #include <mbedtls/ctr_drbg.h> | 
| 51 | #include <mbedtls/sha256.h> | 
| 52 |  | 
| 53 | #if MBEDTLS_VERSION_MAJOR >= 2 | 
| 54 | #  ifdef MBEDTLS_DEBUG | 
| 55 | #    include <mbedtls/debug.h> | 
| 56 | #  endif | 
| 57 | #endif | 
| 58 |  | 
| 59 | #include "urldata.h" | 
| 60 | #include "sendf.h" | 
| 61 | #include "inet_pton.h" | 
| 62 | #include "mbedtls.h" | 
| 63 | #include "vtls.h" | 
| 64 | #include "vtls_int.h" | 
| 65 | #include "parsedate.h" | 
| 66 | #include "connect.h" /* for the connect timeout */ | 
| 67 | #include "select.h" | 
| 68 | #include "multiif.h" | 
| 69 | #include "mbedtls_threadlock.h" | 
| 70 |  | 
| 71 | /* The last 3 #include files should be in this order */ | 
| 72 | #include "curl_printf.h" | 
| 73 | #include "curl_memory.h" | 
| 74 | #include "memdebug.h" | 
| 75 |  | 
| 76 | /* ALPN for http2 */ | 
| 77 | #ifdef USE_HTTP2 | 
| 78 | #  undef HAS_ALPN | 
| 79 | #  ifdef MBEDTLS_SSL_ALPN | 
| 80 | #    define HAS_ALPN | 
| 81 | #  endif | 
| 82 | #endif | 
| 83 |  | 
| 84 | struct mbed_ssl_backend_data { | 
| 85 |   mbedtls_ctr_drbg_context ctr_drbg; | 
| 86 |   mbedtls_entropy_context entropy; | 
| 87 |   mbedtls_ssl_context ssl; | 
| 88 |   mbedtls_x509_crt cacert; | 
| 89 |   mbedtls_x509_crt clicert; | 
| 90 | #ifdef MBEDTLS_X509_CRL_PARSE_C | 
| 91 |   mbedtls_x509_crl crl; | 
| 92 | #endif | 
| 93 |   mbedtls_pk_context pk; | 
| 94 |   mbedtls_ssl_config config; | 
| 95 | #ifdef HAS_ALPN | 
| 96 |   const char *protocols[3]; | 
| 97 | #endif | 
| 98 | }; | 
| 99 |  | 
| 100 | /* apply threading? */ | 
| 101 | #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) | 
| 102 | #define THREADING_SUPPORT | 
| 103 | #endif | 
| 104 |  | 
| 105 | #ifndef MBEDTLS_ERROR_C | 
| 106 | #define mbedtls_strerror(a,b,c) b[0] = 0 | 
| 107 | #endif | 
| 108 |  | 
| 109 | #if defined(THREADING_SUPPORT) | 
| 110 | static mbedtls_entropy_context ts_entropy; | 
| 111 |  | 
| 112 | static int entropy_init_initialized = 0; | 
| 113 |  | 
| 114 | /* start of entropy_init_mutex() */ | 
| 115 | static void entropy_init_mutex(mbedtls_entropy_context *ctx) | 
| 116 | { | 
| 117 |   /* lock 0 = entropy_init_mutex() */ | 
| 118 |   Curl_mbedtlsthreadlock_lock_function(0); | 
| 119 |   if(entropy_init_initialized == 0) { | 
| 120 |     mbedtls_entropy_init(ctx); | 
| 121 |     entropy_init_initialized = 1; | 
| 122 |   } | 
| 123 |   Curl_mbedtlsthreadlock_unlock_function(0); | 
| 124 | } | 
| 125 | /* end of entropy_init_mutex() */ | 
| 126 |  | 
| 127 | /* start of entropy_func_mutex() */ | 
| 128 | static int entropy_func_mutex(void *data, unsigned char *output, size_t len) | 
| 129 | { | 
| 130 |   int ret; | 
| 131 |   /* lock 1 = entropy_func_mutex() */ | 
| 132 |   Curl_mbedtlsthreadlock_lock_function(1); | 
| 133 |   ret = mbedtls_entropy_func(data, output, len); | 
| 134 |   Curl_mbedtlsthreadlock_unlock_function(1); | 
| 135 |  | 
| 136 |   return ret; | 
| 137 | } | 
| 138 | /* end of entropy_func_mutex() */ | 
| 139 |  | 
| 140 | #endif /* THREADING_SUPPORT */ | 
| 141 |  | 
| 142 | #ifdef MBEDTLS_DEBUG | 
| 143 | static void mbed_debug(void *context, int level, const char *f_name, | 
| 144 |                        int line_nb, const char *line) | 
| 145 | { | 
| 146 |   struct Curl_easy *data = NULL; | 
| 147 |  | 
| 148 |   if(!context) | 
| 149 |     return; | 
| 150 |  | 
| 151 |   data = (struct Curl_easy *)context; | 
| 152 |  | 
| 153 |   infof(data, "%s" , line); | 
| 154 |   (void) level; | 
| 155 | } | 
| 156 | #else | 
| 157 | #endif | 
| 158 |  | 
| 159 | static int mbedtls_bio_cf_write(void *bio, | 
| 160 |                                 const unsigned char *buf, size_t blen) | 
| 161 | { | 
| 162 |   struct Curl_cfilter *cf = bio; | 
| 163 |   struct Curl_easy *data = CF_DATA_CURRENT(cf); | 
| 164 |   ssize_t nwritten; | 
| 165 |   CURLcode result; | 
| 166 |  | 
| 167 |   DEBUGASSERT(data); | 
| 168 |   nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result); | 
| 169 |   CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d" , | 
| 170 |               blen, nwritten, result); | 
| 171 |   if(nwritten < 0 && CURLE_AGAIN == result) { | 
| 172 |     nwritten = MBEDTLS_ERR_SSL_WANT_WRITE; | 
| 173 |   } | 
| 174 |   return (int)nwritten; | 
| 175 | } | 
| 176 |  | 
| 177 | static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) | 
| 178 | { | 
| 179 |   struct Curl_cfilter *cf = bio; | 
| 180 |   struct Curl_easy *data = CF_DATA_CURRENT(cf); | 
| 181 |   ssize_t nread; | 
| 182 |   CURLcode result; | 
| 183 |  | 
| 184 |   DEBUGASSERT(data); | 
| 185 |   /* OpenSSL catches this case, so should we. */ | 
| 186 |   if(!buf) | 
| 187 |     return 0; | 
| 188 |  | 
| 189 |   nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result); | 
| 190 |   CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d" , | 
| 191 |               blen, nread, result); | 
| 192 |   if(nread < 0 && CURLE_AGAIN == result) { | 
| 193 |     nread = MBEDTLS_ERR_SSL_WANT_READ; | 
| 194 |   } | 
| 195 |   return (int)nread; | 
| 196 | } | 
| 197 |  | 
| 198 | /* | 
| 199 |  *  profile | 
| 200 |  */ | 
| 201 | static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = | 
| 202 | { | 
| 203 |   /* Hashes from SHA-1 and above */ | 
| 204 |   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | | 
| 205 |   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | | 
| 206 |   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | | 
| 207 |   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | | 
| 208 |   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | | 
| 209 |   MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), | 
| 210 |   0xFFFFFFF, /* Any PK alg    */ | 
| 211 |   0xFFFFFFF, /* Any curve     */ | 
| 212 |   1024,      /* RSA min key len */ | 
| 213 | }; | 
| 214 |  | 
| 215 | /* See https://tls.mbed.org/discussions/generic/ | 
| 216 |    howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der | 
| 217 | */ | 
| 218 | #define RSA_PUB_DER_MAX_BYTES   (38 + 2 * MBEDTLS_MPI_MAX_SIZE) | 
| 219 | #define ECP_PUB_DER_MAX_BYTES   (30 + 2 * MBEDTLS_ECP_MAX_BYTES) | 
| 220 |  | 
| 221 | #define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ | 
| 222 |                              RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) | 
| 223 |  | 
| 224 | static CURLcode mbedtls_version_from_curl(int *mbedver, long version) | 
| 225 | { | 
| 226 | #if MBEDTLS_VERSION_NUMBER >= 0x03000000 | 
| 227 |   switch(version) { | 
| 228 |     case CURL_SSLVERSION_TLSv1_0: | 
| 229 |     case CURL_SSLVERSION_TLSv1_1: | 
| 230 |     case CURL_SSLVERSION_TLSv1_2: | 
| 231 |       *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; | 
| 232 |       return CURLE_OK; | 
| 233 |     case CURL_SSLVERSION_TLSv1_3: | 
| 234 |       break; | 
| 235 |   } | 
| 236 | #else | 
| 237 |   switch(version) { | 
| 238 |     case CURL_SSLVERSION_TLSv1_0: | 
| 239 |       *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; | 
| 240 |       return CURLE_OK; | 
| 241 |     case CURL_SSLVERSION_TLSv1_1: | 
| 242 |       *mbedver = MBEDTLS_SSL_MINOR_VERSION_2; | 
| 243 |       return CURLE_OK; | 
| 244 |     case CURL_SSLVERSION_TLSv1_2: | 
| 245 |       *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; | 
| 246 |       return CURLE_OK; | 
| 247 |     case CURL_SSLVERSION_TLSv1_3: | 
| 248 |       break; | 
| 249 |   } | 
| 250 | #endif | 
| 251 |  | 
| 252 |   return CURLE_SSL_CONNECT_ERROR; | 
| 253 | } | 
| 254 |  | 
| 255 | static CURLcode | 
| 256 | set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data) | 
| 257 | { | 
| 258 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 259 |   struct mbed_ssl_backend_data *backend = | 
| 260 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 261 |   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); | 
| 262 | #if MBEDTLS_VERSION_NUMBER >= 0x03000000 | 
| 263 |   int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3; | 
| 264 |   int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3; | 
| 265 | #else | 
| 266 |   int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; | 
| 267 |   int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; | 
| 268 | #endif | 
| 269 |   long ssl_version = conn_config->version; | 
| 270 |   long ssl_version_max = conn_config->version_max; | 
| 271 |   CURLcode result = CURLE_OK; | 
| 272 |  | 
| 273 |   DEBUGASSERT(backend); | 
| 274 |  | 
| 275 |   switch(ssl_version) { | 
| 276 |     case CURL_SSLVERSION_DEFAULT: | 
| 277 |     case CURL_SSLVERSION_TLSv1: | 
| 278 |       ssl_version = CURL_SSLVERSION_TLSv1_0; | 
| 279 |       break; | 
| 280 |   } | 
| 281 |  | 
| 282 |   switch(ssl_version_max) { | 
| 283 |     case CURL_SSLVERSION_MAX_NONE: | 
| 284 |     case CURL_SSLVERSION_MAX_DEFAULT: | 
| 285 |       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; | 
| 286 |       break; | 
| 287 |   } | 
| 288 |  | 
| 289 |   result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version); | 
| 290 |   if(result) { | 
| 291 |     failf(data, "unsupported min version passed via CURLOPT_SSLVERSION" ); | 
| 292 |     return result; | 
| 293 |   } | 
| 294 |   result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16); | 
| 295 |   if(result) { | 
| 296 |     failf(data, "unsupported max version passed via CURLOPT_SSLVERSION" ); | 
| 297 |     return result; | 
| 298 |   } | 
| 299 |  | 
| 300 |   mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, | 
| 301 |                                mbedtls_ver_min); | 
| 302 |   mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, | 
| 303 |                                mbedtls_ver_max); | 
| 304 |  | 
| 305 |   return result; | 
| 306 | } | 
| 307 |  | 
| 308 | static CURLcode | 
| 309 | mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) | 
| 310 | { | 
| 311 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 312 |   struct mbed_ssl_backend_data *backend = | 
| 313 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 314 |   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); | 
| 315 |   const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; | 
| 316 |   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); | 
| 317 |   const char * const ssl_cafile = | 
| 318 |     /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ | 
| 319 |     (ca_info_blob ? NULL : conn_config->CAfile); | 
| 320 |   const bool verifypeer = conn_config->verifypeer; | 
| 321 |   const char * const ssl_capath = conn_config->CApath; | 
| 322 |   char * const ssl_cert = ssl_config->primary.clientcert; | 
| 323 |   const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; | 
| 324 |   const char * const ssl_crlfile = ssl_config->primary.CRLfile; | 
| 325 |   const char *hostname = connssl->hostname; | 
| 326 |   int ret = -1; | 
| 327 |   char errorbuf[128]; | 
| 328 |  | 
| 329 |   DEBUGASSERT(backend); | 
| 330 |  | 
| 331 |   if((conn_config->version == CURL_SSLVERSION_SSLv2) || | 
| 332 |      (conn_config->version == CURL_SSLVERSION_SSLv3)) { | 
| 333 |     failf(data, "Not supported SSL version" ); | 
| 334 |     return CURLE_NOT_BUILT_IN; | 
| 335 |   } | 
| 336 |  | 
| 337 | #ifdef THREADING_SUPPORT | 
| 338 |   entropy_init_mutex(&ts_entropy); | 
| 339 |   mbedtls_ctr_drbg_init(&backend->ctr_drbg); | 
| 340 |  | 
| 341 |   ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex, | 
| 342 |                               &ts_entropy, NULL, 0); | 
| 343 |   if(ret) { | 
| 344 |     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 345 |     failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s" , | 
| 346 |           -ret, errorbuf); | 
| 347 |     return CURLE_FAILED_INIT; | 
| 348 |   } | 
| 349 | #else | 
| 350 |   mbedtls_entropy_init(&backend->entropy); | 
| 351 |   mbedtls_ctr_drbg_init(&backend->ctr_drbg); | 
| 352 |  | 
| 353 |   ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func, | 
| 354 |                               &backend->entropy, NULL, 0); | 
| 355 |   if(ret) { | 
| 356 |     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 357 |     failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s" , | 
| 358 |           -ret, errorbuf); | 
| 359 |     return CURLE_FAILED_INIT; | 
| 360 |   } | 
| 361 | #endif /* THREADING_SUPPORT */ | 
| 362 |  | 
| 363 |   /* Load the trusted CA */ | 
| 364 |   mbedtls_x509_crt_init(&backend->cacert); | 
| 365 |  | 
| 366 |   if(ca_info_blob && verifypeer) { | 
| 367 |     /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null | 
| 368 |        terminated even when provided the exact length, forcing us to waste | 
| 369 |        extra memory here. */ | 
| 370 |     unsigned char *newblob = malloc(ca_info_blob->len + 1); | 
| 371 |     if(!newblob) | 
| 372 |       return CURLE_OUT_OF_MEMORY; | 
| 373 |     memcpy(newblob, ca_info_blob->data, ca_info_blob->len); | 
| 374 |     newblob[ca_info_blob->len] = 0; /* null terminate */ | 
| 375 |     ret = mbedtls_x509_crt_parse(&backend->cacert, newblob, | 
| 376 |                                  ca_info_blob->len + 1); | 
| 377 |     free(newblob); | 
| 378 |     if(ret<0) { | 
| 379 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 380 |       failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s" , | 
| 381 |             -ret, errorbuf); | 
| 382 |       return CURLE_SSL_CERTPROBLEM; | 
| 383 |     } | 
| 384 |   } | 
| 385 |  | 
| 386 |   if(ssl_cafile && verifypeer) { | 
| 387 | #ifdef MBEDTLS_FS_IO | 
| 388 |     ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); | 
| 389 |  | 
| 390 |     if(ret<0) { | 
| 391 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 392 |       failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s" , | 
| 393 |             ssl_cafile, -ret, errorbuf); | 
| 394 |       return CURLE_SSL_CACERT_BADFILE; | 
| 395 |     } | 
| 396 | #else | 
| 397 |     failf(data, "mbedtls: functions that use the filesystem not built in" ); | 
| 398 |     return CURLE_NOT_BUILT_IN; | 
| 399 | #endif | 
| 400 |   } | 
| 401 |  | 
| 402 |   if(ssl_capath) { | 
| 403 | #ifdef MBEDTLS_FS_IO | 
| 404 |     ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath); | 
| 405 |  | 
| 406 |     if(ret<0) { | 
| 407 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 408 |       failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s" , | 
| 409 |             ssl_capath, -ret, errorbuf); | 
| 410 |  | 
| 411 |       if(verifypeer) | 
| 412 |         return CURLE_SSL_CACERT_BADFILE; | 
| 413 |     } | 
| 414 | #else | 
| 415 |     failf(data, "mbedtls: functions that use the filesystem not built in" ); | 
| 416 |     return CURLE_NOT_BUILT_IN; | 
| 417 | #endif | 
| 418 |   } | 
| 419 |  | 
| 420 |   /* Load the client certificate */ | 
| 421 |   mbedtls_x509_crt_init(&backend->clicert); | 
| 422 |  | 
| 423 |   if(ssl_cert) { | 
| 424 | #ifdef MBEDTLS_FS_IO | 
| 425 |     ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert); | 
| 426 |  | 
| 427 |     if(ret) { | 
| 428 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 429 |       failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s" , | 
| 430 |             ssl_cert, -ret, errorbuf); | 
| 431 |  | 
| 432 |       return CURLE_SSL_CERTPROBLEM; | 
| 433 |     } | 
| 434 | #else | 
| 435 |     failf(data, "mbedtls: functions that use the filesystem not built in" ); | 
| 436 |     return CURLE_NOT_BUILT_IN; | 
| 437 | #endif | 
| 438 |   } | 
| 439 |  | 
| 440 |   if(ssl_cert_blob) { | 
| 441 |     /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null | 
| 442 |        terminated even when provided the exact length, forcing us to waste | 
| 443 |        extra memory here. */ | 
| 444 |     unsigned char *newblob = malloc(ssl_cert_blob->len + 1); | 
| 445 |     if(!newblob) | 
| 446 |       return CURLE_OUT_OF_MEMORY; | 
| 447 |     memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len); | 
| 448 |     newblob[ssl_cert_blob->len] = 0; /* null terminate */ | 
| 449 |     ret = mbedtls_x509_crt_parse(&backend->clicert, newblob, | 
| 450 |                                  ssl_cert_blob->len + 1); | 
| 451 |     free(newblob); | 
| 452 |  | 
| 453 |     if(ret) { | 
| 454 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 455 |       failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s" , | 
| 456 |             ssl_config->key, -ret, errorbuf); | 
| 457 |       return CURLE_SSL_CERTPROBLEM; | 
| 458 |     } | 
| 459 |   } | 
| 460 |  | 
| 461 |   /* Load the client private key */ | 
| 462 |   mbedtls_pk_init(&backend->pk); | 
| 463 |  | 
| 464 |   if(ssl_config->key || ssl_config->key_blob) { | 
| 465 |     if(ssl_config->key) { | 
| 466 | #ifdef MBEDTLS_FS_IO | 
| 467 | #if MBEDTLS_VERSION_NUMBER >= 0x03000000 | 
| 468 |       ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, | 
| 469 |                                      ssl_config->key_passwd, | 
| 470 |                                      mbedtls_ctr_drbg_random, | 
| 471 |                                      &backend->ctr_drbg); | 
| 472 | #else | 
| 473 |       ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, | 
| 474 |                                      ssl_config->key_passwd); | 
| 475 | #endif | 
| 476 |  | 
| 477 |       if(ret) { | 
| 478 |         mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 479 |         failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s" , | 
| 480 |               ssl_config->key, -ret, errorbuf); | 
| 481 |         return CURLE_SSL_CERTPROBLEM; | 
| 482 |       } | 
| 483 | #else | 
| 484 |       failf(data, "mbedtls: functions that use the filesystem not built in" ); | 
| 485 |       return CURLE_NOT_BUILT_IN; | 
| 486 | #endif | 
| 487 |     } | 
| 488 |     else { | 
| 489 |       const struct curl_blob *ssl_key_blob = ssl_config->key_blob; | 
| 490 |       const unsigned char *key_data = | 
| 491 |         (const unsigned char *)ssl_key_blob->data; | 
| 492 |       const char *passwd = ssl_config->key_passwd; | 
| 493 | #if MBEDTLS_VERSION_NUMBER >= 0x03000000 | 
| 494 |       ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, | 
| 495 |                                  (const unsigned char *)passwd, | 
| 496 |                                  passwd ? strlen(passwd) : 0, | 
| 497 |                                  mbedtls_ctr_drbg_random, | 
| 498 |                                  &backend->ctr_drbg); | 
| 499 | #else | 
| 500 |       ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, | 
| 501 |                                  (const unsigned char *)passwd, | 
| 502 |                                  passwd ? strlen(passwd) : 0); | 
| 503 | #endif | 
| 504 |  | 
| 505 |       if(ret) { | 
| 506 |         mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 507 |         failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s" , | 
| 508 |               -ret, errorbuf); | 
| 509 |         return CURLE_SSL_CERTPROBLEM; | 
| 510 |       } | 
| 511 |     } | 
| 512 |  | 
| 513 |     if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || | 
| 514 |                      mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) | 
| 515 |       ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; | 
| 516 |   } | 
| 517 |  | 
| 518 |   /* Load the CRL */ | 
| 519 | #ifdef MBEDTLS_X509_CRL_PARSE_C | 
| 520 |   mbedtls_x509_crl_init(&backend->crl); | 
| 521 |  | 
| 522 |   if(ssl_crlfile) { | 
| 523 | #ifdef MBEDTLS_FS_IO | 
| 524 |     ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile); | 
| 525 |  | 
| 526 |     if(ret) { | 
| 527 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 528 |       failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s" , | 
| 529 |             ssl_crlfile, -ret, errorbuf); | 
| 530 |  | 
| 531 |       return CURLE_SSL_CRL_BADFILE; | 
| 532 |     } | 
| 533 | #else | 
| 534 |     failf(data, "mbedtls: functions that use the filesystem not built in" ); | 
| 535 |     return CURLE_NOT_BUILT_IN; | 
| 536 | #endif | 
| 537 |   } | 
| 538 | #else | 
| 539 |   if(ssl_crlfile) { | 
| 540 |     failf(data, "mbedtls: crl support not built in" ); | 
| 541 |     return CURLE_NOT_BUILT_IN; | 
| 542 |   } | 
| 543 | #endif | 
| 544 |  | 
| 545 |   infof(data, "mbedTLS: Connecting to %s:%d" , hostname, connssl->port); | 
| 546 |  | 
| 547 |   mbedtls_ssl_config_init(&backend->config); | 
| 548 |   ret = mbedtls_ssl_config_defaults(&backend->config, | 
| 549 |                                     MBEDTLS_SSL_IS_CLIENT, | 
| 550 |                                     MBEDTLS_SSL_TRANSPORT_STREAM, | 
| 551 |                                     MBEDTLS_SSL_PRESET_DEFAULT); | 
| 552 |   if(ret) { | 
| 553 |     failf(data, "mbedTLS: ssl_config failed" ); | 
| 554 |     return CURLE_SSL_CONNECT_ERROR; | 
| 555 |   } | 
| 556 |  | 
| 557 |   mbedtls_ssl_init(&backend->ssl); | 
| 558 |   if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) { | 
| 559 |     failf(data, "mbedTLS: ssl_init failed" ); | 
| 560 |     return CURLE_SSL_CONNECT_ERROR; | 
| 561 |   } | 
| 562 |  | 
| 563 |   /* new profile with RSA min key len = 1024 ... */ | 
| 564 |   mbedtls_ssl_conf_cert_profile(&backend->config, | 
| 565 |                                 &mbedtls_x509_crt_profile_fr); | 
| 566 |  | 
| 567 |   switch(conn_config->version) { | 
| 568 |   case CURL_SSLVERSION_DEFAULT: | 
| 569 |   case CURL_SSLVERSION_TLSv1: | 
| 570 | #if MBEDTLS_VERSION_NUMBER < 0x03000000 | 
| 571 |     mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, | 
| 572 |                                  MBEDTLS_SSL_MINOR_VERSION_1); | 
| 573 |     infof(data, "mbedTLS: Set min SSL version to TLS 1.0" ); | 
| 574 |     break; | 
| 575 | #endif | 
| 576 |   case CURL_SSLVERSION_TLSv1_0: | 
| 577 |   case CURL_SSLVERSION_TLSv1_1: | 
| 578 |   case CURL_SSLVERSION_TLSv1_2: | 
| 579 |   case CURL_SSLVERSION_TLSv1_3: | 
| 580 |     { | 
| 581 |       CURLcode result = set_ssl_version_min_max(cf, data); | 
| 582 |       if(result != CURLE_OK) | 
| 583 |         return result; | 
| 584 |       break; | 
| 585 |     } | 
| 586 |   default: | 
| 587 |     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION" ); | 
| 588 |     return CURLE_SSL_CONNECT_ERROR; | 
| 589 |   } | 
| 590 |  | 
| 591 |   mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL); | 
| 592 |  | 
| 593 |   mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random, | 
| 594 |                        &backend->ctr_drbg); | 
| 595 |   mbedtls_ssl_set_bio(&backend->ssl, cf, | 
| 596 |                       mbedtls_bio_cf_write, | 
| 597 |                       mbedtls_bio_cf_read, | 
| 598 |                       NULL /*  rev_timeout() */); | 
| 599 |  | 
| 600 |   mbedtls_ssl_conf_ciphersuites(&backend->config, | 
| 601 |                                 mbedtls_ssl_list_ciphersuites()); | 
| 602 |  | 
| 603 | #if defined(MBEDTLS_SSL_RENEGOTIATION) | 
| 604 |   mbedtls_ssl_conf_renegotiation(&backend->config, | 
| 605 |                                  MBEDTLS_SSL_RENEGOTIATION_ENABLED); | 
| 606 | #endif | 
| 607 |  | 
| 608 | #if defined(MBEDTLS_SSL_SESSION_TICKETS) | 
| 609 |   mbedtls_ssl_conf_session_tickets(&backend->config, | 
| 610 |                                    MBEDTLS_SSL_SESSION_TICKETS_DISABLED); | 
| 611 | #endif | 
| 612 |  | 
| 613 |   /* Check if there's a cached ID we can/should use here! */ | 
| 614 |   if(ssl_config->primary.sessionid) { | 
| 615 |     void *old_session = NULL; | 
| 616 |  | 
| 617 |     Curl_ssl_sessionid_lock(data); | 
| 618 |     if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) { | 
| 619 |       ret = mbedtls_ssl_set_session(&backend->ssl, old_session); | 
| 620 |       if(ret) { | 
| 621 |         Curl_ssl_sessionid_unlock(data); | 
| 622 |         failf(data, "mbedtls_ssl_set_session returned -0x%x" , -ret); | 
| 623 |         return CURLE_SSL_CONNECT_ERROR; | 
| 624 |       } | 
| 625 |       infof(data, "mbedTLS reusing session" ); | 
| 626 |     } | 
| 627 |     Curl_ssl_sessionid_unlock(data); | 
| 628 |   } | 
| 629 |  | 
| 630 |   mbedtls_ssl_conf_ca_chain(&backend->config, | 
| 631 |                             &backend->cacert, | 
| 632 | #ifdef MBEDTLS_X509_CRL_PARSE_C | 
| 633 |                             &backend->crl); | 
| 634 | #else | 
| 635 |                             NULL); | 
| 636 | #endif | 
| 637 |  | 
| 638 |   if(ssl_config->key || ssl_config->key_blob) { | 
| 639 |     mbedtls_ssl_conf_own_cert(&backend->config, | 
| 640 |                               &backend->clicert, &backend->pk); | 
| 641 |   } | 
| 642 |   { | 
| 643 |     char *snihost = Curl_ssl_snihost(data, hostname, NULL); | 
| 644 |     if(!snihost || mbedtls_ssl_set_hostname(&backend->ssl, snihost)) { | 
| 645 |       /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and | 
| 646 |          the name to set in the SNI extension. So even if curl connects to a | 
| 647 |          host specified as an IP address, this function must be used. */ | 
| 648 |       failf(data, "Failed to set SNI" ); | 
| 649 |       return CURLE_SSL_CONNECT_ERROR; | 
| 650 |     } | 
| 651 |   } | 
| 652 |  | 
| 653 | #ifdef HAS_ALPN | 
| 654 |   if(connssl->alpn) { | 
| 655 |     struct alpn_proto_buf proto; | 
| 656 |     size_t i; | 
| 657 |  | 
| 658 |     for(i = 0; i < connssl->alpn->count; ++i) { | 
| 659 |       backend->protocols[i] = connssl->alpn->entries[i]; | 
| 660 |     } | 
| 661 |     /* this function doesn't clone the protocols array, which is why we need | 
| 662 |        to keep it around */ | 
| 663 |     if(mbedtls_ssl_conf_alpn_protocols(&backend->config, | 
| 664 |                                        &backend->protocols[0])) { | 
| 665 |       failf(data, "Failed setting ALPN protocols" ); | 
| 666 |       return CURLE_SSL_CONNECT_ERROR; | 
| 667 |     } | 
| 668 |     Curl_alpn_to_proto_str(&proto, connssl->alpn); | 
| 669 |     infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); | 
| 670 |   } | 
| 671 | #endif | 
| 672 |  | 
| 673 | #ifdef MBEDTLS_DEBUG | 
| 674 |   /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ | 
| 675 |   mbedtls_ssl_conf_dbg(&backend->config, mbed_debug, data); | 
| 676 |   /* - 0 No debug | 
| 677 |    * - 1 Error | 
| 678 |    * - 2 State change | 
| 679 |    * - 3 Informational | 
| 680 |    * - 4 Verbose | 
| 681 |    */ | 
| 682 |   mbedtls_debug_set_threshold(4); | 
| 683 | #endif | 
| 684 |  | 
| 685 |   /* give application a chance to interfere with mbedTLS set up. */ | 
| 686 |   if(data->set.ssl.fsslctx) { | 
| 687 |     ret = (*data->set.ssl.fsslctx)(data, &backend->config, | 
| 688 |                                    data->set.ssl.fsslctxp); | 
| 689 |     if(ret) { | 
| 690 |       failf(data, "error signaled by ssl ctx callback" ); | 
| 691 |       return ret; | 
| 692 |     } | 
| 693 |   } | 
| 694 |  | 
| 695 |   connssl->connecting_state = ssl_connect_2; | 
| 696 |  | 
| 697 |   return CURLE_OK; | 
| 698 | } | 
| 699 |  | 
| 700 | static CURLcode | 
| 701 | mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) | 
| 702 | { | 
| 703 |   int ret; | 
| 704 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 705 |   struct mbed_ssl_backend_data *backend = | 
| 706 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 707 |   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); | 
| 708 |   const mbedtls_x509_crt *peercert; | 
| 709 |   const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? | 
| 710 |     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: | 
| 711 |     data->set.str[STRING_SSL_PINNEDPUBLICKEY]; | 
| 712 |  | 
| 713 |   DEBUGASSERT(backend); | 
| 714 |  | 
| 715 |   ret = mbedtls_ssl_handshake(&backend->ssl); | 
| 716 |  | 
| 717 |   if(ret == MBEDTLS_ERR_SSL_WANT_READ) { | 
| 718 |     connssl->connecting_state = ssl_connect_2_reading; | 
| 719 |     return CURLE_OK; | 
| 720 |   } | 
| 721 |   else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) { | 
| 722 |     connssl->connecting_state = ssl_connect_2_writing; | 
| 723 |     return CURLE_OK; | 
| 724 |   } | 
| 725 |   else if(ret) { | 
| 726 |     char errorbuf[128]; | 
| 727 |     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 728 |     failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s" , | 
| 729 |           -ret, errorbuf); | 
| 730 |     return CURLE_SSL_CONNECT_ERROR; | 
| 731 |   } | 
| 732 |  | 
| 733 |   infof(data, "mbedTLS: Handshake complete, cipher is %s" , | 
| 734 |         mbedtls_ssl_get_ciphersuite(&backend->ssl)); | 
| 735 |  | 
| 736 |   ret = mbedtls_ssl_get_verify_result(&backend->ssl); | 
| 737 |  | 
| 738 |   if(!conn_config->verifyhost) | 
| 739 |     /* Ignore hostname errors if verifyhost is disabled */ | 
| 740 |     ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; | 
| 741 |  | 
| 742 |   if(ret && conn_config->verifypeer) { | 
| 743 |     if(ret & MBEDTLS_X509_BADCERT_EXPIRED) | 
| 744 |       failf(data, "Cert verify failed: BADCERT_EXPIRED" ); | 
| 745 |  | 
| 746 |     else if(ret & MBEDTLS_X509_BADCERT_REVOKED) | 
| 747 |       failf(data, "Cert verify failed: BADCERT_REVOKED" ); | 
| 748 |  | 
| 749 |     else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH) | 
| 750 |       failf(data, "Cert verify failed: BADCERT_CN_MISMATCH" ); | 
| 751 |  | 
| 752 |     else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED) | 
| 753 |       failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED" ); | 
| 754 |  | 
| 755 |     else if(ret & MBEDTLS_X509_BADCERT_FUTURE) | 
| 756 |       failf(data, "Cert verify failed: BADCERT_FUTURE" ); | 
| 757 |  | 
| 758 |     return CURLE_PEER_FAILED_VERIFICATION; | 
| 759 |   } | 
| 760 |  | 
| 761 |   peercert = mbedtls_ssl_get_peer_cert(&backend->ssl); | 
| 762 |  | 
| 763 |   if(peercert && data->set.verbose) { | 
| 764 |     const size_t bufsize = 16384; | 
| 765 |     char *buffer = malloc(bufsize); | 
| 766 |  | 
| 767 |     if(!buffer) | 
| 768 |       return CURLE_OUT_OF_MEMORY; | 
| 769 |  | 
| 770 |     if(mbedtls_x509_crt_info(buffer, bufsize, "* " , peercert) > 0) | 
| 771 |       infof(data, "Dumping cert info: %s" , buffer); | 
| 772 |     else | 
| 773 |       infof(data, "Unable to dump certificate information" ); | 
| 774 |  | 
| 775 |     free(buffer); | 
| 776 |   } | 
| 777 |  | 
| 778 |   if(pinnedpubkey) { | 
| 779 |     int size; | 
| 780 |     CURLcode result; | 
| 781 |     mbedtls_x509_crt *p = NULL; | 
| 782 |     unsigned char *pubkey = NULL; | 
| 783 |  | 
| 784 | #if MBEDTLS_VERSION_NUMBER == 0x03000000 | 
| 785 |     if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || | 
| 786 |        !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { | 
| 787 | #else | 
| 788 |     if(!peercert || !peercert->raw.p || !peercert->raw.len) { | 
| 789 | #endif | 
| 790 |       failf(data, "Failed due to missing peer certificate" ); | 
| 791 |       return CURLE_SSL_PINNEDPUBKEYNOTMATCH; | 
| 792 |     } | 
| 793 |  | 
| 794 |     p = calloc(1, sizeof(*p)); | 
| 795 |  | 
| 796 |     if(!p) | 
| 797 |       return CURLE_OUT_OF_MEMORY; | 
| 798 |  | 
| 799 |     pubkey = malloc(PUB_DER_MAX_BYTES); | 
| 800 |  | 
| 801 |     if(!pubkey) { | 
| 802 |       result = CURLE_OUT_OF_MEMORY; | 
| 803 |       goto pinnedpubkey_error; | 
| 804 |     } | 
| 805 |  | 
| 806 |     mbedtls_x509_crt_init(p); | 
| 807 |  | 
| 808 |     /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der | 
| 809 |        needs a non-const key, for now. | 
| 810 |        https://github.com/ARMmbed/mbedtls/issues/396 */ | 
| 811 | #if MBEDTLS_VERSION_NUMBER == 0x03000000 | 
| 812 |     if(mbedtls_x509_crt_parse_der(p, | 
| 813 |                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), | 
| 814 |                         peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { | 
| 815 | #else | 
| 816 |     if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { | 
| 817 | #endif | 
| 818 |       failf(data, "Failed copying peer certificate" ); | 
| 819 |       result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; | 
| 820 |       goto pinnedpubkey_error; | 
| 821 |     } | 
| 822 |  | 
| 823 | #if MBEDTLS_VERSION_NUMBER == 0x03000000 | 
| 824 |     size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, | 
| 825 |                                        PUB_DER_MAX_BYTES); | 
| 826 | #else | 
| 827 |     size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); | 
| 828 | #endif | 
| 829 |  | 
| 830 |     if(size <= 0) { | 
| 831 |       failf(data, "Failed copying public key from peer certificate" ); | 
| 832 |       result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; | 
| 833 |       goto pinnedpubkey_error; | 
| 834 |     } | 
| 835 |  | 
| 836 |     /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ | 
| 837 |     result = Curl_pin_peer_pubkey(data, | 
| 838 |                                   pinnedpubkey, | 
| 839 |                                   &pubkey[PUB_DER_MAX_BYTES - size], size); | 
| 840 | pinnedpubkey_error: | 
| 841 |     mbedtls_x509_crt_free(p); | 
| 842 |     free(p); | 
| 843 |     free(pubkey); | 
| 844 |     if(result) { | 
| 845 |       return result; | 
| 846 |     } | 
| 847 |   } | 
| 848 |  | 
| 849 | #ifdef HAS_ALPN | 
| 850 |   if(connssl->alpn) { | 
| 851 |     const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl); | 
| 852 |  | 
| 853 |     Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto, | 
| 854 |                              proto? strlen(proto) : 0); | 
| 855 |   } | 
| 856 | #endif | 
| 857 |  | 
| 858 |   connssl->connecting_state = ssl_connect_3; | 
| 859 |   infof(data, "SSL connected" ); | 
| 860 |  | 
| 861 |   return CURLE_OK; | 
| 862 | } | 
| 863 |  | 
| 864 | static CURLcode | 
| 865 | mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) | 
| 866 | { | 
| 867 |   CURLcode retcode = CURLE_OK; | 
| 868 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 869 |   struct mbed_ssl_backend_data *backend = | 
| 870 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 871 |   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); | 
| 872 |  | 
| 873 |   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); | 
| 874 |   DEBUGASSERT(backend); | 
| 875 |  | 
| 876 |   if(ssl_config->primary.sessionid) { | 
| 877 |     int ret; | 
| 878 |     mbedtls_ssl_session *our_ssl_sessionid; | 
| 879 |     void *old_ssl_sessionid = NULL; | 
| 880 |     bool added = FALSE; | 
| 881 |  | 
| 882 |     our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); | 
| 883 |     if(!our_ssl_sessionid) | 
| 884 |       return CURLE_OUT_OF_MEMORY; | 
| 885 |  | 
| 886 |     mbedtls_ssl_session_init(our_ssl_sessionid); | 
| 887 |  | 
| 888 |     ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid); | 
| 889 |     if(ret) { | 
| 890 |       if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED) | 
| 891 |         mbedtls_ssl_session_free(our_ssl_sessionid); | 
| 892 |       free(our_ssl_sessionid); | 
| 893 |       failf(data, "mbedtls_ssl_get_session returned -0x%x" , -ret); | 
| 894 |       return CURLE_SSL_CONNECT_ERROR; | 
| 895 |     } | 
| 896 |  | 
| 897 |     /* If there's already a matching session in the cache, delete it */ | 
| 898 |     Curl_ssl_sessionid_lock(data); | 
| 899 |     if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)) | 
| 900 |       Curl_ssl_delsessionid(data, old_ssl_sessionid); | 
| 901 |  | 
| 902 |     retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, | 
| 903 |                                     0, &added); | 
| 904 |     Curl_ssl_sessionid_unlock(data); | 
| 905 |     if(!added) { | 
| 906 |       mbedtls_ssl_session_free(our_ssl_sessionid); | 
| 907 |       free(our_ssl_sessionid); | 
| 908 |     } | 
| 909 |     if(retcode) { | 
| 910 |       failf(data, "failed to store ssl session" ); | 
| 911 |       return retcode; | 
| 912 |     } | 
| 913 |   } | 
| 914 |  | 
| 915 |   connssl->connecting_state = ssl_connect_done; | 
| 916 |  | 
| 917 |   return CURLE_OK; | 
| 918 | } | 
| 919 |  | 
| 920 | static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, | 
| 921 |                          const void *mem, size_t len, | 
| 922 |                          CURLcode *curlcode) | 
| 923 | { | 
| 924 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 925 |   struct mbed_ssl_backend_data *backend = | 
| 926 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 927 |   int ret = -1; | 
| 928 |  | 
| 929 |   (void)data; | 
| 930 |   DEBUGASSERT(backend); | 
| 931 |   ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len); | 
| 932 |  | 
| 933 |   if(ret < 0) { | 
| 934 |     *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ? | 
| 935 |       CURLE_AGAIN : CURLE_SEND_ERROR; | 
| 936 |     ret = -1; | 
| 937 |   } | 
| 938 |  | 
| 939 |   return ret; | 
| 940 | } | 
| 941 |  | 
| 942 | static void mbedtls_close_all(struct Curl_easy *data) | 
| 943 | { | 
| 944 |   (void)data; | 
| 945 | } | 
| 946 |  | 
| 947 | static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data) | 
| 948 | { | 
| 949 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 950 |   struct mbed_ssl_backend_data *backend = | 
| 951 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 952 |   char buf[32]; | 
| 953 |  | 
| 954 |   (void)data; | 
| 955 |   DEBUGASSERT(backend); | 
| 956 |  | 
| 957 |   /* Maybe the server has already sent a close notify alert. | 
| 958 |      Read it to avoid an RST on the TCP connection. */ | 
| 959 |   (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf)); | 
| 960 |  | 
| 961 |   mbedtls_pk_free(&backend->pk); | 
| 962 |   mbedtls_x509_crt_free(&backend->clicert); | 
| 963 |   mbedtls_x509_crt_free(&backend->cacert); | 
| 964 | #ifdef MBEDTLS_X509_CRL_PARSE_C | 
| 965 |   mbedtls_x509_crl_free(&backend->crl); | 
| 966 | #endif | 
| 967 |   mbedtls_ssl_config_free(&backend->config); | 
| 968 |   mbedtls_ssl_free(&backend->ssl); | 
| 969 |   mbedtls_ctr_drbg_free(&backend->ctr_drbg); | 
| 970 | #ifndef THREADING_SUPPORT | 
| 971 |   mbedtls_entropy_free(&backend->entropy); | 
| 972 | #endif /* THREADING_SUPPORT */ | 
| 973 | } | 
| 974 |  | 
| 975 | static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, | 
| 976 |                          char *buf, size_t buffersize, | 
| 977 |                          CURLcode *curlcode) | 
| 978 | { | 
| 979 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 980 |   struct mbed_ssl_backend_data *backend = | 
| 981 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 982 |   int ret = -1; | 
| 983 |   ssize_t len = -1; | 
| 984 |  | 
| 985 |   (void)data; | 
| 986 |   DEBUGASSERT(backend); | 
| 987 |  | 
| 988 |   ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, | 
| 989 |                          buffersize); | 
| 990 |  | 
| 991 |   if(ret <= 0) { | 
| 992 |     if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) | 
| 993 |       return 0; | 
| 994 |  | 
| 995 |     *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ? | 
| 996 |       CURLE_AGAIN : CURLE_RECV_ERROR; | 
| 997 |     return -1; | 
| 998 |   } | 
| 999 |  | 
| 1000 |   len = ret; | 
| 1001 |  | 
| 1002 |   return len; | 
| 1003 | } | 
| 1004 |  | 
| 1005 | static void mbedtls_session_free(void *ptr) | 
| 1006 | { | 
| 1007 |   mbedtls_ssl_session_free(ptr); | 
| 1008 |   free(ptr); | 
| 1009 | } | 
| 1010 |  | 
| 1011 | static size_t mbedtls_version(char *buffer, size_t size) | 
| 1012 | { | 
| 1013 | #ifdef MBEDTLS_VERSION_C | 
| 1014 |   /* if mbedtls_version_get_number() is available it is better */ | 
| 1015 |   unsigned int version = mbedtls_version_get_number(); | 
| 1016 |   return msnprintf(buffer, size, "mbedTLS/%u.%u.%u" , version>>24, | 
| 1017 |                    (version>>16)&0xff, (version>>8)&0xff); | 
| 1018 | #else | 
| 1019 |   return msnprintf(buffer, size, "mbedTLS/%s" , MBEDTLS_VERSION_STRING); | 
| 1020 | #endif | 
| 1021 | } | 
| 1022 |  | 
| 1023 | static CURLcode mbedtls_random(struct Curl_easy *data, | 
| 1024 |                                unsigned char *entropy, size_t length) | 
| 1025 | { | 
| 1026 | #if defined(MBEDTLS_CTR_DRBG_C) | 
| 1027 |   int ret = -1; | 
| 1028 |   char errorbuf[128]; | 
| 1029 |   mbedtls_entropy_context ctr_entropy; | 
| 1030 |   mbedtls_ctr_drbg_context ctr_drbg; | 
| 1031 |   mbedtls_entropy_init(&ctr_entropy); | 
| 1032 |   mbedtls_ctr_drbg_init(&ctr_drbg); | 
| 1033 |  | 
| 1034 |   ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, | 
| 1035 |                               &ctr_entropy, NULL, 0); | 
| 1036 |  | 
| 1037 |   if(ret) { | 
| 1038 |     mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 1039 |     failf(data, "mbedtls_ctr_drbg_seed returned (-0x%04X) %s" , | 
| 1040 |           -ret, errorbuf); | 
| 1041 |   } | 
| 1042 |   else { | 
| 1043 |     ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); | 
| 1044 |  | 
| 1045 |     if(ret) { | 
| 1046 |       mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); | 
| 1047 |       failf(data, "mbedtls_ctr_drbg_random returned (-0x%04X) %s" , | 
| 1048 |             -ret, errorbuf); | 
| 1049 |     } | 
| 1050 |   } | 
| 1051 |  | 
| 1052 |   mbedtls_ctr_drbg_free(&ctr_drbg); | 
| 1053 |   mbedtls_entropy_free(&ctr_entropy); | 
| 1054 |  | 
| 1055 |   return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; | 
| 1056 | #elif defined(MBEDTLS_HAVEGE_C) | 
| 1057 |   mbedtls_havege_state hs; | 
| 1058 |   mbedtls_havege_init(&hs); | 
| 1059 |   mbedtls_havege_random(&hs, entropy, length); | 
| 1060 |   mbedtls_havege_free(&hs); | 
| 1061 |   return CURLE_OK; | 
| 1062 | #else | 
| 1063 |   return CURLE_NOT_BUILT_IN; | 
| 1064 | #endif | 
| 1065 | } | 
| 1066 |  | 
| 1067 | static CURLcode | 
| 1068 | mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, | 
| 1069 |                     bool nonblocking, | 
| 1070 |                     bool *done) | 
| 1071 | { | 
| 1072 |   CURLcode retcode; | 
| 1073 |   struct ssl_connect_data *connssl = cf->ctx; | 
| 1074 |   curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); | 
| 1075 |   timediff_t timeout_ms; | 
| 1076 |   int what; | 
| 1077 |  | 
| 1078 |   /* check if the connection has already been established */ | 
| 1079 |   if(ssl_connection_complete == connssl->state) { | 
| 1080 |     *done = TRUE; | 
| 1081 |     return CURLE_OK; | 
| 1082 |   } | 
| 1083 |  | 
| 1084 |   if(ssl_connect_1 == connssl->connecting_state) { | 
| 1085 |     /* Find out how much more time we're allowed */ | 
| 1086 |     timeout_ms = Curl_timeleft(data, NULL, TRUE); | 
| 1087 |  | 
| 1088 |     if(timeout_ms < 0) { | 
| 1089 |       /* no need to continue if time already is up */ | 
| 1090 |       failf(data, "SSL connection timeout" ); | 
| 1091 |       return CURLE_OPERATION_TIMEDOUT; | 
| 1092 |     } | 
| 1093 |     retcode = mbed_connect_step1(cf, data); | 
| 1094 |     if(retcode) | 
| 1095 |       return retcode; | 
| 1096 |   } | 
| 1097 |  | 
| 1098 |   while(ssl_connect_2 == connssl->connecting_state || | 
| 1099 |         ssl_connect_2_reading == connssl->connecting_state || | 
| 1100 |         ssl_connect_2_writing == connssl->connecting_state) { | 
| 1101 |  | 
| 1102 |     /* check allowed time left */ | 
| 1103 |     timeout_ms = Curl_timeleft(data, NULL, TRUE); | 
| 1104 |  | 
| 1105 |     if(timeout_ms < 0) { | 
| 1106 |       /* no need to continue if time already is up */ | 
| 1107 |       failf(data, "SSL connection timeout" ); | 
| 1108 |       return CURLE_OPERATION_TIMEDOUT; | 
| 1109 |     } | 
| 1110 |  | 
| 1111 |     /* if ssl is expecting something, check if it's available. */ | 
| 1112 |     if(connssl->connecting_state == ssl_connect_2_reading | 
| 1113 |        || connssl->connecting_state == ssl_connect_2_writing) { | 
| 1114 |  | 
| 1115 |       curl_socket_t writefd = ssl_connect_2_writing == | 
| 1116 |         connssl->connecting_state?sockfd:CURL_SOCKET_BAD; | 
| 1117 |       curl_socket_t readfd = ssl_connect_2_reading == | 
| 1118 |         connssl->connecting_state?sockfd:CURL_SOCKET_BAD; | 
| 1119 |  | 
| 1120 |       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, | 
| 1121 |                                nonblocking ? 0 : timeout_ms); | 
| 1122 |       if(what < 0) { | 
| 1123 |         /* fatal error */ | 
| 1124 |         failf(data, "select/poll on SSL socket, errno: %d" , SOCKERRNO); | 
| 1125 |         return CURLE_SSL_CONNECT_ERROR; | 
| 1126 |       } | 
| 1127 |       else if(0 == what) { | 
| 1128 |         if(nonblocking) { | 
| 1129 |           *done = FALSE; | 
| 1130 |           return CURLE_OK; | 
| 1131 |         } | 
| 1132 |         else { | 
| 1133 |           /* timeout */ | 
| 1134 |           failf(data, "SSL connection timeout" ); | 
| 1135 |           return CURLE_OPERATION_TIMEDOUT; | 
| 1136 |         } | 
| 1137 |       } | 
| 1138 |       /* socket is readable or writable */ | 
| 1139 |     } | 
| 1140 |  | 
| 1141 |     /* Run transaction, and return to the caller if it failed or if | 
| 1142 |      * this connection is part of a multi handle and this loop would | 
| 1143 |      * execute again. This permits the owner of a multi handle to | 
| 1144 |      * abort a connection attempt before step2 has completed while | 
| 1145 |      * ensuring that a client using select() or epoll() will always | 
| 1146 |      * have a valid fdset to wait on. | 
| 1147 |      */ | 
| 1148 |     retcode = mbed_connect_step2(cf, data); | 
| 1149 |     if(retcode || (nonblocking && | 
| 1150 |                    (ssl_connect_2 == connssl->connecting_state || | 
| 1151 |                     ssl_connect_2_reading == connssl->connecting_state || | 
| 1152 |                     ssl_connect_2_writing == connssl->connecting_state))) | 
| 1153 |       return retcode; | 
| 1154 |  | 
| 1155 |   } /* repeat step2 until all transactions are done. */ | 
| 1156 |  | 
| 1157 |   if(ssl_connect_3 == connssl->connecting_state) { | 
| 1158 |     retcode = mbed_connect_step3(cf, data); | 
| 1159 |     if(retcode) | 
| 1160 |       return retcode; | 
| 1161 |   } | 
| 1162 |  | 
| 1163 |   if(ssl_connect_done == connssl->connecting_state) { | 
| 1164 |     connssl->state = ssl_connection_complete; | 
| 1165 |     *done = TRUE; | 
| 1166 |   } | 
| 1167 |   else | 
| 1168 |     *done = FALSE; | 
| 1169 |  | 
| 1170 |   /* Reset our connect state machine */ | 
| 1171 |   connssl->connecting_state = ssl_connect_1; | 
| 1172 |  | 
| 1173 |   return CURLE_OK; | 
| 1174 | } | 
| 1175 |  | 
| 1176 | static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf, | 
| 1177 |                                             struct Curl_easy *data, | 
| 1178 |                                             bool *done) | 
| 1179 | { | 
| 1180 |   return mbed_connect_common(cf, data, TRUE, done); | 
| 1181 | } | 
| 1182 |  | 
| 1183 |  | 
| 1184 | static CURLcode mbedtls_connect(struct Curl_cfilter *cf, | 
| 1185 |                                 struct Curl_easy *data) | 
| 1186 | { | 
| 1187 |   CURLcode retcode; | 
| 1188 |   bool done = FALSE; | 
| 1189 |  | 
| 1190 |   retcode = mbed_connect_common(cf, data, FALSE, &done); | 
| 1191 |   if(retcode) | 
| 1192 |     return retcode; | 
| 1193 |  | 
| 1194 |   DEBUGASSERT(done); | 
| 1195 |  | 
| 1196 |   return CURLE_OK; | 
| 1197 | } | 
| 1198 |  | 
| 1199 | /* | 
| 1200 |  * return 0 error initializing SSL | 
| 1201 |  * return 1 SSL initialized successfully | 
| 1202 |  */ | 
| 1203 | static int mbedtls_init(void) | 
| 1204 | { | 
| 1205 |   return Curl_mbedtlsthreadlock_thread_setup(); | 
| 1206 | } | 
| 1207 |  | 
| 1208 | static void mbedtls_cleanup(void) | 
| 1209 | { | 
| 1210 |   (void)Curl_mbedtlsthreadlock_thread_cleanup(); | 
| 1211 | } | 
| 1212 |  | 
| 1213 | static bool mbedtls_data_pending(struct Curl_cfilter *cf, | 
| 1214 |                                  const struct Curl_easy *data) | 
| 1215 | { | 
| 1216 |   struct ssl_connect_data *ctx = cf->ctx; | 
| 1217 |   struct mbed_ssl_backend_data *backend; | 
| 1218 |  | 
| 1219 |   (void)data; | 
| 1220 |   DEBUGASSERT(ctx && ctx->backend); | 
| 1221 |   backend = (struct mbed_ssl_backend_data *)ctx->backend; | 
| 1222 |   return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0; | 
| 1223 | } | 
| 1224 |  | 
| 1225 | static CURLcode mbedtls_sha256sum(const unsigned char *input, | 
| 1226 |                                   size_t inputlen, | 
| 1227 |                                   unsigned char *sha256sum, | 
| 1228 |                                   size_t sha256len UNUSED_PARAM) | 
| 1229 | { | 
| 1230 |   /* TODO: explain this for different mbedtls 2.x vs 3 version */ | 
| 1231 |   (void)sha256len; | 
| 1232 | #if MBEDTLS_VERSION_NUMBER < 0x02070000 | 
| 1233 |   mbedtls_sha256(input, inputlen, sha256sum, 0); | 
| 1234 | #else | 
| 1235 |   /* returns 0 on success, otherwise failure */ | 
| 1236 | #if MBEDTLS_VERSION_NUMBER >= 0x03000000 | 
| 1237 |   if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0) | 
| 1238 | #else | 
| 1239 |   if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) | 
| 1240 | #endif | 
| 1241 |     return CURLE_BAD_FUNCTION_ARGUMENT; | 
| 1242 | #endif | 
| 1243 |   return CURLE_OK; | 
| 1244 | } | 
| 1245 |  | 
| 1246 | static void *mbedtls_get_internals(struct ssl_connect_data *connssl, | 
| 1247 |                                    CURLINFO info UNUSED_PARAM) | 
| 1248 | { | 
| 1249 |   struct mbed_ssl_backend_data *backend = | 
| 1250 |     (struct mbed_ssl_backend_data *)connssl->backend; | 
| 1251 |   (void)info; | 
| 1252 |   DEBUGASSERT(backend); | 
| 1253 |   return &backend->ssl; | 
| 1254 | } | 
| 1255 |  | 
| 1256 | const struct Curl_ssl Curl_ssl_mbedtls = { | 
| 1257 |   { CURLSSLBACKEND_MBEDTLS, "mbedtls"  }, /* info */ | 
| 1258 |  | 
| 1259 |   SSLSUPP_CA_PATH | | 
| 1260 |   SSLSUPP_CAINFO_BLOB | | 
| 1261 |   SSLSUPP_PINNEDPUBKEY | | 
| 1262 |   SSLSUPP_SSL_CTX | | 
| 1263 |   SSLSUPP_HTTPS_PROXY, | 
| 1264 |  | 
| 1265 |   sizeof(struct mbed_ssl_backend_data), | 
| 1266 |  | 
| 1267 |   mbedtls_init,                     /* init */ | 
| 1268 |   mbedtls_cleanup,                  /* cleanup */ | 
| 1269 |   mbedtls_version,                  /* version */ | 
| 1270 |   Curl_none_check_cxn,              /* check_cxn */ | 
| 1271 |   Curl_none_shutdown,               /* shutdown */ | 
| 1272 |   mbedtls_data_pending,             /* data_pending */ | 
| 1273 |   mbedtls_random,                   /* random */ | 
| 1274 |   Curl_none_cert_status_request,    /* cert_status_request */ | 
| 1275 |   mbedtls_connect,                  /* connect */ | 
| 1276 |   mbedtls_connect_nonblocking,      /* connect_nonblocking */ | 
| 1277 |   Curl_ssl_get_select_socks,                 /* getsock */ | 
| 1278 |   mbedtls_get_internals,            /* get_internals */ | 
| 1279 |   mbedtls_close,                    /* close_one */ | 
| 1280 |   mbedtls_close_all,                /* close_all */ | 
| 1281 |   mbedtls_session_free,             /* session_free */ | 
| 1282 |   Curl_none_set_engine,             /* set_engine */ | 
| 1283 |   Curl_none_set_engine_default,     /* set_engine_default */ | 
| 1284 |   Curl_none_engines_list,           /* engines_list */ | 
| 1285 |   Curl_none_false_start,            /* false_start */ | 
| 1286 |   mbedtls_sha256sum,                /* sha256sum */ | 
| 1287 |   NULL,                             /* associate_connection */ | 
| 1288 |   NULL,                             /* disassociate_connection */ | 
| 1289 |   NULL,                             /* free_multi_ssl_backend_data */ | 
| 1290 |   mbed_recv,                        /* recv decrypted data */ | 
| 1291 |   mbed_send,                        /* send data to encrypt */ | 
| 1292 | }; | 
| 1293 |  | 
| 1294 | #endif /* USE_MBEDTLS */ | 
| 1295 |  |