libcurl: updated to 7.49.1
[tomato.git] / release / src / router / libcurl / lib / vtls / mbedtls.c
blobef0b9492ab7d9831f2b10ba31f940ea20a9dc964
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
9 * Copyright (C) 2012 - 2016, 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"
32 #ifdef USE_MBEDTLS
34 #include <mbedtls/net.h>
35 #include <mbedtls/ssl.h>
36 #include <mbedtls/certs.h>
37 #include <mbedtls/x509.h>
38 #include <mbedtls/version.h>
40 #include <mbedtls/error.h>
41 #include <mbedtls/entropy.h>
42 #include <mbedtls/ctr_drbg.h>
43 #include <mbedtls/sha256.h>
45 #include "urldata.h"
46 #include "sendf.h"
47 #include "inet_pton.h"
48 #include "mbedtls.h"
49 #include "vtls.h"
50 #include "parsedate.h"
51 #include "connect.h" /* for the connect timeout */
52 #include "select.h"
53 #include "rawstr.h"
54 #include "polarssl_threadlock.h"
56 /* The last 3 #include files should be in this order */
57 #include "curl_printf.h"
58 #include "curl_memory.h"
59 #include "memdebug.h"
61 /* apply threading? */
62 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
63 #define THREADING_SUPPORT
64 #endif
66 #if defined(THREADING_SUPPORT)
67 static mbedtls_entropy_context entropy;
69 static int entropy_init_initialized = 0;
71 /* start of entropy_init_mutex() */
72 static void entropy_init_mutex(mbedtls_entropy_context *ctx)
74 /* lock 0 = entropy_init_mutex() */
75 Curl_polarsslthreadlock_lock_function(0);
76 if(entropy_init_initialized == 0) {
77 mbedtls_entropy_init(ctx);
78 entropy_init_initialized = 1;
80 Curl_polarsslthreadlock_unlock_function(0);
82 /* end of entropy_init_mutex() */
84 /* start of entropy_func_mutex() */
85 static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
87 int ret;
88 /* lock 1 = entropy_func_mutex() */
89 Curl_polarsslthreadlock_lock_function(1);
90 ret = mbedtls_entropy_func(data, output, len);
91 Curl_polarsslthreadlock_unlock_function(1);
93 return ret;
95 /* end of entropy_func_mutex() */
97 #endif /* THREADING_SUPPORT */
99 /* Define this to enable lots of debugging for mbedTLS */
100 #undef MBEDTLS_DEBUG
102 #ifdef MBEDTLS_DEBUG
103 static void mbed_debug(void *context, int level, const char *f_name,
104 int line_nb, const char *line)
106 struct SessionHandle *data = NULL;
108 if(!context)
109 return;
111 data = (struct SessionHandle *)context;
113 infof(data, "%s", line);
114 (void) level;
116 #else
117 #endif
119 /* ALPN for http2? */
120 #ifdef USE_NGHTTP2
121 # undef HAS_ALPN
122 # ifdef MBEDTLS_SSL_ALPN
123 # define HAS_ALPN
124 # endif
125 #endif
129 * profile
131 const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
133 /* Hashes from SHA-1 and above */
134 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
135 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
136 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
137 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
138 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
139 MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
140 0xFFFFFFF, /* Any PK alg */
141 0xFFFFFFF, /* Any curve */
142 1024, /* RSA min key len */
145 /* See https://tls.mbed.org/discussions/generic/
146 howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
148 #define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
149 #define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
151 #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
152 RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
154 static Curl_recv mbed_recv;
155 static Curl_send mbed_send;
157 static CURLcode
158 mbed_connect_step1(struct connectdata *conn,
159 int sockindex)
161 struct SessionHandle *data = conn->data;
162 struct ssl_connect_data* connssl = &conn->ssl[sockindex];
164 bool sni = TRUE; /* default is SNI enabled */
165 int ret = -1;
166 #ifdef ENABLE_IPV6
167 struct in6_addr addr;
168 #else
169 struct in_addr addr;
170 #endif
171 void *old_session = NULL;
172 char errorbuf[128];
173 errorbuf[0]=0;
175 /* mbedTLS only supports SSLv3 and TLSv1 */
176 if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
177 failf(data, "mbedTLS does not support SSLv2");
178 return CURLE_SSL_CONNECT_ERROR;
180 else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
181 sni = FALSE; /* SSLv3 has no SNI */
183 #ifdef THREADING_SUPPORT
184 entropy_init_mutex(&entropy);
185 mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
187 ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex,
188 &entropy, NULL, 0);
189 if(ret) {
190 #ifdef MBEDTLS_ERROR_C
191 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
192 #endif /* MBEDTLS_ERROR_C */
193 failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
194 -ret, errorbuf);
196 #else
197 mbedtls_entropy_init(&connssl->entropy);
198 mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
200 ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func,
201 &connssl->entropy, NULL, 0);
202 if(ret) {
203 #ifdef MBEDTLS_ERROR_C
204 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
205 #endif /* MBEDTLS_ERROR_C */
206 failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
207 -ret, errorbuf);
209 #endif /* THREADING_SUPPORT */
211 /* Load the trusted CA */
212 mbedtls_x509_crt_init(&connssl->cacert);
214 if(data->set.str[STRING_SSL_CAFILE]) {
215 ret = mbedtls_x509_crt_parse_file(&connssl->cacert,
216 data->set.str[STRING_SSL_CAFILE]);
218 if(ret<0) {
219 #ifdef MBEDTLS_ERROR_C
220 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
221 #endif /* MBEDTLS_ERROR_C */
222 failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
223 data->set.str[STRING_SSL_CAFILE], -ret, errorbuf);
225 if(data->set.ssl.verifypeer)
226 return CURLE_SSL_CACERT_BADFILE;
230 if(data->set.str[STRING_SSL_CAPATH]) {
231 ret = mbedtls_x509_crt_parse_path(&connssl->cacert,
232 data->set.str[STRING_SSL_CAPATH]);
234 if(ret<0) {
235 #ifdef MBEDTLS_ERROR_C
236 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
237 #endif /* MBEDTLS_ERROR_C */
238 failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
239 data->set.str[STRING_SSL_CAPATH], -ret, errorbuf);
241 if(data->set.ssl.verifypeer)
242 return CURLE_SSL_CACERT_BADFILE;
246 /* Load the client certificate */
247 mbedtls_x509_crt_init(&connssl->clicert);
249 if(data->set.str[STRING_CERT]) {
250 ret = mbedtls_x509_crt_parse_file(&connssl->clicert,
251 data->set.str[STRING_CERT]);
253 if(ret) {
254 #ifdef MBEDTLS_ERROR_C
255 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
256 #endif /* MBEDTLS_ERROR_C */
257 failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
258 data->set.str[STRING_CERT], -ret, errorbuf);
260 return CURLE_SSL_CERTPROBLEM;
264 /* Load the client private key */
265 mbedtls_pk_init(&connssl->pk);
267 if(data->set.str[STRING_KEY]) {
268 ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY],
269 data->set.str[STRING_KEY_PASSWD]);
270 if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
271 ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
273 if(ret) {
274 #ifdef MBEDTLS_ERROR_C
275 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
276 #endif /* MBEDTLS_ERROR_C */
277 failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
278 data->set.str[STRING_KEY], -ret, errorbuf);
280 return CURLE_SSL_CERTPROBLEM;
284 /* Load the CRL */
285 mbedtls_x509_crl_init(&connssl->crl);
287 if(data->set.str[STRING_SSL_CRLFILE]) {
288 ret = mbedtls_x509_crl_parse_file(&connssl->crl,
289 data->set.str[STRING_SSL_CRLFILE]);
291 if(ret) {
292 #ifdef MBEDTLS_ERROR_C
293 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
294 #endif /* MBEDTLS_ERROR_C */
295 failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
296 data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
298 return CURLE_SSL_CRL_BADFILE;
302 infof(data, "mbedTLS: Connecting to %s:%d\n",
303 conn->host.name, conn->remote_port);
305 mbedtls_ssl_config_init(&connssl->config);
307 mbedtls_ssl_init(&connssl->ssl);
308 if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) {
309 failf(data, "mbedTLS: ssl_init failed");
310 return CURLE_SSL_CONNECT_ERROR;
312 ret = mbedtls_ssl_config_defaults(&connssl->config,
313 MBEDTLS_SSL_IS_CLIENT,
314 MBEDTLS_SSL_TRANSPORT_STREAM,
315 MBEDTLS_SSL_PRESET_DEFAULT);
316 if(ret) {
317 failf(data, "mbedTLS: ssl_config failed");
318 return CURLE_SSL_CONNECT_ERROR;
321 /* new profile with RSA min key len = 1024 ... */
322 mbedtls_ssl_conf_cert_profile(&connssl->config,
323 &mbedtls_x509_crt_profile_fr);
325 switch(data->set.ssl.version) {
326 case CURL_SSLVERSION_DEFAULT:
327 case CURL_SSLVERSION_TLSv1:
328 mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
329 MBEDTLS_SSL_MINOR_VERSION_1);
330 infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
331 break;
332 case CURL_SSLVERSION_SSLv3:
333 mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
334 MBEDTLS_SSL_MINOR_VERSION_0);
335 mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
336 MBEDTLS_SSL_MINOR_VERSION_0);
337 infof(data, "mbedTLS: Set SSL version to SSLv3\n");
338 break;
339 case CURL_SSLVERSION_TLSv1_0:
340 mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
341 MBEDTLS_SSL_MINOR_VERSION_1);
342 mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
343 MBEDTLS_SSL_MINOR_VERSION_1);
344 infof(data, "mbedTLS: Set SSL version to TLS 1.0\n");
345 break;
346 case CURL_SSLVERSION_TLSv1_1:
347 mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
348 MBEDTLS_SSL_MINOR_VERSION_2);
349 mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
350 MBEDTLS_SSL_MINOR_VERSION_2);
351 infof(data, "mbedTLS: Set SSL version to TLS 1.1\n");
352 break;
353 case CURL_SSLVERSION_TLSv1_2:
354 mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
355 MBEDTLS_SSL_MINOR_VERSION_3);
356 mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
357 MBEDTLS_SSL_MINOR_VERSION_3);
358 infof(data, "mbedTLS: Set SSL version to TLS 1.2\n");
359 break;
360 default:
361 failf(data, "mbedTLS: Unsupported SSL protocol version");
362 return CURLE_SSL_CONNECT_ERROR;
365 mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
367 mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random,
368 &connssl->ctr_drbg);
369 mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex],
370 mbedtls_net_send,
371 mbedtls_net_recv,
372 NULL /* rev_timeout() */);
374 mbedtls_ssl_conf_ciphersuites(&connssl->config,
375 mbedtls_ssl_list_ciphersuites());
376 if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
377 ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
378 if(ret) {
379 failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
380 return CURLE_SSL_CONNECT_ERROR;
382 infof(data, "mbedTLS re-using session\n");
385 mbedtls_ssl_conf_ca_chain(&connssl->config,
386 &connssl->cacert,
387 &connssl->crl);
389 if(data->set.str[STRING_KEY]) {
390 mbedtls_ssl_conf_own_cert(&connssl->config,
391 &connssl->clicert, &connssl->pk);
393 if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) {
394 /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
395 the name to set in the SNI extension. So even if curl connects to a
396 host specified as an IP address, this function must be used. */
397 failf(data, "couldn't set hostname in mbedTLS");
398 return CURLE_SSL_CONNECT_ERROR;
401 #ifdef HAS_ALPN
402 if(conn->bits.tls_enable_alpn) {
403 const char **p = &connssl->protocols[0];
404 #ifdef USE_NGHTTP2
405 if(data->set.httpversion >= CURL_HTTP_VERSION_2)
406 *p++ = NGHTTP2_PROTO_VERSION_ID;
407 #endif
408 *p++ = ALPN_HTTP_1_1;
409 *p = NULL;
410 /* this function doesn't clone the protocols array, which is why we need
411 to keep it around */
412 if(mbedtls_ssl_conf_alpn_protocols(&connssl->config,
413 &connssl->protocols[0])) {
414 failf(data, "Failed setting ALPN protocols");
415 return CURLE_SSL_CONNECT_ERROR;
417 for(p = &connssl->protocols[0]; *p; ++p)
418 infof(data, "ALPN, offering %s\n", *p);
420 #endif
422 #ifdef MBEDTLS_DEBUG
423 mbedtls_ssl_conf_dbg(&connssl->config, mbedtls_debug, data);
424 #endif
426 connssl->connecting_state = ssl_connect_2;
428 return CURLE_OK;
431 static CURLcode
432 mbed_connect_step2(struct connectdata *conn,
433 int sockindex)
435 int ret;
436 struct SessionHandle *data = conn->data;
437 struct ssl_connect_data* connssl = &conn->ssl[sockindex];
438 const mbedtls_x509_crt *peercert;
440 #ifdef HAS_ALPN
441 const char* next_protocol;
442 #endif
444 char errorbuf[128];
445 errorbuf[0] = 0;
447 conn->recv[sockindex] = mbed_recv;
448 conn->send[sockindex] = mbed_send;
450 ret = mbedtls_ssl_handshake(&connssl->ssl);
452 if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
453 connssl->connecting_state = ssl_connect_2_reading;
454 return CURLE_OK;
456 else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
457 connssl->connecting_state = ssl_connect_2_writing;
458 return CURLE_OK;
460 else if(ret) {
461 #ifdef MBEDTLS_ERROR_C
462 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
463 #endif /* MBEDTLS_ERROR_C */
464 failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
465 -ret, errorbuf);
466 return CURLE_SSL_CONNECT_ERROR;
469 infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
470 mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
473 ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
475 if(ret && data->set.ssl.verifypeer) {
476 if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
477 failf(data, "Cert verify failed: BADCERT_EXPIRED");
479 if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
480 failf(data, "Cert verify failed: BADCERT_REVOKED");
481 return CURLE_SSL_CACERT;
484 if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
485 failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
487 if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
488 failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
490 return CURLE_PEER_FAILED_VERIFICATION;
493 peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl);
495 if(peercert && data->set.verbose) {
496 const size_t bufsize = 16384;
497 char *buffer = malloc(bufsize);
499 if(!buffer)
500 return CURLE_OUT_OF_MEMORY;
502 if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
503 infof(data, "Dumping cert info:\n%s\n", buffer);
504 else
505 infof(data, "Unable to dump certificate information.\n");
507 free(buffer);
510 if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
511 int size;
512 CURLcode result;
513 mbedtls_x509_crt *p;
514 unsigned char pubkey[PUB_DER_MAX_BYTES];
516 if(!peercert || !peercert->raw.p || !peercert->raw.len) {
517 failf(data, "Failed due to missing peer certificate");
518 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
521 p = calloc(1, sizeof(*p));
523 if(!p)
524 return CURLE_OUT_OF_MEMORY;
526 mbedtls_x509_crt_init(p);
528 /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
529 needs a non-const key, for now.
530 https://github.com/ARMmbed/mbedtls/issues/396 */
531 if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
532 failf(data, "Failed copying peer certificate");
533 mbedtls_x509_crt_free(p);
534 free(p);
535 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
538 size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
540 if(size <= 0) {
541 failf(data, "Failed copying public key from peer certificate");
542 mbedtls_x509_crt_free(p);
543 free(p);
544 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
547 /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
548 result = Curl_pin_peer_pubkey(data,
549 data->set.str[STRING_SSL_PINNEDPUBLICKEY],
550 &pubkey[PUB_DER_MAX_BYTES - size], size);
551 if(result) {
552 mbedtls_x509_crt_free(p);
553 free(p);
554 return result;
557 mbedtls_x509_crt_free(p);
558 free(p);
561 #ifdef HAS_ALPN
562 if(conn->bits.tls_enable_alpn) {
563 next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl);
565 if(next_protocol) {
566 infof(data, "ALPN, server accepted to use %s\n", next_protocol);
567 #ifdef USE_NGHTTP2
568 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
569 NGHTTP2_PROTO_VERSION_ID_LEN) &&
570 !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) {
571 conn->negnpn = CURL_HTTP_VERSION_2;
573 else
574 #endif
575 if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
576 !next_protocol[ALPN_HTTP_1_1_LENGTH]) {
577 conn->negnpn = CURL_HTTP_VERSION_1_1;
580 else {
581 infof(data, "ALPN, server did not agree to a protocol\n");
584 #endif
586 connssl->connecting_state = ssl_connect_3;
587 infof(data, "SSL connected\n");
589 return CURLE_OK;
592 static CURLcode
593 mbed_connect_step3(struct connectdata *conn,
594 int sockindex)
596 CURLcode retcode = CURLE_OK;
597 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
598 struct SessionHandle *data = conn->data;
599 void *old_ssl_sessionid = NULL;
600 mbedtls_ssl_session *our_ssl_sessionid;
601 int ret;
603 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
605 our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
606 if(!our_ssl_sessionid)
607 return CURLE_OUT_OF_MEMORY;
609 mbedtls_ssl_session_init(our_ssl_sessionid);
611 ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid);
612 if(ret) {
613 failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
614 return CURLE_SSL_CONNECT_ERROR;
617 /* If there's already a matching session in the cache, delete it */
618 if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
619 Curl_ssl_delsessionid(conn, old_ssl_sessionid);
621 retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
622 if(retcode) {
623 free(our_ssl_sessionid);
624 failf(data, "failed to store ssl session");
625 return retcode;
628 connssl->connecting_state = ssl_connect_done;
630 return CURLE_OK;
633 static ssize_t mbed_send(struct connectdata *conn, int sockindex,
634 const void *mem, size_t len,
635 CURLcode *curlcode)
637 int ret = -1;
639 ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl,
640 (unsigned char *)mem, len);
642 if(ret < 0) {
643 *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
644 CURLE_AGAIN : CURLE_SEND_ERROR;
645 ret = -1;
648 return ret;
651 void Curl_mbedtls_close_all(struct SessionHandle *data)
653 (void)data;
656 void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
658 mbedtls_pk_free(&conn->ssl[sockindex].pk);
659 mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert);
660 mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert);
661 mbedtls_x509_crl_free(&conn->ssl[sockindex].crl);
662 mbedtls_ssl_config_free(&conn->ssl[sockindex].config);
663 mbedtls_ssl_free(&conn->ssl[sockindex].ssl);
664 mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg);
665 #ifndef THREADING_SUPPORT
666 mbedtls_entropy_free(&conn->ssl[sockindex].entropy);
667 #endif /* THREADING_SUPPORT */
670 static ssize_t mbed_recv(struct connectdata *conn, int num,
671 char *buf, size_t buffersize,
672 CURLcode *curlcode)
674 int ret = -1;
675 ssize_t len = -1;
677 memset(buf, 0, buffersize);
678 ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf,
679 buffersize);
681 if(ret <= 0) {
682 if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
683 return 0;
685 *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
686 CURLE_AGAIN : CURLE_RECV_ERROR;
687 return -1;
690 len = ret;
692 return len;
695 void Curl_mbedtls_session_free(void *ptr)
697 mbedtls_ssl_session_free(ptr);
698 free(ptr);
701 size_t Curl_mbedtls_version(char *buffer, size_t size)
703 unsigned int version = mbedtls_version_get_number();
704 return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
705 (version>>16)&0xff, (version>>8)&0xff);
708 static CURLcode
709 mbed_connect_common(struct connectdata *conn,
710 int sockindex,
711 bool nonblocking,
712 bool *done)
714 CURLcode retcode;
715 struct SessionHandle *data = conn->data;
716 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
717 curl_socket_t sockfd = conn->sock[sockindex];
718 long timeout_ms;
719 int what;
721 /* check if the connection has already been established */
722 if(ssl_connection_complete == connssl->state) {
723 *done = TRUE;
724 return CURLE_OK;
727 if(ssl_connect_1==connssl->connecting_state) {
728 /* Find out how much more time we're allowed */
729 timeout_ms = Curl_timeleft(data, NULL, TRUE);
731 if(timeout_ms < 0) {
732 /* no need to continue if time already is up */
733 failf(data, "SSL connection timeout");
734 return CURLE_OPERATION_TIMEDOUT;
736 retcode = mbed_connect_step1(conn, sockindex);
737 if(retcode)
738 return retcode;
741 while(ssl_connect_2 == connssl->connecting_state ||
742 ssl_connect_2_reading == connssl->connecting_state ||
743 ssl_connect_2_writing == connssl->connecting_state) {
745 /* check allowed time left */
746 timeout_ms = Curl_timeleft(data, NULL, TRUE);
748 if(timeout_ms < 0) {
749 /* no need to continue if time already is up */
750 failf(data, "SSL connection timeout");
751 return CURLE_OPERATION_TIMEDOUT;
754 /* if ssl is expecting something, check if it's available. */
755 if(connssl->connecting_state == ssl_connect_2_reading
756 || connssl->connecting_state == ssl_connect_2_writing) {
758 curl_socket_t writefd = ssl_connect_2_writing==
759 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
760 curl_socket_t readfd = ssl_connect_2_reading==
761 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
763 what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
764 if(what < 0) {
765 /* fatal error */
766 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
767 return CURLE_SSL_CONNECT_ERROR;
769 else if(0 == what) {
770 if(nonblocking) {
771 *done = FALSE;
772 return CURLE_OK;
774 else {
775 /* timeout */
776 failf(data, "SSL connection timeout");
777 return CURLE_OPERATION_TIMEDOUT;
780 /* socket is readable or writable */
783 /* Run transaction, and return to the caller if it failed or if
784 * this connection is part of a multi handle and this loop would
785 * execute again. This permits the owner of a multi handle to
786 * abort a connection attempt before step2 has completed while
787 * ensuring that a client using select() or epoll() will always
788 * have a valid fdset to wait on.
790 retcode = mbed_connect_step2(conn, sockindex);
791 if(retcode || (nonblocking &&
792 (ssl_connect_2 == connssl->connecting_state ||
793 ssl_connect_2_reading == connssl->connecting_state ||
794 ssl_connect_2_writing == connssl->connecting_state)))
795 return retcode;
797 } /* repeat step2 until all transactions are done. */
799 if(ssl_connect_3==connssl->connecting_state) {
800 retcode = mbed_connect_step3(conn, sockindex);
801 if(retcode)
802 return retcode;
805 if(ssl_connect_done==connssl->connecting_state) {
806 connssl->state = ssl_connection_complete;
807 conn->recv[sockindex] = mbed_recv;
808 conn->send[sockindex] = mbed_send;
809 *done = TRUE;
811 else
812 *done = FALSE;
814 /* Reset our connect state machine */
815 connssl->connecting_state = ssl_connect_1;
817 return CURLE_OK;
820 CURLcode
821 Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
822 int sockindex,
823 bool *done)
825 return mbed_connect_common(conn, sockindex, TRUE, done);
829 CURLcode
830 Curl_mbedtls_connect(struct connectdata *conn,
831 int sockindex)
833 CURLcode retcode;
834 bool done = FALSE;
836 retcode = mbed_connect_common(conn, sockindex, FALSE, &done);
837 if(retcode)
838 return retcode;
840 DEBUGASSERT(done);
842 return CURLE_OK;
846 * return 0 error initializing SSL
847 * return 1 SSL initialized successfully
849 int Curl_mbedtls_init(void)
851 return Curl_polarsslthreadlock_thread_setup();
854 void Curl_mbedtls_cleanup(void)
856 (void)Curl_polarsslthreadlock_thread_cleanup();
859 int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex)
861 mbedtls_ssl_context *ssl =
862 (mbedtls_ssl_context *)&conn->ssl[sockindex].ssl;
863 return ssl->in_msglen != 0;
866 #endif /* USE_MBEDTLS */