Imported Upstream version 7.59.0
[platform/upstream/curl.git] / lib / vtls / polarssl.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
9  * Copyright (C) 2010 - 2011, 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.haxx.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  ***************************************************************************/
23
24 /*
25  * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code
26  * but vtls.c should ever call or use these functions.
27  *
28  */
29
30 #include "curl_setup.h"
31
32 #ifdef USE_POLARSSL
33 #include <polarssl/net.h>
34 #include <polarssl/ssl.h>
35 #include <polarssl/certs.h>
36 #include <polarssl/x509.h>
37 #include <polarssl/version.h>
38 #include <polarssl/sha256.h>
39
40 #if POLARSSL_VERSION_NUMBER < 0x01030000
41 #error too old PolarSSL
42 #endif
43
44 #include <polarssl/error.h>
45 #include <polarssl/entropy.h>
46 #include <polarssl/ctr_drbg.h>
47
48 #include "urldata.h"
49 #include "sendf.h"
50 #include "inet_pton.h"
51 #include "polarssl.h"
52 #include "vtls.h"
53 #include "parsedate.h"
54 #include "connect.h" /* for the connect timeout */
55 #include "select.h"
56 #include "strcase.h"
57 #include "polarssl_threadlock.h"
58 #include "curl_printf.h"
59 #include "curl_memory.h"
60 /* The last #include file should be: */
61 #include "memdebug.h"
62
63 /* See https://tls.mbed.org/discussions/generic/
64    howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
65 */
66 #define RSA_PUB_DER_MAX_BYTES   (38 + 2 * POLARSSL_MPI_MAX_SIZE)
67 #define ECP_PUB_DER_MAX_BYTES   (30 + 2 * POLARSSL_ECP_MAX_BYTES)
68
69 #define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
70                              RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
71
72 struct ssl_backend_data {
73   ctr_drbg_context ctr_drbg;
74   entropy_context entropy;
75   ssl_context ssl;
76   int server_fd;
77   x509_crt cacert;
78   x509_crt clicert;
79   x509_crl crl;
80   rsa_context rsa;
81 };
82
83 #define BACKEND connssl->backend
84
85 /* apply threading? */
86 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
87 #define THREADING_SUPPORT
88 #endif
89
90 #ifndef POLARSSL_ERROR_C
91 #define error_strerror(x,y,z)
92 #endif /* POLARSSL_ERROR_C */
93
94
95 #if defined(THREADING_SUPPORT)
96 static entropy_context entropy;
97
98 static int  entropy_init_initialized  = 0;
99
100 /* start of entropy_init_mutex() */
101 static void entropy_init_mutex(entropy_context *ctx)
102 {
103   /* lock 0 = entropy_init_mutex() */
104   Curl_polarsslthreadlock_lock_function(0);
105   if(entropy_init_initialized == 0) {
106     entropy_init(ctx);
107     entropy_init_initialized = 1;
108   }
109   Curl_polarsslthreadlock_unlock_function(0);
110 }
111 /* end of entropy_init_mutex() */
112
113 /* start of entropy_func_mutex() */
114 static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
115 {
116   int ret;
117   /* lock 1 = entropy_func_mutex() */
118   Curl_polarsslthreadlock_lock_function(1);
119   ret = entropy_func(data, output, len);
120   Curl_polarsslthreadlock_unlock_function(1);
121
122   return ret;
123 }
124 /* end of entropy_func_mutex() */
125
126 #endif /* THREADING_SUPPORT */
127
128 /* Define this to enable lots of debugging for PolarSSL */
129 #undef POLARSSL_DEBUG
130
131 #ifdef POLARSSL_DEBUG
132 static void polarssl_debug(void *context, int level, const char *line)
133 {
134   struct Curl_easy *data = NULL;
135
136   if(!context)
137     return;
138
139   data = (struct Curl_easy *)context;
140
141   infof(data, "%s", line);
142   (void) level;
143 }
144 #else
145 #endif
146
147 /* ALPN for http2? */
148 #ifdef POLARSSL_SSL_ALPN
149 #  define HAS_ALPN
150 #endif
151
152 static Curl_recv polarssl_recv;
153 static Curl_send polarssl_send;
154
155 static CURLcode polarssl_version_from_curl(int *polarver, long ssl_version)
156 {
157   switch(ssl_version) {
158     case CURL_SSLVERSION_TLSv1_0:
159       *polarver = SSL_MINOR_VERSION_1;
160       return CURLE_OK;
161     case CURL_SSLVERSION_TLSv1_1:
162       *polarver = SSL_MINOR_VERSION_2;
163       return CURLE_OK;
164     case CURL_SSLVERSION_TLSv1_2:
165       *polarver = SSL_MINOR_VERSION_3;
166       return CURLE_OK;
167     case CURL_SSLVERSION_TLSv1_3:
168       break;
169   }
170   return CURLE_SSL_CONNECT_ERROR;
171 }
172
173 static CURLcode
174 set_ssl_version_min_max(struct connectdata *conn, int sockindex)
175 {
176   struct Curl_easy *data = conn->data;
177   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
178   long ssl_version = SSL_CONN_CONFIG(version);
179   long ssl_version_max = SSL_CONN_CONFIG(version_max);
180   int ssl_min_ver = SSL_MINOR_VERSION_1;
181   int ssl_max_ver = SSL_MINOR_VERSION_1;
182   CURLcode result = CURLE_OK;
183
184   switch(ssl_version) {
185     case CURL_SSLVERSION_DEFAULT:
186     case CURL_SSLVERSION_TLSv1:
187       ssl_version = CURL_SSLVERSION_TLSv1_0;
188       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
189       break;
190   }
191
192   switch(ssl_version_max) {
193     case CURL_SSLVERSION_MAX_NONE:
194       ssl_version_max = ssl_version << 16;
195       break;
196     case CURL_SSLVERSION_MAX_DEFAULT:
197       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
198       break;
199   }
200
201   result = polarssl_version_from_curl(&ssl_min_ver, ssl_version);
202   if(result) {
203     failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
204     return result;
205   }
206   result = polarssl_version_from_curl(&ssl_max_ver, ssl_version_max >> 16);
207   if(result) {
208     failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
209     return result;
210   }
211
212   ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver);
213   ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver);
214
215   return result;
216 }
217
218 static CURLcode
219 polarssl_connect_step1(struct connectdata *conn,
220                        int sockindex)
221 {
222   struct Curl_easy *data = conn->data;
223   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
224   const char *capath = SSL_CONN_CONFIG(CApath);
225   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
226     conn->host.name;
227   const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
228   int ret = -1;
229   char errorbuf[128];
230   errorbuf[0] = 0;
231
232   /* PolarSSL only supports SSLv3 and TLSv1 */
233   if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
234     failf(data, "PolarSSL does not support SSLv2");
235     return CURLE_SSL_CONNECT_ERROR;
236   }
237
238 #ifdef THREADING_SUPPORT
239   entropy_init_mutex(&entropy);
240
241   if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func_mutex, &entropy,
242                           NULL, 0)) != 0) {
243     error_strerror(ret, errorbuf, sizeof(errorbuf));
244     failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
245           -ret, errorbuf);
246   }
247 #else
248   entropy_init(&BACKEND->entropy);
249
250   if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func, &BACKEND->entropy,
251                           NULL, 0)) != 0) {
252     error_strerror(ret, errorbuf, sizeof(errorbuf));
253     failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
254           -ret, errorbuf);
255   }
256 #endif /* THREADING_SUPPORT */
257
258   /* Load the trusted CA */
259   memset(&BACKEND->cacert, 0, sizeof(x509_crt));
260
261   if(SSL_CONN_CONFIG(CAfile)) {
262     ret = x509_crt_parse_file(&BACKEND->cacert,
263                               SSL_CONN_CONFIG(CAfile));
264
265     if(ret<0) {
266       error_strerror(ret, errorbuf, sizeof(errorbuf));
267       failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s",
268             SSL_CONN_CONFIG(CAfile), -ret, errorbuf);
269
270       if(SSL_CONN_CONFIG(verifypeer))
271         return CURLE_SSL_CACERT_BADFILE;
272     }
273   }
274
275   if(capath) {
276     ret = x509_crt_parse_path(&BACKEND->cacert, capath);
277
278     if(ret<0) {
279       error_strerror(ret, errorbuf, sizeof(errorbuf));
280       failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s",
281             capath, -ret, errorbuf);
282
283       if(SSL_CONN_CONFIG(verifypeer))
284         return CURLE_SSL_CACERT_BADFILE;
285     }
286   }
287
288   /* Load the client certificate */
289   memset(&BACKEND->clicert, 0, sizeof(x509_crt));
290
291   if(SSL_SET_OPTION(cert)) {
292     ret = x509_crt_parse_file(&BACKEND->clicert,
293                               SSL_SET_OPTION(cert));
294
295     if(ret) {
296       error_strerror(ret, errorbuf, sizeof(errorbuf));
297       failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s",
298             SSL_SET_OPTION(cert), -ret, errorbuf);
299
300       return CURLE_SSL_CERTPROBLEM;
301     }
302   }
303
304   /* Load the client private key */
305   if(SSL_SET_OPTION(key)) {
306     pk_context pk;
307     pk_init(&pk);
308     ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key),
309                            SSL_SET_OPTION(key_passwd));
310     if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA))
311       ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
312     if(ret == 0)
313       rsa_copy(&BACKEND->rsa, pk_rsa(pk));
314     else
315       rsa_free(&BACKEND->rsa);
316     pk_free(&pk);
317
318     if(ret) {
319       error_strerror(ret, errorbuf, sizeof(errorbuf));
320       failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s",
321             SSL_SET_OPTION(key), -ret, errorbuf);
322
323       return CURLE_SSL_CERTPROBLEM;
324     }
325   }
326
327   /* Load the CRL */
328   memset(&BACKEND->crl, 0, sizeof(x509_crl));
329
330   if(SSL_SET_OPTION(CRLfile)) {
331     ret = x509_crl_parse_file(&BACKEND->crl,
332                               SSL_SET_OPTION(CRLfile));
333
334     if(ret) {
335       error_strerror(ret, errorbuf, sizeof(errorbuf));
336       failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s",
337             SSL_SET_OPTION(CRLfile), -ret, errorbuf);
338
339       return CURLE_SSL_CRL_BADFILE;
340     }
341   }
342
343   infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port);
344
345   if(ssl_init(&BACKEND->ssl)) {
346     failf(data, "PolarSSL: ssl_init failed");
347     return CURLE_SSL_CONNECT_ERROR;
348   }
349
350   switch(SSL_CONN_CONFIG(version)) {
351   case CURL_SSLVERSION_DEFAULT:
352   case CURL_SSLVERSION_TLSv1:
353     ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3,
354                         SSL_MINOR_VERSION_1);
355     break;
356   case CURL_SSLVERSION_SSLv3:
357     ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3,
358                         SSL_MINOR_VERSION_0);
359     ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3,
360                         SSL_MINOR_VERSION_0);
361     infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n");
362     break;
363   case CURL_SSLVERSION_TLSv1_0:
364   case CURL_SSLVERSION_TLSv1_1:
365   case CURL_SSLVERSION_TLSv1_2:
366   case CURL_SSLVERSION_TLSv1_3:
367     {
368       CURLcode result = set_ssl_version_min_max(conn, sockindex);
369       if(result != CURLE_OK)
370         return result;
371       break;
372     }
373   default:
374     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
375     return CURLE_SSL_CONNECT_ERROR;
376   }
377
378   ssl_set_endpoint(&BACKEND->ssl, SSL_IS_CLIENT);
379   ssl_set_authmode(&BACKEND->ssl, SSL_VERIFY_OPTIONAL);
380
381   ssl_set_rng(&BACKEND->ssl, ctr_drbg_random,
382               &BACKEND->ctr_drbg);
383   ssl_set_bio(&BACKEND->ssl,
384               net_recv, &conn->sock[sockindex],
385               net_send, &conn->sock[sockindex]);
386
387   ssl_set_ciphersuites(&BACKEND->ssl, ssl_list_ciphersuites());
388
389   /* Check if there's a cached ID we can/should use here! */
390   if(SSL_SET_OPTION(primary.sessionid)) {
391     void *old_session = NULL;
392
393     Curl_ssl_sessionid_lock(conn);
394     if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
395       ret = ssl_set_session(&BACKEND->ssl, old_session);
396       if(ret) {
397         Curl_ssl_sessionid_unlock(conn);
398         failf(data, "ssl_set_session returned -0x%x", -ret);
399         return CURLE_SSL_CONNECT_ERROR;
400       }
401       infof(data, "PolarSSL re-using session\n");
402     }
403     Curl_ssl_sessionid_unlock(conn);
404   }
405
406   ssl_set_ca_chain(&BACKEND->ssl,
407                    &BACKEND->cacert,
408                    &BACKEND->crl,
409                    hostname);
410
411   ssl_set_own_cert_rsa(&BACKEND->ssl,
412                        &BACKEND->clicert, &BACKEND->rsa);
413
414   if(ssl_set_hostname(&BACKEND->ssl, hostname)) {
415     /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name
416        to set in the SNI extension. So even if curl connects to a host
417        specified as an IP address, this function must be used. */
418     failf(data, "couldn't set hostname in PolarSSL");
419     return CURLE_SSL_CONNECT_ERROR;
420   }
421
422 #ifdef HAS_ALPN
423   if(conn->bits.tls_enable_alpn) {
424     static const char *protocols[3];
425     int cur = 0;
426
427 #ifdef USE_NGHTTP2
428     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
429       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
430       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
431     }
432 #endif
433
434     protocols[cur++] = ALPN_HTTP_1_1;
435     infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
436
437     protocols[cur] = NULL;
438
439     ssl_set_alpn_protocols(&BACKEND->ssl, protocols);
440   }
441 #endif
442
443 #ifdef POLARSSL_DEBUG
444   ssl_set_dbg(&BACKEND->ssl, polarssl_debug, data);
445 #endif
446
447   connssl->connecting_state = ssl_connect_2;
448
449   return CURLE_OK;
450 }
451
452 static CURLcode
453 polarssl_connect_step2(struct connectdata *conn,
454                        int sockindex)
455 {
456   int ret;
457   struct Curl_easy *data = conn->data;
458   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
459   char buffer[1024];
460   const char * const pinnedpubkey = SSL_IS_PROXY() ?
461             data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
462             data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
463
464
465   char errorbuf[128];
466   errorbuf[0] = 0;
467
468   conn->recv[sockindex] = polarssl_recv;
469   conn->send[sockindex] = polarssl_send;
470
471   ret = ssl_handshake(&BACKEND->ssl);
472
473   switch(ret) {
474   case 0:
475     break;
476
477   case POLARSSL_ERR_NET_WANT_READ:
478     connssl->connecting_state = ssl_connect_2_reading;
479     return CURLE_OK;
480
481   case POLARSSL_ERR_NET_WANT_WRITE:
482     connssl->connecting_state = ssl_connect_2_writing;
483     return CURLE_OK;
484
485   default:
486     error_strerror(ret, errorbuf, sizeof(errorbuf));
487     failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s",
488           -ret, errorbuf);
489     return CURLE_SSL_CONNECT_ERROR;
490   }
491
492   infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
493         ssl_get_ciphersuite(&BACKEND->ssl) );
494
495   ret = ssl_get_verify_result(&BACKEND->ssl);
496
497   if(ret && SSL_CONN_CONFIG(verifypeer)) {
498     if(ret & BADCERT_EXPIRED)
499       failf(data, "Cert verify failed: BADCERT_EXPIRED");
500
501     if(ret & BADCERT_REVOKED) {
502       failf(data, "Cert verify failed: BADCERT_REVOKED");
503       return CURLE_SSL_CACERT;
504     }
505
506     if(ret & BADCERT_CN_MISMATCH)
507       failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
508
509     if(ret & BADCERT_NOT_TRUSTED)
510       failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
511
512     return CURLE_PEER_FAILED_VERIFICATION;
513   }
514
515   if(ssl_get_peer_cert(&(BACKEND->ssl))) {
516     /* If the session was resumed, there will be no peer certs */
517     memset(buffer, 0, sizeof(buffer));
518
519     if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ",
520                      ssl_get_peer_cert(&(BACKEND->ssl))) != -1)
521       infof(data, "Dumping cert info:\n%s\n", buffer);
522   }
523
524   /* adapted from mbedtls.c */
525   if(pinnedpubkey) {
526     int size;
527     CURLcode result;
528     x509_crt *p;
529     unsigned char pubkey[PUB_DER_MAX_BYTES];
530     const x509_crt *peercert;
531
532     peercert = ssl_get_peer_cert(&BACKEND->ssl);
533
534     if(!peercert || !peercert->raw.p || !peercert->raw.len) {
535       failf(data, "Failed due to missing peer certificate");
536       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
537     }
538
539     p = calloc(1, sizeof(*p));
540
541     if(!p)
542       return CURLE_OUT_OF_MEMORY;
543
544     x509_crt_init(p);
545
546     /* Make a copy of our const peercert because pk_write_pubkey_der
547        needs a non-const key, for now.
548        https://github.com/ARMmbed/mbedtls/issues/396 */
549     if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
550       failf(data, "Failed copying peer certificate");
551       x509_crt_free(p);
552       free(p);
553       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
554     }
555
556     size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
557
558     if(size <= 0) {
559       failf(data, "Failed copying public key from peer certificate");
560       x509_crt_free(p);
561       free(p);
562       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
563     }
564
565     /* pk_write_pubkey_der writes data at the end of the buffer. */
566     result = Curl_pin_peer_pubkey(data,
567                                   pinnedpubkey,
568                                   &pubkey[PUB_DER_MAX_BYTES - size], size);
569     if(result) {
570       x509_crt_free(p);
571       free(p);
572       return result;
573     }
574
575     x509_crt_free(p);
576     free(p);
577   }
578
579 #ifdef HAS_ALPN
580   if(conn->bits.tls_enable_alpn) {
581     const char *next_protocol = ssl_get_alpn_protocol(&BACKEND->ssl);
582
583     if(next_protocol != NULL) {
584       infof(data, "ALPN, server accepted to use %s\n", next_protocol);
585
586 #ifdef USE_NGHTTP2
587       if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
588                   NGHTTP2_PROTO_VERSION_ID_LEN)) {
589         conn->negnpn = CURL_HTTP_VERSION_2;
590       }
591       else
592 #endif
593         if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) {
594           conn->negnpn = CURL_HTTP_VERSION_1_1;
595         }
596     }
597     else
598       infof(data, "ALPN, server did not agree to a protocol\n");
599   }
600 #endif
601
602   connssl->connecting_state = ssl_connect_3;
603   infof(data, "SSL connected\n");
604
605   return CURLE_OK;
606 }
607
608 static CURLcode
609 polarssl_connect_step3(struct connectdata *conn,
610                        int sockindex)
611 {
612   CURLcode retcode = CURLE_OK;
613   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
614   struct Curl_easy *data = conn->data;
615
616   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
617
618   if(SSL_SET_OPTION(primary.sessionid)) {
619     int ret;
620     ssl_session *our_ssl_sessionid;
621     void *old_ssl_sessionid = NULL;
622
623     our_ssl_sessionid = malloc(sizeof(ssl_session));
624     if(!our_ssl_sessionid)
625       return CURLE_OUT_OF_MEMORY;
626
627     memset(our_ssl_sessionid, 0, sizeof(ssl_session));
628
629     ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
630     if(ret) {
631       failf(data, "ssl_get_session returned -0x%x", -ret);
632       return CURLE_SSL_CONNECT_ERROR;
633     }
634
635     /* If there's already a matching session in the cache, delete it */
636     Curl_ssl_sessionid_lock(conn);
637     if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
638       Curl_ssl_delsessionid(conn, old_ssl_sessionid);
639
640     retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
641     Curl_ssl_sessionid_unlock(conn);
642     if(retcode) {
643       free(our_ssl_sessionid);
644       failf(data, "failed to store ssl session");
645       return retcode;
646     }
647   }
648
649   connssl->connecting_state = ssl_connect_done;
650
651   return CURLE_OK;
652 }
653
654 static ssize_t polarssl_send(struct connectdata *conn,
655                              int sockindex,
656                              const void *mem,
657                              size_t len,
658                              CURLcode *curlcode)
659 {
660   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
661   int ret = -1;
662
663   ret = ssl_write(&BACKEND->ssl,
664                   (unsigned char *)mem, len);
665
666   if(ret < 0) {
667     *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ?
668       CURLE_AGAIN : CURLE_SEND_ERROR;
669     ret = -1;
670   }
671
672   return ret;
673 }
674
675 static void Curl_polarssl_close(struct connectdata *conn, int sockindex)
676 {
677   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
678   rsa_free(&BACKEND->rsa);
679   x509_crt_free(&BACKEND->clicert);
680   x509_crt_free(&BACKEND->cacert);
681   x509_crl_free(&BACKEND->crl);
682   ssl_free(&BACKEND->ssl);
683 }
684
685 static ssize_t polarssl_recv(struct connectdata *conn,
686                              int num,
687                              char *buf,
688                              size_t buffersize,
689                              CURLcode *curlcode)
690 {
691   struct ssl_connect_data *connssl = &conn->ssl[num];
692   int ret = -1;
693   ssize_t len = -1;
694
695   memset(buf, 0, buffersize);
696   ret = ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize);
697
698   if(ret <= 0) {
699     if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
700       return 0;
701
702     *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ?
703       CURLE_AGAIN : CURLE_RECV_ERROR;
704     return -1;
705   }
706
707   len = ret;
708
709   return len;
710 }
711
712 static void Curl_polarssl_session_free(void *ptr)
713 {
714   ssl_session_free(ptr);
715   free(ptr);
716 }
717
718 /* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and
719    higher) will be mbed TLS branded.. */
720
721 static size_t Curl_polarssl_version(char *buffer, size_t size)
722 {
723   unsigned int version = version_get_number();
724   return snprintf(buffer, size, "%s/%d.%d.%d",
725                   version >= 0x01030A00?"mbedTLS":"PolarSSL",
726                   version>>24, (version>>16)&0xff, (version>>8)&0xff);
727 }
728
729 static CURLcode
730 polarssl_connect_common(struct connectdata *conn,
731                         int sockindex,
732                         bool nonblocking,
733                         bool *done)
734 {
735   CURLcode result;
736   struct Curl_easy *data = conn->data;
737   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
738   curl_socket_t sockfd = conn->sock[sockindex];
739   long timeout_ms;
740   int what;
741
742   /* check if the connection has already been established */
743   if(ssl_connection_complete == connssl->state) {
744     *done = TRUE;
745     return CURLE_OK;
746   }
747
748   if(ssl_connect_1 == connssl->connecting_state) {
749     /* Find out how much more time we're allowed */
750     timeout_ms = Curl_timeleft(data, NULL, TRUE);
751
752     if(timeout_ms < 0) {
753       /* no need to continue if time already is up */
754       failf(data, "SSL connection timeout");
755       return CURLE_OPERATION_TIMEDOUT;
756     }
757
758     result = polarssl_connect_step1(conn, sockindex);
759     if(result)
760       return result;
761   }
762
763   while(ssl_connect_2 == connssl->connecting_state ||
764         ssl_connect_2_reading == connssl->connecting_state ||
765         ssl_connect_2_writing == connssl->connecting_state) {
766
767     /* check allowed time left */
768     timeout_ms = Curl_timeleft(data, NULL, TRUE);
769
770     if(timeout_ms < 0) {
771       /* no need to continue if time already is up */
772       failf(data, "SSL connection timeout");
773       return CURLE_OPERATION_TIMEDOUT;
774     }
775
776     /* if ssl is expecting something, check if it's available. */
777     if(connssl->connecting_state == ssl_connect_2_reading ||
778        connssl->connecting_state == ssl_connect_2_writing) {
779
780       curl_socket_t writefd = ssl_connect_2_writing ==
781         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
782       curl_socket_t readfd = ssl_connect_2_reading ==
783         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
784
785       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
786                                nonblocking?0:timeout_ms);
787       if(what < 0) {
788         /* fatal error */
789         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
790         return CURLE_SSL_CONNECT_ERROR;
791       }
792       else if(0 == what) {
793         if(nonblocking) {
794           *done = FALSE;
795           return CURLE_OK;
796         }
797         else {
798           /* timeout */
799           failf(data, "SSL connection timeout");
800           return CURLE_OPERATION_TIMEDOUT;
801         }
802       }
803       /* socket is readable or writable */
804     }
805
806     /* Run transaction, and return to the caller if it failed or if
807      * this connection is part of a multi handle and this loop would
808      * execute again. This permits the owner of a multi handle to
809      * abort a connection attempt before step2 has completed while
810      * ensuring that a client using select() or epoll() will always
811      * have a valid fdset to wait on.
812      */
813     result = polarssl_connect_step2(conn, sockindex);
814     if(result || (nonblocking &&
815                   (ssl_connect_2 == connssl->connecting_state ||
816                    ssl_connect_2_reading == connssl->connecting_state ||
817                    ssl_connect_2_writing == connssl->connecting_state)))
818       return result;
819
820   } /* repeat step2 until all transactions are done. */
821
822   if(ssl_connect_3 == connssl->connecting_state) {
823     result = polarssl_connect_step3(conn, sockindex);
824     if(result)
825       return result;
826   }
827
828   if(ssl_connect_done == connssl->connecting_state) {
829     connssl->state = ssl_connection_complete;
830     conn->recv[sockindex] = polarssl_recv;
831     conn->send[sockindex] = polarssl_send;
832     *done = TRUE;
833   }
834   else
835     *done = FALSE;
836
837   /* Reset our connect state machine */
838   connssl->connecting_state = ssl_connect_1;
839
840   return CURLE_OK;
841 }
842
843 static CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
844                                                   int sockindex, bool *done)
845 {
846   return polarssl_connect_common(conn, sockindex, TRUE, done);
847 }
848
849
850 static CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex)
851 {
852   CURLcode result;
853   bool done = FALSE;
854
855   result = polarssl_connect_common(conn, sockindex, FALSE, &done);
856   if(result)
857     return result;
858
859   DEBUGASSERT(done);
860
861   return CURLE_OK;
862 }
863
864 /*
865  * return 0 error initializing SSL
866  * return 1 SSL initialized successfully
867  */
868 static int Curl_polarssl_init(void)
869 {
870   return Curl_polarsslthreadlock_thread_setup();
871 }
872
873 static void Curl_polarssl_cleanup(void)
874 {
875   (void)Curl_polarsslthreadlock_thread_cleanup();
876 }
877
878 static bool Curl_polarssl_data_pending(const struct connectdata *conn,
879                                        int sockindex)
880 {
881   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
882   return ssl_get_bytes_avail(&BACKEND->ssl) != 0;
883 }
884
885 static void Curl_polarssl_sha256sum(const unsigned char *input,
886                                     size_t inputlen,
887                                     unsigned char *sha256sum,
888                                     size_t sha256len UNUSED_PARAM)
889 {
890   (void)sha256len;
891   sha256(input, inputlen, sha256sum, 0);
892 }
893
894 static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl,
895                                          CURLINFO info UNUSED_PARAM)
896 {
897   (void)info;
898   return &BACKEND->ssl;
899 }
900
901 const struct Curl_ssl Curl_ssl_polarssl = {
902   { CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */
903
904   1, /* have_ca_path */
905   0, /* have_certinfo */
906   1, /* have_pinnedpubkey */
907   0, /* have_ssl_ctx */
908   0, /* support_https_proxy */
909
910   sizeof(struct ssl_backend_data),
911
912   Curl_polarssl_init,                /* init */
913   Curl_polarssl_cleanup,             /* cleanup */
914   Curl_polarssl_version,             /* version */
915   Curl_none_check_cxn,               /* check_cxn */
916   Curl_none_shutdown,                /* shutdown */
917   Curl_polarssl_data_pending,        /* data_pending */
918   /* This might cause libcurl to use a weeker random!
919    * TODO: use Polarssl's CTR-DRBG or HMAC-DRBG
920   */
921   Curl_none_random,                  /* random */
922   Curl_none_cert_status_request,     /* cert_status_request */
923   Curl_polarssl_connect,             /* connect */
924   Curl_polarssl_connect_nonblocking, /* connect_nonblocking */
925   Curl_polarssl_get_internals,       /* get_internals */
926   Curl_polarssl_close,               /* close_one */
927   Curl_none_close_all,               /* close_all */
928   Curl_polarssl_session_free,        /* session_free */
929   Curl_none_set_engine,              /* set_engine */
930   Curl_none_set_engine_default,      /* set_engine_default */
931   Curl_none_engines_list,            /* engines_list */
932   Curl_none_false_start,             /* false_start */
933   Curl_none_md5sum,                  /* md5sum */
934   Curl_polarssl_sha256sum            /* sha256sum */
935 };
936
937 #endif /* USE_POLARSSL */