VirtualBox

source: vbox/trunk/src/libs/curl-8.0.1/lib/vtls/gtls.c@ 99344

Last change on this file since 99344 was 99344, checked in by vboxsync, 22 months ago

curl-8.0.1: Applied and adjusted our curl changes to 7.87.0 bugref:10417

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