libcurl: updated to 7.49.1
[tomato.git] / release / src / router / libcurl / lib / vtls / gtls.c
blob1b5a6a4d5273c110d4c7765e5341537f030b6e0a
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
24 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
25 * but vtls.c should ever call or use these functions.
27 * Note: don't use the GnuTLS' *_t variable type names in this source code,
28 * since they were not present in 1.0.X.
31 #include "curl_setup.h"
33 #ifdef USE_GNUTLS
35 #include <gnutls/abstract.h>
36 #include <gnutls/gnutls.h>
37 #include <gnutls/x509.h>
39 #ifdef USE_GNUTLS_NETTLE
40 #include <gnutls/crypto.h>
41 #include <nettle/md5.h>
42 #include <nettle/sha2.h>
43 #else
44 #include <gcrypt.h>
45 #endif
47 #include "urldata.h"
48 #include "sendf.h"
49 #include "inet_pton.h"
50 #include "gtls.h"
51 #include "vtls.h"
52 #include "parsedate.h"
53 #include "connect.h" /* for the connect timeout */
54 #include "select.h"
55 #include "rawstr.h"
56 #include "warnless.h"
57 #include "x509asn1.h"
58 #include "curl_printf.h"
59 #include "curl_memory.h"
60 /* The last #include file should be: */
61 #include "memdebug.h"
64 Some hackish cast macros based on:
65 https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html
67 #ifndef GNUTLS_POINTER_TO_INT_CAST
68 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
69 #endif
70 #ifndef GNUTLS_INT_TO_POINTER_CAST
71 #define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
72 #endif
74 /* Enable GnuTLS debugging by defining GTLSDEBUG */
75 /*#define GTLSDEBUG */
77 #ifdef GTLSDEBUG
78 static void tls_log_func(int level, const char *str)
80 fprintf(stderr, "|<%d>| %s", level, str);
82 #endif
83 static bool gtls_inited = FALSE;
85 #if defined(GNUTLS_VERSION_NUMBER)
86 # if (GNUTLS_VERSION_NUMBER >= 0x020c00)
87 # undef gnutls_transport_set_lowat
88 # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
89 # define USE_GNUTLS_PRIORITY_SET_DIRECT 1
90 # endif
91 # if (GNUTLS_VERSION_NUMBER >= 0x020c03)
92 # define GNUTLS_MAPS_WINSOCK_ERRORS 1
93 # endif
95 # if (GNUTLS_VERSION_NUMBER >= 0x030200)
96 # define HAS_ALPN
97 # endif
99 # if (GNUTLS_VERSION_NUMBER >= 0x03020d)
100 # define HAS_OCSP
101 # endif
103 # if (GNUTLS_VERSION_NUMBER >= 0x030306)
104 # define HAS_CAPATH
105 # endif
106 #endif
108 #ifdef HAS_OCSP
109 # include <gnutls/ocsp.h>
110 #endif
113 * Custom push and pull callback functions used by GNU TLS to read and write
114 * to the socket. These functions are simple wrappers to send() and recv()
115 * (although here using the sread/swrite macros as defined by
116 * curl_setup_once.h).
117 * We use custom functions rather than the GNU TLS defaults because it allows
118 * us to get specific about the fourth "flags" argument, and to use arbitrary
119 * private data with gnutls_transport_set_ptr if we wish.
121 * When these custom push and pull callbacks fail, GNU TLS checks its own
122 * session-specific error variable, and when not set also its own global
123 * errno variable, in order to take appropriate action. GNU TLS does not
124 * require that the transport is actually a socket. This implies that for
125 * Windows builds these callbacks should ideally set the session-specific
126 * error variable using function gnutls_transport_set_errno or as a last
127 * resort global errno variable using gnutls_transport_set_global_errno,
128 * with a transport agnostic error value. This implies that some winsock
129 * error translation must take place in these callbacks.
131 * Paragraph above applies to GNU TLS versions older than 2.12.3, since
132 * this version GNU TLS does its own internal winsock error translation
133 * using system_errno() function.
136 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
137 # define gtls_EINTR 4
138 # define gtls_EIO 5
139 # define gtls_EAGAIN 11
140 static int gtls_mapped_sockerrno(void)
142 switch(SOCKERRNO) {
143 case WSAEWOULDBLOCK:
144 return gtls_EAGAIN;
145 case WSAEINTR:
146 return gtls_EINTR;
147 default:
148 break;
150 return gtls_EIO;
152 #endif
154 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
156 ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
157 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
158 if(ret < 0)
159 gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
160 #endif
161 return ret;
164 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
166 ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
167 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
168 if(ret < 0)
169 gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
170 #endif
171 return ret;
174 /* Curl_gtls_init()
176 * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
177 * are not thread-safe and thus this function itself is not thread-safe and
178 * must only be called from within curl_global_init() to keep the thread
179 * situation under control!
181 int Curl_gtls_init(void)
183 int ret = 1;
184 if(!gtls_inited) {
185 ret = gnutls_global_init()?0:1;
186 #ifdef GTLSDEBUG
187 gnutls_global_set_log_function(tls_log_func);
188 gnutls_global_set_log_level(2);
189 #endif
190 gtls_inited = TRUE;
192 return ret;
195 int Curl_gtls_cleanup(void)
197 if(gtls_inited) {
198 gnutls_global_deinit();
199 gtls_inited = FALSE;
201 return 1;
204 static void showtime(struct SessionHandle *data,
205 const char *text,
206 time_t stamp)
208 struct tm buffer;
209 const struct tm *tm = &buffer;
210 CURLcode result = Curl_gmtime(stamp, &buffer);
211 if(result)
212 return;
214 snprintf(data->state.buffer,
215 BUFSIZE,
216 "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
217 text,
218 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
219 tm->tm_mday,
220 Curl_month[tm->tm_mon],
221 tm->tm_year + 1900,
222 tm->tm_hour,
223 tm->tm_min,
224 tm->tm_sec);
225 infof(data, "%s\n", data->state.buffer);
228 static gnutls_datum_t load_file (const char *file)
230 FILE *f;
231 gnutls_datum_t loaded_file = { NULL, 0 };
232 long filelen;
233 void *ptr;
235 if(!(f = fopen(file, "rb")))
236 return loaded_file;
237 if(fseek(f, 0, SEEK_END) != 0
238 || (filelen = ftell(f)) < 0
239 || fseek(f, 0, SEEK_SET) != 0
240 || !(ptr = malloc((size_t)filelen)))
241 goto out;
242 if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
243 free(ptr);
244 goto out;
247 loaded_file.data = ptr;
248 loaded_file.size = (unsigned int)filelen;
249 out:
250 fclose(f);
251 return loaded_file;
254 static void unload_file(gnutls_datum_t data) {
255 free(data.data);
259 /* this function does a SSL/TLS (re-)handshake */
260 static CURLcode handshake(struct connectdata *conn,
261 int sockindex,
262 bool duringconnect,
263 bool nonblocking)
265 struct SessionHandle *data = conn->data;
266 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
267 gnutls_session_t session = conn->ssl[sockindex].session;
268 curl_socket_t sockfd = conn->sock[sockindex];
269 long timeout_ms;
270 int rc;
271 int what;
273 for(;;) {
274 /* check allowed time left */
275 timeout_ms = Curl_timeleft(data, NULL, duringconnect);
277 if(timeout_ms < 0) {
278 /* no need to continue if time already is up */
279 failf(data, "SSL connection timeout");
280 return CURLE_OPERATION_TIMEDOUT;
283 /* if ssl is expecting something, check if it's available. */
284 if(connssl->connecting_state == ssl_connect_2_reading
285 || connssl->connecting_state == ssl_connect_2_writing) {
287 curl_socket_t writefd = ssl_connect_2_writing==
288 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
289 curl_socket_t readfd = ssl_connect_2_reading==
290 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
292 what = Curl_socket_ready(readfd, writefd,
293 nonblocking?0:
294 timeout_ms?timeout_ms:1000);
295 if(what < 0) {
296 /* fatal error */
297 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
298 return CURLE_SSL_CONNECT_ERROR;
300 else if(0 == what) {
301 if(nonblocking)
302 return CURLE_OK;
303 else if(timeout_ms) {
304 /* timeout */
305 failf(data, "SSL connection timeout at %ld", timeout_ms);
306 return CURLE_OPERATION_TIMEDOUT;
309 /* socket is readable or writable */
312 rc = gnutls_handshake(session);
314 if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
315 connssl->connecting_state =
316 gnutls_record_get_direction(session)?
317 ssl_connect_2_writing:ssl_connect_2_reading;
318 continue;
320 else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
321 const char *strerr = NULL;
323 if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
324 int alert = gnutls_alert_get(session);
325 strerr = gnutls_alert_get_name(alert);
328 if(strerr == NULL)
329 strerr = gnutls_strerror(rc);
331 infof(data, "gnutls_handshake() warning: %s\n", strerr);
332 continue;
334 else if(rc < 0) {
335 const char *strerr = NULL;
337 if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
338 int alert = gnutls_alert_get(session);
339 strerr = gnutls_alert_get_name(alert);
342 if(strerr == NULL)
343 strerr = gnutls_strerror(rc);
345 failf(data, "gnutls_handshake() failed: %s", strerr);
346 return CURLE_SSL_CONNECT_ERROR;
349 /* Reset our connect state machine */
350 connssl->connecting_state = ssl_connect_1;
351 return CURLE_OK;
355 static gnutls_x509_crt_fmt_t do_file_type(const char *type)
357 if(!type || !type[0])
358 return GNUTLS_X509_FMT_PEM;
359 if(Curl_raw_equal(type, "PEM"))
360 return GNUTLS_X509_FMT_PEM;
361 if(Curl_raw_equal(type, "DER"))
362 return GNUTLS_X509_FMT_DER;
363 return -1;
366 static CURLcode
367 gtls_connect_step1(struct connectdata *conn,
368 int sockindex)
370 struct SessionHandle *data = conn->data;
371 gnutls_session_t session;
372 int rc;
373 void *ssl_sessionid;
374 size_t ssl_idsize;
375 bool sni = TRUE; /* default is SNI enabled */
376 #ifdef ENABLE_IPV6
377 struct in6_addr addr;
378 #else
379 struct in_addr addr;
380 #endif
381 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
382 static const int cipher_priority[] = {
383 /* These two ciphers were added to GnuTLS as late as ver. 3.0.1,
384 but this code path is only ever used for ver. < 2.12.0.
385 GNUTLS_CIPHER_AES_128_GCM,
386 GNUTLS_CIPHER_AES_256_GCM,
388 GNUTLS_CIPHER_AES_128_CBC,
389 GNUTLS_CIPHER_AES_256_CBC,
390 GNUTLS_CIPHER_CAMELLIA_128_CBC,
391 GNUTLS_CIPHER_CAMELLIA_256_CBC,
392 GNUTLS_CIPHER_3DES_CBC,
394 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
395 static int protocol_priority[] = { 0, 0, 0, 0 };
396 #else
397 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
398 /* If GnuTLS was compiled without support for SRP it will error out if SRP is
399 requested in the priority string, so treat it specially
401 #define GNUTLS_SRP "+SRP"
402 const char* prioritylist;
403 const char *err = NULL;
404 #endif
406 if(conn->ssl[sockindex].state == ssl_connection_complete)
407 /* to make us tolerant against being called more than once for the
408 same connection */
409 return CURLE_OK;
411 if(!gtls_inited)
412 Curl_gtls_init();
414 /* GnuTLS only supports SSLv3 and TLSv1 */
415 if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
416 failf(data, "GnuTLS does not support SSLv2");
417 return CURLE_SSL_CONNECT_ERROR;
419 else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
420 sni = FALSE; /* SSLv3 has no SNI */
422 /* allocate a cred struct */
423 rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
424 if(rc != GNUTLS_E_SUCCESS) {
425 failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
426 return CURLE_SSL_CONNECT_ERROR;
429 #ifdef USE_TLS_SRP
430 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
431 infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
433 rc = gnutls_srp_allocate_client_credentials(
434 &conn->ssl[sockindex].srp_client_cred);
435 if(rc != GNUTLS_E_SUCCESS) {
436 failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
437 gnutls_strerror(rc));
438 return CURLE_OUT_OF_MEMORY;
441 rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
442 srp_client_cred,
443 data->set.ssl.username,
444 data->set.ssl.password);
445 if(rc != GNUTLS_E_SUCCESS) {
446 failf(data, "gnutls_srp_set_client_cred() failed: %s",
447 gnutls_strerror(rc));
448 return CURLE_BAD_FUNCTION_ARGUMENT;
451 #endif
453 if(data->set.ssl.CAfile) {
454 /* set the trusted CA cert bundle file */
455 gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
456 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
458 rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
459 data->set.ssl.CAfile,
460 GNUTLS_X509_FMT_PEM);
461 if(rc < 0) {
462 infof(data, "error reading ca cert file %s (%s)\n",
463 data->set.ssl.CAfile, gnutls_strerror(rc));
464 if(data->set.ssl.verifypeer)
465 return CURLE_SSL_CACERT_BADFILE;
467 else
468 infof(data, "found %d certificates in %s\n",
469 rc, data->set.ssl.CAfile);
472 #ifdef HAS_CAPATH
473 if(data->set.ssl.CApath) {
474 /* set the trusted CA cert directory */
475 rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
476 data->set.ssl.CApath,
477 GNUTLS_X509_FMT_PEM);
478 if(rc < 0) {
479 infof(data, "error reading ca cert file %s (%s)\n",
480 data->set.ssl.CAfile, gnutls_strerror(rc));
481 if(data->set.ssl.verifypeer)
482 return CURLE_SSL_CACERT_BADFILE;
484 else
485 infof(data, "found %d certificates in %s\n",
486 rc, data->set.ssl.CApath);
488 #endif
490 #ifdef CURL_CA_FALLBACK
491 /* use system ca certificate store as fallback */
492 if(data->set.ssl.verifypeer &&
493 !(data->set.ssl.CAfile || data->set.ssl.CApath)) {
494 gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
496 #endif
498 if(data->set.ssl.CRLfile) {
499 /* set the CRL list file */
500 rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
501 data->set.ssl.CRLfile,
502 GNUTLS_X509_FMT_PEM);
503 if(rc < 0) {
504 failf(data, "error reading crl file %s (%s)",
505 data->set.ssl.CRLfile, gnutls_strerror(rc));
506 return CURLE_SSL_CRL_BADFILE;
508 else
509 infof(data, "found %d CRL in %s\n",
510 rc, data->set.ssl.CRLfile);
513 /* Initialize TLS session as a client */
514 rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
515 if(rc != GNUTLS_E_SUCCESS) {
516 failf(data, "gnutls_init() failed: %d", rc);
517 return CURLE_SSL_CONNECT_ERROR;
520 /* convenient assign */
521 session = conn->ssl[sockindex].session;
523 if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
524 #ifdef ENABLE_IPV6
525 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
526 #endif
527 sni &&
528 (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
529 strlen(conn->host.name)) < 0))
530 infof(data, "WARNING: failed to configure server name indication (SNI) "
531 "TLS extension\n");
533 /* Use default priorities */
534 rc = gnutls_set_default_priority(session);
535 if(rc != GNUTLS_E_SUCCESS)
536 return CURLE_SSL_CONNECT_ERROR;
538 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
539 rc = gnutls_cipher_set_priority(session, cipher_priority);
540 if(rc != GNUTLS_E_SUCCESS)
541 return CURLE_SSL_CONNECT_ERROR;
543 /* Sets the priority on the certificate types supported by gnutls. Priority
544 is higher for types specified before others. After specifying the types
545 you want, you must append a 0. */
546 rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
547 if(rc != GNUTLS_E_SUCCESS)
548 return CURLE_SSL_CONNECT_ERROR;
550 if(data->set.ssl.cipher_list != NULL) {
551 failf(data, "can't pass a custom cipher list to older GnuTLS"
552 " versions");
553 return CURLE_SSL_CONNECT_ERROR;
556 switch (data->set.ssl.version) {
557 case CURL_SSLVERSION_SSLv3:
558 protocol_priority[0] = GNUTLS_SSL3;
559 break;
560 case CURL_SSLVERSION_DEFAULT:
561 case CURL_SSLVERSION_TLSv1:
562 protocol_priority[0] = GNUTLS_TLS1_0;
563 protocol_priority[1] = GNUTLS_TLS1_1;
564 protocol_priority[2] = GNUTLS_TLS1_2;
565 break;
566 case CURL_SSLVERSION_TLSv1_0:
567 protocol_priority[0] = GNUTLS_TLS1_0;
568 break;
569 case CURL_SSLVERSION_TLSv1_1:
570 protocol_priority[0] = GNUTLS_TLS1_1;
571 break;
572 case CURL_SSLVERSION_TLSv1_2:
573 protocol_priority[0] = GNUTLS_TLS1_2;
574 break;
575 case CURL_SSLVERSION_SSLv2:
576 default:
577 failf(data, "GnuTLS does not support SSLv2");
578 return CURLE_SSL_CONNECT_ERROR;
579 break;
581 rc = gnutls_protocol_set_priority(session, protocol_priority);
582 if(rc != GNUTLS_E_SUCCESS) {
583 failf(data, "Did you pass a valid GnuTLS cipher list?");
584 return CURLE_SSL_CONNECT_ERROR;
587 #else
588 /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
589 * removed if a run-time error indicates that SRP is not supported by this
590 * GnuTLS version */
591 switch (data->set.ssl.version) {
592 case CURL_SSLVERSION_SSLv3:
593 prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
594 sni = false;
595 break;
596 case CURL_SSLVERSION_DEFAULT:
597 case CURL_SSLVERSION_TLSv1:
598 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
599 break;
600 case CURL_SSLVERSION_TLSv1_0:
601 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
602 "+VERS-TLS1.0:" GNUTLS_SRP;
603 break;
604 case CURL_SSLVERSION_TLSv1_1:
605 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
606 "+VERS-TLS1.1:" GNUTLS_SRP;
607 break;
608 case CURL_SSLVERSION_TLSv1_2:
609 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
610 "+VERS-TLS1.2:" GNUTLS_SRP;
611 break;
612 case CURL_SSLVERSION_SSLv2:
613 default:
614 failf(data, "GnuTLS does not support SSLv2");
615 return CURLE_SSL_CONNECT_ERROR;
616 break;
618 rc = gnutls_priority_set_direct(session, prioritylist, &err);
619 if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
620 if(!strcmp(err, GNUTLS_SRP)) {
621 /* This GnuTLS was probably compiled without support for SRP.
622 * Note that fact and try again without it. */
623 int validprioritylen = curlx_uztosi(err - prioritylist);
624 char *prioritycopy = strdup(prioritylist);
625 if(!prioritycopy)
626 return CURLE_OUT_OF_MEMORY;
628 infof(data, "This GnuTLS does not support SRP\n");
629 if(validprioritylen)
630 /* Remove the :+SRP */
631 prioritycopy[validprioritylen - 1] = 0;
632 rc = gnutls_priority_set_direct(session, prioritycopy, &err);
633 free(prioritycopy);
636 if(rc != GNUTLS_E_SUCCESS) {
637 failf(data, "Error %d setting GnuTLS cipher list starting with %s",
638 rc, err);
639 return CURLE_SSL_CONNECT_ERROR;
641 #endif
643 #ifdef HAS_ALPN
644 if(conn->bits.tls_enable_alpn) {
645 int cur = 0;
646 gnutls_datum_t protocols[2];
648 #ifdef USE_NGHTTP2
649 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
650 protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
651 protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
652 cur++;
653 infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
655 #endif
657 protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
658 protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
659 cur++;
660 infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
662 gnutls_alpn_set_protocols(session, protocols, cur, 0);
664 #endif
666 if(data->set.str[STRING_CERT]) {
667 if(data->set.str[STRING_KEY_PASSWD]) {
668 #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
669 const unsigned int supported_key_encryption_algorithms =
670 GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
671 GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
672 GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
673 GNUTLS_PKCS_USE_PBES2_AES_256;
674 rc = gnutls_certificate_set_x509_key_file2(
675 conn->ssl[sockindex].cred,
676 data->set.str[STRING_CERT],
677 data->set.str[STRING_KEY] ?
678 data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
679 do_file_type(data->set.str[STRING_CERT_TYPE]),
680 data->set.str[STRING_KEY_PASSWD],
681 supported_key_encryption_algorithms);
682 if(rc != GNUTLS_E_SUCCESS) {
683 failf(data,
684 "error reading X.509 potentially-encrypted key file: %s",
685 gnutls_strerror(rc));
686 return CURLE_SSL_CONNECT_ERROR;
688 #else
689 failf(data, "gnutls lacks support for encrypted key files");
690 return CURLE_SSL_CONNECT_ERROR;
691 #endif
693 else {
694 rc = gnutls_certificate_set_x509_key_file(
695 conn->ssl[sockindex].cred,
696 data->set.str[STRING_CERT],
697 data->set.str[STRING_KEY] ?
698 data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
699 do_file_type(data->set.str[STRING_CERT_TYPE]) );
700 if(rc != GNUTLS_E_SUCCESS) {
701 failf(data, "error reading X.509 key or certificate file: %s",
702 gnutls_strerror(rc));
703 return CURLE_SSL_CONNECT_ERROR;
708 #ifdef USE_TLS_SRP
709 /* put the credentials to the current session */
710 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
711 rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
712 conn->ssl[sockindex].srp_client_cred);
713 if(rc != GNUTLS_E_SUCCESS) {
714 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
715 return CURLE_SSL_CONNECT_ERROR;
718 else
719 #endif
721 rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
722 conn->ssl[sockindex].cred);
723 if(rc != GNUTLS_E_SUCCESS) {
724 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
725 return CURLE_SSL_CONNECT_ERROR;
729 /* set the connection handle (file descriptor for the socket) */
730 gnutls_transport_set_ptr(session,
731 GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
733 /* register callback functions to send and receive data. */
734 gnutls_transport_set_push_function(session, Curl_gtls_push);
735 gnutls_transport_set_pull_function(session, Curl_gtls_pull);
737 /* lowat must be set to zero when using custom push and pull functions. */
738 gnutls_transport_set_lowat(session, 0);
740 #ifdef HAS_OCSP
741 if(data->set.ssl.verifystatus) {
742 rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
743 if(rc != GNUTLS_E_SUCCESS) {
744 failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
745 return CURLE_SSL_CONNECT_ERROR;
748 #endif
750 /* This might be a reconnect, so we check for a session ID in the cache
751 to speed up things */
753 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
754 /* we got a session id, use it! */
755 gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
757 /* Informational message */
758 infof (data, "SSL re-using session ID\n");
761 return CURLE_OK;
764 static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data,
765 gnutls_x509_crt_t cert,
766 const char *pinnedpubkey)
768 /* Scratch */
769 size_t len1 = 0, len2 = 0;
770 unsigned char *buff1 = NULL;
772 gnutls_pubkey_t key = NULL;
774 /* Result is returned to caller */
775 int ret = 0;
776 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
778 /* if a path wasn't specified, don't pin */
779 if(NULL == pinnedpubkey)
780 return CURLE_OK;
782 if(NULL == cert)
783 return result;
785 do {
786 /* Begin Gyrations to get the public key */
787 gnutls_pubkey_init(&key);
789 ret = gnutls_pubkey_import_x509(key, cert, 0);
790 if(ret < 0)
791 break; /* failed */
793 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
794 if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
795 break; /* failed */
797 buff1 = malloc(len1);
798 if(NULL == buff1)
799 break; /* failed */
801 len2 = len1;
803 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
804 if(ret < 0 || len1 != len2)
805 break; /* failed */
807 /* End Gyrations */
809 /* The one good exit point */
810 result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
811 } while(0);
813 if(NULL != key)
814 gnutls_pubkey_deinit(key);
816 Curl_safefree(buff1);
818 return result;
821 static Curl_recv gtls_recv;
822 static Curl_send gtls_send;
824 static CURLcode
825 gtls_connect_step3(struct connectdata *conn,
826 int sockindex)
828 unsigned int cert_list_size;
829 const gnutls_datum_t *chainp;
830 unsigned int verify_status = 0;
831 gnutls_x509_crt_t x509_cert, x509_issuer;
832 gnutls_datum_t issuerp;
833 char certbuf[256] = ""; /* big enough? */
834 size_t size;
835 unsigned int algo;
836 unsigned int bits;
837 time_t certclock;
838 const char *ptr;
839 struct SessionHandle *data = conn->data;
840 gnutls_session_t session = conn->ssl[sockindex].session;
841 int rc;
842 bool incache;
843 void *ssl_sessionid;
844 #ifdef HAS_ALPN
845 gnutls_datum_t proto;
846 #endif
847 CURLcode result = CURLE_OK;
849 gnutls_protocol_t version = gnutls_protocol_get_version(session);
851 /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
852 ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
853 gnutls_cipher_get(session),
854 gnutls_mac_get(session));
856 infof(data, "SSL connection using %s / %s\n",
857 gnutls_protocol_get_name(version), ptr);
859 /* This function will return the peer's raw certificate (chain) as sent by
860 the peer. These certificates are in raw format (DER encoded for
861 X.509). In case of a X.509 then a certificate list may be present. The
862 first certificate in the list is the peer's certificate, following the
863 issuer's certificate, then the issuer's issuer etc. */
865 chainp = gnutls_certificate_get_peers(session, &cert_list_size);
866 if(!chainp) {
867 if(data->set.ssl.verifypeer ||
868 data->set.ssl.verifyhost ||
869 data->set.ssl.issuercert) {
870 #ifdef USE_TLS_SRP
871 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
872 && data->set.ssl.username != NULL
873 && !data->set.ssl.verifypeer
874 && gnutls_cipher_get(session)) {
875 /* no peer cert, but auth is ok if we have SRP user and cipher and no
876 peer verify */
878 else {
879 #endif
880 failf(data, "failed to get server cert");
881 return CURLE_PEER_FAILED_VERIFICATION;
882 #ifdef USE_TLS_SRP
884 #endif
886 infof(data, "\t common name: WARNING couldn't obtain\n");
889 if(data->set.ssl.certinfo && chainp) {
890 unsigned int i;
892 result = Curl_ssl_init_certinfo(data, cert_list_size);
893 if(result)
894 return result;
896 for(i = 0; i < cert_list_size; i++) {
897 const char *beg = (const char *) chainp[i].data;
898 const char *end = beg + chainp[i].size;
900 result = Curl_extract_certinfo(conn, i, beg, end);
901 if(result)
902 return result;
906 if(data->set.ssl.verifypeer) {
907 /* This function will try to verify the peer's certificate and return its
908 status (trusted, invalid etc.). The value of status should be one or
909 more of the gnutls_certificate_status_t enumerated elements bitwise
910 or'd. To avoid denial of service attacks some default upper limits
911 regarding the certificate key size and chain size are set. To override
912 them use gnutls_certificate_set_verify_limits(). */
914 rc = gnutls_certificate_verify_peers2(session, &verify_status);
915 if(rc < 0) {
916 failf(data, "server cert verify failed: %d", rc);
917 return CURLE_SSL_CONNECT_ERROR;
920 /* verify_status is a bitmask of gnutls_certificate_status bits */
921 if(verify_status & GNUTLS_CERT_INVALID) {
922 if(data->set.ssl.verifypeer) {
923 failf(data, "server certificate verification failed. CAfile: %s "
924 "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
925 data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
926 return CURLE_SSL_CACERT;
928 else
929 infof(data, "\t server certificate verification FAILED\n");
931 else
932 infof(data, "\t server certificate verification OK\n");
934 else
935 infof(data, "\t server certificate verification SKIPPED\n");
937 #ifdef HAS_OCSP
938 if(data->set.ssl.verifystatus) {
939 if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
940 gnutls_datum_t status_request;
941 gnutls_ocsp_resp_t ocsp_resp;
943 gnutls_ocsp_cert_status_t status;
944 gnutls_x509_crl_reason_t reason;
946 rc = gnutls_ocsp_status_request_get(session, &status_request);
948 infof(data, "\t server certificate status verification FAILED\n");
950 if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
951 failf(data, "No OCSP response received");
952 return CURLE_SSL_INVALIDCERTSTATUS;
955 if(rc < 0) {
956 failf(data, "Invalid OCSP response received");
957 return CURLE_SSL_INVALIDCERTSTATUS;
960 gnutls_ocsp_resp_init(&ocsp_resp);
962 rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
963 if(rc < 0) {
964 failf(data, "Invalid OCSP response received");
965 return CURLE_SSL_INVALIDCERTSTATUS;
968 rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
969 &status, NULL, NULL, NULL, &reason);
971 switch(status) {
972 case GNUTLS_OCSP_CERT_GOOD:
973 break;
975 case GNUTLS_OCSP_CERT_REVOKED: {
976 const char *crl_reason;
978 switch(reason) {
979 default:
980 case GNUTLS_X509_CRLREASON_UNSPECIFIED:
981 crl_reason = "unspecified reason";
982 break;
984 case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
985 crl_reason = "private key compromised";
986 break;
988 case GNUTLS_X509_CRLREASON_CACOMPROMISE:
989 crl_reason = "CA compromised";
990 break;
992 case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
993 crl_reason = "affiliation has changed";
994 break;
996 case GNUTLS_X509_CRLREASON_SUPERSEDED:
997 crl_reason = "certificate superseded";
998 break;
1000 case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
1001 crl_reason = "operation has ceased";
1002 break;
1004 case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
1005 crl_reason = "certificate is on hold";
1006 break;
1008 case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
1009 crl_reason = "will be removed from delta CRL";
1010 break;
1012 case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
1013 crl_reason = "privilege withdrawn";
1014 break;
1016 case GNUTLS_X509_CRLREASON_AACOMPROMISE:
1017 crl_reason = "AA compromised";
1018 break;
1021 failf(data, "Server certificate was revoked: %s", crl_reason);
1022 break;
1025 default:
1026 case GNUTLS_OCSP_CERT_UNKNOWN:
1027 failf(data, "Server certificate status is unknown");
1028 break;
1031 gnutls_ocsp_resp_deinit(ocsp_resp);
1033 return CURLE_SSL_INVALIDCERTSTATUS;
1035 else
1036 infof(data, "\t server certificate status verification OK\n");
1038 else
1039 infof(data, "\t server certificate status verification SKIPPED\n");
1040 #endif
1042 /* initialize an X.509 certificate structure. */
1043 gnutls_x509_crt_init(&x509_cert);
1045 if(chainp)
1046 /* convert the given DER or PEM encoded Certificate to the native
1047 gnutls_x509_crt_t format */
1048 gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
1050 if(data->set.ssl.issuercert) {
1051 gnutls_x509_crt_init(&x509_issuer);
1052 issuerp = load_file(data->set.ssl.issuercert);
1053 gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
1054 rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
1055 gnutls_x509_crt_deinit(x509_issuer);
1056 unload_file(issuerp);
1057 if(rc <= 0) {
1058 failf(data, "server certificate issuer check failed (IssuerCert: %s)",
1059 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
1060 gnutls_x509_crt_deinit(x509_cert);
1061 return CURLE_SSL_ISSUER_ERROR;
1063 infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
1064 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
1067 size=sizeof(certbuf);
1068 rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
1069 0, /* the first and only one */
1070 FALSE,
1071 certbuf,
1072 &size);
1073 if(rc) {
1074 infof(data, "error fetching CN from cert:%s\n",
1075 gnutls_strerror(rc));
1078 /* This function will check if the given certificate's subject matches the
1079 given hostname. This is a basic implementation of the matching described
1080 in RFC2818 (HTTPS), which takes into account wildcards, and the subject
1081 alternative name PKIX extension. Returns non zero on success, and zero on
1082 failure. */
1083 rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
1084 #if GNUTLS_VERSION_NUMBER < 0x030306
1085 /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
1086 addresses. */
1087 if(!rc) {
1088 #ifdef ENABLE_IPV6
1089 #define use_addr in6_addr
1090 #else
1091 #define use_addr in_addr
1092 #endif
1093 unsigned char addrbuf[sizeof(struct use_addr)];
1094 unsigned char certaddr[sizeof(struct use_addr)];
1095 size_t addrlen = 0, certaddrlen;
1096 int i;
1097 int ret = 0;
1099 if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0)
1100 addrlen = 4;
1101 #ifdef ENABLE_IPV6
1102 else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0)
1103 addrlen = 16;
1104 #endif
1106 if(addrlen) {
1107 for(i=0; ; i++) {
1108 certaddrlen = sizeof(certaddr);
1109 ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
1110 &certaddrlen, NULL);
1111 /* If this happens, it wasn't an IP address. */
1112 if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
1113 continue;
1114 if(ret < 0)
1115 break;
1116 if(ret != GNUTLS_SAN_IPADDRESS)
1117 continue;
1118 if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
1119 rc = 1;
1120 break;
1125 #endif
1126 if(!rc) {
1127 if(data->set.ssl.verifyhost) {
1128 failf(data, "SSL: certificate subject name (%s) does not match "
1129 "target host name '%s'", certbuf, conn->host.dispname);
1130 gnutls_x509_crt_deinit(x509_cert);
1131 return CURLE_PEER_FAILED_VERIFICATION;
1133 else
1134 infof(data, "\t common name: %s (does not match '%s')\n",
1135 certbuf, conn->host.dispname);
1137 else
1138 infof(data, "\t common name: %s (matched)\n", certbuf);
1140 /* Check for time-based validity */
1141 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1143 if(certclock == (time_t)-1) {
1144 if(data->set.ssl.verifypeer) {
1145 failf(data, "server cert expiration date verify failed");
1146 gnutls_x509_crt_deinit(x509_cert);
1147 return CURLE_SSL_CONNECT_ERROR;
1149 else
1150 infof(data, "\t server certificate expiration date verify FAILED\n");
1152 else {
1153 if(certclock < time(NULL)) {
1154 if(data->set.ssl.verifypeer) {
1155 failf(data, "server certificate expiration date has passed.");
1156 gnutls_x509_crt_deinit(x509_cert);
1157 return CURLE_PEER_FAILED_VERIFICATION;
1159 else
1160 infof(data, "\t server certificate expiration date FAILED\n");
1162 else
1163 infof(data, "\t server certificate expiration date OK\n");
1166 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1168 if(certclock == (time_t)-1) {
1169 if(data->set.ssl.verifypeer) {
1170 failf(data, "server cert activation date verify failed");
1171 gnutls_x509_crt_deinit(x509_cert);
1172 return CURLE_SSL_CONNECT_ERROR;
1174 else
1175 infof(data, "\t server certificate activation date verify FAILED\n");
1177 else {
1178 if(certclock > time(NULL)) {
1179 if(data->set.ssl.verifypeer) {
1180 failf(data, "server certificate not activated yet.");
1181 gnutls_x509_crt_deinit(x509_cert);
1182 return CURLE_PEER_FAILED_VERIFICATION;
1184 else
1185 infof(data, "\t server certificate activation date FAILED\n");
1187 else
1188 infof(data, "\t server certificate activation date OK\n");
1191 ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1192 if(ptr) {
1193 result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
1194 if(result != CURLE_OK) {
1195 failf(data, "SSL: public key does not match pinned public key!");
1196 gnutls_x509_crt_deinit(x509_cert);
1197 return result;
1201 /* Show:
1203 - subject
1204 - start date
1205 - expire date
1206 - common name
1207 - issuer
1211 /* public key algorithm's parameters */
1212 algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
1213 infof(data, "\t certificate public key: %s\n",
1214 gnutls_pk_algorithm_get_name(algo));
1216 /* version of the X.509 certificate. */
1217 infof(data, "\t certificate version: #%d\n",
1218 gnutls_x509_crt_get_version(x509_cert));
1221 size = sizeof(certbuf);
1222 gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
1223 infof(data, "\t subject: %s\n", certbuf);
1225 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1226 showtime(data, "start date", certclock);
1228 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1229 showtime(data, "expire date", certclock);
1231 size = sizeof(certbuf);
1232 gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
1233 infof(data, "\t issuer: %s\n", certbuf);
1235 gnutls_x509_crt_deinit(x509_cert);
1237 /* compression algorithm (if any) */
1238 ptr = gnutls_compression_get_name(gnutls_compression_get(session));
1239 /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
1240 infof(data, "\t compression: %s\n", ptr);
1242 #ifdef HAS_ALPN
1243 if(conn->bits.tls_enable_alpn) {
1244 rc = gnutls_alpn_get_selected_protocol(session, &proto);
1245 if(rc == 0) {
1246 infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
1247 proto.data);
1249 #ifdef USE_NGHTTP2
1250 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
1251 !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
1252 NGHTTP2_PROTO_VERSION_ID_LEN)) {
1253 conn->negnpn = CURL_HTTP_VERSION_2;
1255 else
1256 #endif
1257 if(proto.size == ALPN_HTTP_1_1_LENGTH &&
1258 !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
1259 conn->negnpn = CURL_HTTP_VERSION_1_1;
1262 else
1263 infof(data, "ALPN, server did not agree to a protocol\n");
1265 #endif
1267 conn->ssl[sockindex].state = ssl_connection_complete;
1268 conn->recv[sockindex] = gtls_recv;
1269 conn->send[sockindex] = gtls_send;
1272 /* we always unconditionally get the session id here, as even if we
1273 already got it from the cache and asked to use it in the connection, it
1274 might've been rejected and then a new one is in use now and we need to
1275 detect that. */
1276 void *connect_sessionid;
1277 size_t connect_idsize = 0;
1279 /* get the session ID data size */
1280 gnutls_session_get_data(session, NULL, &connect_idsize);
1281 connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
1283 if(connect_sessionid) {
1284 /* extract session ID to the allocated buffer */
1285 gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
1287 incache = !(Curl_ssl_getsessionid(conn, &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(conn, ssl_sessionid);
1294 /* store this session id */
1295 result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
1296 if(result) {
1297 free(connect_sessionid);
1298 result = CURLE_OUT_OF_MEMORY;
1301 else
1302 result = CURLE_OUT_OF_MEMORY;
1305 return result;
1310 * This function is called after the TCP connect has completed. Setup the TLS
1311 * layer and do all necessary magic.
1313 /* We use connssl->connecting_state to keep track of the connection status;
1314 there are three states: 'ssl_connect_1' (not started yet or complete),
1315 'ssl_connect_2_reading' (waiting for data from server), and
1316 'ssl_connect_2_writing' (waiting to be able to write).
1318 static CURLcode
1319 gtls_connect_common(struct connectdata *conn,
1320 int sockindex,
1321 bool nonblocking,
1322 bool *done)
1324 int rc;
1325 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1327 /* Initiate the connection, if not already done */
1328 if(ssl_connect_1==connssl->connecting_state) {
1329 rc = gtls_connect_step1 (conn, sockindex);
1330 if(rc)
1331 return rc;
1334 rc = handshake(conn, sockindex, TRUE, nonblocking);
1335 if(rc)
1336 /* handshake() sets its own error message with failf() */
1337 return rc;
1339 /* Finish connecting once the handshake is done */
1340 if(ssl_connect_1==connssl->connecting_state) {
1341 rc = gtls_connect_step3(conn, sockindex);
1342 if(rc)
1343 return rc;
1346 *done = ssl_connect_1==connssl->connecting_state;
1348 return CURLE_OK;
1351 CURLcode
1352 Curl_gtls_connect_nonblocking(struct connectdata *conn,
1353 int sockindex,
1354 bool *done)
1356 return gtls_connect_common(conn, sockindex, TRUE, done);
1359 CURLcode
1360 Curl_gtls_connect(struct connectdata *conn,
1361 int sockindex)
1364 CURLcode result;
1365 bool done = FALSE;
1367 result = gtls_connect_common(conn, sockindex, FALSE, &done);
1368 if(result)
1369 return result;
1371 DEBUGASSERT(done);
1373 return CURLE_OK;
1376 static ssize_t gtls_send(struct connectdata *conn,
1377 int sockindex,
1378 const void *mem,
1379 size_t len,
1380 CURLcode *curlcode)
1382 ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
1384 if(rc < 0) {
1385 *curlcode = (rc == GNUTLS_E_AGAIN)
1386 ? CURLE_AGAIN
1387 : CURLE_SEND_ERROR;
1389 rc = -1;
1392 return rc;
1395 static void close_one(struct connectdata *conn,
1396 int idx)
1398 if(conn->ssl[idx].session) {
1399 gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
1400 gnutls_deinit(conn->ssl[idx].session);
1401 conn->ssl[idx].session = NULL;
1403 if(conn->ssl[idx].cred) {
1404 gnutls_certificate_free_credentials(conn->ssl[idx].cred);
1405 conn->ssl[idx].cred = NULL;
1407 #ifdef USE_TLS_SRP
1408 if(conn->ssl[idx].srp_client_cred) {
1409 gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
1410 conn->ssl[idx].srp_client_cred = NULL;
1412 #endif
1415 void Curl_gtls_close(struct connectdata *conn, int sockindex)
1417 close_one(conn, sockindex);
1421 * This function is called to shut down the SSL layer but keep the
1422 * socket open (CCC - Clear Command Channel)
1424 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
1426 ssize_t result;
1427 int retval = 0;
1428 struct SessionHandle *data = conn->data;
1429 int done = 0;
1430 char buf[120];
1432 /* This has only been tested on the proftpd server, and the mod_tls code
1433 sends a close notify alert without waiting for a close notify alert in
1434 response. Thus we wait for a close notify alert from the server, but
1435 we do not send one. Let's hope other servers do the same... */
1437 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
1438 gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
1440 if(conn->ssl[sockindex].session) {
1441 while(!done) {
1442 int what = Curl_socket_ready(conn->sock[sockindex],
1443 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
1444 if(what > 0) {
1445 /* Something to read, let's do it and hope that it is the close
1446 notify alert from the server */
1447 result = gnutls_record_recv(conn->ssl[sockindex].session,
1448 buf, sizeof(buf));
1449 switch(result) {
1450 case 0:
1451 /* This is the expected response. There was no data but only
1452 the close notify alert */
1453 done = 1;
1454 break;
1455 case GNUTLS_E_AGAIN:
1456 case GNUTLS_E_INTERRUPTED:
1457 infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
1458 break;
1459 default:
1460 retval = -1;
1461 done = 1;
1462 break;
1465 else if(0 == what) {
1466 /* timeout */
1467 failf(data, "SSL shutdown timeout");
1468 done = 1;
1469 break;
1471 else {
1472 /* anything that gets here is fatally bad */
1473 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1474 retval = -1;
1475 done = 1;
1478 gnutls_deinit(conn->ssl[sockindex].session);
1480 gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
1482 #ifdef USE_TLS_SRP
1483 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
1484 && data->set.ssl.username != NULL)
1485 gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
1486 #endif
1488 conn->ssl[sockindex].cred = NULL;
1489 conn->ssl[sockindex].session = NULL;
1491 return retval;
1494 static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
1495 int num, /* socketindex */
1496 char *buf, /* store read data here */
1497 size_t buffersize, /* max amount to read */
1498 CURLcode *curlcode)
1500 ssize_t ret;
1502 ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
1503 if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
1504 *curlcode = CURLE_AGAIN;
1505 return -1;
1508 if(ret == GNUTLS_E_REHANDSHAKE) {
1509 /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
1510 proper way" takes a whole lot of work. */
1511 CURLcode result = handshake(conn, num, FALSE, FALSE);
1512 if(result)
1513 /* handshake() writes error message on its own */
1514 *curlcode = result;
1515 else
1516 *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
1517 return -1;
1520 if(ret < 0) {
1521 failf(conn->data, "GnuTLS recv error (%d): %s",
1522 (int)ret, gnutls_strerror((int)ret));
1523 *curlcode = CURLE_RECV_ERROR;
1524 return -1;
1527 return ret;
1530 void Curl_gtls_session_free(void *ptr)
1532 free(ptr);
1535 size_t Curl_gtls_version(char *buffer, size_t size)
1537 return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1540 #ifndef USE_GNUTLS_NETTLE
1541 static int Curl_gtls_seed(struct SessionHandle *data)
1543 /* we have the "SSL is seeded" boolean static to prevent multiple
1544 time-consuming seedings in vain */
1545 static bool ssl_seeded = FALSE;
1547 /* Quickly add a bit of entropy */
1548 gcry_fast_random_poll();
1550 if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
1551 data->set.str[STRING_SSL_EGDSOCKET]) {
1553 /* TODO: to a good job seeding the RNG
1554 This may involve the gcry_control function and these options:
1555 GCRYCTL_SET_RANDOM_SEED_FILE
1556 GCRYCTL_SET_RNDEGD_SOCKET
1558 ssl_seeded = TRUE;
1560 return 0;
1562 #endif
1564 /* data might be NULL! */
1565 int Curl_gtls_random(struct SessionHandle *data,
1566 unsigned char *entropy,
1567 size_t length)
1569 #if defined(USE_GNUTLS_NETTLE)
1570 (void)data;
1571 gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
1572 #elif defined(USE_GNUTLS)
1573 if(data)
1574 Curl_gtls_seed(data); /* Initiate the seed if not already done */
1575 gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
1576 #endif
1577 return 0;
1580 void Curl_gtls_md5sum(unsigned char *tmp, /* input */
1581 size_t tmplen,
1582 unsigned char *md5sum, /* output */
1583 size_t md5len)
1585 #if defined(USE_GNUTLS_NETTLE)
1586 struct md5_ctx MD5pw;
1587 md5_init(&MD5pw);
1588 md5_update(&MD5pw, (unsigned int)tmplen, tmp);
1589 md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
1590 #elif defined(USE_GNUTLS)
1591 gcry_md_hd_t MD5pw;
1592 gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
1593 gcry_md_write(MD5pw, tmp, tmplen);
1594 memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len);
1595 gcry_md_close(MD5pw);
1596 #endif
1599 void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
1600 size_t tmplen,
1601 unsigned char *sha256sum, /* output */
1602 size_t sha256len)
1604 #if defined(USE_GNUTLS_NETTLE)
1605 struct sha256_ctx SHA256pw;
1606 sha256_init(&SHA256pw);
1607 sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
1608 sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
1609 #elif defined(USE_GNUTLS)
1610 gcry_md_hd_t SHA256pw;
1611 gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
1612 gcry_md_write(SHA256pw, tmp, tmplen);
1613 memcpy(sha256sum, gcry_md_read (SHA256pw, 0), sha256len);
1614 gcry_md_close(SHA256pw);
1615 #endif
1618 bool Curl_gtls_cert_status_request(void)
1620 #ifdef HAS_OCSP
1621 return TRUE;
1622 #else
1623 return FALSE;
1624 #endif
1627 #endif /* USE_GNUTLS */