Imported Upstream version 7.48.0
[platform/upstream/curl.git] / lib / vtls / cyassl.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 /*
24  * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code
25  * but vtls.c should ever call or use these functions.
26  *
27  */
28
29 #include "curl_setup.h"
30
31 #ifdef USE_CYASSL
32
33 #define WOLFSSL_OPTIONS_IGNORE_SYS
34 /* CyaSSL's version.h, which should contain only the version, should come
35 before all other CyaSSL includes and be immediately followed by build config
36 aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */
37 #include <cyassl/version.h>
38 #if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008)
39 #if defined(CYASSL_API) || defined(WOLFSSL_API)
40 /* Safety measure. If either is defined some API include was already included
41 and that's a problem since options.h hasn't been included yet. */
42 #error "CyaSSL API was included before the CyaSSL build options."
43 #endif
44 #include <cyassl/options.h>
45 #endif
46
47 #ifdef HAVE_LIMITS_H
48 #include <limits.h>
49 #endif
50
51 #include "urldata.h"
52 #include "sendf.h"
53 #include "inet_pton.h"
54 #include "cyassl.h"
55 #include "vtls.h"
56 #include "parsedate.h"
57 #include "connect.h" /* for the connect timeout */
58 #include "select.h"
59 #include "rawstr.h"
60 #include "x509asn1.h"
61 #include "curl_printf.h"
62
63 #include <cyassl/ssl.h>
64 #ifdef HAVE_CYASSL_ERROR_SSL_H
65 #include <cyassl/error-ssl.h>
66 #else
67 #include <cyassl/error.h>
68 #endif
69 #include <cyassl/ctaocrypt/random.h>
70 #include <cyassl/ctaocrypt/sha256.h>
71
72 /* The last #include files should be: */
73 #include "curl_memory.h"
74 #include "memdebug.h"
75
76 #if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */
77 #define CYASSL_MAX_ERROR_SZ 80
78 #endif
79
80 static Curl_recv cyassl_recv;
81 static Curl_send cyassl_send;
82
83
84 static int do_file_type(const char *type)
85 {
86   if(!type || !type[0])
87     return SSL_FILETYPE_PEM;
88   if(Curl_raw_equal(type, "PEM"))
89     return SSL_FILETYPE_PEM;
90   if(Curl_raw_equal(type, "DER"))
91     return SSL_FILETYPE_ASN1;
92   return -1;
93 }
94
95 /*
96  * This function loads all the client/CA certificates and CRLs. Setup the TLS
97  * layer and do all necessary magic.
98  */
99 static CURLcode
100 cyassl_connect_step1(struct connectdata *conn,
101                      int sockindex)
102 {
103   char error_buffer[CYASSL_MAX_ERROR_SZ];
104   struct SessionHandle *data = conn->data;
105   struct ssl_connect_data* conssl = &conn->ssl[sockindex];
106   SSL_METHOD* req_method = NULL;
107   void* ssl_sessionid = NULL;
108   curl_socket_t sockfd = conn->sock[sockindex];
109 #ifdef HAVE_SNI
110   bool sni = FALSE;
111 #define use_sni(x)  sni = (x)
112 #else
113 #define use_sni(x)  Curl_nop_stmt
114 #endif
115
116   if(conssl->state == ssl_connection_complete)
117     return CURLE_OK;
118
119   /* check to see if we've been told to use an explicit SSL/TLS version */
120   switch(data->set.ssl.version) {
121   case CURL_SSLVERSION_DEFAULT:
122   case CURL_SSLVERSION_TLSv1:
123 #if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
124     /* minimum protocol version is set later after the CTX object is created */
125     req_method = SSLv23_client_method();
126 #else
127     infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
128           "TLS 1.0 is used exclusively\n");
129     req_method = TLSv1_client_method();
130 #endif
131     use_sni(TRUE);
132     break;
133   case CURL_SSLVERSION_TLSv1_0:
134     req_method = TLSv1_client_method();
135     use_sni(TRUE);
136     break;
137   case CURL_SSLVERSION_TLSv1_1:
138     req_method = TLSv1_1_client_method();
139     use_sni(TRUE);
140     break;
141   case CURL_SSLVERSION_TLSv1_2:
142     req_method = TLSv1_2_client_method();
143     use_sni(TRUE);
144     break;
145   case CURL_SSLVERSION_SSLv3:
146     /* before WolfSSL SSLv3 was enabled by default, and starting in WolfSSL
147        we check for its presence since it is built without it by default */
148 #if !defined(WOLFSSL_VERSION) || defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
149     req_method = SSLv3_client_method();
150     use_sni(FALSE);
151 #else
152     failf(data, "No support for SSLv3");
153     return CURLE_NOT_BUILT_IN;
154 #endif
155     break;
156   case CURL_SSLVERSION_SSLv2:
157     failf(data, "CyaSSL does not support SSLv2");
158     return CURLE_SSL_CONNECT_ERROR;
159   default:
160     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
161     return CURLE_SSL_CONNECT_ERROR;
162   }
163
164   if(!req_method) {
165     failf(data, "SSL: couldn't create a method!");
166     return CURLE_OUT_OF_MEMORY;
167   }
168
169   if(conssl->ctx)
170     SSL_CTX_free(conssl->ctx);
171   conssl->ctx = SSL_CTX_new(req_method);
172
173   if(!conssl->ctx) {
174     failf(data, "SSL: couldn't create a context!");
175     return CURLE_OUT_OF_MEMORY;
176   }
177
178   switch(data->set.ssl.version) {
179   case CURL_SSLVERSION_DEFAULT:
180   case CURL_SSLVERSION_TLSv1:
181 #if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
182     /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever
183     minimum version of TLS was built in and at least TLS 1.0. For later library
184     versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so
185     we have this short circuit evaluation to find the minimum supported TLS
186     version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
187     because only the former will work before the user's CTX callback is called.
188     */
189     if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) &&
190        (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) &&
191        (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) {
192       failf(data, "SSL: couldn't set the minimum protocol version");
193       return CURLE_SSL_CONNECT_ERROR;
194     }
195 #endif
196     break;
197   }
198
199 #ifndef NO_FILESYSTEM
200   /* load trusted cacert */
201   if(data->set.str[STRING_SSL_CAFILE]) {
202     if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
203                                           data->set.str[STRING_SSL_CAFILE],
204                                           data->set.str[STRING_SSL_CAPATH])) {
205       if(data->set.ssl.verifypeer) {
206         /* Fail if we insist on successfully verifying the server. */
207         failf(data, "error setting certificate verify locations:\n"
208               "  CAfile: %s\n  CApath: %s",
209               data->set.str[STRING_SSL_CAFILE]?
210               data->set.str[STRING_SSL_CAFILE]: "none",
211               data->set.str[STRING_SSL_CAPATH]?
212               data->set.str[STRING_SSL_CAPATH] : "none");
213         return CURLE_SSL_CACERT_BADFILE;
214       }
215       else {
216         /* Just continue with a warning if no strict certificate
217            verification is required. */
218         infof(data, "error setting certificate verify locations,"
219               " continuing anyway:\n");
220       }
221     }
222     else {
223       /* Everything is fine. */
224       infof(data, "successfully set certificate verify locations:\n");
225     }
226     infof(data,
227           "  CAfile: %s\n"
228           "  CApath: %s\n",
229           data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
230           "none",
231           data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
232           "none");
233   }
234
235   /* Load the client certificate, and private key */
236   if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
237     int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);
238
239     if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
240                                      file_type) != 1) {
241       failf(data, "unable to use client certificate (no key or wrong pass"
242             " phrase?)");
243       return CURLE_SSL_CONNECT_ERROR;
244     }
245
246     file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
247     if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
248                                     file_type) != 1) {
249       failf(data, "unable to set private key");
250       return CURLE_SSL_CONNECT_ERROR;
251     }
252   }
253 #endif /* !NO_FILESYSTEM */
254
255   /* SSL always tries to verify the peer, this only says whether it should
256    * fail to connect if the verification fails, or if it should continue
257    * anyway. In the latter case the result of the verification is checked with
258    * SSL_get_verify_result() below. */
259   SSL_CTX_set_verify(conssl->ctx,
260                      data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
261                      NULL);
262
263 #ifdef HAVE_SNI
264   if(sni) {
265     struct in_addr addr4;
266 #ifdef ENABLE_IPV6
267     struct in6_addr addr6;
268 #endif
269     size_t hostname_len = strlen(conn->host.name);
270     if((hostname_len < USHRT_MAX) &&
271        (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) &&
272 #ifdef ENABLE_IPV6
273        (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) &&
274 #endif
275        (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name,
276                           (unsigned short)hostname_len) != 1)) {
277       infof(data, "WARNING: failed to configure server name indication (SNI) "
278             "TLS extension\n");
279     }
280   }
281 #endif
282
283   /* give application a chance to interfere with SSL set up. */
284   if(data->set.ssl.fsslctx) {
285     CURLcode result = CURLE_OK;
286     result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
287                                       data->set.ssl.fsslctxp);
288     if(result) {
289       failf(data, "error signaled by ssl ctx callback");
290       return result;
291     }
292   }
293 #ifdef NO_FILESYSTEM
294   else if(data->set.ssl.verifypeer) {
295     failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
296           " with \"no filesystem\". Either disable peer verification"
297           " (insecure) or if you are building an application with libcurl you"
298           " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
299     return CURLE_SSL_CONNECT_ERROR;
300   }
301 #endif
302
303   /* Let's make an SSL structure */
304   if(conssl->handle)
305     SSL_free(conssl->handle);
306   conssl->handle = SSL_new(conssl->ctx);
307   if(!conssl->handle) {
308     failf(data, "SSL: couldn't create a context (handle)!");
309     return CURLE_OUT_OF_MEMORY;
310   }
311
312   /* Check if there's a cached ID we can/should use here! */
313   if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
314     /* we got a session id, use it! */
315     if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
316       failf(data, "SSL: SSL_set_session failed: %s",
317             ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer));
318       return CURLE_SSL_CONNECT_ERROR;
319     }
320     /* Informational message */
321     infof (data, "SSL re-using session ID\n");
322   }
323
324   /* pass the raw socket into the SSL layer */
325   if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
326     failf(data, "SSL: SSL_set_fd failed");
327     return CURLE_SSL_CONNECT_ERROR;
328   }
329
330   conssl->connecting_state = ssl_connect_2;
331   return CURLE_OK;
332 }
333
334
335 static CURLcode
336 cyassl_connect_step2(struct connectdata *conn,
337                      int sockindex)
338 {
339   int ret = -1;
340   struct SessionHandle *data = conn->data;
341   struct ssl_connect_data* conssl = &conn->ssl[sockindex];
342
343   conn->recv[sockindex] = cyassl_recv;
344   conn->send[sockindex] = cyassl_send;
345
346   /* Enable RFC2818 checks */
347   if(data->set.ssl.verifyhost) {
348     ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name);
349     if(ret == SSL_FAILURE)
350       return CURLE_OUT_OF_MEMORY;
351   }
352
353   ret = SSL_connect(conssl->handle);
354   if(ret != 1) {
355     char error_buffer[CYASSL_MAX_ERROR_SZ];
356     int  detail = SSL_get_error(conssl->handle, ret);
357
358     if(SSL_ERROR_WANT_READ == detail) {
359       conssl->connecting_state = ssl_connect_2_reading;
360       return CURLE_OK;
361     }
362     else if(SSL_ERROR_WANT_WRITE == detail) {
363       conssl->connecting_state = ssl_connect_2_writing;
364       return CURLE_OK;
365     }
366     /* There is no easy way to override only the CN matching.
367      * This will enable the override of both mismatching SubjectAltNames
368      * as also mismatching CN fields */
369     else if(DOMAIN_NAME_MISMATCH == detail) {
370 #if 1
371       failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
372             conn->host.dispname);
373       return CURLE_PEER_FAILED_VERIFICATION;
374 #else
375       /* When the CyaSSL_check_domain_name() is used and you desire to continue
376        * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0',
377        * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
378        * way to do this is currently to switch the CyaSSL_check_domain_name()
379        * in and out based on the 'data->set.ssl.verifyhost' value. */
380       if(data->set.ssl.verifyhost) {
381         failf(data,
382               "\tsubject alt name(s) or common name do not match \"%s\"\n",
383               conn->host.dispname);
384         return CURLE_PEER_FAILED_VERIFICATION;
385       }
386       else {
387         infof(data,
388               "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
389               conn->host.dispname);
390         return CURLE_OK;
391       }
392 #endif
393     }
394 #if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
395     else if(ASN_NO_SIGNER_E == detail) {
396       if(data->set.ssl.verifypeer) {
397         failf(data, "\tCA signer not available for verification\n");
398         return CURLE_SSL_CACERT_BADFILE;
399       }
400       else {
401         /* Just continue with a warning if no strict certificate
402            verification is required. */
403         infof(data, "CA signer not available for verification, "
404                     "continuing anyway\n");
405       }
406     }
407 #endif
408     else {
409       failf(data, "SSL_connect failed with error %d: %s", detail,
410           ERR_error_string(detail, error_buffer));
411       return CURLE_SSL_CONNECT_ERROR;
412     }
413   }
414
415   if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
416 #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) ||       \
417   defined(HAVE_CYASSL_GET_PEER_CERTIFICATE)
418     X509 *x509;
419     const char *x509_der;
420     int x509_der_len;
421     curl_X509certificate x509_parsed;
422     curl_asn1Element *pubkey;
423     CURLcode result;
424
425     x509 = SSL_get_peer_certificate(conssl->handle);
426     if(!x509) {
427       failf(data, "SSL: failed retrieving server certificate");
428       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
429     }
430
431     x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len);
432     if(!x509_der) {
433       failf(data, "SSL: failed retrieving ASN.1 server certificate");
434       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
435     }
436
437     memset(&x509_parsed, 0, sizeof x509_parsed);
438     Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len);
439
440     pubkey = &x509_parsed.subjectPublicKeyInfo;
441     if(!pubkey->header || pubkey->end <= pubkey->header) {
442       failf(data, "SSL: failed retrieving public key from server certificate");
443       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
444     }
445
446     result = Curl_pin_peer_pubkey(data,
447                                   data->set.str[STRING_SSL_PINNEDPUBLICKEY],
448                                   (const unsigned char *)pubkey->header,
449                                   (size_t)(pubkey->end - pubkey->header));
450     if(result) {
451       failf(data, "SSL: public key does not match pinned public key!");
452       return result;
453     }
454 #else
455     failf(data, "Library lacks pinning support built-in");
456     return CURLE_NOT_BUILT_IN;
457 #endif
458   }
459
460   conssl->connecting_state = ssl_connect_3;
461   infof(data, "SSL connected\n");
462
463   return CURLE_OK;
464 }
465
466
467 static CURLcode
468 cyassl_connect_step3(struct connectdata *conn,
469                      int sockindex)
470 {
471   CURLcode result = CURLE_OK;
472   void *old_ssl_sessionid=NULL;
473   struct SessionHandle *data = conn->data;
474   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
475   bool incache;
476   SSL_SESSION *our_ssl_sessionid;
477
478   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
479
480   our_ssl_sessionid = SSL_get_session(connssl->handle);
481
482   incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
483   if(incache) {
484     if(old_ssl_sessionid != our_ssl_sessionid) {
485       infof(data, "old SSL session ID is stale, removing\n");
486       Curl_ssl_delsessionid(conn, old_ssl_sessionid);
487       incache = FALSE;
488     }
489   }
490
491   if(!incache) {
492     result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
493                                    0 /* unknown size */);
494     if(result) {
495       failf(data, "failed to store ssl session");
496       return result;
497     }
498   }
499
500   connssl->connecting_state = ssl_connect_done;
501
502   return result;
503 }
504
505
506 static ssize_t cyassl_send(struct connectdata *conn,
507                            int sockindex,
508                            const void *mem,
509                            size_t len,
510                            CURLcode *curlcode)
511 {
512   char error_buffer[CYASSL_MAX_ERROR_SZ];
513   int  memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
514   int  rc     = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
515
516   if(rc < 0) {
517     int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
518
519     switch(err) {
520     case SSL_ERROR_WANT_READ:
521     case SSL_ERROR_WANT_WRITE:
522       /* there's data pending, re-invoke SSL_write() */
523       *curlcode = CURLE_AGAIN;
524       return -1;
525     default:
526       failf(conn->data, "SSL write: %s, errno %d",
527             ERR_error_string(err, error_buffer),
528             SOCKERRNO);
529       *curlcode = CURLE_SEND_ERROR;
530       return -1;
531     }
532   }
533   return rc;
534 }
535
536 void Curl_cyassl_close(struct connectdata *conn, int sockindex)
537 {
538   struct ssl_connect_data *conssl = &conn->ssl[sockindex];
539
540   if(conssl->handle) {
541     (void)SSL_shutdown(conssl->handle);
542     SSL_free (conssl->handle);
543     conssl->handle = NULL;
544   }
545   if(conssl->ctx) {
546     SSL_CTX_free (conssl->ctx);
547     conssl->ctx = NULL;
548   }
549 }
550
551 static ssize_t cyassl_recv(struct connectdata *conn,
552                            int num,
553                            char *buf,
554                            size_t buffersize,
555                            CURLcode *curlcode)
556 {
557   char error_buffer[CYASSL_MAX_ERROR_SZ];
558   int  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
559   int  nread    = SSL_read(conn->ssl[num].handle, buf, buffsize);
560
561   if(nread < 0) {
562     int err = SSL_get_error(conn->ssl[num].handle, nread);
563
564     switch(err) {
565     case SSL_ERROR_ZERO_RETURN: /* no more data */
566       break;
567     case SSL_ERROR_WANT_READ:
568     case SSL_ERROR_WANT_WRITE:
569       /* there's data pending, re-invoke SSL_read() */
570       *curlcode = CURLE_AGAIN;
571       return -1;
572     default:
573       failf(conn->data, "SSL read: %s, errno %d",
574             ERR_error_string(err, error_buffer),
575             SOCKERRNO);
576       *curlcode = CURLE_RECV_ERROR;
577       return -1;
578     }
579   }
580   return nread;
581 }
582
583
584 void Curl_cyassl_session_free(void *ptr)
585 {
586   (void)ptr;
587   /* CyaSSL reuses sessions on own, no free */
588 }
589
590
591 size_t Curl_cyassl_version(char *buffer, size_t size)
592 {
593 #ifdef WOLFSSL_VERSION
594   return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
595 #elif defined(CYASSL_VERSION)
596   return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
597 #else
598   return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
599 #endif
600 }
601
602
603 int Curl_cyassl_init(void)
604 {
605   return (CyaSSL_Init() == SSL_SUCCESS);
606 }
607
608
609 bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
610 {
611   if(conn->ssl[connindex].handle)   /* SSL is in use */
612     return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
613   else
614     return FALSE;
615 }
616
617
618 /*
619  * This function is called to shut down the SSL layer but keep the
620  * socket open (CCC - Clear Command Channel)
621  */
622 int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
623 {
624   int retval = 0;
625   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
626
627   if(connssl->handle) {
628     SSL_free (connssl->handle);
629     connssl->handle = NULL;
630   }
631   return retval;
632 }
633
634
635 static CURLcode
636 cyassl_connect_common(struct connectdata *conn,
637                       int sockindex,
638                       bool nonblocking,
639                       bool *done)
640 {
641   CURLcode result;
642   struct SessionHandle *data = conn->data;
643   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
644   curl_socket_t sockfd = conn->sock[sockindex];
645   long timeout_ms;
646   int what;
647
648   /* check if the connection has already been established */
649   if(ssl_connection_complete == connssl->state) {
650     *done = TRUE;
651     return CURLE_OK;
652   }
653
654   if(ssl_connect_1==connssl->connecting_state) {
655     /* Find out how much more time we're allowed */
656     timeout_ms = Curl_timeleft(data, NULL, TRUE);
657
658     if(timeout_ms < 0) {
659       /* no need to continue if time already is up */
660       failf(data, "SSL connection timeout");
661       return CURLE_OPERATION_TIMEDOUT;
662     }
663
664     result = cyassl_connect_step1(conn, sockindex);
665     if(result)
666       return result;
667   }
668
669   while(ssl_connect_2 == connssl->connecting_state ||
670         ssl_connect_2_reading == connssl->connecting_state ||
671         ssl_connect_2_writing == connssl->connecting_state) {
672
673     /* check allowed time left */
674     timeout_ms = Curl_timeleft(data, NULL, TRUE);
675
676     if(timeout_ms < 0) {
677       /* no need to continue if time already is up */
678       failf(data, "SSL connection timeout");
679       return CURLE_OPERATION_TIMEDOUT;
680     }
681
682     /* if ssl is expecting something, check if it's available. */
683     if(connssl->connecting_state == ssl_connect_2_reading
684        || connssl->connecting_state == ssl_connect_2_writing) {
685
686       curl_socket_t writefd = ssl_connect_2_writing==
687         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
688       curl_socket_t readfd = ssl_connect_2_reading==
689         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
690
691       what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
692       if(what < 0) {
693         /* fatal error */
694         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
695         return CURLE_SSL_CONNECT_ERROR;
696       }
697       else if(0 == what) {
698         if(nonblocking) {
699           *done = FALSE;
700           return CURLE_OK;
701         }
702         else {
703           /* timeout */
704           failf(data, "SSL connection timeout");
705           return CURLE_OPERATION_TIMEDOUT;
706         }
707       }
708       /* socket is readable or writable */
709     }
710
711     /* Run transaction, and return to the caller if it failed or if
712      * this connection is part of a multi handle and this loop would
713      * execute again. This permits the owner of a multi handle to
714      * abort a connection attempt before step2 has completed while
715      * ensuring that a client using select() or epoll() will always
716      * have a valid fdset to wait on.
717      */
718     result = cyassl_connect_step2(conn, sockindex);
719     if(result || (nonblocking &&
720                   (ssl_connect_2 == connssl->connecting_state ||
721                    ssl_connect_2_reading == connssl->connecting_state ||
722                    ssl_connect_2_writing == connssl->connecting_state)))
723       return result;
724   } /* repeat step2 until all transactions are done. */
725
726   if(ssl_connect_3 == connssl->connecting_state) {
727     result = cyassl_connect_step3(conn, sockindex);
728     if(result)
729       return result;
730   }
731
732   if(ssl_connect_done == connssl->connecting_state) {
733     connssl->state = ssl_connection_complete;
734     conn->recv[sockindex] = cyassl_recv;
735     conn->send[sockindex] = cyassl_send;
736     *done = TRUE;
737   }
738   else
739     *done = FALSE;
740
741   /* Reset our connect state machine */
742   connssl->connecting_state = ssl_connect_1;
743
744   return CURLE_OK;
745 }
746
747
748 CURLcode
749 Curl_cyassl_connect_nonblocking(struct connectdata *conn,
750                                 int sockindex,
751                                 bool *done)
752 {
753   return cyassl_connect_common(conn, sockindex, TRUE, done);
754 }
755
756
757 CURLcode
758 Curl_cyassl_connect(struct connectdata *conn,
759                     int sockindex)
760 {
761   CURLcode result;
762   bool done = FALSE;
763
764   result = cyassl_connect_common(conn, sockindex, FALSE, &done);
765   if(result)
766     return result;
767
768   DEBUGASSERT(done);
769
770   return CURLE_OK;
771 }
772
773 int Curl_cyassl_random(struct SessionHandle *data,
774                        unsigned char *entropy,
775                        size_t length)
776 {
777   RNG rng;
778   (void)data;
779   if(InitRng(&rng))
780     return 1;
781   if(length > UINT_MAX)
782     return 1;
783   if(RNG_GenerateBlock(&rng, entropy, (unsigned)length))
784     return 1;
785   return 0;
786 }
787
788 void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
789                       size_t tmplen,
790                       unsigned char *sha256sum /* output */,
791                       size_t unused)
792 {
793   Sha256 SHA256pw;
794   (void)unused;
795   InitSha256(&SHA256pw);
796   Sha256Update(&SHA256pw, tmp, (word32)tmplen);
797   Sha256Final(&SHA256pw, sha256sum);
798 }
799
800 #endif