source: EcnlProtoTool/trunk/curl-7.57.0/lib/vtls/gtls.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 55.8 KB
Line 
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
76static void tls_log_func(int level, const char *str)
77{
78 fprintf(stderr, "|<%d>| %s", level, str);
79}
80#endif
81static 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
110struct 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
148static 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
162static 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
172static 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
182static 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
187static 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 */
199static 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
213static 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
222static 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
248static 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;
270out:
271 fclose(f);
272 return loaded_file;
273}
274
275static void unload_file(gnutls_datum_t data)
276{
277 free(data.data);
278}
279
280
281/* this function does a SSL/TLS (re-)handshake */
282static 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");
302 return CURLE_OPERATION_TIMEDOUT;
303 }
304
305 /* if ssl is expecting something, check if it's available. */
306 if(connssl->connecting_state == ssl_connect_2_reading
307 || connssl->connecting_state == ssl_connect_2_writing) {
308
309 curl_socket_t writefd = ssl_connect_2_writing ==
310 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
311 curl_socket_t readfd = ssl_connect_2_reading ==
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);
320 return CURLE_SSL_CONNECT_ERROR;
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);
328 return CURLE_OPERATION_TIMEDOUT;
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)?
339 ssl_connect_2_writing:ssl_connect_2_reading;
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);
368 return CURLE_SSL_CONNECT_ERROR;
369 }
370
371 /* Reset our connect state machine */
372 connssl->connecting_state = ssl_connect_1;
373 return CURLE_OK;
374 }
375}
376
377static 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
389static CURLcode
390set_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) {
399 case CURL_SSLVERSION_MAX_NONE:
400 ssl_version_max = ssl_version << 16;
401 break;
402 case CURL_SSLVERSION_MAX_DEFAULT:
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) {
410 case CURL_SSLVERSION_TLSv1_0:
411 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0;
412 break;
413 case CURL_SSLVERSION_TLSv1_1:
414 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1;
415 break;
416 case CURL_SSLVERSION_TLSv1_2:
417 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2;
418 break;
419 case CURL_SSLVERSION_TLSv1_3:
420 failf(data, "GnuTLS: TLS 1.3 is not yet supported");
421 return CURLE_SSL_CONNECT_ERROR;
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
433static CURLcode
434set_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");
442 return CURLE_SSL_CONNECT_ERROR;
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) {
448 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
449 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
450 "+VERS-TLS1.0:" GNUTLS_SRP;
451 return CURLE_OK;
452 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
453 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
454 "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP;
455 return CURLE_OK;
456 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
457 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
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;
461 case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
462 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
463 "+VERS-TLS1.1:" GNUTLS_SRP;
464 return CURLE_OK;
465 case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
466 case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
467 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
468 "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
469 return CURLE_OK;
470 case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
471 case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
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");
478 return CURLE_SSL_CONNECT_ERROR;
479}
480#endif
481
482static CURLcode
483gtls_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");
533 return CURLE_SSL_CONNECT_ERROR;
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));
542 return CURLE_SSL_CONNECT_ERROR;
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),
559 SSL_SET_OPTION(password));
560 if(rc != GNUTLS_E_SUCCESS) {
561 failf(data, "gnutls_srp_set_client_cred() failed: %s",
562 gnutls_strerror(rc));
563 return CURLE_BAD_FUNCTION_ARGUMENT;
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))
580 return CURLE_SSL_CACERT_BADFILE;
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))
597 return CURLE_SSL_CACERT_BADFILE;
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);
639 return CURLE_SSL_CONNECT_ERROR;
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)
658 return CURLE_SSL_CONNECT_ERROR;
659
660#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
661 rc = gnutls_cipher_set_priority(session, cipher_priority);
662 if(rc != GNUTLS_E_SUCCESS)
663 return CURLE_SSL_CONNECT_ERROR;
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)
670 return CURLE_SSL_CONNECT_ERROR;
671
672 if(SSL_CONN_CONFIG(cipher_list) != NULL) {
673 failf(data, "can't pass a custom cipher list to older GnuTLS"
674 " versions");
675 return CURLE_SSL_CONNECT_ERROR;
676 }
677
678 switch(SSL_CONN_CONFIG(version)) {
679 case CURL_SSLVERSION_SSLv3:
680 protocol_priority[0] = GNUTLS_SSL3;
681 break;
682 case CURL_SSLVERSION_DEFAULT:
683 case CURL_SSLVERSION_TLSv1:
684 protocol_priority[0] = GNUTLS_TLS1_0;
685 protocol_priority[1] = GNUTLS_TLS1_1;
686 protocol_priority[2] = GNUTLS_TLS1_2;
687 break;
688 case CURL_SSLVERSION_TLSv1_0:
689 case CURL_SSLVERSION_TLSv1_1:
690 case CURL_SSLVERSION_TLSv1_2:
691 case CURL_SSLVERSION_TLSv1_3:
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 }
699 case CURL_SSLVERSION_SSLv2:
700 failf(data, "GnuTLS does not support SSLv2");
701 return CURLE_SSL_CONNECT_ERROR;
702 default:
703 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
704 return CURLE_SSL_CONNECT_ERROR;
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?");
709 return CURLE_SSL_CONNECT_ERROR;
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)) {
717 case CURL_SSLVERSION_SSLv3:
718 prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
719 sni = false;
720 break;
721 case CURL_SSLVERSION_DEFAULT:
722 case CURL_SSLVERSION_TLSv1:
723 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
724 break;
725 case CURL_SSLVERSION_TLSv1_0:
726 case CURL_SSLVERSION_TLSv1_1:
727 case CURL_SSLVERSION_TLSv1_2:
728 case CURL_SSLVERSION_TLSv1_3:
729 {
730 CURLcode result = set_ssl_version_min_max(&prioritylist, conn);
731 if(result != CURLE_OK)
732 return result;
733 break;
734 }
735 case CURL_SSLVERSION_SSLv2:
736 failf(data, "GnuTLS does not support SSLv2");
737 return CURLE_SSL_CONNECT_ERROR;
738 default:
739 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
740 return CURLE_SSL_CONNECT_ERROR;
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);
763 return CURLE_SSL_CONNECT_ERROR;
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),
802 SSL_SET_OPTION(key) ?
803 SSL_SET_OPTION(key) : 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));
811 return CURLE_SSL_CONNECT_ERROR;
812 }
813#else
814 failf(data, "gnutls lacks support for encrypted key files");
815 return CURLE_SSL_CONNECT_ERROR;
816#endif
817 }
818 else {
819 if(gnutls_certificate_set_x509_key_file(
820 BACKEND->cred,
821 SSL_SET_OPTION(cert),
822 SSL_SET_OPTION(key) ?
823 SSL_SET_OPTION(key) : 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");
827 return CURLE_SSL_CONNECT_ERROR;
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));
839 return CURLE_SSL_CONNECT_ERROR;
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));
849 return CURLE_SSL_CONNECT_ERROR;
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);
880 return CURLE_SSL_CONNECT_ERROR;
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
905static 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;
917 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
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
962static Curl_recv gtls_recv;
963static Curl_send gtls_send;
964
965static CURLcode
966gtls_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");
1024 return CURLE_PEER_FAILED_VERIFICATION;
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");
1096 return CURLE_SSL_INVALIDCERTSTATUS;
1097 }
1098
1099 if(rc < 0) {
1100 failf(data, "Invalid OCSP response received");
1101 return CURLE_SSL_INVALIDCERTSTATUS;
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");
1109 return CURLE_SSL_INVALIDCERTSTATUS;
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
1177 return CURLE_SSL_INVALIDCERTSTATUS;
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);
1278 return CURLE_PEER_FAILED_VERIFICATION;
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);
1304 return CURLE_PEER_FAILED_VERIFICATION;
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);
1329 return CURLE_PEER_FAILED_VERIFICATION;
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
1338 ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1339 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
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 */
1474static CURLcode
1475gtls_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
1507static 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
1513static 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
1527static 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
1544static 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
1564static 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
1583static 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 */
1593static 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
1664static 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
1702static void Curl_gtls_session_free(void *ptr)
1703{
1704 free(ptr);
1705}
1706
1707static 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
1713static 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! */
1737static 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
1753static 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
1773static 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
1792static bool Curl_gtls_cert_status_request(void)
1793{
1794#ifdef HAS_OCSP
1795 return TRUE;
1796#else
1797 return FALSE;
1798#endif
1799}
1800
1801static 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
1808const 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_one */
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 */
Note: See TracBrowser for help on using the repository browser.