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