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