VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/vtls/gtls.c@ 106542

最後變更 在這個檔案從106542是 104083,由 vboxsync 提交於 11 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

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