1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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.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 
keylog_callback(const SSL *ssl, const char *line)85 static void keylog_callback(const SSL *ssl, const char *line)
86 {
87   (void)ssl;
88   Curl_tls_keylog_write_line(line);
89 }
90 
curl_ossl_init_ctx(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data, Curl_vquic_tls_ctx_setup *ctx_setup)91 static 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 
179 out:
180   if(result && ctx->ssl_ctx) {
181     SSL_CTX_free(ctx->ssl_ctx);
182     ctx->ssl_ctx = NULL;
183   }
184   return result;
185 }
186 
curl_ossl_set_client_cert(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data)187 static 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 
curl_ossl_init_ssl(struct quic_tls_ctx *ctx, struct Curl_easy *data, struct ssl_peer *peer, const char *alpn, size_t alpn_len, void *user_data)212 static 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)
keylog_callback(gnutls_session_t session, const char *label, const gnutls_datum_t *secret)242 static 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 
curl_gtls_init_ctx(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data, struct ssl_peer *peer, const char *alpn, size_t alpn_len, Curl_vquic_tls_ctx_setup *ctx_setup, void *user_data)257 static 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)
keylog_callback(const WOLFSSL *ssl, const char *line)337 static void keylog_callback(const WOLFSSL *ssl, const char *line)
338 {
339   (void)ssl;
340   Curl_tls_keylog_write_line(line);
341 }
342 #endif
343 
curl_wssl_init_ctx(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data, Curl_vquic_tls_ctx_setup *ctx_setup)344 static 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;
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 
451 out:
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 
curl_wssl_init_ssl(struct quic_tls_ctx *ctx, struct Curl_easy *data, struct ssl_peer *peer, const char *alpn, size_t alpn_len, void *user_data)461 static 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 
Curl_vquic_tls_init(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data, struct ssl_peer *peer, const char *alpn, size_t alpn_len, Curl_vquic_tls_ctx_setup *ctx_setup, void *user_data)489 CURLcode 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 
Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx)525 void 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 
Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data)549 CURLcode 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 
Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx, struct Curl_cfilter *cf, struct Curl_easy *data, struct ssl_peer *peer)566 CURLcode 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) */
614