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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:08