• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*
26  * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
27  * but vtls.c should ever call or use these functions.
28  *
29  * Note: don't use the GnuTLS' *_t variable type names in this source code,
30  * since they were not present in 1.0.X.
31  */
32 
33 #include "curl_setup.h"
34 
35 #ifdef USE_GNUTLS
36 
37 #include <gnutls/abstract.h>
38 #include <gnutls/gnutls.h>
39 #include <gnutls/x509.h>
40 #include <gnutls/crypto.h>
41 #include <nettle/sha2.h>
42 
43 #include "urldata.h"
44 #include "sendf.h"
45 #include "inet_pton.h"
46 #include "keylog.h"
47 #include "gtls.h"
48 #include "vtls.h"
49 #include "vtls_int.h"
50 #include "vauth/vauth.h"
51 #include "parsedate.h"
52 #include "connect.h" /* for the connect timeout */
53 #include "select.h"
54 #include "strcase.h"
55 #include "warnless.h"
56 #include "x509asn1.h"
57 #include "multiif.h"
58 #include "curl_printf.h"
59 #include "curl_memory.h"
60 /* The last #include file should be: */
61 #include "memdebug.h"
62 
63 #ifndef ARRAYSIZE
64 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
65 #endif
66 
67 #define QUIC_PRIORITY \
68   "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
69   "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
70   "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
71   "%DISABLE_TLS13_COMPAT_MODE"
72 
73 /* Enable GnuTLS debugging by defining GTLSDEBUG */
74 /*#define GTLSDEBUG */
75 
76 #ifdef GTLSDEBUG
tls_log_func(int level,const char * str)77 static void tls_log_func(int level, const char *str)
78 {
79     fprintf(stderr, "|<%d>| %s", level, str);
80 }
81 #endif
82 static bool gtls_inited = FALSE;
83 
84 #if !defined(GNUTLS_VERSION_NUMBER) || (GNUTLS_VERSION_NUMBER < 0x03010a)
85 #error "too old GnuTLS version"
86 #endif
87 
88 # include <gnutls/ocsp.h>
89 
90 struct gtls_ssl_backend_data {
91   struct gtls_ctx gtls;
92 };
93 
gtls_push(void * s,const void * buf,size_t blen)94 static ssize_t gtls_push(void *s, const void *buf, size_t blen)
95 {
96   struct Curl_cfilter *cf = s;
97   struct ssl_connect_data *connssl = cf->ctx;
98   struct gtls_ssl_backend_data *backend =
99     (struct gtls_ssl_backend_data *)connssl->backend;
100   struct Curl_easy *data = CF_DATA_CURRENT(cf);
101   ssize_t nwritten;
102   CURLcode result;
103 
104   DEBUGASSERT(data);
105   nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
106   CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
107               blen, nwritten, result);
108   backend->gtls.io_result = result;
109   if(nwritten < 0) {
110     gnutls_transport_set_errno(backend->gtls.session,
111                                (CURLE_AGAIN == result)? EAGAIN : EINVAL);
112     nwritten = -1;
113   }
114   return nwritten;
115 }
116 
gtls_pull(void * s,void * buf,size_t blen)117 static ssize_t gtls_pull(void *s, void *buf, size_t blen)
118 {
119   struct Curl_cfilter *cf = s;
120   struct ssl_connect_data *connssl = cf->ctx;
121   struct gtls_ssl_backend_data *backend =
122     (struct gtls_ssl_backend_data *)connssl->backend;
123   struct Curl_easy *data = CF_DATA_CURRENT(cf);
124   ssize_t nread;
125   CURLcode result;
126 
127   DEBUGASSERT(data);
128   if(!backend->gtls.trust_setup) {
129     result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
130     if(result) {
131       gnutls_transport_set_errno(backend->gtls.session, EINVAL);
132       backend->gtls.io_result = result;
133       return -1;
134     }
135   }
136 
137   nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
138   CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d",
139               blen, nread, result);
140   backend->gtls.io_result = result;
141   if(nread < 0) {
142     gnutls_transport_set_errno(backend->gtls.session,
143                                (CURLE_AGAIN == result)? EAGAIN : EINVAL);
144     nread = -1;
145   }
146   else if(nread == 0)
147     connssl->peer_closed = TRUE;
148   return nread;
149 }
150 
151 /* gtls_init()
152  *
153  * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
154  * are not thread-safe and thus this function itself is not thread-safe and
155  * must only be called from within curl_global_init() to keep the thread
156  * situation under control!
157  */
gtls_init(void)158 static int gtls_init(void)
159 {
160   int ret = 1;
161   if(!gtls_inited) {
162     ret = gnutls_global_init()?0:1;
163 #ifdef GTLSDEBUG
164     gnutls_global_set_log_function(tls_log_func);
165     gnutls_global_set_log_level(2);
166 #endif
167     gtls_inited = TRUE;
168   }
169   return ret;
170 }
171 
gtls_cleanup(void)172 static void gtls_cleanup(void)
173 {
174   if(gtls_inited) {
175     gnutls_global_deinit();
176     gtls_inited = FALSE;
177   }
178 }
179 
180 #ifndef CURL_DISABLE_VERBOSE_STRINGS
showtime(struct Curl_easy * data,const char * text,time_t stamp)181 static void showtime(struct Curl_easy *data,
182                      const char *text,
183                      time_t stamp)
184 {
185   struct tm buffer;
186   const struct tm *tm = &buffer;
187   char str[96];
188   CURLcode result = Curl_gmtime(stamp, &buffer);
189   if(result)
190     return;
191 
192   msnprintf(str,
193             sizeof(str),
194             "  %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
195             text,
196             Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
197             tm->tm_mday,
198             Curl_month[tm->tm_mon],
199             tm->tm_year + 1900,
200             tm->tm_hour,
201             tm->tm_min,
202             tm->tm_sec);
203   infof(data, "%s", str);
204 }
205 #endif
206 
load_file(const char * file)207 static gnutls_datum_t load_file(const char *file)
208 {
209   FILE *f;
210   gnutls_datum_t loaded_file = { NULL, 0 };
211   long filelen;
212   void *ptr;
213 
214   f = fopen(file, "rb");
215   if(!f)
216     return loaded_file;
217   if(fseek(f, 0, SEEK_END) != 0
218      || (filelen = ftell(f)) < 0
219      || fseek(f, 0, SEEK_SET) != 0
220      || !(ptr = malloc((size_t)filelen)))
221     goto out;
222   if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
223     free(ptr);
224     goto out;
225   }
226 
227   loaded_file.data = ptr;
228   loaded_file.size = (unsigned int)filelen;
229 out:
230   fclose(f);
231   return loaded_file;
232 }
233 
unload_file(gnutls_datum_t data)234 static void unload_file(gnutls_datum_t data)
235 {
236   free(data.data);
237 }
238 
239 
240 /* this function does a SSL/TLS (re-)handshake */
handshake(struct Curl_cfilter * cf,struct Curl_easy * data,bool duringconnect,bool nonblocking)241 static CURLcode handshake(struct Curl_cfilter *cf,
242                           struct Curl_easy *data,
243                           bool duringconnect,
244                           bool nonblocking)
245 {
246   struct ssl_connect_data *connssl = cf->ctx;
247   struct gtls_ssl_backend_data *backend =
248     (struct gtls_ssl_backend_data *)connssl->backend;
249   gnutls_session_t session;
250   curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
251 
252   DEBUGASSERT(backend);
253   session = backend->gtls.session;
254 
255   for(;;) {
256     timediff_t timeout_ms;
257     int rc;
258 
259     /* check allowed time left */
260     timeout_ms = Curl_timeleft(data, NULL, duringconnect);
261 
262     if(timeout_ms < 0) {
263       /* no need to continue if time already is up */
264       failf(data, "SSL connection timeout");
265       return CURLE_OPERATION_TIMEDOUT;
266     }
267 
268     /* if ssl is expecting something, check if it's available. */
269     if(connssl->connecting_state == ssl_connect_2_reading
270        || connssl->connecting_state == ssl_connect_2_writing) {
271       int what;
272       curl_socket_t writefd = ssl_connect_2_writing ==
273         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
274       curl_socket_t readfd = ssl_connect_2_reading ==
275         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
276 
277       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
278                                nonblocking?0:
279                                timeout_ms?timeout_ms:1000);
280       if(what < 0) {
281         /* fatal error */
282         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
283         return CURLE_SSL_CONNECT_ERROR;
284       }
285       else if(0 == what) {
286         if(nonblocking)
287           return CURLE_OK;
288         else if(timeout_ms) {
289           /* timeout */
290           failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
291           return CURLE_OPERATION_TIMEDOUT;
292         }
293       }
294       /* socket is readable or writable */
295     }
296 
297     backend->gtls.io_result = CURLE_OK;
298     rc = gnutls_handshake(session);
299 
300     if(!backend->gtls.trust_setup) {
301       /* After having send off the ClientHello, we prepare the trust
302        * store to verify the coming certificate from the server */
303       CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
304       if(result)
305         return result;
306     }
307 
308     if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
309       connssl->connecting_state =
310         gnutls_record_get_direction(session)?
311         ssl_connect_2_writing:ssl_connect_2_reading;
312       continue;
313     }
314     else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
315       const char *strerr = NULL;
316 
317       if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
318         int alert = gnutls_alert_get(session);
319         strerr = gnutls_alert_get_name(alert);
320       }
321 
322       if(!strerr)
323         strerr = gnutls_strerror(rc);
324 
325       infof(data, "gnutls_handshake() warning: %s", strerr);
326       continue;
327     }
328     else if((rc < 0) && backend->gtls.io_result) {
329       return backend->gtls.io_result;
330     }
331     else if(rc < 0) {
332       const char *strerr = NULL;
333 
334       if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
335         int alert = gnutls_alert_get(session);
336         strerr = gnutls_alert_get_name(alert);
337       }
338 
339       if(!strerr)
340         strerr = gnutls_strerror(rc);
341 
342       failf(data, "gnutls_handshake() failed: %s", strerr);
343       return CURLE_SSL_CONNECT_ERROR;
344     }
345 
346     /* Reset our connect state machine */
347     connssl->connecting_state = ssl_connect_1;
348     return CURLE_OK;
349   }
350 }
351 
do_file_type(const char * type)352 static gnutls_x509_crt_fmt_t do_file_type(const char *type)
353 {
354   if(!type || !type[0])
355     return GNUTLS_X509_FMT_PEM;
356   if(strcasecompare(type, "PEM"))
357     return GNUTLS_X509_FMT_PEM;
358   if(strcasecompare(type, "DER"))
359     return GNUTLS_X509_FMT_DER;
360   return GNUTLS_X509_FMT_PEM; /* default to PEM */
361 }
362 
363 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
364 /* If GnuTLS was compiled without support for SRP it will error out if SRP is
365    requested in the priority string, so treat it specially
366  */
367 #define GNUTLS_SRP "+SRP"
368 
369 static CURLcode
set_ssl_version_min_max(struct Curl_easy * data,struct ssl_peer * peer,struct ssl_primary_config * conn_config,const char ** prioritylist,const char * tls13support)370 set_ssl_version_min_max(struct Curl_easy *data,
371                         struct ssl_peer *peer,
372                         struct ssl_primary_config *conn_config,
373                         const char **prioritylist,
374                         const char *tls13support)
375 {
376   long ssl_version = conn_config->version;
377   long ssl_version_max = conn_config->version_max;
378 
379   if(peer->transport == TRNSPRT_QUIC) {
380     if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
381        (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
382       failf(data, "QUIC needs at least TLS version 1.3");
383       return CURLE_SSL_CONNECT_ERROR;
384      }
385     *prioritylist = QUIC_PRIORITY;
386     return CURLE_OK;
387   }
388 
389   if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
390      (ssl_version == CURL_SSLVERSION_TLSv1))
391     ssl_version = CURL_SSLVERSION_TLSv1_0;
392   if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
393     ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
394   if(!tls13support) {
395     /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a
396        prioritylist involving that since it will make GnuTLS return an en
397        error back at us */
398     if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
399        (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) {
400       ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
401     }
402   }
403   else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) {
404     ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
405   }
406 
407   switch(ssl_version | ssl_version_max) {
408   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
409     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
410       "+VERS-TLS1.0";
411     return CURLE_OK;
412   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
413     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
414       "+VERS-TLS1.1:+VERS-TLS1.0";
415     return CURLE_OK;
416   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
417     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
418       "+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0";
419     return CURLE_OK;
420   case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
421     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
422       "+VERS-TLS1.1";
423     return CURLE_OK;
424   case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
425     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
426       "+VERS-TLS1.2:+VERS-TLS1.1";
427     return CURLE_OK;
428   case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
429     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
430       "+VERS-TLS1.2";
431     return CURLE_OK;
432   case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3:
433     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
434       "+VERS-TLS1.3";
435     return CURLE_OK;
436   case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_3:
437     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0";
438     return CURLE_OK;
439   case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_3:
440     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
441       "+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1";
442     return CURLE_OK;
443   case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3:
444     *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
445       "+VERS-TLS1.3:+VERS-TLS1.2";
446     return CURLE_OK;
447   }
448 
449   failf(data, "GnuTLS: cannot set ssl protocol");
450   return CURLE_SSL_CONNECT_ERROR;
451 }
452 
Curl_gtls_client_trust_setup(struct Curl_cfilter * cf,struct Curl_easy * data,struct gtls_ctx * gtls)453 CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
454                                       struct Curl_easy *data,
455                                       struct gtls_ctx *gtls)
456 {
457   struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
458   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
459   int rc;
460 
461   CURL_TRC_CF(data, cf, "setup trust anchors and CRLs");
462   if(config->verifypeer) {
463     bool imported_native_ca = false;
464 
465     if(ssl_config->native_ca_store) {
466       rc = gnutls_certificate_set_x509_system_trust(gtls->cred);
467       if(rc < 0)
468         infof(data, "error reading native ca store (%s), continuing anyway",
469               gnutls_strerror(rc));
470       else {
471         infof(data, "found %d certificates in native ca store", rc);
472         if(rc > 0)
473           imported_native_ca = true;
474       }
475     }
476 
477     if(config->CAfile) {
478       /* set the trusted CA cert bundle file */
479       gnutls_certificate_set_verify_flags(gtls->cred,
480                                           GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
481 
482       rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
483                                                   config->CAfile,
484                                                   GNUTLS_X509_FMT_PEM);
485       if(rc < 0) {
486         infof(data, "error reading ca cert file %s (%s)%s",
487               config->CAfile, gnutls_strerror(rc),
488               (imported_native_ca ? ", continuing anyway" : ""));
489         if(!imported_native_ca) {
490           ssl_config->certverifyresult = rc;
491           return CURLE_SSL_CACERT_BADFILE;
492         }
493       }
494       else
495         infof(data, "found %d certificates in %s", rc, config->CAfile);
496     }
497 
498     if(config->CApath) {
499       /* set the trusted CA cert directory */
500       rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
501                                                  config->CApath,
502                                                  GNUTLS_X509_FMT_PEM);
503       if(rc < 0) {
504         infof(data, "error reading ca cert file %s (%s)%s",
505               config->CApath, gnutls_strerror(rc),
506               (imported_native_ca ? ", continuing anyway" : ""));
507         if(!imported_native_ca) {
508           ssl_config->certverifyresult = rc;
509           return CURLE_SSL_CACERT_BADFILE;
510         }
511       }
512       else
513         infof(data, "found %d certificates in %s", rc, config->CApath);
514     }
515   }
516 
517   if(config->CRLfile) {
518     /* set the CRL list file */
519     rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
520                                               config->CRLfile,
521                                               GNUTLS_X509_FMT_PEM);
522     if(rc < 0) {
523       failf(data, "error reading crl file %s (%s)",
524             config->CRLfile, gnutls_strerror(rc));
525       return CURLE_SSL_CRL_BADFILE;
526     }
527     else
528       infof(data, "found %d CRL in %s", rc, config->CRLfile);
529   }
530 
531   gtls->trust_setup = TRUE;
532   return CURLE_OK;
533 }
534 
gtls_sessionid_free(void * sessionid,size_t idsize)535 static void gtls_sessionid_free(void *sessionid, size_t idsize)
536 {
537   (void)idsize;
538   free(sessionid);
539 }
540 
gtls_update_session_id(struct Curl_cfilter * cf,struct Curl_easy * data,gnutls_session_t session)541 static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
542                                        struct Curl_easy *data,
543                                        gnutls_session_t session)
544 {
545   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
546   struct ssl_connect_data *connssl = cf->ctx;
547   CURLcode result = CURLE_OK;
548 
549   if(ssl_config->primary.sessionid) {
550     /* we always unconditionally get the session id here, as even if we
551        already got it from the cache and asked to use it in the connection, it
552        might've been rejected and then a new one is in use now and we need to
553        detect that. */
554     void *connect_sessionid;
555     size_t connect_idsize = 0;
556 
557     /* get the session ID data size */
558     gnutls_session_get_data(session, NULL, &connect_idsize);
559     connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
560     if(!connect_sessionid) {
561       return CURLE_OUT_OF_MEMORY;
562     }
563     else {
564       bool incache;
565       void *ssl_sessionid;
566 
567       /* extract session ID to the allocated buffer */
568       gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
569 
570       DEBUGF(infof(data, "get session id (len=%zu) and store in cache",
571                    connect_idsize));
572       Curl_ssl_sessionid_lock(data);
573       incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
574                                         &ssl_sessionid, NULL));
575       if(incache) {
576         /* there was one before in the cache, so instead of risking that the
577            previous one was rejected, we just kill that and store the new */
578         Curl_ssl_delsessionid(data, ssl_sessionid);
579       }
580 
581       /* store this session id, takes ownership */
582       result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
583                                      connect_sessionid, connect_idsize,
584                                      gtls_sessionid_free);
585       Curl_ssl_sessionid_unlock(data);
586     }
587   }
588   return result;
589 }
590 
gtls_handshake_cb(gnutls_session_t session,unsigned int htype,unsigned when,unsigned int incoming,const gnutls_datum_t * msg)591 static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
592                              unsigned when, unsigned int incoming,
593                              const gnutls_datum_t *msg)
594 {
595   struct Curl_cfilter *cf = gnutls_session_get_ptr(session);
596 
597   (void)msg;
598   (void)incoming;
599   if(when) { /* after message has been processed */
600     struct Curl_easy *data = CF_DATA_CURRENT(cf);
601     if(data) {
602       DEBUGF(infof(data, "handshake: %s message type %d",
603              incoming? "incoming" : "outgoing", htype));
604       switch(htype) {
605       case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
606         gtls_update_session_id(cf, data, session);
607         break;
608       }
609       default:
610         break;
611       }
612     }
613   }
614   return 0;
615 }
616 
gtls_client_init(struct Curl_cfilter * cf,struct Curl_easy * data,struct ssl_peer * peer,struct gtls_ctx * gtls)617 static CURLcode gtls_client_init(struct Curl_cfilter *cf,
618                                  struct Curl_easy *data,
619                                  struct ssl_peer *peer,
620                                  struct gtls_ctx *gtls)
621 {
622   struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
623   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
624   unsigned int init_flags;
625   int rc;
626   bool sni = TRUE; /* default is SNI enabled */
627   const char *prioritylist;
628   const char *err = NULL;
629   const char *tls13support;
630   CURLcode result;
631 
632   if(!gtls_inited)
633     gtls_init();
634 
635   if(config->version == CURL_SSLVERSION_SSLv2) {
636     failf(data, "GnuTLS does not support SSLv2");
637     return CURLE_SSL_CONNECT_ERROR;
638   }
639   else if(config->version == CURL_SSLVERSION_SSLv3)
640     sni = FALSE; /* SSLv3 has no SNI */
641 
642   /* allocate a cred struct */
643   rc = gnutls_certificate_allocate_credentials(&gtls->cred);
644   if(rc != GNUTLS_E_SUCCESS) {
645     failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
646     return CURLE_SSL_CONNECT_ERROR;
647   }
648 
649 #ifdef USE_GNUTLS_SRP
650   if(config->username && Curl_auth_allowed_to_host(data)) {
651     infof(data, "Using TLS-SRP username: %s", config->username);
652 
653     rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
654     if(rc != GNUTLS_E_SUCCESS) {
655       failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
656             gnutls_strerror(rc));
657       return CURLE_OUT_OF_MEMORY;
658     }
659 
660     rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
661                                            config->username,
662                                            config->password);
663     if(rc != GNUTLS_E_SUCCESS) {
664       failf(data, "gnutls_srp_set_client_cred() failed: %s",
665             gnutls_strerror(rc));
666       return CURLE_BAD_FUNCTION_ARGUMENT;
667     }
668   }
669 #endif
670 
671   ssl_config->certverifyresult = 0;
672 
673   /* Initialize TLS session as a client */
674   init_flags = GNUTLS_CLIENT;
675 
676 #if defined(GNUTLS_FORCE_CLIENT_CERT)
677   init_flags |= GNUTLS_FORCE_CLIENT_CERT;
678 #endif
679 
680 #if defined(GNUTLS_NO_TICKETS)
681   /* Disable TLS session tickets */
682   init_flags |= GNUTLS_NO_TICKETS;
683 #endif
684 
685   rc = gnutls_init(&gtls->session, init_flags);
686   if(rc != GNUTLS_E_SUCCESS) {
687     failf(data, "gnutls_init() failed: %d", rc);
688     return CURLE_SSL_CONNECT_ERROR;
689   }
690 
691   if(sni && peer->sni) {
692     if(gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
693                               peer->sni, strlen(peer->sni)) < 0) {
694       failf(data, "Failed to set SNI");
695       return CURLE_SSL_CONNECT_ERROR;
696     }
697   }
698 
699   /* Use default priorities */
700   rc = gnutls_set_default_priority(gtls->session);
701   if(rc != GNUTLS_E_SUCCESS)
702     return CURLE_SSL_CONNECT_ERROR;
703 
704   /* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */
705   tls13support = gnutls_check_version("3.6.5");
706 
707   /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
708    * removed if a run-time error indicates that SRP is not supported by this
709    * GnuTLS version */
710 
711   if(config->version == CURL_SSLVERSION_SSLv2 ||
712      config->version == CURL_SSLVERSION_SSLv3) {
713     failf(data, "GnuTLS does not support SSLv2 or SSLv3");
714     return CURLE_SSL_CONNECT_ERROR;
715   }
716 
717   if(config->version == CURL_SSLVERSION_TLSv1_3) {
718     if(!tls13support) {
719       failf(data, "This GnuTLS installation does not support TLS 1.3");
720       return CURLE_SSL_CONNECT_ERROR;
721     }
722   }
723 
724   /* At this point we know we have a supported TLS version, so set it */
725   result = set_ssl_version_min_max(data, peer,
726                                    config, &prioritylist, tls13support);
727   if(result)
728     return result;
729 
730 #ifdef USE_GNUTLS_SRP
731   /* Only add SRP to the cipher list if SRP is requested. Otherwise
732    * GnuTLS will disable TLS 1.3 support. */
733   if(config->username) {
734     char *prioritysrp = aprintf("%s:" GNUTLS_SRP, prioritylist);
735     if(!prioritysrp)
736       return CURLE_OUT_OF_MEMORY;
737     rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err);
738     free(prioritysrp);
739 
740     if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
741       infof(data, "This GnuTLS does not support SRP");
742     }
743   }
744   else {
745 #endif
746     infof(data, "GnuTLS ciphers: %s", prioritylist);
747     rc = gnutls_priority_set_direct(gtls->session, prioritylist, &err);
748 #ifdef USE_GNUTLS_SRP
749   }
750 #endif
751 
752   if(rc != GNUTLS_E_SUCCESS) {
753     failf(data, "Error %d setting GnuTLS cipher list starting with %s",
754           rc, err);
755     return CURLE_SSL_CONNECT_ERROR;
756   }
757 
758   if(config->clientcert) {
759     if(!gtls->trust_setup) {
760       result = Curl_gtls_client_trust_setup(cf, data, gtls);
761       if(result)
762         return result;
763     }
764     if(ssl_config->key_passwd) {
765       const unsigned int supported_key_encryption_algorithms =
766         GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
767         GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
768         GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
769         GNUTLS_PKCS_USE_PBES2_AES_256;
770       rc = gnutls_certificate_set_x509_key_file2(
771            gtls->cred,
772            config->clientcert,
773            ssl_config->key ? ssl_config->key : config->clientcert,
774            do_file_type(ssl_config->cert_type),
775            ssl_config->key_passwd,
776            supported_key_encryption_algorithms);
777       if(rc != GNUTLS_E_SUCCESS) {
778         failf(data,
779               "error reading X.509 potentially-encrypted key file: %s",
780               gnutls_strerror(rc));
781         return CURLE_SSL_CONNECT_ERROR;
782       }
783     }
784     else {
785       if(gnutls_certificate_set_x509_key_file(
786            gtls->cred,
787            config->clientcert,
788            ssl_config->key ? ssl_config->key : config->clientcert,
789            do_file_type(ssl_config->cert_type) ) !=
790          GNUTLS_E_SUCCESS) {
791         failf(data, "error reading X.509 key or certificate file");
792         return CURLE_SSL_CONNECT_ERROR;
793       }
794     }
795   }
796 
797 #ifdef USE_GNUTLS_SRP
798   /* put the credentials to the current session */
799   if(config->username) {
800     rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_SRP,
801                                 gtls->srp_client_cred);
802     if(rc != GNUTLS_E_SUCCESS) {
803       failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
804       return CURLE_SSL_CONNECT_ERROR;
805     }
806   }
807   else
808 #endif
809   {
810     rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
811                                 gtls->cred);
812     if(rc != GNUTLS_E_SUCCESS) {
813       failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
814       return CURLE_SSL_CONNECT_ERROR;
815     }
816   }
817 
818   if(config->verifystatus) {
819     rc = gnutls_ocsp_status_request_enable_client(gtls->session,
820                                                   NULL, 0, NULL);
821     if(rc != GNUTLS_E_SUCCESS) {
822       failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
823       return CURLE_SSL_CONNECT_ERROR;
824     }
825   }
826 
827   return CURLE_OK;
828 }
829 
keylog_callback(gnutls_session_t session,const char * label,const gnutls_datum_t * secret)830 static int keylog_callback(gnutls_session_t session, const char *label,
831                            const gnutls_datum_t *secret)
832 {
833   gnutls_datum_t crandom;
834   gnutls_datum_t srandom;
835 
836   gnutls_session_get_random(session, &crandom, &srandom);
837   if(crandom.size != 32) {
838     return -1;
839   }
840 
841   Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
842   return 0;
843 }
844 
Curl_gtls_ctx_init(struct gtls_ctx * gctx,struct Curl_cfilter * cf,struct Curl_easy * data,struct ssl_peer * peer,const unsigned char * alpn,size_t alpn_len,Curl_gtls_ctx_setup_cb * cb_setup,void * cb_user_data,void * ssl_user_data)845 CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
846                             struct Curl_cfilter *cf,
847                             struct Curl_easy *data,
848                             struct ssl_peer *peer,
849                             const unsigned char *alpn, size_t alpn_len,
850                             Curl_gtls_ctx_setup_cb *cb_setup,
851                             void *cb_user_data,
852                             void *ssl_user_data)
853 {
854   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
855   CURLcode result;
856 
857   DEBUGASSERT(gctx);
858 
859   result = gtls_client_init(cf, data, peer, gctx);
860   if(result)
861     return result;
862 
863   gnutls_session_set_ptr(gctx->session, ssl_user_data);
864 
865   if(cb_setup) {
866     result = cb_setup(cf, data, cb_user_data);
867     if(result)
868       return result;
869   }
870 
871   /* Open the file if a TLS or QUIC backend has not done this before. */
872   Curl_tls_keylog_open();
873   if(Curl_tls_keylog_enabled()) {
874     gnutls_session_set_keylog_function(gctx->session, keylog_callback);
875   }
876 
877   /* convert the ALPN string from our arguments to a list of strings
878    * that gnutls wants and will convert internally back to this very
879    * string for sending to the server. nice. */
880   if(alpn && alpn_len) {
881     gnutls_datum_t alpns[5];
882     size_t i, alen = alpn_len;
883     unsigned char *s = (unsigned char *)alpn;
884     unsigned char slen;
885     for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
886       slen = s[0];
887       if(slen >= alen)
888         return CURLE_FAILED_INIT;
889       alpns[i].data = s + 1;
890       alpns[i].size = slen;
891       s += slen + 1;
892       alen -= (size_t)slen + 1;
893     }
894     if(alen) /* not all alpn chars used, wrong format or too many */
895         return CURLE_FAILED_INIT;
896     if(i && gnutls_alpn_set_protocols(gctx->session,
897                                       alpns, (unsigned int)i,
898                                       GNUTLS_ALPN_MANDATORY)) {
899       failf(data, "failed setting ALPN");
900       return CURLE_SSL_CONNECT_ERROR;
901     }
902   }
903 
904   /* This might be a reconnect, so we check for a session ID in the cache
905      to speed up things */
906   if(conn_config->sessionid) {
907     void *ssl_sessionid;
908     size_t ssl_idsize;
909 
910     Curl_ssl_sessionid_lock(data);
911     if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
912       /* we got a session id, use it! */
913       int rc;
914 
915       rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
916       if(rc < 0)
917         infof(data, "SSL failed to set session ID");
918       else
919         infof(data, "SSL reusing session ID (size=%zu)", ssl_idsize);
920     }
921     Curl_ssl_sessionid_unlock(data);
922   }
923   return CURLE_OK;
924 }
925 
926 static CURLcode
gtls_connect_step1(struct Curl_cfilter * cf,struct Curl_easy * data)927 gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
928 {
929   struct ssl_connect_data *connssl = cf->ctx;
930   struct gtls_ssl_backend_data *backend =
931     (struct gtls_ssl_backend_data *)connssl->backend;
932   struct alpn_proto_buf proto;
933   CURLcode result;
934 
935   DEBUGASSERT(backend);
936   DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
937 
938   if(connssl->state == ssl_connection_complete)
939     /* to make us tolerant against being called more than once for the
940        same connection */
941     return CURLE_OK;
942 
943   memset(&proto, 0, sizeof(proto));
944   if(connssl->alpn) {
945     result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
946     if(result) {
947       failf(data, "Error determining ALPN");
948       return CURLE_SSL_CONNECT_ERROR;
949     }
950   }
951 
952   result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
953                               proto.data, proto.len, NULL, NULL, cf);
954   if(result)
955     return result;
956 
957   gnutls_handshake_set_hook_function(backend->gtls.session,
958                                      GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
959                                      gtls_handshake_cb);
960 
961   /* register callback functions and handle to send and receive data. */
962   gnutls_transport_set_ptr(backend->gtls.session, cf);
963   gnutls_transport_set_push_function(backend->gtls.session, gtls_push);
964   gnutls_transport_set_pull_function(backend->gtls.session, gtls_pull);
965 
966   return CURLE_OK;
967 }
968 
pkp_pin_peer_pubkey(struct Curl_easy * data,gnutls_x509_crt_t cert,const char * pinnedpubkey)969 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
970                                     gnutls_x509_crt_t cert,
971                                     const char *pinnedpubkey)
972 {
973   /* Scratch */
974   size_t len1 = 0, len2 = 0;
975   unsigned char *buff1 = NULL;
976 
977   gnutls_pubkey_t key = NULL;
978 
979   /* Result is returned to caller */
980   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
981 
982   /* if a path wasn't specified, don't pin */
983   if(!pinnedpubkey)
984     return CURLE_OK;
985 
986   if(!cert)
987     return result;
988 
989   do {
990     int ret;
991 
992     /* Begin Gyrations to get the public key     */
993     gnutls_pubkey_init(&key);
994 
995     ret = gnutls_pubkey_import_x509(key, cert, 0);
996     if(ret < 0)
997       break; /* failed */
998 
999     ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
1000     if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
1001       break; /* failed */
1002 
1003     buff1 = malloc(len1);
1004     if(!buff1)
1005       break; /* failed */
1006 
1007     len2 = len1;
1008 
1009     ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
1010     if(ret < 0 || len1 != len2)
1011       break; /* failed */
1012 
1013     /* End Gyrations */
1014 
1015     /* The one good exit point */
1016     result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
1017   } while(0);
1018 
1019   if(key)
1020     gnutls_pubkey_deinit(key);
1021 
1022   Curl_safefree(buff1);
1023 
1024   return result;
1025 }
1026 
1027 CURLcode
Curl_gtls_verifyserver(struct Curl_easy * data,gnutls_session_t session,struct ssl_primary_config * config,struct ssl_config_data * ssl_config,struct ssl_peer * peer,const char * pinned_key)1028 Curl_gtls_verifyserver(struct Curl_easy *data,
1029                        gnutls_session_t session,
1030                        struct ssl_primary_config *config,
1031                        struct ssl_config_data *ssl_config,
1032                        struct ssl_peer *peer,
1033                        const char *pinned_key)
1034 {
1035   unsigned int cert_list_size;
1036   const gnutls_datum_t *chainp;
1037   unsigned int verify_status = 0;
1038   gnutls_x509_crt_t x509_cert, x509_issuer;
1039   gnutls_datum_t issuerp;
1040   gnutls_datum_t certfields;
1041   char certname[65] = ""; /* limited to 64 chars by ASN.1 */
1042   size_t size;
1043   time_t certclock;
1044   int rc;
1045   CURLcode result = CURLE_OK;
1046 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1047   const char *ptr;
1048   unsigned int algo;
1049   unsigned int bits;
1050   gnutls_protocol_t version = gnutls_protocol_get_version(session);
1051 #endif
1052   long * const certverifyresult = &ssl_config->certverifyresult;
1053 
1054 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1055   /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
1056   ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
1057                                      gnutls_cipher_get(session),
1058                                      gnutls_mac_get(session));
1059 
1060   infof(data, "SSL connection using %s / %s",
1061         gnutls_protocol_get_name(version), ptr);
1062 #endif
1063 
1064   /* This function will return the peer's raw certificate (chain) as sent by
1065      the peer. These certificates are in raw format (DER encoded for
1066      X.509). In case of a X.509 then a certificate list may be present. The
1067      first certificate in the list is the peer's certificate, following the
1068      issuer's certificate, then the issuer's issuer etc. */
1069 
1070   chainp = gnutls_certificate_get_peers(session, &cert_list_size);
1071   if(!chainp) {
1072     if(config->verifypeer ||
1073        config->verifyhost ||
1074        config->issuercert) {
1075 #ifdef USE_GNUTLS_SRP
1076       if(ssl_config->primary.username && !config->verifypeer &&
1077          gnutls_cipher_get(session)) {
1078         /* no peer cert, but auth is ok if we have SRP user and cipher and no
1079            peer verify */
1080       }
1081       else {
1082 #endif
1083         failf(data, "failed to get server cert");
1084         *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND;
1085         return CURLE_PEER_FAILED_VERIFICATION;
1086 #ifdef USE_GNUTLS_SRP
1087       }
1088 #endif
1089     }
1090     infof(data, " common name: WARNING couldn't obtain");
1091   }
1092 
1093   if(data->set.ssl.certinfo && chainp) {
1094     unsigned int i;
1095 
1096     result = Curl_ssl_init_certinfo(data, cert_list_size);
1097     if(result)
1098       return result;
1099 
1100     for(i = 0; i < cert_list_size; i++) {
1101       const char *beg = (const char *) chainp[i].data;
1102       const char *end = beg + chainp[i].size;
1103 
1104       result = Curl_extract_certinfo(data, i, beg, end);
1105       if(result)
1106         return result;
1107     }
1108   }
1109 
1110   if(config->verifypeer) {
1111     /* This function will try to verify the peer's certificate and return its
1112        status (trusted, invalid etc.). The value of status should be one or
1113        more of the gnutls_certificate_status_t enumerated elements bitwise
1114        or'd. To avoid denial of service attacks some default upper limits
1115        regarding the certificate key size and chain size are set. To override
1116        them use gnutls_certificate_set_verify_limits(). */
1117 
1118     rc = gnutls_certificate_verify_peers2(session, &verify_status);
1119     if(rc < 0) {
1120       failf(data, "server cert verify failed: %d", rc);
1121       *certverifyresult = rc;
1122       return CURLE_SSL_CONNECT_ERROR;
1123     }
1124 
1125     *certverifyresult = verify_status;
1126 
1127     /* verify_status is a bitmask of gnutls_certificate_status bits */
1128     if(verify_status & GNUTLS_CERT_INVALID) {
1129       if(config->verifypeer) {
1130         failf(data, "server certificate verification failed. CAfile: %s "
1131               "CRLfile: %s", config->CAfile ? config->CAfile:
1132               "none",
1133               ssl_config->primary.CRLfile ?
1134               ssl_config->primary.CRLfile : "none");
1135         return CURLE_PEER_FAILED_VERIFICATION;
1136       }
1137       else
1138         infof(data, "  server certificate verification FAILED");
1139     }
1140     else
1141       infof(data, "  server certificate verification OK");
1142   }
1143   else
1144     infof(data, "  server certificate verification SKIPPED");
1145 
1146   if(config->verifystatus) {
1147     if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
1148       gnutls_datum_t status_request;
1149       gnutls_ocsp_resp_t ocsp_resp;
1150 
1151       gnutls_ocsp_cert_status_t status;
1152       gnutls_x509_crl_reason_t reason;
1153 
1154       rc = gnutls_ocsp_status_request_get(session, &status_request);
1155 
1156       infof(data, " server certificate status verification FAILED");
1157 
1158       if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1159         failf(data, "No OCSP response received");
1160         return CURLE_SSL_INVALIDCERTSTATUS;
1161       }
1162 
1163       if(rc < 0) {
1164         failf(data, "Invalid OCSP response received");
1165         return CURLE_SSL_INVALIDCERTSTATUS;
1166       }
1167 
1168       gnutls_ocsp_resp_init(&ocsp_resp);
1169 
1170       rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
1171       if(rc < 0) {
1172         failf(data, "Invalid OCSP response received");
1173         return CURLE_SSL_INVALIDCERTSTATUS;
1174       }
1175 
1176       (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
1177                                         &status, NULL, NULL, NULL, &reason);
1178 
1179       switch(status) {
1180       case GNUTLS_OCSP_CERT_GOOD:
1181         break;
1182 
1183       case GNUTLS_OCSP_CERT_REVOKED: {
1184         const char *crl_reason;
1185 
1186         switch(reason) {
1187           default:
1188           case GNUTLS_X509_CRLREASON_UNSPECIFIED:
1189             crl_reason = "unspecified reason";
1190             break;
1191 
1192           case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
1193             crl_reason = "private key compromised";
1194             break;
1195 
1196           case GNUTLS_X509_CRLREASON_CACOMPROMISE:
1197             crl_reason = "CA compromised";
1198             break;
1199 
1200           case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
1201             crl_reason = "affiliation has changed";
1202             break;
1203 
1204           case GNUTLS_X509_CRLREASON_SUPERSEDED:
1205             crl_reason = "certificate superseded";
1206             break;
1207 
1208           case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
1209             crl_reason = "operation has ceased";
1210             break;
1211 
1212           case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
1213             crl_reason = "certificate is on hold";
1214             break;
1215 
1216           case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
1217             crl_reason = "will be removed from delta CRL";
1218             break;
1219 
1220           case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
1221             crl_reason = "privilege withdrawn";
1222             break;
1223 
1224           case GNUTLS_X509_CRLREASON_AACOMPROMISE:
1225             crl_reason = "AA compromised";
1226             break;
1227         }
1228 
1229         failf(data, "Server certificate was revoked: %s", crl_reason);
1230         break;
1231       }
1232 
1233       default:
1234       case GNUTLS_OCSP_CERT_UNKNOWN:
1235         failf(data, "Server certificate status is unknown");
1236         break;
1237       }
1238 
1239       gnutls_ocsp_resp_deinit(ocsp_resp);
1240 
1241       return CURLE_SSL_INVALIDCERTSTATUS;
1242     }
1243     else
1244       infof(data, "  server certificate status verification OK");
1245   }
1246   else
1247     infof(data, "  server certificate status verification SKIPPED");
1248 
1249   /* initialize an X.509 certificate structure. */
1250   gnutls_x509_crt_init(&x509_cert);
1251 
1252   if(chainp)
1253     /* convert the given DER or PEM encoded Certificate to the native
1254        gnutls_x509_crt_t format */
1255     gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
1256 
1257   if(config->issuercert) {
1258     gnutls_x509_crt_init(&x509_issuer);
1259     issuerp = load_file(config->issuercert);
1260     gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
1261     rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
1262     gnutls_x509_crt_deinit(x509_issuer);
1263     unload_file(issuerp);
1264     if(rc <= 0) {
1265       failf(data, "server certificate issuer check failed (IssuerCert: %s)",
1266             config->issuercert?config->issuercert:"none");
1267       gnutls_x509_crt_deinit(x509_cert);
1268       return CURLE_SSL_ISSUER_ERROR;
1269     }
1270     infof(data, "  server certificate issuer check OK (Issuer Cert: %s)",
1271           config->issuercert?config->issuercert:"none");
1272   }
1273 
1274   size = sizeof(certname);
1275   rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
1276                                      0, /* the first and only one */
1277                                      FALSE,
1278                                      certname,
1279                                      &size);
1280   if(rc) {
1281     infof(data, "error fetching CN from cert:%s",
1282           gnutls_strerror(rc));
1283   }
1284 
1285   /* This function will check if the given certificate's subject matches the
1286      given hostname. This is a basic implementation of the matching described
1287      in RFC2818 (HTTPS), which takes into account wildcards, and the subject
1288      alternative name PKIX extension. Returns non zero on success, and zero on
1289      failure. */
1290   rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);
1291 #if GNUTLS_VERSION_NUMBER < 0x030306
1292   /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
1293      addresses. */
1294   if(!rc) {
1295 #ifdef USE_IPV6
1296     #define use_addr in6_addr
1297 #else
1298     #define use_addr in_addr
1299 #endif
1300     unsigned char addrbuf[sizeof(struct use_addr)];
1301     size_t addrlen = 0;
1302 
1303     if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
1304       addrlen = 4;
1305 #ifdef USE_IPV6
1306     else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
1307       addrlen = 16;
1308 #endif
1309 
1310     if(addrlen) {
1311       unsigned char certaddr[sizeof(struct use_addr)];
1312       int i;
1313 
1314       for(i = 0; ; i++) {
1315         size_t certaddrlen = sizeof(certaddr);
1316         int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
1317                                                        &certaddrlen, NULL);
1318         /* If this happens, it wasn't an IP address. */
1319         if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
1320           continue;
1321         if(ret < 0)
1322           break;
1323         if(ret != GNUTLS_SAN_IPADDRESS)
1324           continue;
1325         if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
1326           rc = 1;
1327           break;
1328         }
1329       }
1330     }
1331   }
1332 #endif
1333   if(!rc) {
1334     if(config->verifyhost) {
1335       failf(data, "SSL: certificate subject name (%s) does not match "
1336             "target host name '%s'", certname, peer->dispname);
1337       gnutls_x509_crt_deinit(x509_cert);
1338       return CURLE_PEER_FAILED_VERIFICATION;
1339     }
1340     else
1341       infof(data, "  common name: %s (does not match '%s')",
1342             certname, peer->dispname);
1343   }
1344   else
1345     infof(data, "  common name: %s (matched)", certname);
1346 
1347   /* Check for time-based validity */
1348   certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1349 
1350   if(certclock == (time_t)-1) {
1351     if(config->verifypeer) {
1352       failf(data, "server cert expiration date verify failed");
1353       *certverifyresult = GNUTLS_CERT_EXPIRED;
1354       gnutls_x509_crt_deinit(x509_cert);
1355       return CURLE_SSL_CONNECT_ERROR;
1356     }
1357     else
1358       infof(data, "  server certificate expiration date verify FAILED");
1359   }
1360   else {
1361     if(certclock < time(NULL)) {
1362       if(config->verifypeer) {
1363         failf(data, "server certificate expiration date has passed.");
1364         *certverifyresult = GNUTLS_CERT_EXPIRED;
1365         gnutls_x509_crt_deinit(x509_cert);
1366         return CURLE_PEER_FAILED_VERIFICATION;
1367       }
1368       else
1369         infof(data, "  server certificate expiration date FAILED");
1370     }
1371     else
1372       infof(data, "  server certificate expiration date OK");
1373   }
1374 
1375   certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1376 
1377   if(certclock == (time_t)-1) {
1378     if(config->verifypeer) {
1379       failf(data, "server cert activation date verify failed");
1380       *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
1381       gnutls_x509_crt_deinit(x509_cert);
1382       return CURLE_SSL_CONNECT_ERROR;
1383     }
1384     else
1385       infof(data, "  server certificate activation date verify FAILED");
1386   }
1387   else {
1388     if(certclock > time(NULL)) {
1389       if(config->verifypeer) {
1390         failf(data, "server certificate not activated yet.");
1391         *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
1392         gnutls_x509_crt_deinit(x509_cert);
1393         return CURLE_PEER_FAILED_VERIFICATION;
1394       }
1395       else
1396         infof(data, "  server certificate activation date FAILED");
1397     }
1398     else
1399       infof(data, "  server certificate activation date OK");
1400   }
1401 
1402   if(pinned_key) {
1403     result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key);
1404     if(result != CURLE_OK) {
1405       failf(data, "SSL: public key does not match pinned public key");
1406       gnutls_x509_crt_deinit(x509_cert);
1407       return result;
1408     }
1409   }
1410 
1411   /* Show:
1412 
1413   - subject
1414   - start date
1415   - expire date
1416   - common name
1417   - issuer
1418 
1419   */
1420 
1421 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1422   /* public key algorithm's parameters */
1423   algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
1424   infof(data, "  certificate public key: %s",
1425         gnutls_pk_algorithm_get_name(algo));
1426 
1427   /* version of the X.509 certificate. */
1428   infof(data, "  certificate version: #%d",
1429         gnutls_x509_crt_get_version(x509_cert));
1430 
1431 
1432   rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
1433   if(rc)
1434     infof(data, "Failed to get certificate name");
1435   else {
1436     infof(data, "  subject: %s", certfields.data);
1437 
1438     certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1439     showtime(data, "start date", certclock);
1440 
1441     certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1442     showtime(data, "expire date", certclock);
1443 
1444     gnutls_free(certfields.data);
1445   }
1446 
1447   rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
1448   if(rc)
1449     infof(data, "Failed to get certificate issuer");
1450   else {
1451     infof(data, "  issuer: %s", certfields.data);
1452 
1453     gnutls_free(certfields.data);
1454   }
1455 #endif
1456 
1457   gnutls_x509_crt_deinit(x509_cert);
1458 
1459   return result;
1460 }
1461 
gtls_verifyserver(struct Curl_cfilter * cf,struct Curl_easy * data,gnutls_session_t session)1462 static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
1463                                   struct Curl_easy *data,
1464                                   gnutls_session_t session)
1465 {
1466   struct ssl_connect_data *connssl = cf->ctx;
1467   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1468   struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1469 #ifndef CURL_DISABLE_PROXY
1470   const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
1471     data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
1472     data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1473 #else
1474   const char *pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1475 #endif
1476   CURLcode result;
1477 
1478   result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
1479                                   &connssl->peer, pinned_key);
1480   if(result)
1481     goto out;
1482 
1483   if(connssl->alpn) {
1484     gnutls_datum_t proto;
1485     int rc;
1486 
1487     rc = gnutls_alpn_get_selected_protocol(session, &proto);
1488     if(rc == 0)
1489       Curl_alpn_set_negotiated(cf, data, proto.data, proto.size);
1490     else
1491       Curl_alpn_set_negotiated(cf, data, NULL, 0);
1492   }
1493 
1494   /* Only on TLSv1.2 or lower do we have the session id now. For
1495    * TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */
1496   if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3)
1497     result = gtls_update_session_id(cf, data, session);
1498 
1499 out:
1500   return result;
1501 }
1502 
1503 /*
1504  * This function is called after the TCP connect has completed. Setup the TLS
1505  * layer and do all necessary magic.
1506  */
1507 /* We use connssl->connecting_state to keep track of the connection status;
1508    there are three states: 'ssl_connect_1' (not started yet or complete),
1509    'ssl_connect_2_reading' (waiting for data from server), and
1510    'ssl_connect_2_writing' (waiting to be able to write).
1511  */
1512 static CURLcode
gtls_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool nonblocking,bool * done)1513 gtls_connect_common(struct Curl_cfilter *cf,
1514                     struct Curl_easy *data,
1515                     bool nonblocking,
1516                     bool *done)
1517 {
1518   struct ssl_connect_data *connssl = cf->ctx;
1519   int rc;
1520   CURLcode result = CURLE_OK;
1521 
1522   /* Initiate the connection, if not already done */
1523   if(ssl_connect_1 == connssl->connecting_state) {
1524     rc = gtls_connect_step1(cf, data);
1525     if(rc) {
1526       result = rc;
1527       goto out;
1528     }
1529   }
1530 
1531   rc = handshake(cf, data, TRUE, nonblocking);
1532   if(rc) {
1533     /* handshake() sets its own error message with failf() */
1534     result = rc;
1535     goto out;
1536   }
1537 
1538   /* Finish connecting once the handshake is done */
1539   if(ssl_connect_1 == connssl->connecting_state) {
1540     struct gtls_ssl_backend_data *backend =
1541       (struct gtls_ssl_backend_data *)connssl->backend;
1542     gnutls_session_t session;
1543     DEBUGASSERT(backend);
1544     session = backend->gtls.session;
1545     rc = gtls_verifyserver(cf, data, session);
1546     if(rc) {
1547       result = rc;
1548       goto out;
1549     }
1550     connssl->state = ssl_connection_complete;
1551   }
1552 
1553 out:
1554   *done = ssl_connect_1 == connssl->connecting_state;
1555 
1556   return result;
1557 }
1558 
gtls_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)1559 static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf,
1560                                          struct Curl_easy *data,
1561                                          bool *done)
1562 {
1563   return gtls_connect_common(cf, data, TRUE, done);
1564 }
1565 
gtls_connect(struct Curl_cfilter * cf,struct Curl_easy * data)1566 static CURLcode gtls_connect(struct Curl_cfilter *cf,
1567                              struct Curl_easy *data)
1568 {
1569   CURLcode result;
1570   bool done = FALSE;
1571 
1572   result = gtls_connect_common(cf, data, FALSE, &done);
1573   if(result)
1574     return result;
1575 
1576   DEBUGASSERT(done);
1577 
1578   return CURLE_OK;
1579 }
1580 
gtls_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1581 static bool gtls_data_pending(struct Curl_cfilter *cf,
1582                               const struct Curl_easy *data)
1583 {
1584   struct ssl_connect_data *ctx = cf->ctx;
1585   struct gtls_ssl_backend_data *backend;
1586 
1587   (void)data;
1588   DEBUGASSERT(ctx && ctx->backend);
1589   backend = (struct gtls_ssl_backend_data *)ctx->backend;
1590   if(backend->gtls.session &&
1591      0 != gnutls_record_check_pending(backend->gtls.session))
1592     return TRUE;
1593   return FALSE;
1594 }
1595 
gtls_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * mem,size_t len,CURLcode * curlcode)1596 static ssize_t gtls_send(struct Curl_cfilter *cf,
1597                          struct Curl_easy *data,
1598                          const void *mem,
1599                          size_t len,
1600                          CURLcode *curlcode)
1601 {
1602   struct ssl_connect_data *connssl = cf->ctx;
1603   struct gtls_ssl_backend_data *backend =
1604     (struct gtls_ssl_backend_data *)connssl->backend;
1605   ssize_t rc;
1606 
1607   (void)data;
1608   DEBUGASSERT(backend);
1609   backend->gtls.io_result = CURLE_OK;
1610   rc = gnutls_record_send(backend->gtls.session, mem, len);
1611 
1612   if(rc < 0) {
1613     *curlcode = (rc == GNUTLS_E_AGAIN)?
1614       CURLE_AGAIN :
1615       (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
1616 
1617     rc = -1;
1618   }
1619 
1620   return rc;
1621 }
1622 
gtls_close(struct Curl_cfilter * cf,struct Curl_easy * data)1623 static void gtls_close(struct Curl_cfilter *cf,
1624                        struct Curl_easy *data)
1625 {
1626   struct ssl_connect_data *connssl = cf->ctx;
1627   struct gtls_ssl_backend_data *backend =
1628     (struct gtls_ssl_backend_data *)connssl->backend;
1629 
1630   (void) data;
1631   DEBUGASSERT(backend);
1632 
1633   if(backend->gtls.session) {
1634     char buf[32];
1635     /* Maybe the server has already sent a close notify alert.
1636        Read it to avoid an RST on the TCP connection. */
1637     (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
1638     gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
1639     gnutls_deinit(backend->gtls.session);
1640     backend->gtls.session = NULL;
1641   }
1642   if(backend->gtls.cred) {
1643     gnutls_certificate_free_credentials(backend->gtls.cred);
1644     backend->gtls.cred = NULL;
1645   }
1646 #ifdef USE_GNUTLS_SRP
1647   if(backend->gtls.srp_client_cred) {
1648     gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
1649     backend->gtls.srp_client_cred = NULL;
1650   }
1651 #endif
1652 }
1653 
1654 /*
1655  * This function is called to shut down the SSL layer but keep the
1656  * socket open (CCC - Clear Command Channel)
1657  */
gtls_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data)1658 static int gtls_shutdown(struct Curl_cfilter *cf,
1659                          struct Curl_easy *data)
1660 {
1661   struct ssl_connect_data *connssl = cf->ctx;
1662   struct gtls_ssl_backend_data *backend =
1663     (struct gtls_ssl_backend_data *)connssl->backend;
1664   int retval = 0;
1665 
1666   DEBUGASSERT(backend);
1667 
1668 #ifndef CURL_DISABLE_FTP
1669   /* This has only been tested on the proftpd server, and the mod_tls code
1670      sends a close notify alert without waiting for a close notify alert in
1671      response. Thus we wait for a close notify alert from the server, but
1672      we do not send one. Let's hope other servers do the same... */
1673 
1674   if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
1675     gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
1676 #endif
1677 
1678   if(backend->gtls.session) {
1679     ssize_t result;
1680     bool done = FALSE;
1681     char buf[120];
1682 
1683     while(!done && !connssl->peer_closed) {
1684       int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
1685                                  SSL_SHUTDOWN_TIMEOUT);
1686       if(what > 0) {
1687         /* Something to read, let's do it and hope that it is the close
1688            notify alert from the server */
1689         result = gnutls_record_recv(backend->gtls.session,
1690                                     buf, sizeof(buf));
1691         switch(result) {
1692         case 0:
1693           /* This is the expected response. There was no data but only
1694              the close notify alert */
1695           done = TRUE;
1696           break;
1697         case GNUTLS_E_AGAIN:
1698         case GNUTLS_E_INTERRUPTED:
1699           infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
1700           break;
1701         default:
1702           retval = -1;
1703           done = TRUE;
1704           break;
1705         }
1706       }
1707       else if(0 == what) {
1708         /* timeout */
1709         failf(data, "SSL shutdown timeout");
1710         done = TRUE;
1711       }
1712       else {
1713         /* anything that gets here is fatally bad */
1714         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1715         retval = -1;
1716         done = TRUE;
1717       }
1718     }
1719     gnutls_deinit(backend->gtls.session);
1720   }
1721   gnutls_certificate_free_credentials(backend->gtls.cred);
1722 
1723 #ifdef USE_GNUTLS_SRP
1724   {
1725     struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1726     if(ssl_config->primary.username)
1727       gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
1728   }
1729 #endif
1730 
1731   backend->gtls.cred = NULL;
1732   backend->gtls.session = NULL;
1733 
1734   return retval;
1735 }
1736 
gtls_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t buffersize,CURLcode * curlcode)1737 static ssize_t gtls_recv(struct Curl_cfilter *cf,
1738                          struct Curl_easy *data,
1739                          char *buf,
1740                          size_t buffersize,
1741                          CURLcode *curlcode)
1742 {
1743   struct ssl_connect_data *connssl = cf->ctx;
1744   struct gtls_ssl_backend_data *backend =
1745     (struct gtls_ssl_backend_data *)connssl->backend;
1746   ssize_t ret;
1747 
1748   (void)data;
1749   DEBUGASSERT(backend);
1750 
1751   backend->gtls.io_result = CURLE_OK;
1752   ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
1753   if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
1754     *curlcode = CURLE_AGAIN;
1755     ret = -1;
1756     goto out;
1757   }
1758 
1759   if(ret == GNUTLS_E_REHANDSHAKE) {
1760     /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
1761        proper way" takes a whole lot of work. */
1762     CURLcode result = handshake(cf, data, FALSE, FALSE);
1763     if(result)
1764       /* handshake() writes error message on its own */
1765       *curlcode = result;
1766     else
1767       *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
1768     ret = -1;
1769     goto out;
1770   }
1771 
1772   if(ret < 0) {
1773     failf(data, "GnuTLS recv error (%d): %s",
1774 
1775           (int)ret, gnutls_strerror((int)ret));
1776     *curlcode = backend->gtls.io_result?
1777                 backend->gtls.io_result : CURLE_RECV_ERROR;
1778     ret = -1;
1779     goto out;
1780   }
1781 
1782 out:
1783   return ret;
1784 }
1785 
gtls_version(char * buffer,size_t size)1786 static size_t gtls_version(char *buffer, size_t size)
1787 {
1788   return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1789 }
1790 
1791 /* data might be NULL! */
gtls_random(struct Curl_easy * data,unsigned char * entropy,size_t length)1792 static CURLcode gtls_random(struct Curl_easy *data,
1793                             unsigned char *entropy, size_t length)
1794 {
1795   int rc;
1796   (void)data;
1797   rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
1798   return rc?CURLE_FAILED_INIT:CURLE_OK;
1799 }
1800 
gtls_sha256sum(const unsigned char * tmp,size_t tmplen,unsigned char * sha256sum,size_t sha256len)1801 static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
1802                                size_t tmplen,
1803                                unsigned char *sha256sum, /* output */
1804                                size_t sha256len)
1805 {
1806   struct sha256_ctx SHA256pw;
1807   sha256_init(&SHA256pw);
1808   sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
1809   sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
1810   return CURLE_OK;
1811 }
1812 
gtls_cert_status_request(void)1813 static bool gtls_cert_status_request(void)
1814 {
1815   return TRUE;
1816 }
1817 
gtls_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)1818 static void *gtls_get_internals(struct ssl_connect_data *connssl,
1819                                 CURLINFO info UNUSED_PARAM)
1820 {
1821   struct gtls_ssl_backend_data *backend =
1822     (struct gtls_ssl_backend_data *)connssl->backend;
1823   (void)info;
1824   DEBUGASSERT(backend);
1825   return backend->gtls.session;
1826 }
1827 
1828 const struct Curl_ssl Curl_ssl_gnutls = {
1829   { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
1830 
1831   SSLSUPP_CA_PATH  |
1832   SSLSUPP_CERTINFO |
1833   SSLSUPP_PINNEDPUBKEY |
1834   SSLSUPP_HTTPS_PROXY,
1835 
1836   sizeof(struct gtls_ssl_backend_data),
1837 
1838   gtls_init,                     /* init */
1839   gtls_cleanup,                  /* cleanup */
1840   gtls_version,                  /* version */
1841   Curl_none_check_cxn,           /* check_cxn */
1842   gtls_shutdown,                 /* shutdown */
1843   gtls_data_pending,             /* data_pending */
1844   gtls_random,                   /* random */
1845   gtls_cert_status_request,      /* cert_status_request */
1846   gtls_connect,                  /* connect */
1847   gtls_connect_nonblocking,      /* connect_nonblocking */
1848   Curl_ssl_adjust_pollset,       /* adjust_pollset */
1849   gtls_get_internals,            /* get_internals */
1850   gtls_close,                    /* close_one */
1851   Curl_none_close_all,           /* close_all */
1852   Curl_none_set_engine,          /* set_engine */
1853   Curl_none_set_engine_default,  /* set_engine_default */
1854   Curl_none_engines_list,        /* engines_list */
1855   Curl_none_false_start,         /* false_start */
1856   gtls_sha256sum,                /* sha256sum */
1857   NULL,                          /* associate_connection */
1858   NULL,                          /* disassociate_connection */
1859   NULL,                          /* free_multi_ssl_backend_data */
1860   gtls_recv,                     /* recv decrypted data */
1861   gtls_send,                     /* send data to encrypt */
1862 };
1863 
1864 #endif /* USE_GNUTLS */
1865