1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
9 * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
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.haxx.se/docs/copyright.html.
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.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ***************************************************************************/
25 * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code
26 * but vtls.c should ever call or use these functions.
30 #include "curl_setup.h"
34 #include <mbedtls/version.h>
35 #if MBEDTLS_VERSION_NUMBER >= 0x02040000
36 #include <mbedtls/net_sockets.h>
38 #include <mbedtls/net.h>
40 #include <mbedtls/ssl.h>
41 #include <mbedtls/certs.h>
42 #include <mbedtls/x509.h>
44 #include <mbedtls/error.h>
45 #include <mbedtls/entropy.h>
46 #include <mbedtls/ctr_drbg.h>
47 #include <mbedtls/sha256.h>
51 #include "inet_pton.h"
54 #include "parsedate.h"
55 #include "connect.h" /* for the connect timeout */
57 #include "polarssl_threadlock.h"
59 /* The last 3 #include files should be in this order */
60 #include "curl_printf.h"
61 #include "curl_memory.h"
64 struct ssl_backend_data {
65 mbedtls_ctr_drbg_context ctr_drbg;
66 mbedtls_entropy_context entropy;
67 mbedtls_ssl_context ssl;
69 mbedtls_x509_crt cacert;
70 mbedtls_x509_crt clicert;
72 mbedtls_pk_context pk;
73 mbedtls_ssl_config config;
74 const char *protocols[3];
77 #define BACKEND connssl->backend
79 /* apply threading? */
80 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
81 #define THREADING_SUPPORT
84 #if defined(THREADING_SUPPORT)
85 static mbedtls_entropy_context ts_entropy;
87 static int entropy_init_initialized = 0;
89 /* start of entropy_init_mutex() */
90 static void entropy_init_mutex(mbedtls_entropy_context *ctx)
92 /* lock 0 = entropy_init_mutex() */
93 Curl_polarsslthreadlock_lock_function(0);
94 if(entropy_init_initialized == 0) {
95 mbedtls_entropy_init(ctx);
96 entropy_init_initialized = 1;
98 Curl_polarsslthreadlock_unlock_function(0);
100 /* end of entropy_init_mutex() */
102 /* start of entropy_func_mutex() */
103 static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
106 /* lock 1 = entropy_func_mutex() */
107 Curl_polarsslthreadlock_lock_function(1);
108 ret = mbedtls_entropy_func(data, output, len);
109 Curl_polarsslthreadlock_unlock_function(1);
113 /* end of entropy_func_mutex() */
115 #endif /* THREADING_SUPPORT */
117 /* Define this to enable lots of debugging for mbedTLS */
121 static void mbed_debug(void *context, int level, const char *f_name,
122 int line_nb, const char *line)
124 struct Curl_easy *data = NULL;
129 data = (struct Curl_easy *)context;
131 infof(data, "%s", line);
137 /* ALPN for http2? */
140 # ifdef MBEDTLS_SSL_ALPN
149 static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
151 /* Hashes from SHA-1 and above */
152 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
153 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
154 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
155 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
156 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
157 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
158 0xFFFFFFF, /* Any PK alg */
159 0xFFFFFFF, /* Any curve */
160 1024, /* RSA min key len */
163 /* See https://tls.mbed.org/discussions/generic/
164 howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
166 #define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
167 #define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
169 #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
170 RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
172 static Curl_recv mbed_recv;
173 static Curl_send mbed_send;
175 static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
178 case CURL_SSLVERSION_TLSv1_0:
179 *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
181 case CURL_SSLVERSION_TLSv1_1:
182 *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
184 case CURL_SSLVERSION_TLSv1_2:
185 *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
187 case CURL_SSLVERSION_TLSv1_3:
190 return CURLE_SSL_CONNECT_ERROR;
194 set_ssl_version_min_max(struct connectdata *conn, int sockindex)
196 struct Curl_easy *data = conn->data;
197 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
198 int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
199 int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
200 long ssl_version = SSL_CONN_CONFIG(version);
201 long ssl_version_max = SSL_CONN_CONFIG(version_max);
202 CURLcode result = CURLE_OK;
204 switch(ssl_version) {
205 case CURL_SSLVERSION_DEFAULT:
206 case CURL_SSLVERSION_TLSv1:
207 ssl_version = CURL_SSLVERSION_TLSv1_0;
208 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
212 switch(ssl_version_max) {
213 case CURL_SSLVERSION_MAX_NONE:
214 ssl_version_max = ssl_version << 16;
216 case CURL_SSLVERSION_MAX_DEFAULT:
217 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
221 result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
223 failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
226 result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
228 failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
232 mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
234 mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
241 mbed_connect_step1(struct connectdata *conn,
244 struct Curl_easy *data = conn->data;
245 struct ssl_connect_data* connssl = &conn->ssl[sockindex];
246 const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
247 const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
248 const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
249 char * const ssl_cert = SSL_SET_OPTION(cert);
250 const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
251 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
253 const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
258 /* mbedTLS only supports SSLv3 and TLSv1 */
259 if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
260 failf(data, "mbedTLS does not support SSLv2");
261 return CURLE_SSL_CONNECT_ERROR;
264 #ifdef THREADING_SUPPORT
265 entropy_init_mutex(&ts_entropy);
266 mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg);
268 ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex,
269 &ts_entropy, NULL, 0);
271 #ifdef MBEDTLS_ERROR_C
272 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
273 #endif /* MBEDTLS_ERROR_C */
274 failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
278 mbedtls_entropy_init(&BACKEND->entropy);
279 mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg);
281 ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func,
282 &BACKEND->entropy, NULL, 0);
284 #ifdef MBEDTLS_ERROR_C
285 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
286 #endif /* MBEDTLS_ERROR_C */
287 failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
290 #endif /* THREADING_SUPPORT */
292 /* Load the trusted CA */
293 mbedtls_x509_crt_init(&BACKEND->cacert);
296 ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile);
299 #ifdef MBEDTLS_ERROR_C
300 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
301 #endif /* MBEDTLS_ERROR_C */
302 failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
303 ssl_cafile, -ret, errorbuf);
306 return CURLE_SSL_CACERT_BADFILE;
311 ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath);
314 #ifdef MBEDTLS_ERROR_C
315 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
316 #endif /* MBEDTLS_ERROR_C */
317 failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
318 ssl_capath, -ret, errorbuf);
321 return CURLE_SSL_CACERT_BADFILE;
325 /* Load the client certificate */
326 mbedtls_x509_crt_init(&BACKEND->clicert);
329 ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert);
332 #ifdef MBEDTLS_ERROR_C
333 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
334 #endif /* MBEDTLS_ERROR_C */
335 failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
336 ssl_cert, -ret, errorbuf);
338 return CURLE_SSL_CERTPROBLEM;
342 /* Load the client private key */
343 mbedtls_pk_init(&BACKEND->pk);
345 if(SSL_SET_OPTION(key)) {
346 ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key),
347 SSL_SET_OPTION(key_passwd));
348 if(ret == 0 && !mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA))
349 ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
352 #ifdef MBEDTLS_ERROR_C
353 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
354 #endif /* MBEDTLS_ERROR_C */
355 failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
356 SSL_SET_OPTION(key), -ret, errorbuf);
358 return CURLE_SSL_CERTPROBLEM;
363 mbedtls_x509_crl_init(&BACKEND->crl);
366 ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile);
369 #ifdef MBEDTLS_ERROR_C
370 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
371 #endif /* MBEDTLS_ERROR_C */
372 failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
373 ssl_crlfile, -ret, errorbuf);
375 return CURLE_SSL_CRL_BADFILE;
379 infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
381 mbedtls_ssl_config_init(&BACKEND->config);
383 mbedtls_ssl_init(&BACKEND->ssl);
384 if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) {
385 failf(data, "mbedTLS: ssl_init failed");
386 return CURLE_SSL_CONNECT_ERROR;
388 ret = mbedtls_ssl_config_defaults(&BACKEND->config,
389 MBEDTLS_SSL_IS_CLIENT,
390 MBEDTLS_SSL_TRANSPORT_STREAM,
391 MBEDTLS_SSL_PRESET_DEFAULT);
393 failf(data, "mbedTLS: ssl_config failed");
394 return CURLE_SSL_CONNECT_ERROR;
397 /* new profile with RSA min key len = 1024 ... */
398 mbedtls_ssl_conf_cert_profile(&BACKEND->config,
399 &mbedtls_x509_crt_profile_fr);
401 switch(SSL_CONN_CONFIG(version)) {
402 case CURL_SSLVERSION_DEFAULT:
403 case CURL_SSLVERSION_TLSv1:
404 mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
405 MBEDTLS_SSL_MINOR_VERSION_1);
406 infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
408 case CURL_SSLVERSION_SSLv3:
409 mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
410 MBEDTLS_SSL_MINOR_VERSION_0);
411 mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
412 MBEDTLS_SSL_MINOR_VERSION_0);
413 infof(data, "mbedTLS: Set SSL version to SSLv3\n");
415 case CURL_SSLVERSION_TLSv1_0:
416 case CURL_SSLVERSION_TLSv1_1:
417 case CURL_SSLVERSION_TLSv1_2:
418 case CURL_SSLVERSION_TLSv1_3:
420 CURLcode result = set_ssl_version_min_max(conn, sockindex);
421 if(result != CURLE_OK)
426 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
427 return CURLE_SSL_CONNECT_ERROR;
430 mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
432 mbedtls_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random,
434 mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex],
437 NULL /* rev_timeout() */);
439 mbedtls_ssl_conf_ciphersuites(&BACKEND->config,
440 mbedtls_ssl_list_ciphersuites());
442 #if defined(MBEDTLS_SSL_RENEGOTIATION)
443 mbedtls_ssl_conf_renegotiation(&BACKEND->config,
444 MBEDTLS_SSL_RENEGOTIATION_ENABLED);
447 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
448 mbedtls_ssl_conf_session_tickets(&BACKEND->config,
449 MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
452 /* Check if there's a cached ID we can/should use here! */
453 if(SSL_SET_OPTION(primary.sessionid)) {
454 void *old_session = NULL;
456 Curl_ssl_sessionid_lock(conn);
457 if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
458 ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session);
460 Curl_ssl_sessionid_unlock(conn);
461 failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
462 return CURLE_SSL_CONNECT_ERROR;
464 infof(data, "mbedTLS re-using session\n");
466 Curl_ssl_sessionid_unlock(conn);
469 mbedtls_ssl_conf_ca_chain(&BACKEND->config,
473 if(SSL_SET_OPTION(key)) {
474 mbedtls_ssl_conf_own_cert(&BACKEND->config,
475 &BACKEND->clicert, &BACKEND->pk);
477 if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) {
478 /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
479 the name to set in the SNI extension. So even if curl connects to a
480 host specified as an IP address, this function must be used. */
481 failf(data, "couldn't set hostname in mbedTLS");
482 return CURLE_SSL_CONNECT_ERROR;
486 if(conn->bits.tls_enable_alpn) {
487 const char **p = &BACKEND->protocols[0];
489 if(data->set.httpversion >= CURL_HTTP_VERSION_2)
490 *p++ = NGHTTP2_PROTO_VERSION_ID;
492 *p++ = ALPN_HTTP_1_1;
494 /* this function doesn't clone the protocols array, which is why we need
496 if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config,
497 &BACKEND->protocols[0])) {
498 failf(data, "Failed setting ALPN protocols");
499 return CURLE_SSL_CONNECT_ERROR;
501 for(p = &BACKEND->protocols[0]; *p; ++p)
502 infof(data, "ALPN, offering %s\n", *p);
507 /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
508 mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data);
515 mbedtls_debug_set_threshold(4);
518 /* give application a chance to interfere with mbedTLS set up. */
519 if(data->set.ssl.fsslctx) {
520 ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config,
521 data->set.ssl.fsslctxp);
523 failf(data, "error signaled by ssl ctx callback");
528 connssl->connecting_state = ssl_connect_2;
534 mbed_connect_step2(struct connectdata *conn,
538 struct Curl_easy *data = conn->data;
539 struct ssl_connect_data* connssl = &conn->ssl[sockindex];
540 const mbedtls_x509_crt *peercert;
541 const char * const pinnedpubkey = SSL_IS_PROXY() ?
542 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
543 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
546 const char *next_protocol;
552 conn->recv[sockindex] = mbed_recv;
553 conn->send[sockindex] = mbed_send;
555 ret = mbedtls_ssl_handshake(&BACKEND->ssl);
557 if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
558 connssl->connecting_state = ssl_connect_2_reading;
561 else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
562 connssl->connecting_state = ssl_connect_2_writing;
566 #ifdef MBEDTLS_ERROR_C
567 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
568 #endif /* MBEDTLS_ERROR_C */
569 failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
571 return CURLE_SSL_CONNECT_ERROR;
574 infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
575 mbedtls_ssl_get_ciphersuite(&BACKEND->ssl)
578 ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl);
580 if(ret && SSL_CONN_CONFIG(verifypeer)) {
581 if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
582 failf(data, "Cert verify failed: BADCERT_EXPIRED");
584 if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
585 failf(data, "Cert verify failed: BADCERT_REVOKED");
586 return CURLE_SSL_CACERT;
589 if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
590 failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
592 if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
593 failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
595 return CURLE_PEER_FAILED_VERIFICATION;
598 peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl);
600 if(peercert && data->set.verbose) {
601 const size_t bufsize = 16384;
602 char *buffer = malloc(bufsize);
605 return CURLE_OUT_OF_MEMORY;
607 if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
608 infof(data, "Dumping cert info:\n%s\n", buffer);
610 infof(data, "Unable to dump certificate information.\n");
619 unsigned char pubkey[PUB_DER_MAX_BYTES];
621 if(!peercert || !peercert->raw.p || !peercert->raw.len) {
622 failf(data, "Failed due to missing peer certificate");
623 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
626 p = calloc(1, sizeof(*p));
629 return CURLE_OUT_OF_MEMORY;
631 mbedtls_x509_crt_init(p);
633 /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
634 needs a non-const key, for now.
635 https://github.com/ARMmbed/mbedtls/issues/396 */
636 if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
637 failf(data, "Failed copying peer certificate");
638 mbedtls_x509_crt_free(p);
640 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
643 size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
646 failf(data, "Failed copying public key from peer certificate");
647 mbedtls_x509_crt_free(p);
649 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
652 /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
653 result = Curl_pin_peer_pubkey(data,
655 &pubkey[PUB_DER_MAX_BYTES - size], size);
657 mbedtls_x509_crt_free(p);
662 mbedtls_x509_crt_free(p);
667 if(conn->bits.tls_enable_alpn) {
668 next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl);
671 infof(data, "ALPN, server accepted to use %s\n", next_protocol);
673 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
674 NGHTTP2_PROTO_VERSION_ID_LEN) &&
675 !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) {
676 conn->negnpn = CURL_HTTP_VERSION_2;
680 if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
681 !next_protocol[ALPN_HTTP_1_1_LENGTH]) {
682 conn->negnpn = CURL_HTTP_VERSION_1_1;
686 infof(data, "ALPN, server did not agree to a protocol\n");
691 connssl->connecting_state = ssl_connect_3;
692 infof(data, "SSL connected\n");
698 mbed_connect_step3(struct connectdata *conn,
701 CURLcode retcode = CURLE_OK;
702 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
703 struct Curl_easy *data = conn->data;
705 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
707 if(SSL_SET_OPTION(primary.sessionid)) {
709 mbedtls_ssl_session *our_ssl_sessionid;
710 void *old_ssl_sessionid = NULL;
712 our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
713 if(!our_ssl_sessionid)
714 return CURLE_OUT_OF_MEMORY;
716 mbedtls_ssl_session_init(our_ssl_sessionid);
718 ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
720 free(our_ssl_sessionid);
721 failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
722 return CURLE_SSL_CONNECT_ERROR;
725 /* If there's already a matching session in the cache, delete it */
726 Curl_ssl_sessionid_lock(conn);
727 if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
728 Curl_ssl_delsessionid(conn, old_ssl_sessionid);
730 retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
731 Curl_ssl_sessionid_unlock(conn);
733 free(our_ssl_sessionid);
734 failf(data, "failed to store ssl session");
739 connssl->connecting_state = ssl_connect_done;
744 static ssize_t mbed_send(struct connectdata *conn, int sockindex,
745 const void *mem, size_t len,
748 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
751 ret = mbedtls_ssl_write(&BACKEND->ssl,
752 (unsigned char *)mem, len);
755 *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
756 CURLE_AGAIN : CURLE_SEND_ERROR;
763 static void Curl_mbedtls_close_all(struct Curl_easy *data)
768 static void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
770 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
771 mbedtls_pk_free(&BACKEND->pk);
772 mbedtls_x509_crt_free(&BACKEND->clicert);
773 mbedtls_x509_crt_free(&BACKEND->cacert);
774 mbedtls_x509_crl_free(&BACKEND->crl);
775 mbedtls_ssl_config_free(&BACKEND->config);
776 mbedtls_ssl_free(&BACKEND->ssl);
777 mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg);
778 #ifndef THREADING_SUPPORT
779 mbedtls_entropy_free(&BACKEND->entropy);
780 #endif /* THREADING_SUPPORT */
783 static ssize_t mbed_recv(struct connectdata *conn, int num,
784 char *buf, size_t buffersize,
787 struct ssl_connect_data *connssl = &conn->ssl[num];
791 memset(buf, 0, buffersize);
792 ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf,
796 if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
799 *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
800 CURLE_AGAIN : CURLE_RECV_ERROR;
809 static void Curl_mbedtls_session_free(void *ptr)
811 mbedtls_ssl_session_free(ptr);
815 static size_t Curl_mbedtls_version(char *buffer, size_t size)
817 unsigned int version = mbedtls_version_get_number();
818 return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
819 (version>>16)&0xff, (version>>8)&0xff);
822 static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
823 unsigned char *entropy, size_t length)
825 #if defined(MBEDTLS_CTR_DRBG_C)
828 mbedtls_entropy_context ctr_entropy;
829 mbedtls_ctr_drbg_context ctr_drbg;
830 mbedtls_entropy_init(&ctr_entropy);
831 mbedtls_ctr_drbg_init(&ctr_drbg);
834 ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
835 &ctr_entropy, NULL, 0);
838 #ifdef MBEDTLS_ERROR_C
839 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
840 #endif /* MBEDTLS_ERROR_C */
841 failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n",
845 ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
848 #ifdef MBEDTLS_ERROR_C
849 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
850 #endif /* MBEDTLS_ERROR_C */
851 failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
856 mbedtls_ctr_drbg_free(&ctr_drbg);
857 mbedtls_entropy_free(&ctr_entropy);
859 return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT;
860 #elif defined(MBEDTLS_HAVEGE_C)
861 mbedtls_havege_state hs;
862 mbedtls_havege_init(&hs);
863 mbedtls_havege_random(&hs, entropy, length);
864 mbedtls_havege_free(&hs);
867 return CURLE_NOT_BUILT_IN;
872 mbed_connect_common(struct connectdata *conn,
878 struct Curl_easy *data = conn->data;
879 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
880 curl_socket_t sockfd = conn->sock[sockindex];
884 /* check if the connection has already been established */
885 if(ssl_connection_complete == connssl->state) {
890 if(ssl_connect_1 == connssl->connecting_state) {
891 /* Find out how much more time we're allowed */
892 timeout_ms = Curl_timeleft(data, NULL, TRUE);
895 /* no need to continue if time already is up */
896 failf(data, "SSL connection timeout");
897 return CURLE_OPERATION_TIMEDOUT;
899 retcode = mbed_connect_step1(conn, sockindex);
904 while(ssl_connect_2 == connssl->connecting_state ||
905 ssl_connect_2_reading == connssl->connecting_state ||
906 ssl_connect_2_writing == connssl->connecting_state) {
908 /* check allowed time left */
909 timeout_ms = Curl_timeleft(data, NULL, TRUE);
912 /* no need to continue if time already is up */
913 failf(data, "SSL connection timeout");
914 return CURLE_OPERATION_TIMEDOUT;
917 /* if ssl is expecting something, check if it's available. */
918 if(connssl->connecting_state == ssl_connect_2_reading
919 || connssl->connecting_state == ssl_connect_2_writing) {
921 curl_socket_t writefd = ssl_connect_2_writing ==
922 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
923 curl_socket_t readfd = ssl_connect_2_reading ==
924 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
926 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
927 nonblocking ? 0 : timeout_ms);
930 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
931 return CURLE_SSL_CONNECT_ERROR;
940 failf(data, "SSL connection timeout");
941 return CURLE_OPERATION_TIMEDOUT;
944 /* socket is readable or writable */
947 /* Run transaction, and return to the caller if it failed or if
948 * this connection is part of a multi handle and this loop would
949 * execute again. This permits the owner of a multi handle to
950 * abort a connection attempt before step2 has completed while
951 * ensuring that a client using select() or epoll() will always
952 * have a valid fdset to wait on.
954 retcode = mbed_connect_step2(conn, sockindex);
955 if(retcode || (nonblocking &&
956 (ssl_connect_2 == connssl->connecting_state ||
957 ssl_connect_2_reading == connssl->connecting_state ||
958 ssl_connect_2_writing == connssl->connecting_state)))
961 } /* repeat step2 until all transactions are done. */
963 if(ssl_connect_3 == connssl->connecting_state) {
964 retcode = mbed_connect_step3(conn, sockindex);
969 if(ssl_connect_done == connssl->connecting_state) {
970 connssl->state = ssl_connection_complete;
971 conn->recv[sockindex] = mbed_recv;
972 conn->send[sockindex] = mbed_send;
978 /* Reset our connect state machine */
979 connssl->connecting_state = ssl_connect_1;
984 static CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
985 int sockindex, bool *done)
987 return mbed_connect_common(conn, sockindex, TRUE, done);
991 static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex)
996 retcode = mbed_connect_common(conn, sockindex, FALSE, &done);
1006 * return 0 error initializing SSL
1007 * return 1 SSL initialized successfully
1009 static int Curl_mbedtls_init(void)
1011 return Curl_polarsslthreadlock_thread_setup();
1014 static void Curl_mbedtls_cleanup(void)
1016 (void)Curl_polarsslthreadlock_thread_cleanup();
1019 static bool Curl_mbedtls_data_pending(const struct connectdata *conn,
1022 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1023 return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0;
1026 static void Curl_mbedtls_sha256sum(const unsigned char *input,
1028 unsigned char *sha256sum,
1029 size_t sha256len UNUSED_PARAM)
1032 mbedtls_sha256(input, inputlen, sha256sum, 0);
1035 static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
1036 CURLINFO info UNUSED_PARAM)
1039 return &BACKEND->ssl;
1042 const struct Curl_ssl Curl_ssl_mbedtls = {
1043 { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
1045 1, /* have_ca_path */
1046 0, /* have_certinfo */
1047 1, /* have_pinnedpubkey */
1048 1, /* have_ssl_ctx */
1049 0, /* support_https_proxy */
1051 sizeof(struct ssl_backend_data),
1053 Curl_mbedtls_init, /* init */
1054 Curl_mbedtls_cleanup, /* cleanup */
1055 Curl_mbedtls_version, /* version */
1056 Curl_none_check_cxn, /* check_cxn */
1057 Curl_none_shutdown, /* shutdown */
1058 Curl_mbedtls_data_pending, /* data_pending */
1059 Curl_mbedtls_random, /* random */
1060 Curl_none_cert_status_request, /* cert_status_request */
1061 Curl_mbedtls_connect, /* connect */
1062 Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */
1063 Curl_mbedtls_get_internals, /* get_internals */
1064 Curl_mbedtls_close, /* close_one */
1065 Curl_mbedtls_close_all, /* close_all */
1066 Curl_mbedtls_session_free, /* session_free */
1067 Curl_none_set_engine, /* set_engine */
1068 Curl_none_set_engine_default, /* set_engine_default */
1069 Curl_none_engines_list, /* engines_list */
1070 Curl_none_false_start, /* false_start */
1071 Curl_none_md5sum, /* md5sum */
1072 Curl_mbedtls_sha256sum /* sha256sum */
1075 #endif /* USE_MBEDTLS */