gtls.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 /*
24  * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
25  * but vtls.c should ever call or use these functions.
26  *
27  * Note: don't use the GnuTLS' *_t variable type names in this source code,
28  * since they were not present in 1.0.X.
29  */
30 
31 #include "curl_setup.h"
32 
33 #ifdef USE_GNUTLS
34 
35 #include <gnutls/abstract.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/x509.h>
38 
39 #ifdef USE_GNUTLS_NETTLE
40 #include <gnutls/crypto.h>
41 #include <nettle/md5.h>
42 #include <nettle/sha2.h>
43 #else
44 #include <gcrypt.h>
45 #endif
46 
47 #include "urldata.h"
48 #include "sendf.h"
49 #include "inet_pton.h"
50 #include "gtls.h"
51 #include "vtls.h"
52 #include "parsedate.h"
53 #include "connect.h" /* for the connect timeout */
54 #include "select.h"
55 #include "strcase.h"
56 #include "warnless.h"
57 #include "x509asn1.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 GNUTLS_POINTER_TO_SOCKET_CAST
64 #define GNUTLS_POINTER_TO_SOCKET_CAST(p) \
65  ((curl_socket_t) ((char *)(p) - (char *)NULL))
66 #endif
67 #ifndef GNUTLS_SOCKET_TO_POINTER_CAST
68 #define GNUTLS_SOCKET_TO_POINTER_CAST(s) \
69  ((void *) ((char *)NULL + (s)))
70 #endif
71 
72 /* Enable GnuTLS debugging by defining GTLSDEBUG */
73 /*#define GTLSDEBUG */
74 
75 #ifdef GTLSDEBUG
76 static void tls_log_func(int level, const char *str)
77 {
78  fprintf(stderr, "|<%d>| %s", level, str);
79 }
80 #endif
81 static bool gtls_inited = FALSE;
82 
83 #if defined(GNUTLS_VERSION_NUMBER)
84 # if (GNUTLS_VERSION_NUMBER >= 0x020c00)
85 # undef gnutls_transport_set_lowat
86 # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
87 # define USE_GNUTLS_PRIORITY_SET_DIRECT 1
88 # endif
89 # if (GNUTLS_VERSION_NUMBER >= 0x020c03)
90 # define GNUTLS_MAPS_WINSOCK_ERRORS 1
91 # endif
92 
93 # if HAVE_GNUTLS_ALPN_SET_PROTOCOLS
94 # define HAS_ALPN
95 # endif
96 
97 # if HAVE_GNUTLS_OCSP_REQ_INIT
98 # define HAS_OCSP
99 # endif
100 
101 # if (GNUTLS_VERSION_NUMBER >= 0x030306)
102 # define HAS_CAPATH
103 # endif
104 #endif
105 
106 #ifdef HAS_OCSP
107 # include <gnutls/ocsp.h>
108 #endif
109 
110 struct ssl_backend_data {
111  gnutls_session_t session;
112  gnutls_certificate_credentials_t cred;
113 #ifdef USE_TLS_SRP
114  gnutls_srp_client_credentials_t srp_client_cred;
115 #endif
116 };
117 
118 #define BACKEND connssl->backend
119 
120 /*
121  * Custom push and pull callback functions used by GNU TLS to read and write
122  * to the socket. These functions are simple wrappers to send() and recv()
123  * (although here using the sread/swrite macros as defined by
124  * curl_setup_once.h).
125  * We use custom functions rather than the GNU TLS defaults because it allows
126  * us to get specific about the fourth "flags" argument, and to use arbitrary
127  * private data with gnutls_transport_set_ptr if we wish.
128  *
129  * When these custom push and pull callbacks fail, GNU TLS checks its own
130  * session-specific error variable, and when not set also its own global
131  * errno variable, in order to take appropriate action. GNU TLS does not
132  * require that the transport is actually a socket. This implies that for
133  * Windows builds these callbacks should ideally set the session-specific
134  * error variable using function gnutls_transport_set_errno or as a last
135  * resort global errno variable using gnutls_transport_set_global_errno,
136  * with a transport agnostic error value. This implies that some winsock
137  * error translation must take place in these callbacks.
138  *
139  * Paragraph above applies to GNU TLS versions older than 2.12.3, since
140  * this version GNU TLS does its own internal winsock error translation
141  * using system_errno() function.
142  */
143 
144 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
145 # define gtls_EINTR 4
146 # define gtls_EIO 5
147 # define gtls_EAGAIN 11
148 static int gtls_mapped_sockerrno(void)
149 {
150  switch(SOCKERRNO) {
151  case WSAEWOULDBLOCK:
152  return gtls_EAGAIN;
153  case WSAEINTR:
154  return gtls_EINTR;
155  default:
156  break;
157  }
158  return gtls_EIO;
159 }
160 #endif
161 
162 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
163 {
164  ssize_t ret = swrite(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len);
165 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
166  if(ret < 0)
167  gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
168 #endif
169  return ret;
170 }
171 
172 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
173 {
174  ssize_t ret = sread(GNUTLS_POINTER_TO_SOCKET_CAST(s), buf, len);
175 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
176  if(ret < 0)
177  gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
178 #endif
179  return ret;
180 }
181 
182 static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
183 {
184  return gnutls_record_send((gnutls_session_t) s, buf, len);
185 }
186 
187 static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
188 {
189  return gnutls_record_recv((gnutls_session_t) s, buf, len);
190 }
191 
192 /* Curl_gtls_init()
193  *
194  * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
195  * are not thread-safe and thus this function itself is not thread-safe and
196  * must only be called from within curl_global_init() to keep the thread
197  * situation under control!
198  */
199 static int Curl_gtls_init(void)
200 {
201  int ret = 1;
202  if(!gtls_inited) {
203  ret = gnutls_global_init()?0:1;
204 #ifdef GTLSDEBUG
205  gnutls_global_set_log_function(tls_log_func);
206  gnutls_global_set_log_level(2);
207 #endif
208  gtls_inited = TRUE;
209  }
210  return ret;
211 }
212 
213 static void Curl_gtls_cleanup(void)
214 {
215  if(gtls_inited) {
216  gnutls_global_deinit();
217  gtls_inited = FALSE;
218  }
219 }
220 
221 #ifndef CURL_DISABLE_VERBOSE_STRINGS
222 static void showtime(struct Curl_easy *data,
223  const char *text,
224  time_t stamp)
225 {
226  struct tm buffer;
227  const struct tm *tm = &buffer;
228  char str[96];
229  CURLcode result = Curl_gmtime(stamp, &buffer);
230  if(result)
231  return;
232 
233  snprintf(str,
234  sizeof(str),
235  "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
236  text,
237  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
238  tm->tm_mday,
239  Curl_month[tm->tm_mon],
240  tm->tm_year + 1900,
241  tm->tm_hour,
242  tm->tm_min,
243  tm->tm_sec);
244  infof(data, "%s\n", str);
245 }
246 #endif
247 
248 static gnutls_datum_t load_file(const char *file)
249 {
250  FILE *f;
251  gnutls_datum_t loaded_file = { NULL, 0 };
252  long filelen;
253  void *ptr;
254 
255  f = fopen(file, "rb");
256  if(!f)
257  return loaded_file;
258  if(fseek(f, 0, SEEK_END) != 0
259  || (filelen = ftell(f)) < 0
260  || fseek(f, 0, SEEK_SET) != 0
261  || !(ptr = malloc((size_t)filelen)))
262  goto out;
263  if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
264  free(ptr);
265  goto out;
266  }
267 
268  loaded_file.data = ptr;
269  loaded_file.size = (unsigned int)filelen;
270 out:
271  fclose(f);
272  return loaded_file;
273 }
274 
275 static void unload_file(gnutls_datum_t data)
276 {
277  free(data.data);
278 }
279 
280 
281 /* this function does a SSL/TLS (re-)handshake */
282 static CURLcode handshake(struct connectdata *conn,
283  int sockindex,
284  bool duringconnect,
285  bool nonblocking)
286 {
287  struct Curl_easy *data = conn->data;
288  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
289  gnutls_session_t session = BACKEND->session;
290  curl_socket_t sockfd = conn->sock[sockindex];
291  time_t timeout_ms;
292  int rc;
293  int what;
294 
295  for(;;) {
296  /* check allowed time left */
297  timeout_ms = Curl_timeleft(data, NULL, duringconnect);
298 
299  if(timeout_ms < 0) {
300  /* no need to continue if time already is up */
301  failf(data, "SSL connection timeout");
303  }
304 
305  /* if ssl is expecting something, check if it's available. */
307  || connssl->connecting_state == ssl_connect_2_writing) {
308 
310  connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
312  connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
313 
314  what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
315  nonblocking?0:
316  timeout_ms?timeout_ms:1000);
317  if(what < 0) {
318  /* fatal error */
319  failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
321  }
322  else if(0 == what) {
323  if(nonblocking)
324  return CURLE_OK;
325  else if(timeout_ms) {
326  /* timeout */
327  failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
329  }
330  }
331  /* socket is readable or writable */
332  }
333 
334  rc = gnutls_handshake(session);
335 
336  if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
337  connssl->connecting_state =
338  gnutls_record_get_direction(session)?
340  continue;
341  }
342  else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
343  const char *strerr = NULL;
344 
345  if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
346  int alert = gnutls_alert_get(session);
347  strerr = gnutls_alert_get_name(alert);
348  }
349 
350  if(strerr == NULL)
351  strerr = gnutls_strerror(rc);
352 
353  infof(data, "gnutls_handshake() warning: %s\n", strerr);
354  continue;
355  }
356  else if(rc < 0) {
357  const char *strerr = NULL;
358 
359  if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
360  int alert = gnutls_alert_get(session);
361  strerr = gnutls_alert_get_name(alert);
362  }
363 
364  if(strerr == NULL)
365  strerr = gnutls_strerror(rc);
366 
367  failf(data, "gnutls_handshake() failed: %s", strerr);
369  }
370 
371  /* Reset our connect state machine */
372  connssl->connecting_state = ssl_connect_1;
373  return CURLE_OK;
374  }
375 }
376 
377 static gnutls_x509_crt_fmt_t do_file_type(const char *type)
378 {
379  if(!type || !type[0])
380  return GNUTLS_X509_FMT_PEM;
381  if(strcasecompare(type, "PEM"))
382  return GNUTLS_X509_FMT_PEM;
383  if(strcasecompare(type, "DER"))
384  return GNUTLS_X509_FMT_DER;
385  return -1;
386 }
387 
388 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
389 static CURLcode
390 set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn)
391 {
392  struct Curl_easy *data = conn->data;
393  long ssl_version = SSL_CONN_CONFIG(version);
394  long ssl_version_max = SSL_CONN_CONFIG(version_max);
395  long i = ssl_version;
396  long protocol_priority_idx = 0;
397 
398  switch(ssl_version_max) {
400  ssl_version_max = ssl_version << 16;
401  break;
403  ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
404  break;
405  }
406 
407  for(; i <= (ssl_version_max >> 16) &&
408  protocol_priority_idx < list_size; ++i) {
409  switch(i) {
411  protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0;
412  break;
414  protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1;
415  break;
417  protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2;
418  break;
420  failf(data, "GnuTLS: TLS 1.3 is not yet supported");
422  }
423  }
424  return CURLE_OK;
425 }
426 #else
427 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
428 /* If GnuTLS was compiled without support for SRP it will error out if SRP is
429  requested in the priority string, so treat it specially
430  */
431 #define GNUTLS_SRP "+SRP"
432 
433 static CURLcode
434 set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
435 {
436  struct Curl_easy *data = conn->data;
437  long ssl_version = SSL_CONN_CONFIG(version);
438  long ssl_version_max = SSL_CONN_CONFIG(version_max);
439  if(ssl_version == CURL_SSLVERSION_TLSv1_3 ||
440  ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) {
441  failf(data, "GnuTLS: TLS 1.3 is not yet supported");
443  }
444  if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
445  ssl_version_max = ssl_version << 16;
446  }
447  switch(ssl_version | ssl_version_max) {
449  *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
450  "+VERS-TLS1.0:" GNUTLS_SRP;
451  return CURLE_OK;
453  *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
454  "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP;
455  return CURLE_OK;
458  *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
459  "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
460  return CURLE_OK;
462  *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
463  "+VERS-TLS1.1:" GNUTLS_SRP;
464  return CURLE_OK;
467  *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
468  "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
469  return CURLE_OK;
472  *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
473  "+VERS-TLS1.2:" GNUTLS_SRP;
474  return CURLE_OK;
475  }
476 
477  failf(data, "GnuTLS: cannot set ssl protocol");
479 }
480 #endif
481 
482 static CURLcode
483 gtls_connect_step1(struct connectdata *conn,
484  int sockindex)
485 {
486  struct Curl_easy *data = conn->data;
487  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
488  unsigned int init_flags;
489  gnutls_session_t session;
490  int rc;
491  bool sni = TRUE; /* default is SNI enabled */
492  void *transport_ptr = NULL;
493  gnutls_push_func gnutls_transport_push = NULL;
494  gnutls_pull_func gnutls_transport_pull = NULL;
495 #ifdef ENABLE_IPV6
496  struct in6_addr addr;
497 #else
498  struct in_addr addr;
499 #endif
500 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
501  static const int cipher_priority[] = {
502  /* These two ciphers were added to GnuTLS as late as ver. 3.0.1,
503  but this code path is only ever used for ver. < 2.12.0.
504  GNUTLS_CIPHER_AES_128_GCM,
505  GNUTLS_CIPHER_AES_256_GCM,
506  */
507  GNUTLS_CIPHER_AES_128_CBC,
508  GNUTLS_CIPHER_AES_256_CBC,
509  GNUTLS_CIPHER_CAMELLIA_128_CBC,
510  GNUTLS_CIPHER_CAMELLIA_256_CBC,
511  GNUTLS_CIPHER_3DES_CBC,
512  };
513  static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
514  int protocol_priority[] = { 0, 0, 0, 0 };
515 #else
516  const char *prioritylist;
517  const char *err = NULL;
518 #endif
519 
520  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
521  conn->host.name;
522 
523  if(connssl->state == ssl_connection_complete)
524  /* to make us tolerant against being called more than once for the
525  same connection */
526  return CURLE_OK;
527 
528  if(!gtls_inited)
529  Curl_gtls_init();
530 
531  if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
532  failf(data, "GnuTLS does not support SSLv2");
534  }
535  else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
536  sni = FALSE; /* SSLv3 has no SNI */
537 
538  /* allocate a cred struct */
539  rc = gnutls_certificate_allocate_credentials(&BACKEND->cred);
540  if(rc != GNUTLS_E_SUCCESS) {
541  failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
543  }
544 
545 #ifdef USE_TLS_SRP
546  if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
547  infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
548 
549  rc = gnutls_srp_allocate_client_credentials(
550  &BACKEND->srp_client_cred);
551  if(rc != GNUTLS_E_SUCCESS) {
552  failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
553  gnutls_strerror(rc));
554  return CURLE_OUT_OF_MEMORY;
555  }
556 
557  rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred,
558  SSL_SET_OPTION(username),
560  if(rc != GNUTLS_E_SUCCESS) {
561  failf(data, "gnutls_srp_set_client_cred() failed: %s",
562  gnutls_strerror(rc));
564  }
565  }
566 #endif
567 
568  if(SSL_CONN_CONFIG(CAfile)) {
569  /* set the trusted CA cert bundle file */
570  gnutls_certificate_set_verify_flags(BACKEND->cred,
571  GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
572 
573  rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred,
574  SSL_CONN_CONFIG(CAfile),
575  GNUTLS_X509_FMT_PEM);
576  if(rc < 0) {
577  infof(data, "error reading ca cert file %s (%s)\n",
578  SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
579  if(SSL_CONN_CONFIG(verifypeer))
581  }
582  else
583  infof(data, "found %d certificates in %s\n", rc,
584  SSL_CONN_CONFIG(CAfile));
585  }
586 
587 #ifdef HAS_CAPATH
588  if(SSL_CONN_CONFIG(CApath)) {
589  /* set the trusted CA cert directory */
590  rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred,
591  SSL_CONN_CONFIG(CApath),
592  GNUTLS_X509_FMT_PEM);
593  if(rc < 0) {
594  infof(data, "error reading ca cert file %s (%s)\n",
595  SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
596  if(SSL_CONN_CONFIG(verifypeer))
598  }
599  else
600  infof(data, "found %d certificates in %s\n",
601  rc, SSL_CONN_CONFIG(CApath));
602  }
603 #endif
604 
605 #ifdef CURL_CA_FALLBACK
606  /* use system ca certificate store as fallback */
607  if(SSL_CONN_CONFIG(verifypeer) &&
608  !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
609  gnutls_certificate_set_x509_system_trust(BACKEND->cred);
610  }
611 #endif
612 
613  if(SSL_SET_OPTION(CRLfile)) {
614  /* set the CRL list file */
615  rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred,
616  SSL_SET_OPTION(CRLfile),
617  GNUTLS_X509_FMT_PEM);
618  if(rc < 0) {
619  failf(data, "error reading crl file %s (%s)",
620  SSL_SET_OPTION(CRLfile), gnutls_strerror(rc));
621  return CURLE_SSL_CRL_BADFILE;
622  }
623  else
624  infof(data, "found %d CRL in %s\n",
625  rc, SSL_SET_OPTION(CRLfile));
626  }
627 
628  /* Initialize TLS session as a client */
629  init_flags = GNUTLS_CLIENT;
630 
631 #if defined(GNUTLS_NO_TICKETS)
632  /* Disable TLS session tickets */
633  init_flags |= GNUTLS_NO_TICKETS;
634 #endif
635 
636  rc = gnutls_init(&BACKEND->session, init_flags);
637  if(rc != GNUTLS_E_SUCCESS) {
638  failf(data, "gnutls_init() failed: %d", rc);
640  }
641 
642  /* convenient assign */
643  session = BACKEND->session;
644 
645  if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
646 #ifdef ENABLE_IPV6
647  (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
648 #endif
649  sni &&
650  (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
651  strlen(hostname)) < 0))
652  infof(data, "WARNING: failed to configure server name indication (SNI) "
653  "TLS extension\n");
654 
655  /* Use default priorities */
656  rc = gnutls_set_default_priority(session);
657  if(rc != GNUTLS_E_SUCCESS)
659 
660 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
661  rc = gnutls_cipher_set_priority(session, cipher_priority);
662  if(rc != GNUTLS_E_SUCCESS)
664 
665  /* Sets the priority on the certificate types supported by gnutls. Priority
666  is higher for types specified before others. After specifying the types
667  you want, you must append a 0. */
668  rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
669  if(rc != GNUTLS_E_SUCCESS)
671 
672  if(SSL_CONN_CONFIG(cipher_list) != NULL) {
673  failf(data, "can't pass a custom cipher list to older GnuTLS"
674  " versions");
676  }
677 
678  switch(SSL_CONN_CONFIG(version)) {
680  protocol_priority[0] = GNUTLS_SSL3;
681  break;
684  protocol_priority[0] = GNUTLS_TLS1_0;
685  protocol_priority[1] = GNUTLS_TLS1_1;
686  protocol_priority[2] = GNUTLS_TLS1_2;
687  break;
692  {
693  CURLcode result = set_ssl_version_min_max(protocol_priority,
694  sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn);
695  if(result != CURLE_OK)
696  return result;
697  break;
698  }
700  failf(data, "GnuTLS does not support SSLv2");
702  default:
703  failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
705  }
706  rc = gnutls_protocol_set_priority(session, protocol_priority);
707  if(rc != GNUTLS_E_SUCCESS) {
708  failf(data, "Did you pass a valid GnuTLS cipher list?");
710  }
711 
712 #else
713  /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
714  * removed if a run-time error indicates that SRP is not supported by this
715  * GnuTLS version */
716  switch(SSL_CONN_CONFIG(version)) {
718  prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
719  sni = false;
720  break;
723  prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
724  break;
729  {
730  CURLcode result = set_ssl_version_min_max(&prioritylist, conn);
731  if(result != CURLE_OK)
732  return result;
733  break;
734  }
736  failf(data, "GnuTLS does not support SSLv2");
738  default:
739  failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
741  }
742  rc = gnutls_priority_set_direct(session, prioritylist, &err);
743  if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
744  if(!strcmp(err, GNUTLS_SRP)) {
745  /* This GnuTLS was probably compiled without support for SRP.
746  * Note that fact and try again without it. */
747  int validprioritylen = curlx_uztosi(err - prioritylist);
748  char *prioritycopy = strdup(prioritylist);
749  if(!prioritycopy)
750  return CURLE_OUT_OF_MEMORY;
751 
752  infof(data, "This GnuTLS does not support SRP\n");
753  if(validprioritylen)
754  /* Remove the :+SRP */
755  prioritycopy[validprioritylen - 1] = 0;
756  rc = gnutls_priority_set_direct(session, prioritycopy, &err);
757  free(prioritycopy);
758  }
759  }
760  if(rc != GNUTLS_E_SUCCESS) {
761  failf(data, "Error %d setting GnuTLS cipher list starting with %s",
762  rc, err);
764  }
765 #endif
766 
767 #ifdef HAS_ALPN
768  if(conn->bits.tls_enable_alpn) {
769  int cur = 0;
770  gnutls_datum_t protocols[2];
771 
772 #ifdef USE_NGHTTP2
773  if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
774  (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
775  protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
776  protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
777  cur++;
778  infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
779  }
780 #endif
781 
782  protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
783  protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
784  cur++;
785  infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
786 
787  gnutls_alpn_set_protocols(session, protocols, cur, 0);
788  }
789 #endif
790 
791  if(SSL_SET_OPTION(cert)) {
792  if(SSL_SET_OPTION(key_passwd)) {
793 #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
794  const unsigned int supported_key_encryption_algorithms =
795  GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
796  GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
797  GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
798  GNUTLS_PKCS_USE_PBES2_AES_256;
799  rc = gnutls_certificate_set_x509_key_file2(
800  BACKEND->cred,
801  SSL_SET_OPTION(cert),
804  do_file_type(SSL_SET_OPTION(cert_type)),
805  SSL_SET_OPTION(key_passwd),
806  supported_key_encryption_algorithms);
807  if(rc != GNUTLS_E_SUCCESS) {
808  failf(data,
809  "error reading X.509 potentially-encrypted key file: %s",
810  gnutls_strerror(rc));
812  }
813 #else
814  failf(data, "gnutls lacks support for encrypted key files");
816 #endif
817  }
818  else {
819  if(gnutls_certificate_set_x509_key_file(
820  BACKEND->cred,
821  SSL_SET_OPTION(cert),
824  do_file_type(SSL_SET_OPTION(cert_type)) ) !=
825  GNUTLS_E_SUCCESS) {
826  failf(data, "error reading X.509 key or certificate file");
828  }
829  }
830  }
831 
832 #ifdef USE_TLS_SRP
833  /* put the credentials to the current session */
834  if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
835  rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
836  BACKEND->srp_client_cred);
837  if(rc != GNUTLS_E_SUCCESS) {
838  failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
840  }
841  }
842  else
843 #endif
844  {
845  rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
846  BACKEND->cred);
847  if(rc != GNUTLS_E_SUCCESS) {
848  failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
850  }
851  }
852 
853  if(conn->proxy_ssl[sockindex].use) {
854  transport_ptr = conn->proxy_ssl[sockindex].backend->session;
855  gnutls_transport_push = Curl_gtls_push_ssl;
856  gnutls_transport_pull = Curl_gtls_pull_ssl;
857  }
858  else {
859  /* file descriptor for the socket */
860  transport_ptr = GNUTLS_SOCKET_TO_POINTER_CAST(conn->sock[sockindex]);
861  gnutls_transport_push = Curl_gtls_push;
862  gnutls_transport_pull = Curl_gtls_pull;
863  }
864 
865  /* set the connection handle */
866  gnutls_transport_set_ptr(session, transport_ptr);
867 
868  /* register callback functions to send and receive data. */
869  gnutls_transport_set_push_function(session, gnutls_transport_push);
870  gnutls_transport_set_pull_function(session, gnutls_transport_pull);
871 
872  /* lowat must be set to zero when using custom push and pull functions. */
873  gnutls_transport_set_lowat(session, 0);
874 
875 #ifdef HAS_OCSP
876  if(SSL_CONN_CONFIG(verifystatus)) {
877  rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
878  if(rc != GNUTLS_E_SUCCESS) {
879  failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
881  }
882  }
883 #endif
884 
885  /* This might be a reconnect, so we check for a session ID in the cache
886  to speed up things */
887  if(SSL_SET_OPTION(primary.sessionid)) {
888  void *ssl_sessionid;
889  size_t ssl_idsize;
890 
891  Curl_ssl_sessionid_lock(conn);
892  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) {
893  /* we got a session id, use it! */
894  gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
895 
896  /* Informational message */
897  infof(data, "SSL re-using session ID\n");
898  }
899  Curl_ssl_sessionid_unlock(conn);
900  }
901 
902  return CURLE_OK;
903 }
904 
905 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
906  gnutls_x509_crt_t cert,
907  const char *pinnedpubkey)
908 {
909  /* Scratch */
910  size_t len1 = 0, len2 = 0;
911  unsigned char *buff1 = NULL;
912 
913  gnutls_pubkey_t key = NULL;
914 
915  /* Result is returned to caller */
916  int ret = 0;
918 
919  /* if a path wasn't specified, don't pin */
920  if(NULL == pinnedpubkey)
921  return CURLE_OK;
922 
923  if(NULL == cert)
924  return result;
925 
926  do {
927  /* Begin Gyrations to get the public key */
928  gnutls_pubkey_init(&key);
929 
930  ret = gnutls_pubkey_import_x509(key, cert, 0);
931  if(ret < 0)
932  break; /* failed */
933 
934  ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
935  if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
936  break; /* failed */
937 
938  buff1 = malloc(len1);
939  if(NULL == buff1)
940  break; /* failed */
941 
942  len2 = len1;
943 
944  ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
945  if(ret < 0 || len1 != len2)
946  break; /* failed */
947 
948  /* End Gyrations */
949 
950  /* The one good exit point */
951  result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
952  } while(0);
953 
954  if(NULL != key)
955  gnutls_pubkey_deinit(key);
956 
957  Curl_safefree(buff1);
958 
959  return result;
960 }
961 
962 static Curl_recv gtls_recv;
963 static Curl_send gtls_send;
964 
965 static CURLcode
966 gtls_connect_step3(struct connectdata *conn,
967  int sockindex)
968 {
969  unsigned int cert_list_size;
970  const gnutls_datum_t *chainp;
971  unsigned int verify_status = 0;
972  gnutls_x509_crt_t x509_cert, x509_issuer;
973  gnutls_datum_t issuerp;
974  char certbuf[256] = ""; /* big enough? */
975  size_t size;
976  time_t certclock;
977  const char *ptr;
978  struct Curl_easy *data = conn->data;
979  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
980  gnutls_session_t session = BACKEND->session;
981  int rc;
982 #ifdef HAS_ALPN
983  gnutls_datum_t proto;
984 #endif
985  CURLcode result = CURLE_OK;
986 #ifndef CURL_DISABLE_VERBOSE_STRINGS
987  unsigned int algo;
988  unsigned int bits;
989  gnutls_protocol_t version = gnutls_protocol_get_version(session);
990 #endif
991  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
992  conn->host.name;
993 
994  /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
995  ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
996  gnutls_cipher_get(session),
997  gnutls_mac_get(session));
998 
999  infof(data, "SSL connection using %s / %s\n",
1000  gnutls_protocol_get_name(version), ptr);
1001 
1002  /* This function will return the peer's raw certificate (chain) as sent by
1003  the peer. These certificates are in raw format (DER encoded for
1004  X.509). In case of a X.509 then a certificate list may be present. The
1005  first certificate in the list is the peer's certificate, following the
1006  issuer's certificate, then the issuer's issuer etc. */
1007 
1008  chainp = gnutls_certificate_get_peers(session, &cert_list_size);
1009  if(!chainp) {
1010  if(SSL_CONN_CONFIG(verifypeer) ||
1011  SSL_CONN_CONFIG(verifyhost) ||
1012  SSL_SET_OPTION(issuercert)) {
1013 #ifdef USE_TLS_SRP
1014  if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
1015  && SSL_SET_OPTION(username) != NULL
1016  && !SSL_CONN_CONFIG(verifypeer)
1017  && gnutls_cipher_get(session)) {
1018  /* no peer cert, but auth is ok if we have SRP user and cipher and no
1019  peer verify */
1020  }
1021  else {
1022 #endif
1023  failf(data, "failed to get server cert");
1025 #ifdef USE_TLS_SRP
1026  }
1027 #endif
1028  }
1029  infof(data, "\t common name: WARNING couldn't obtain\n");
1030  }
1031 
1032  if(data->set.ssl.certinfo && chainp) {
1033  unsigned int i;
1034 
1035  result = Curl_ssl_init_certinfo(data, cert_list_size);
1036  if(result)
1037  return result;
1038 
1039  for(i = 0; i < cert_list_size; i++) {
1040  const char *beg = (const char *) chainp[i].data;
1041  const char *end = beg + chainp[i].size;
1042 
1043  result = Curl_extract_certinfo(conn, i, beg, end);
1044  if(result)
1045  return result;
1046  }
1047  }
1048 
1049  if(SSL_CONN_CONFIG(verifypeer)) {
1050  /* This function will try to verify the peer's certificate and return its
1051  status (trusted, invalid etc.). The value of status should be one or
1052  more of the gnutls_certificate_status_t enumerated elements bitwise
1053  or'd. To avoid denial of service attacks some default upper limits
1054  regarding the certificate key size and chain size are set. To override
1055  them use gnutls_certificate_set_verify_limits(). */
1056 
1057  rc = gnutls_certificate_verify_peers2(session, &verify_status);
1058  if(rc < 0) {
1059  failf(data, "server cert verify failed: %d", rc);
1060  return CURLE_SSL_CONNECT_ERROR;
1061  }
1062 
1063  /* verify_status is a bitmask of gnutls_certificate_status bits */
1064  if(verify_status & GNUTLS_CERT_INVALID) {
1065  if(SSL_CONN_CONFIG(verifypeer)) {
1066  failf(data, "server certificate verification failed. CAfile: %s "
1067  "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
1068  "none",
1069  SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
1070  return CURLE_SSL_CACERT;
1071  }
1072  else
1073  infof(data, "\t server certificate verification FAILED\n");
1074  }
1075  else
1076  infof(data, "\t server certificate verification OK\n");
1077  }
1078  else
1079  infof(data, "\t server certificate verification SKIPPED\n");
1080 
1081 #ifdef HAS_OCSP
1082  if(SSL_CONN_CONFIG(verifystatus)) {
1083  if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
1084  gnutls_datum_t status_request;
1085  gnutls_ocsp_resp_t ocsp_resp;
1086 
1087  gnutls_ocsp_cert_status_t status;
1088  gnutls_x509_crl_reason_t reason;
1089 
1090  rc = gnutls_ocsp_status_request_get(session, &status_request);
1091 
1092  infof(data, "\t server certificate status verification FAILED\n");
1093 
1094  if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1095  failf(data, "No OCSP response received");
1097  }
1098 
1099  if(rc < 0) {
1100  failf(data, "Invalid OCSP response received");
1102  }
1103 
1104  gnutls_ocsp_resp_init(&ocsp_resp);
1105 
1106  rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
1107  if(rc < 0) {
1108  failf(data, "Invalid OCSP response received");
1110  }
1111 
1112  rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
1113  &status, NULL, NULL, NULL, &reason);
1114 
1115  switch(status) {
1116  case GNUTLS_OCSP_CERT_GOOD:
1117  break;
1118 
1119  case GNUTLS_OCSP_CERT_REVOKED: {
1120  const char *crl_reason;
1121 
1122  switch(reason) {
1123  default:
1124  case GNUTLS_X509_CRLREASON_UNSPECIFIED:
1125  crl_reason = "unspecified reason";
1126  break;
1127 
1128  case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
1129  crl_reason = "private key compromised";
1130  break;
1131 
1132  case GNUTLS_X509_CRLREASON_CACOMPROMISE:
1133  crl_reason = "CA compromised";
1134  break;
1135 
1136  case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
1137  crl_reason = "affiliation has changed";
1138  break;
1139 
1140  case GNUTLS_X509_CRLREASON_SUPERSEDED:
1141  crl_reason = "certificate superseded";
1142  break;
1143 
1144  case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
1145  crl_reason = "operation has ceased";
1146  break;
1147 
1148  case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
1149  crl_reason = "certificate is on hold";
1150  break;
1151 
1152  case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
1153  crl_reason = "will be removed from delta CRL";
1154  break;
1155 
1156  case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
1157  crl_reason = "privilege withdrawn";
1158  break;
1159 
1160  case GNUTLS_X509_CRLREASON_AACOMPROMISE:
1161  crl_reason = "AA compromised";
1162  break;
1163  }
1164 
1165  failf(data, "Server certificate was revoked: %s", crl_reason);
1166  break;
1167  }
1168 
1169  default:
1170  case GNUTLS_OCSP_CERT_UNKNOWN:
1171  failf(data, "Server certificate status is unknown");
1172  break;
1173  }
1174 
1175  gnutls_ocsp_resp_deinit(ocsp_resp);
1176 
1178  }
1179  else
1180  infof(data, "\t server certificate status verification OK\n");
1181  }
1182  else
1183  infof(data, "\t server certificate status verification SKIPPED\n");
1184 #endif
1185 
1186  /* initialize an X.509 certificate structure. */
1187  gnutls_x509_crt_init(&x509_cert);
1188 
1189  if(chainp)
1190  /* convert the given DER or PEM encoded Certificate to the native
1191  gnutls_x509_crt_t format */
1192  gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
1193 
1194  if(SSL_SET_OPTION(issuercert)) {
1195  gnutls_x509_crt_init(&x509_issuer);
1196  issuerp = load_file(SSL_SET_OPTION(issuercert));
1197  gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
1198  rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
1199  gnutls_x509_crt_deinit(x509_issuer);
1200  unload_file(issuerp);
1201  if(rc <= 0) {
1202  failf(data, "server certificate issuer check failed (IssuerCert: %s)",
1203  SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
1204  gnutls_x509_crt_deinit(x509_cert);
1205  return CURLE_SSL_ISSUER_ERROR;
1206  }
1207  infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
1208  SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
1209  }
1210 
1211  size = sizeof(certbuf);
1212  rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
1213  0, /* the first and only one */
1214  FALSE,
1215  certbuf,
1216  &size);
1217  if(rc) {
1218  infof(data, "error fetching CN from cert:%s\n",
1219  gnutls_strerror(rc));
1220  }
1221 
1222  /* This function will check if the given certificate's subject matches the
1223  given hostname. This is a basic implementation of the matching described
1224  in RFC2818 (HTTPS), which takes into account wildcards, and the subject
1225  alternative name PKIX extension. Returns non zero on success, and zero on
1226  failure. */
1227  rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
1228 #if GNUTLS_VERSION_NUMBER < 0x030306
1229  /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
1230  addresses. */
1231  if(!rc) {
1232 #ifdef ENABLE_IPV6
1233  #define use_addr in6_addr
1234 #else
1235  #define use_addr in_addr
1236 #endif
1237  unsigned char addrbuf[sizeof(struct use_addr)];
1238  unsigned char certaddr[sizeof(struct use_addr)];
1239  size_t addrlen = 0, certaddrlen;
1240  int i;
1241  int ret = 0;
1242 
1243  if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
1244  addrlen = 4;
1245 #ifdef ENABLE_IPV6
1246  else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
1247  addrlen = 16;
1248 #endif
1249 
1250  if(addrlen) {
1251  for(i = 0; ; i++) {
1252  certaddrlen = sizeof(certaddr);
1253  ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
1254  &certaddrlen, NULL);
1255  /* If this happens, it wasn't an IP address. */
1256  if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
1257  continue;
1258  if(ret < 0)
1259  break;
1260  if(ret != GNUTLS_SAN_IPADDRESS)
1261  continue;
1262  if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
1263  rc = 1;
1264  break;
1265  }
1266  }
1267  }
1268  }
1269 #endif
1270  if(!rc) {
1271  const char * const dispname = SSL_IS_PROXY() ?
1272  conn->http_proxy.host.dispname : conn->host.dispname;
1273 
1274  if(SSL_CONN_CONFIG(verifyhost)) {
1275  failf(data, "SSL: certificate subject name (%s) does not match "
1276  "target host name '%s'", certbuf, dispname);
1277  gnutls_x509_crt_deinit(x509_cert);
1279  }
1280  else
1281  infof(data, "\t common name: %s (does not match '%s')\n",
1282  certbuf, dispname);
1283  }
1284  else
1285  infof(data, "\t common name: %s (matched)\n", certbuf);
1286 
1287  /* Check for time-based validity */
1288  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1289 
1290  if(certclock == (time_t)-1) {
1291  if(SSL_CONN_CONFIG(verifypeer)) {
1292  failf(data, "server cert expiration date verify failed");
1293  gnutls_x509_crt_deinit(x509_cert);
1294  return CURLE_SSL_CONNECT_ERROR;
1295  }
1296  else
1297  infof(data, "\t server certificate expiration date verify FAILED\n");
1298  }
1299  else {
1300  if(certclock < time(NULL)) {
1301  if(SSL_CONN_CONFIG(verifypeer)) {
1302  failf(data, "server certificate expiration date has passed.");
1303  gnutls_x509_crt_deinit(x509_cert);
1305  }
1306  else
1307  infof(data, "\t server certificate expiration date FAILED\n");
1308  }
1309  else
1310  infof(data, "\t server certificate expiration date OK\n");
1311  }
1312 
1313  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1314 
1315  if(certclock == (time_t)-1) {
1316  if(SSL_CONN_CONFIG(verifypeer)) {
1317  failf(data, "server cert activation date verify failed");
1318  gnutls_x509_crt_deinit(x509_cert);
1319  return CURLE_SSL_CONNECT_ERROR;
1320  }
1321  else
1322  infof(data, "\t server certificate activation date verify FAILED\n");
1323  }
1324  else {
1325  if(certclock > time(NULL)) {
1326  if(SSL_CONN_CONFIG(verifypeer)) {
1327  failf(data, "server certificate not activated yet.");
1328  gnutls_x509_crt_deinit(x509_cert);
1330  }
1331  else
1332  infof(data, "\t server certificate activation date FAILED\n");
1333  }
1334  else
1335  infof(data, "\t server certificate activation date OK\n");
1336  }
1337 
1340  if(ptr) {
1341  result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
1342  if(result != CURLE_OK) {
1343  failf(data, "SSL: public key does not match pinned public key!");
1344  gnutls_x509_crt_deinit(x509_cert);
1345  return result;
1346  }
1347  }
1348 
1349  /* Show:
1350 
1351  - subject
1352  - start date
1353  - expire date
1354  - common name
1355  - issuer
1356 
1357  */
1358 
1359 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1360  /* public key algorithm's parameters */
1361  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
1362  infof(data, "\t certificate public key: %s\n",
1363  gnutls_pk_algorithm_get_name(algo));
1364 
1365  /* version of the X.509 certificate. */
1366  infof(data, "\t certificate version: #%d\n",
1367  gnutls_x509_crt_get_version(x509_cert));
1368 
1369 
1370  size = sizeof(certbuf);
1371  gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
1372  infof(data, "\t subject: %s\n", certbuf);
1373 
1374  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1375  showtime(data, "start date", certclock);
1376 
1377  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1378  showtime(data, "expire date", certclock);
1379 
1380  size = sizeof(certbuf);
1381  gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
1382  infof(data, "\t issuer: %s\n", certbuf);
1383 
1384  /* compression algorithm (if any) */
1385  ptr = gnutls_compression_get_name(gnutls_compression_get(session));
1386  /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
1387  infof(data, "\t compression: %s\n", ptr);
1388 #endif
1389 
1390  gnutls_x509_crt_deinit(x509_cert);
1391 
1392 #ifdef HAS_ALPN
1393  if(conn->bits.tls_enable_alpn) {
1394  rc = gnutls_alpn_get_selected_protocol(session, &proto);
1395  if(rc == 0) {
1396  infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
1397  proto.data);
1398 
1399 #ifdef USE_NGHTTP2
1400  if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
1401  !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
1402  NGHTTP2_PROTO_VERSION_ID_LEN)) {
1403  conn->negnpn = CURL_HTTP_VERSION_2;
1404  }
1405  else
1406 #endif
1407  if(proto.size == ALPN_HTTP_1_1_LENGTH &&
1408  !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
1409  conn->negnpn = CURL_HTTP_VERSION_1_1;
1410  }
1411  }
1412  else
1413  infof(data, "ALPN, server did not agree to a protocol\n");
1414  }
1415 #endif
1416 
1417  conn->ssl[sockindex].state = ssl_connection_complete;
1418  conn->recv[sockindex] = gtls_recv;
1419  conn->send[sockindex] = gtls_send;
1420 
1421  if(SSL_SET_OPTION(primary.sessionid)) {
1422  /* we always unconditionally get the session id here, as even if we
1423  already got it from the cache and asked to use it in the connection, it
1424  might've been rejected and then a new one is in use now and we need to
1425  detect that. */
1426  bool incache;
1427  void *ssl_sessionid;
1428  void *connect_sessionid;
1429  size_t connect_idsize = 0;
1430 
1431  /* get the session ID data size */
1432  gnutls_session_get_data(session, NULL, &connect_idsize);
1433  connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
1434 
1435  if(connect_sessionid) {
1436  /* extract session ID to the allocated buffer */
1437  gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
1438 
1439  Curl_ssl_sessionid_lock(conn);
1440  incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL,
1441  sockindex));
1442  if(incache) {
1443  /* there was one before in the cache, so instead of risking that the
1444  previous one was rejected, we just kill that and store the new */
1445  Curl_ssl_delsessionid(conn, ssl_sessionid);
1446  }
1447 
1448  /* store this session id */
1449  result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize,
1450  sockindex);
1451  Curl_ssl_sessionid_unlock(conn);
1452  if(result) {
1453  free(connect_sessionid);
1454  result = CURLE_OUT_OF_MEMORY;
1455  }
1456  }
1457  else
1458  result = CURLE_OUT_OF_MEMORY;
1459  }
1460 
1461  return result;
1462 }
1463 
1464 
1465 /*
1466  * This function is called after the TCP connect has completed. Setup the TLS
1467  * layer and do all necessary magic.
1468  */
1469 /* We use connssl->connecting_state to keep track of the connection status;
1470  there are three states: 'ssl_connect_1' (not started yet or complete),
1471  'ssl_connect_2_reading' (waiting for data from server), and
1472  'ssl_connect_2_writing' (waiting to be able to write).
1473  */
1474 static CURLcode
1475 gtls_connect_common(struct connectdata *conn,
1476  int sockindex,
1477  bool nonblocking,
1478  bool *done)
1479 {
1480  int rc;
1481  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1482 
1483  /* Initiate the connection, if not already done */
1484  if(ssl_connect_1 == connssl->connecting_state) {
1485  rc = gtls_connect_step1(conn, sockindex);
1486  if(rc)
1487  return rc;
1488  }
1489 
1490  rc = handshake(conn, sockindex, TRUE, nonblocking);
1491  if(rc)
1492  /* handshake() sets its own error message with failf() */
1493  return rc;
1494 
1495  /* Finish connecting once the handshake is done */
1496  if(ssl_connect_1 == connssl->connecting_state) {
1497  rc = gtls_connect_step3(conn, sockindex);
1498  if(rc)
1499  return rc;
1500  }
1501 
1502  *done = ssl_connect_1 == connssl->connecting_state;
1503 
1504  return CURLE_OK;
1505 }
1506 
1507 static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
1508  int sockindex, bool *done)
1509 {
1510  return gtls_connect_common(conn, sockindex, TRUE, done);
1511 }
1512 
1513 static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex)
1514 {
1515  CURLcode result;
1516  bool done = FALSE;
1517 
1518  result = gtls_connect_common(conn, sockindex, FALSE, &done);
1519  if(result)
1520  return result;
1521 
1522  DEBUGASSERT(done);
1523 
1524  return CURLE_OK;
1525 }
1526 
1527 static bool Curl_gtls_data_pending(const struct connectdata *conn,
1528  int connindex)
1529 {
1530  const struct ssl_connect_data *connssl = &conn->ssl[connindex];
1531  bool res = FALSE;
1532  if(BACKEND->session &&
1533  0 != gnutls_record_check_pending(BACKEND->session))
1534  res = TRUE;
1535 
1536  connssl = &conn->proxy_ssl[connindex];
1537  if(BACKEND->session &&
1538  0 != gnutls_record_check_pending(BACKEND->session))
1539  res = TRUE;
1540 
1541  return res;
1542 }
1543 
1544 static ssize_t gtls_send(struct connectdata *conn,
1545  int sockindex,
1546  const void *mem,
1547  size_t len,
1548  CURLcode *curlcode)
1549 {
1550  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1551  ssize_t rc = gnutls_record_send(BACKEND->session, mem, len);
1552 
1553  if(rc < 0) {
1554  *curlcode = (rc == GNUTLS_E_AGAIN)
1555  ? CURLE_AGAIN
1556  : CURLE_SEND_ERROR;
1557 
1558  rc = -1;
1559  }
1560 
1561  return rc;
1562 }
1563 
1564 static void close_one(struct ssl_connect_data *connssl)
1565 {
1566  if(BACKEND->session) {
1567  gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR);
1568  gnutls_deinit(BACKEND->session);
1569  BACKEND->session = NULL;
1570  }
1571  if(BACKEND->cred) {
1572  gnutls_certificate_free_credentials(BACKEND->cred);
1573  BACKEND->cred = NULL;
1574  }
1575 #ifdef USE_TLS_SRP
1576  if(BACKEND->srp_client_cred) {
1577  gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
1578  BACKEND->srp_client_cred = NULL;
1579  }
1580 #endif
1581 }
1582 
1583 static void Curl_gtls_close(struct connectdata *conn, int sockindex)
1584 {
1585  close_one(&conn->ssl[sockindex]);
1586  close_one(&conn->proxy_ssl[sockindex]);
1587 }
1588 
1589 /*
1590  * This function is called to shut down the SSL layer but keep the
1591  * socket open (CCC - Clear Command Channel)
1592  */
1593 static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
1594 {
1595  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1596  ssize_t result;
1597  int retval = 0;
1598  struct Curl_easy *data = conn->data;
1599  int done = 0;
1600  char buf[120];
1601 
1602  /* This has only been tested on the proftpd server, and the mod_tls code
1603  sends a close notify alert without waiting for a close notify alert in
1604  response. Thus we wait for a close notify alert from the server, but
1605  we do not send one. Let's hope other servers do the same... */
1606 
1607  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
1608  gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR);
1609 
1610  if(BACKEND->session) {
1611  while(!done) {
1612  int what = SOCKET_READABLE(conn->sock[sockindex],
1613  SSL_SHUTDOWN_TIMEOUT);
1614  if(what > 0) {
1615  /* Something to read, let's do it and hope that it is the close
1616  notify alert from the server */
1617  result = gnutls_record_recv(BACKEND->session,
1618  buf, sizeof(buf));
1619  switch(result) {
1620  case 0:
1621  /* This is the expected response. There was no data but only
1622  the close notify alert */
1623  done = 1;
1624  break;
1625  case GNUTLS_E_AGAIN:
1626  case GNUTLS_E_INTERRUPTED:
1627  infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
1628  break;
1629  default:
1630  retval = -1;
1631  done = 1;
1632  break;
1633  }
1634  }
1635  else if(0 == what) {
1636  /* timeout */
1637  failf(data, "SSL shutdown timeout");
1638  done = 1;
1639  break;
1640  }
1641  else {
1642  /* anything that gets here is fatally bad */
1643  failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1644  retval = -1;
1645  done = 1;
1646  }
1647  }
1648  gnutls_deinit(BACKEND->session);
1649  }
1650  gnutls_certificate_free_credentials(BACKEND->cred);
1651 
1652 #ifdef USE_TLS_SRP
1653  if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
1654  && SSL_SET_OPTION(username) != NULL)
1655  gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
1656 #endif
1657 
1658  BACKEND->cred = NULL;
1659  BACKEND->session = NULL;
1660 
1661  return retval;
1662 }
1663 
1664 static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
1665  int num, /* socketindex */
1666  char *buf, /* store read data here */
1667  size_t buffersize, /* max amount to read */
1668  CURLcode *curlcode)
1669 {
1670  struct ssl_connect_data *connssl = &conn->ssl[num];
1671  ssize_t ret;
1672 
1673  ret = gnutls_record_recv(BACKEND->session, buf, buffersize);
1674  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
1675  *curlcode = CURLE_AGAIN;
1676  return -1;
1677  }
1678 
1679  if(ret == GNUTLS_E_REHANDSHAKE) {
1680  /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
1681  proper way" takes a whole lot of work. */
1682  CURLcode result = handshake(conn, num, FALSE, FALSE);
1683  if(result)
1684  /* handshake() writes error message on its own */
1685  *curlcode = result;
1686  else
1687  *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
1688  return -1;
1689  }
1690 
1691  if(ret < 0) {
1692  failf(conn->data, "GnuTLS recv error (%d): %s",
1693 
1694  (int)ret, gnutls_strerror((int)ret));
1695  *curlcode = CURLE_RECV_ERROR;
1696  return -1;
1697  }
1698 
1699  return ret;
1700 }
1701 
1702 static void Curl_gtls_session_free(void *ptr)
1703 {
1704  free(ptr);
1705 }
1706 
1707 static size_t Curl_gtls_version(char *buffer, size_t size)
1708 {
1709  return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1710 }
1711 
1712 #ifndef USE_GNUTLS_NETTLE
1713 static int Curl_gtls_seed(struct Curl_easy *data)
1714 {
1715  /* we have the "SSL is seeded" boolean static to prevent multiple
1716  time-consuming seedings in vain */
1717  static bool ssl_seeded = FALSE;
1718 
1719  /* Quickly add a bit of entropy */
1720  gcry_fast_random_poll();
1721 
1722  if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
1723  data->set.str[STRING_SSL_EGDSOCKET]) {
1724 
1725  /* TODO: to a good job seeding the RNG
1726  This may involve the gcry_control function and these options:
1727  GCRYCTL_SET_RANDOM_SEED_FILE
1728  GCRYCTL_SET_RNDEGD_SOCKET
1729  */
1730  ssl_seeded = TRUE;
1731  }
1732  return 0;
1733 }
1734 #endif
1735 
1736 /* data might be NULL! */
1737 static CURLcode Curl_gtls_random(struct Curl_easy *data,
1738  unsigned char *entropy, size_t length)
1739 {
1740 #if defined(USE_GNUTLS_NETTLE)
1741  int rc;
1742  (void)data;
1743  rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
1744  return rc?CURLE_FAILED_INIT:CURLE_OK;
1745 #elif defined(USE_GNUTLS)
1746  if(data)
1747  Curl_gtls_seed(data); /* Initiate the seed if not already done */
1748  gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
1749 #endif
1750  return CURLE_OK;
1751 }
1752 
1753 static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */
1754  size_t tmplen,
1755  unsigned char *md5sum, /* output */
1756  size_t md5len)
1757 {
1758 #if defined(USE_GNUTLS_NETTLE)
1759  struct md5_ctx MD5pw;
1760  md5_init(&MD5pw);
1761  md5_update(&MD5pw, (unsigned int)tmplen, tmp);
1762  md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
1763 #elif defined(USE_GNUTLS)
1764  gcry_md_hd_t MD5pw;
1765  gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
1766  gcry_md_write(MD5pw, tmp, tmplen);
1767  memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
1768  gcry_md_close(MD5pw);
1769 #endif
1770  return CURLE_OK;
1771 }
1772 
1773 static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
1774  size_t tmplen,
1775  unsigned char *sha256sum, /* output */
1776  size_t sha256len)
1777 {
1778 #if defined(USE_GNUTLS_NETTLE)
1779  struct sha256_ctx SHA256pw;
1780  sha256_init(&SHA256pw);
1781  sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
1782  sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
1783 #elif defined(USE_GNUTLS)
1784  gcry_md_hd_t SHA256pw;
1785  gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
1786  gcry_md_write(SHA256pw, tmp, tmplen);
1787  memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
1788  gcry_md_close(SHA256pw);
1789 #endif
1790 }
1791 
1792 static bool Curl_gtls_cert_status_request(void)
1793 {
1794 #ifdef HAS_OCSP
1795  return TRUE;
1796 #else
1797  return FALSE;
1798 #endif
1799 }
1800 
1801 static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
1802  CURLINFO info UNUSED_PARAM)
1803 {
1804  (void)info;
1805  return BACKEND->session;
1806 }
1807 
1808 const struct Curl_ssl Curl_ssl_gnutls = {
1809  { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
1810 
1811  1, /* have_ca_path */
1812  1, /* have_certinfo */
1813  1, /* have_pinnedpubkey */
1814  0, /* have_ssl_ctx */
1815  1, /* support_https_proxy */
1816 
1817  sizeof(struct ssl_backend_data),
1818 
1819  Curl_gtls_init, /* init */
1820  Curl_gtls_cleanup, /* cleanup */
1821  Curl_gtls_version, /* version */
1822  Curl_none_check_cxn, /* check_cxn */
1823  Curl_gtls_shutdown, /* shutdown */
1824  Curl_gtls_data_pending, /* data_pending */
1825  Curl_gtls_random, /* random */
1826  Curl_gtls_cert_status_request, /* cert_status_request */
1827  Curl_gtls_connect, /* connect */
1828  Curl_gtls_connect_nonblocking, /* connect_nonblocking */
1829  Curl_gtls_get_internals, /* get_internals */
1830  Curl_gtls_close, /* close */
1831  Curl_none_close_all, /* close_all */
1832  Curl_gtls_session_free, /* session_free */
1833  Curl_none_set_engine, /* set_engine */
1834  Curl_none_set_engine_default, /* set_engine_default */
1835  Curl_none_engines_list, /* engines_list */
1836  Curl_none_false_start, /* false_start */
1837  Curl_gtls_md5sum, /* md5sum */
1838  Curl_gtls_sha256sum /* sha256sum */
1839 };
1840 
1841 #endif /* USE_GNUTLS */
#define free(ptr)
Definition: curl_memory.h:130
struct ssl_connect_data ssl[2]
Definition: urldata.h:887
#define UNUSED_PARAM
Definition: curl_setup.h:660
ssize_t( Curl_recv)(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err)
Definition: urldata.h:737
struct ConnectBits bits
Definition: urldata.h:893
const char *const Curl_wkday[]
Definition: parsedate.c:87
static long init_flags
Definition: easy.c:148
struct UserDefined set
Definition: urldata.h:1762
Curl_recv * recv[2]
Definition: urldata.h:881
#define SSL_CONN_CONFIG(var)
Definition: vtls.h:135
int negnpn
Definition: urldata.h:1027
struct hostname host
Definition: urldata.h:758
f
#define ALPN_HTTP_1_1
Definition: vtls.h:125
#define CURL_SOCKET_BAD
Definition: curl.h:131
Definition: vtls.h:29
#define failf
Definition: sendf.h:48
#define SSL_SET_OPTION(var)
Definition: vtls.h:133
ssl_connect_state connecting_state
Definition: urldata.h:201
const char *const Curl_month[]
Definition: parsedate.c:92
#define strdup(ptr)
Definition: curl_memory.h:122
#define SOCKERRNO
#define DEBUGASSERT(x)
UNITTEST_START char * ptr
Definition: unit1330.c:38
CURLcode
Definition: curl.h:454
static const struct Curl_handler *const protocols[]
Definition: url.c:161
CURLINFO
Definition: curl.h:2439
#define ENABLE_IPV6
Definition: config-os400.h:71
static int res
struct hostname host
Definition: urldata.h:833
static char * password
Definition: unit1304.c:27
#define strcasecompare(a, b)
Definition: strcase.h:35
int curlx_uztosi(size_t uznum)
Definition: warnless.c:203
#define malloc(size)
Definition: curl_memory.h:124
char * name
Definition: urldata.h:444
UNITTEST_START int result
Definition: unit1304.c:49
char buffer[]
Definition: unit1308.c:48
struct ssl_config_data ssl
Definition: urldata.h:1586
unsigned int i
Definition: unit1303.c:79
size_t len
Definition: curl_sasl.c:55
struct proxy_info http_proxy
Definition: urldata.h:839
curl_ftpccc ftp_ccc
Definition: urldata.h:1646
ssl_connection_state state
Definition: urldata.h:200
long httpversion
Definition: urldata.h:1583
memcpy(filename, filename1, strlen(filename1))
int Curl_none_check_cxn(struct connectdata *conn)
#define ALPN_HTTP_1_1_LENGTH
Definition: vtls.h:124
const char * str
Definition: unit1398.c:33
#define FALSE
time_t Curl_timeleft(struct Curl_easy *data, struct curltime *nowp, bool duringconnect)
Definition: connect.c:182
UNITTEST_START int rc
Definition: unit1301.c:31
bool tls_enable_alpn
Definition: urldata.h:435
bool Curl_none_false_start(void)
#define SOCKET_READABLE(x, z)
Definition: select.h:79
bool tunnel_proxy
Definition: urldata.h:400
Curl_send * send[2]
Definition: urldata.h:882
Definition: curl.h:455
ssize_t( Curl_send)(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err)
Definition: urldata.h:730
int Curl_inet_pton(int af, const char *src, void *dst)
Definition: inet_pton.c:66
#define Curl_safefree(ptr)
Definition: memdebug.h:170
int Curl_socket_check(curl_socket_t readfd0, curl_socket_t readfd1, curl_socket_t writefd, time_t timeout_ms)
Definition: select.c:145
CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine)
size_t fread(void *, size_t, size_t, FILE *)
#define ssize_t
Definition: config-win32.h:382
curl_socket_t sock[2]
Definition: urldata.h:876
CURLcode Curl_gmtime(time_t intime, struct tm *store)
Definition: parsedate.c:570
struct curl_slist * Curl_none_engines_list(struct Curl_easy *data)
char buf[3]
Definition: unit1398.c:32
#define infof
Definition: sendf.h:44
char * str[STRING_LAST]
Definition: urldata.h:1663
struct ssl_connect_data proxy_ssl[2]
Definition: urldata.h:888
#define CURL_HTTP_VERSION_2
Definition: curl.h:1879
size_t size
Definition: unit1302.c:52
#define fprintf
Definition: curl_printf.h:41
#define snprintf
Definition: curl_printf.h:42
#define TRUE
int curl_socket_t
Definition: curl.h:130
const char * dispname
Definition: urldata.h:445
int key
Definition: unit1602.c:56
CURLcode Curl_none_set_engine_default(struct Curl_easy *data)
Definition: debug.c:29
void Curl_none_close_all(struct Curl_easy *data)
#define SSL_IS_PROXY()
Definition: vtls.h:130
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15