VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/vquic/vquic-tls.c@ 105284

Last change on this file since 105284 was 104204, checked in by vboxsync, 11 months ago

fixing export flags in libs

File size: 18.5 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#if defined(ENABLE_QUIC) && \
28 (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
29
30#ifdef USE_OPENSSL
31#include <openssl/err.h>
32#include "vtls/openssl.h"
33#elif defined(USE_GNUTLS)
34#include <gnutls/abstract.h>
35#include <gnutls/gnutls.h>
36#include <gnutls/x509.h>
37#include <gnutls/crypto.h>
38#include <nettle/sha2.h>
39#include "vtls/gtls.h"
40#elif defined(USE_WOLFSSL)
41#include <wolfssl/options.h>
42#include <wolfssl/ssl.h>
43#include <wolfssl/quic.h>
44#include "vtls/wolfssl.h"
45#endif
46
47#include "urldata.h"
48#include "curl_trc.h"
49#include "cfilters.h"
50#include "multiif.h"
51#include "vtls/keylog.h"
52#include "vtls/vtls.h"
53#include "vquic-tls.h"
54
55/* The last 3 #include files should be in this order */
56#include "curl_printf.h"
57#include "curl_memory.h"
58#include "memdebug.h"
59
60#ifndef ARRAYSIZE
61#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
62#endif
63
64#ifdef USE_OPENSSL
65#define QUIC_CIPHERS \
66 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
67 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
68#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
69#elif defined(USE_GNUTLS)
70#define QUIC_PRIORITY \
71 "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
72 "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
73 "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
74 "%DISABLE_TLS13_COMPAT_MODE"
75#elif defined(USE_WOLFSSL)
76#define QUIC_CIPHERS \
77 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
78 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
79#define QUIC_GROUPS "P-256:P-384:P-521"
80#endif
81
82
83#ifdef USE_OPENSSL
84
85static void keylog_callback(const SSL *ssl, const char *line)
86{
87 (void)ssl;
88 Curl_tls_keylog_write_line(line);
89}
90
91static CURLcode curl_ossl_init_ctx(struct quic_tls_ctx *ctx,
92 struct Curl_cfilter *cf,
93 struct Curl_easy *data,
94 Curl_vquic_tls_ctx_setup *ctx_setup)
95{
96 struct ssl_primary_config *conn_config;
97 CURLcode result = CURLE_FAILED_INIT;
98
99 DEBUGASSERT(!ctx->ssl_ctx);
100#ifdef USE_OPENSSL_QUIC
101 ctx->ssl_ctx = SSL_CTX_new(OSSL_QUIC_client_method());
102#else
103 ctx->ssl_ctx = SSL_CTX_new(TLS_method());
104#endif
105 if(!ctx->ssl_ctx) {
106 result = CURLE_OUT_OF_MEMORY;
107 goto out;
108 }
109 conn_config = Curl_ssl_cf_get_primary_config(cf);
110 if(!conn_config) {
111 result = CURLE_FAILED_INIT;
112 goto out;
113 }
114
115 if(ctx_setup) {
116 result = ctx_setup(ctx, cf, data);
117 if(result)
118 goto out;
119 }
120
121 SSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
122
123 {
124 const char *curves = conn_config->curves ?
125 conn_config->curves : QUIC_GROUPS;
126 if(!SSL_CTX_set1_curves_list(ctx->ssl_ctx, curves)) {
127 failf(data, "failed setting curves list for QUIC: '%s'", curves);
128 return CURLE_SSL_CIPHER;
129 }
130 }
131
132#ifndef OPENSSL_IS_BORINGSSL
133 {
134 const char *ciphers13 = conn_config->cipher_list13 ?
135 conn_config->cipher_list13 : QUIC_CIPHERS;
136 if(SSL_CTX_set_ciphersuites(ctx->ssl_ctx, ciphers13) != 1) {
137 failf(data, "failed setting QUIC cipher suite: %s", ciphers13);
138 return CURLE_SSL_CIPHER;
139 }
140 infof(data, "QUIC cipher selection: %s", ciphers13);
141 }
142#endif
143
144 /* Open the file if a TLS or QUIC backend has not done this before. */
145 Curl_tls_keylog_open();
146 if(Curl_tls_keylog_enabled()) {
147 SSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
148 }
149
150 /* OpenSSL always tries to verify the peer, this only says whether it should
151 * fail to connect if the verification fails, or if it should continue
152 * anyway. In the latter case the result of the verification is checked with
153 * SSL_get_verify_result() below. */
154 SSL_CTX_set_verify(ctx->ssl_ctx, conn_config->verifypeer ?
155 SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
156
157 /* give application a chance to interfere with SSL set up. */
158 if(data->set.ssl.fsslctx) {
159 /* When a user callback is installed to modify the SSL_CTX,
160 * we need to do the full initialization before calling it.
161 * See: #11800 */
162 if(!ctx->x509_store_setup) {
163 result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx);
164 if(result)
165 goto out;
166 ctx->x509_store_setup = TRUE;
167 }
168 Curl_set_in_callback(data, true);
169 result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx,
170 data->set.ssl.fsslctxp);
171 Curl_set_in_callback(data, false);
172 if(result) {
173 failf(data, "error signaled by ssl ctx callback");
174 goto out;
175 }
176 }
177 result = CURLE_OK;
178
179out:
180 if(result && ctx->ssl_ctx) {
181 SSL_CTX_free(ctx->ssl_ctx);
182 ctx->ssl_ctx = NULL;
183 }
184 return result;
185}
186
187static CURLcode curl_ossl_set_client_cert(struct quic_tls_ctx *ctx,
188 struct Curl_cfilter *cf,
189 struct Curl_easy *data)
190{
191 SSL_CTX *ssl_ctx = ctx->ssl_ctx;
192 const struct ssl_config_data *ssl_config;
193
194 ssl_config = Curl_ssl_cf_get_config(cf, data);
195 DEBUGASSERT(ssl_config);
196
197 if(ssl_config->primary.clientcert ||
198 ssl_config->primary.cert_blob ||
199 ssl_config->cert_type) {
200 return Curl_ossl_set_client_cert(
201 data, ssl_ctx, ssl_config->primary.clientcert,
202 ssl_config->primary.cert_blob, ssl_config->cert_type,
203 ssl_config->key, ssl_config->key_blob,
204 ssl_config->key_type, ssl_config->key_passwd);
205 }
206
207 return CURLE_OK;
208}
209
210/** SSL callbacks ***/
211
212static CURLcode curl_ossl_init_ssl(struct quic_tls_ctx *ctx,
213 struct Curl_easy *data,
214 struct ssl_peer *peer,
215 const char *alpn, size_t alpn_len,
216 void *user_data)
217{
218 DEBUGASSERT(!ctx->ssl);
219 ctx->ssl = SSL_new(ctx->ssl_ctx);
220
221 SSL_set_app_data(ctx->ssl, user_data);
222 SSL_set_connect_state(ctx->ssl);
223#ifndef USE_OPENSSL_QUIC
224 SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
225#endif
226
227 if(alpn)
228 SSL_set_alpn_protos(ctx->ssl, (const uint8_t *)alpn, (int)alpn_len);
229
230 if(peer->sni) {
231 if(!SSL_set_tlsext_host_name(ctx->ssl, peer->sni)) {
232 failf(data, "Failed set SNI");
233 SSL_free(ctx->ssl);
234 ctx->ssl = NULL;
235 return CURLE_QUIC_CONNECT_ERROR;
236 }
237 }
238 return CURLE_OK;
239}
240
241#elif defined(USE_GNUTLS)
242static int keylog_callback(gnutls_session_t session, const char *label,
243 const gnutls_datum_t *secret)
244{
245 gnutls_datum_t crandom;
246 gnutls_datum_t srandom;
247
248 gnutls_session_get_random(session, &crandom, &srandom);
249 if(crandom.size != 32) {
250 return -1;
251 }
252
253 Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
254 return 0;
255}
256
257static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx,
258 struct Curl_cfilter *cf,
259 struct Curl_easy *data,
260 struct ssl_peer *peer,
261 const char *alpn, size_t alpn_len,
262 Curl_vquic_tls_ctx_setup *ctx_setup,
263 void *user_data)
264{
265 struct ssl_primary_config *conn_config;
266 CURLcode result;
267 gnutls_datum_t alpns[5];
268 /* this will need some attention when HTTPS proxy over QUIC get fixed */
269 long * const pverifyresult = &data->set.ssl.certverifyresult;
270 int rc;
271
272 conn_config = Curl_ssl_cf_get_primary_config(cf);
273 if(!conn_config)
274 return CURLE_FAILED_INIT;
275
276 DEBUGASSERT(ctx->gtls == NULL);
277 ctx->gtls = calloc(1, sizeof(*(ctx->gtls)));
278 if(!ctx->gtls)
279 return CURLE_OUT_OF_MEMORY;
280
281 result = gtls_client_init(data, conn_config, &data->set.ssl,
282 peer, ctx->gtls, pverifyresult);
283 if(result)
284 return result;
285
286 gnutls_session_set_ptr(ctx->gtls->session, user_data);
287
288 if(ctx_setup) {
289 result = ctx_setup(ctx, cf, data);
290 if(result)
291 return result;
292 }
293
294 rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL);
295 if(rc < 0) {
296 CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n",
297 gnutls_strerror(rc));
298 return CURLE_QUIC_CONNECT_ERROR;
299 }
300
301 /* Open the file if a TLS or QUIC backend has not done this before. */
302 Curl_tls_keylog_open();
303 if(Curl_tls_keylog_enabled()) {
304 gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback);
305 }
306
307 /* convert the ALPN string from our arguments to a list of strings
308 * that gnutls wants and will convert internally back to this very
309 * string for sending to the server. nice. */
310 if(alpn) {
311 size_t i, alen = alpn_len;
312 unsigned char *s = (unsigned char *)alpn;
313 unsigned char slen;
314 for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
315 slen = s[0];
316 if(slen >= alen)
317 return CURLE_FAILED_INIT;
318 alpns[i].data = s + 1;
319 alpns[i].size = slen;
320 s += slen + 1;
321 alen -= (size_t)slen + 1;
322 }
323 if(alen) /* not all alpn chars used, wrong format or too many */
324 return CURLE_FAILED_INIT;
325 if(i) {
326 gnutls_alpn_set_protocols(ctx->gtls->session,
327 alpns, (unsigned int)i,
328 GNUTLS_ALPN_MANDATORY);
329 }
330 }
331
332 return CURLE_OK;
333}
334#elif defined(USE_WOLFSSL)
335
336#if defined(HAVE_SECRET_CALLBACK)
337static void keylog_callback(const WOLFSSL *ssl, const char *line)
338{
339 (void)ssl;
340 Curl_tls_keylog_write_line(line);
341}
342#endif
343
344static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx,
345 struct Curl_cfilter *cf,
346 struct Curl_easy *data,
347 Curl_vquic_tls_ctx_setup *ctx_setup)
348{
349 struct ssl_primary_config *conn_config;
350 CURLcode result = CURLE_FAILED_INIT;
351
352 conn_config = Curl_ssl_cf_get_primary_config(cf);
353 if(!conn_config) {
354 result = CURLE_FAILED_INIT;
355 goto out;
356 }
357
358 ctx->ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
359 if(!ctx->ssl_ctx) {
360 result = CURLE_OUT_OF_MEMORY;
361 goto out;
362 }
363
364 if(ctx_setup) {
365 result = ctx_setup(ctx, cf, data);
366 if(result)
367 goto out;
368 }
369
370 wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
371
372 if(wolfSSL_CTX_set_cipher_list(ctx->ssl_ctx, conn_config->cipher_list13 ?
373 conn_config->cipher_list13 :
374 QUIC_CIPHERS) != 1) {
375 char error_buffer[256];
376 ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
377 failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
378 result = CURLE_BAD_FUNCTION_ARGUMENT;
379 goto out;
380 }
381
382 if(wolfSSL_CTX_set1_groups_list(ctx->ssl_ctx, conn_config->curves ?
383 conn_config->curves :
384 (char *)QUIC_GROUPS) != 1) {
385 failf(data, "wolfSSL failed to set curves");
386 result = CURLE_BAD_FUNCTION_ARGUMENT;
387 goto out;
388 }
389
390 /* Open the file if a TLS or QUIC backend has not done this before. */
391 Curl_tls_keylog_open();
392 if(Curl_tls_keylog_enabled()) {
393#if defined(HAVE_SECRET_CALLBACK)
394 wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
395#else
396 failf(data, "wolfSSL was built without keylog callback");
397 result = CURLE_NOT_BUILT_IN;
398 goto out;
399#endif
400 }
401
402 if(conn_config->verifypeer) {
403 const char * const ssl_cafile = conn_config->CAfile;
404 const char * const ssl_capath = conn_config->CApath;
405
406 wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
407 if(ssl_cafile || ssl_capath) {
408 /* tell wolfSSL where to find CA certificates that are used to verify
409 the server's certificate. */
410 int rc =
411 wolfSSL_CTX_load_verify_locations_ex(ctx->ssl_ctx, ssl_cafile,
412 ssl_capath,
413 WOLFSSL_LOAD_FLAG_IGNORE_ERR);
414 if(SSL_SUCCESS != rc) {
415 /* Fail if we insist on successfully verifying the server. */
416 failf(data, "error setting certificate verify locations:"
417 " CAfile: %s CApath: %s",
418 ssl_cafile ? ssl_cafile : "none",
419 ssl_capath ? ssl_capath : "none");
420 result = CURLE_SSL_CACERT_BADFILE;
421 goto out;
422 }
423 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
424 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
425 }
426#ifdef CURL_CA_FALLBACK
427 else {
428 /* verifying the peer without any CA certificates won't work so
429 use wolfssl's built-in default as fallback */
430 wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
431 }
432#endif
433 }
434 else {
435 wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
436 }
437
438 /* give application a chance to interfere with SSL set up. */
439 if(data->set.ssl.fsslctx) {
440 Curl_set_in_callback(data, true);
441 result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx,
442 data->set.ssl.fsslctxp);
443 Curl_set_in_callback(data, false);
444 if(result) {
445 failf(data, "error signaled by ssl ctx callback");
446 goto out;
447 }
448 }
449 result = CURLE_OK;
450
451out:
452 if(result && ctx->ssl_ctx) {
453 SSL_CTX_free(ctx->ssl_ctx);
454 ctx->ssl_ctx = NULL;
455 }
456 return result;
457}
458
459/** SSL callbacks ***/
460
461static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
462 struct Curl_easy *data,
463 struct ssl_peer *peer,
464 const char *alpn, size_t alpn_len,
465 void *user_data)
466{
467 (void)data;
468 DEBUGASSERT(!ctx->ssl);
469 DEBUGASSERT(ctx->ssl_ctx);
470 ctx->ssl = wolfSSL_new(ctx->ssl_ctx);
471
472 wolfSSL_set_app_data(ctx->ssl, user_data);
473 wolfSSL_set_connect_state(ctx->ssl);
474 wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
475
476 if(alpn)
477 wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn,
478 (int)alpn_len);
479
480 if(peer->sni) {
481 wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME,
482 peer->sni, (unsigned short)strlen(peer->sni));
483 }
484
485 return CURLE_OK;
486}
487#endif /* defined(USE_WOLFSSL) */
488
489CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
490 struct Curl_cfilter *cf,
491 struct Curl_easy *data,
492 struct ssl_peer *peer,
493 const char *alpn, size_t alpn_len,
494 Curl_vquic_tls_ctx_setup *ctx_setup,
495 void *user_data)
496{
497 CURLcode result;
498
499#ifdef USE_OPENSSL
500 result = curl_ossl_init_ctx(ctx, cf, data, ctx_setup);
501 if(result)
502 return result;
503
504 result = curl_ossl_set_client_cert(ctx, cf, data);
505 if(result)
506 return result;
507
508 return curl_ossl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
509#elif defined(USE_GNUTLS)
510 (void)result;
511 return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len,
512 ctx_setup, user_data);
513#elif defined(USE_WOLFSSL)
514 result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup);
515 if(result)
516 return result;
517
518 return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
519#else
520#error "no TLS lib in used, should not happen"
521 return CURLE_FAILED_INIT;
522#endif
523}
524
525void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx)
526{
527#ifdef USE_OPENSSL
528 if(ctx->ssl)
529 SSL_free(ctx->ssl);
530 if(ctx->ssl_ctx)
531 SSL_CTX_free(ctx->ssl_ctx);
532#elif defined(USE_GNUTLS)
533 if(ctx->gtls) {
534 if(ctx->gtls->cred)
535 gnutls_certificate_free_credentials(ctx->gtls->cred);
536 if(ctx->gtls->session)
537 gnutls_deinit(ctx->gtls->session);
538 free(ctx->gtls);
539 }
540#elif defined(USE_WOLFSSL)
541 if(ctx->ssl)
542 wolfSSL_free(ctx->ssl);
543 if(ctx->ssl_ctx)
544 wolfSSL_CTX_free(ctx->ssl_ctx);
545#endif
546 memset(ctx, 0, sizeof(*ctx));
547}
548
549CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
550 struct Curl_cfilter *cf,
551 struct Curl_easy *data)
552{
553#ifdef USE_OPENSSL
554 if(!ctx->x509_store_setup) {
555 CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx);
556 if(result)
557 return result;
558 ctx->x509_store_setup = TRUE;
559 }
560#else
561 (void)ctx; (void)cf; (void)data;
562#endif
563 return CURLE_OK;
564}
565
566CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
567 struct Curl_cfilter *cf,
568 struct Curl_easy *data,
569 struct ssl_peer *peer)
570{
571 struct ssl_primary_config *conn_config;
572 CURLcode result = CURLE_OK;
573
574 conn_config = Curl_ssl_cf_get_primary_config(cf);
575 if(!conn_config)
576 return CURLE_FAILED_INIT;
577
578 if(conn_config->verifyhost) {
579#ifdef USE_OPENSSL
580 X509 *server_cert;
581 server_cert = SSL_get1_peer_certificate(ctx->ssl);
582 if(!server_cert) {
583 return CURLE_PEER_FAILED_VERIFICATION;
584 }
585 result = Curl_ossl_verifyhost(data, cf->conn, peer, server_cert);
586 X509_free(server_cert);
587 if(result)
588 return result;
589#elif defined(USE_GNUTLS)
590 result = Curl_gtls_verifyserver(data, ctx->gtls->session,
591 conn_config, &data->set.ssl, peer,
592 data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
593 if(result)
594 return result;
595#elif defined(USE_WOLFSSL)
596 if(!peer->sni ||
597 wolfSSL_check_domain_name(ctx->ssl, peer->sni) == SSL_FAILURE)
598 return CURLE_PEER_FAILED_VERIFICATION;
599#endif
600 infof(data, "Verified certificate just fine");
601 }
602 else
603 infof(data, "Skipped certificate verification");
604#ifdef USE_OPENSSL
605 if(data->set.ssl.certinfo)
606 /* asked to gather certificate info */
607 (void)Curl_ossl_certchain(data, ctx->ssl);
608#endif
609 return result;
610}
611
612
613#endif /* !ENABLE_QUIC && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
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