VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/vtls/gtls.c@ 90406

Last change on this file since 90406 was 85671, checked in by vboxsync, 5 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette