VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/vtls/cyassl.c@ 90406

Last change on this file since 90406 was 85671, checked in by vboxsync, 5 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette