source: UsbWattMeter/trunk/curl-7.47.1/lib/vtls/gtls.c@ 164

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

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 48.4 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/*
24 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
25 * but vtls.c should ever call or use these functions.
26 *
27 * Note: don't use the GnuTLS' *_t variable type names in this source code,
28 * since they were not present in 1.0.X.
29 */
30
31#include "curl_setup.h"
32
33#ifdef USE_GNUTLS
34
35#include <gnutls/abstract.h>
36#include <gnutls/gnutls.h>
37#include <gnutls/x509.h>
38
39#ifdef USE_GNUTLS_NETTLE
40#include <gnutls/crypto.h>
41#include <nettle/md5.h>
42#include <nettle/sha2.h>
43#else
44#include <gcrypt.h>
45#endif
46
47#include "urldata.h"
48#include "sendf.h"
49#include "inet_pton.h"
50#include "gtls.h"
51#include "vtls.h"
52#include "parsedate.h"
53#include "connect.h" /* for the connect timeout */
54#include "select.h"
55#include "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"
62
63/*
64 Some hackish cast macros based on:
65 https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html
66*/
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
73
74/* Enable GnuTLS debugging by defining GTLSDEBUG */
75/*#define GTLSDEBUG */
76
77#ifdef GTLSDEBUG
78static void tls_log_func(int level, const char *str)
79{
80 fprintf(stderr, "|<%d>| %s", level, str);
81}
82#endif
83static bool gtls_inited = FALSE;
84
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
94
95# if (GNUTLS_VERSION_NUMBER >= 0x030200)
96# define HAS_ALPN
97# endif
98
99# if (GNUTLS_VERSION_NUMBER >= 0x03020d)
100# define HAS_OCSP
101# endif
102
103# if (GNUTLS_VERSION_NUMBER >= 0x030306)
104# define HAS_CAPATH
105# endif
106#endif
107
108#ifdef HAS_OCSP
109# include <gnutls/ocsp.h>
110#endif
111
112/*
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.
120 *
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.
130 *
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.
134 */
135
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
140static int gtls_mapped_sockerrno(void)
141{
142 switch(SOCKERRNO) {
143 case WSAEWOULDBLOCK:
144 return gtls_EAGAIN;
145 case WSAEINTR:
146 return gtls_EINTR;
147 default:
148 break;
149 }
150 return gtls_EIO;
151}
152#endif
153
154static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
155{
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;
162}
163
164static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
165{
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;
172}
173
174/* Curl_gtls_init()
175 *
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!
180 */
181int Curl_gtls_init(void)
182{
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;
191 }
192 return ret;
193}
194
195int Curl_gtls_cleanup(void)
196{
197 if(gtls_inited) {
198 gnutls_global_deinit();
199 gtls_inited = FALSE;
200 }
201 return 1;
202}
203
204static void showtime(struct SessionHandle *data,
205 const char *text,
206 time_t stamp)
207{
208 struct tm buffer;
209 const struct tm *tm = &buffer;
210 CURLcode result = Curl_gmtime(stamp, &buffer);
211 if(result)
212 return;
213
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);
226}
227
228static gnutls_datum_t load_file (const char *file)
229{
230 FILE *f;
231 gnutls_datum_t loaded_file = { NULL, 0 };
232 long filelen;
233 void *ptr;
234
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;
245 }
246
247 loaded_file.data = ptr;
248 loaded_file.size = (unsigned int)filelen;
249out:
250 fclose(f);
251 return loaded_file;
252}
253
254static void unload_file(gnutls_datum_t data) {
255 free(data.data);
256}
257
258
259/* this function does a SSL/TLS (re-)handshake */
260static CURLcode handshake(struct connectdata *conn,
261 int sockindex,
262 bool duringconnect,
263 bool nonblocking)
264{
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;
272
273 for(;;) {
274 /* check allowed time left */
275 timeout_ms = Curl_timeleft(data, NULL, duringconnect);
276
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;
281 }
282
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) {
286
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;
291
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;
299 }
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;
307 }
308 }
309 /* socket is readable or writable */
310 }
311
312 rc = gnutls_handshake(session);
313
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;
319 }
320 else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
321 const char *strerr = NULL;
322
323 if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
324 int alert = gnutls_alert_get(session);
325 strerr = gnutls_alert_get_name(alert);
326 }
327
328 if(strerr == NULL)
329 strerr = gnutls_strerror(rc);
330
331 infof(data, "gnutls_handshake() warning: %s\n", strerr);
332 continue;
333 }
334 else if(rc < 0) {
335 const char *strerr = NULL;
336
337 if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
338 int alert = gnutls_alert_get(session);
339 strerr = gnutls_alert_get_name(alert);
340 }
341
342 if(strerr == NULL)
343 strerr = gnutls_strerror(rc);
344
345 failf(data, "gnutls_handshake() failed: %s", strerr);
346 return CURLE_SSL_CONNECT_ERROR;
347 }
348
349 /* Reset our connect state machine */
350 connssl->connecting_state = ssl_connect_1;
351 return CURLE_OK;
352 }
353}
354
355static gnutls_x509_crt_fmt_t do_file_type(const char *type)
356{
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;
364}
365
366static CURLcode
367gtls_connect_step1(struct connectdata *conn,
368 int sockindex)
369{
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,
387 */
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,
393 };
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
400 */
401#define GNUTLS_SRP "+SRP"
402 const char* prioritylist;
403 const char *err = NULL;
404#endif
405
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;
410
411 if(!gtls_inited)
412 Curl_gtls_init();
413
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;
418 }
419 else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
420 sni = FALSE; /* SSLv3 has no SNI */
421
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;
427 }
428
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);
432
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;
439 }
440
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;
449 }
450 }
451#endif
452
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);
457
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;
466 }
467 else
468 infof(data, "found %d certificates in %s\n",
469 rc, data->set.ssl.CAfile);
470 }
471
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;
483 }
484 else
485 infof(data, "found %d certificates in %s\n",
486 rc, data->set.ssl.CApath);
487 }
488#endif
489
490 if(data->set.ssl.CRLfile) {
491 /* set the CRL list file */
492 rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
493 data->set.ssl.CRLfile,
494 GNUTLS_X509_FMT_PEM);
495 if(rc < 0) {
496 failf(data, "error reading crl file %s (%s)",
497 data->set.ssl.CRLfile, gnutls_strerror(rc));
498 return CURLE_SSL_CRL_BADFILE;
499 }
500 else
501 infof(data, "found %d CRL in %s\n",
502 rc, data->set.ssl.CRLfile);
503 }
504
505 /* Initialize TLS session as a client */
506 rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
507 if(rc != GNUTLS_E_SUCCESS) {
508 failf(data, "gnutls_init() failed: %d", rc);
509 return CURLE_SSL_CONNECT_ERROR;
510 }
511
512 /* convenient assign */
513 session = conn->ssl[sockindex].session;
514
515 if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
516#ifdef ENABLE_IPV6
517 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
518#endif
519 sni &&
520 (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
521 strlen(conn->host.name)) < 0))
522 infof(data, "WARNING: failed to configure server name indication (SNI) "
523 "TLS extension\n");
524
525 /* Use default priorities */
526 rc = gnutls_set_default_priority(session);
527 if(rc != GNUTLS_E_SUCCESS)
528 return CURLE_SSL_CONNECT_ERROR;
529
530#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
531 rc = gnutls_cipher_set_priority(session, cipher_priority);
532 if(rc != GNUTLS_E_SUCCESS)
533 return CURLE_SSL_CONNECT_ERROR;
534
535 /* Sets the priority on the certificate types supported by gnutls. Priority
536 is higher for types specified before others. After specifying the types
537 you want, you must append a 0. */
538 rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
539 if(rc != GNUTLS_E_SUCCESS)
540 return CURLE_SSL_CONNECT_ERROR;
541
542 if(data->set.ssl.cipher_list != NULL) {
543 failf(data, "can't pass a custom cipher list to older GnuTLS"
544 " versions");
545 return CURLE_SSL_CONNECT_ERROR;
546 }
547
548 switch (data->set.ssl.version) {
549 case CURL_SSLVERSION_SSLv3:
550 protocol_priority[0] = GNUTLS_SSL3;
551 break;
552 case CURL_SSLVERSION_DEFAULT:
553 case CURL_SSLVERSION_TLSv1:
554 protocol_priority[0] = GNUTLS_TLS1_0;
555 protocol_priority[1] = GNUTLS_TLS1_1;
556 protocol_priority[2] = GNUTLS_TLS1_2;
557 break;
558 case CURL_SSLVERSION_TLSv1_0:
559 protocol_priority[0] = GNUTLS_TLS1_0;
560 break;
561 case CURL_SSLVERSION_TLSv1_1:
562 protocol_priority[0] = GNUTLS_TLS1_1;
563 break;
564 case CURL_SSLVERSION_TLSv1_2:
565 protocol_priority[0] = GNUTLS_TLS1_2;
566 break;
567 case CURL_SSLVERSION_SSLv2:
568 default:
569 failf(data, "GnuTLS does not support SSLv2");
570 return CURLE_SSL_CONNECT_ERROR;
571 break;
572 }
573 rc = gnutls_protocol_set_priority(session, protocol_priority);
574 if(rc != GNUTLS_E_SUCCESS) {
575 failf(data, "Did you pass a valid GnuTLS cipher list?");
576 return CURLE_SSL_CONNECT_ERROR;
577 }
578
579#else
580 /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
581 * removed if a run-time error indicates that SRP is not supported by this
582 * GnuTLS version */
583 switch (data->set.ssl.version) {
584 case CURL_SSLVERSION_SSLv3:
585 prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
586 sni = false;
587 break;
588 case CURL_SSLVERSION_DEFAULT:
589 case CURL_SSLVERSION_TLSv1:
590 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
591 break;
592 case CURL_SSLVERSION_TLSv1_0:
593 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
594 "+VERS-TLS1.0:" GNUTLS_SRP;
595 break;
596 case CURL_SSLVERSION_TLSv1_1:
597 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
598 "+VERS-TLS1.1:" GNUTLS_SRP;
599 break;
600 case CURL_SSLVERSION_TLSv1_2:
601 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
602 "+VERS-TLS1.2:" GNUTLS_SRP;
603 break;
604 case CURL_SSLVERSION_SSLv2:
605 default:
606 failf(data, "GnuTLS does not support SSLv2");
607 return CURLE_SSL_CONNECT_ERROR;
608 break;
609 }
610 rc = gnutls_priority_set_direct(session, prioritylist, &err);
611 if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
612 if(!strcmp(err, GNUTLS_SRP)) {
613 /* This GnuTLS was probably compiled without support for SRP.
614 * Note that fact and try again without it. */
615 int validprioritylen = curlx_uztosi(err - prioritylist);
616 char *prioritycopy = strdup(prioritylist);
617 if(!prioritycopy)
618 return CURLE_OUT_OF_MEMORY;
619
620 infof(data, "This GnuTLS does not support SRP\n");
621 if(validprioritylen)
622 /* Remove the :+SRP */
623 prioritycopy[validprioritylen - 1] = 0;
624 rc = gnutls_priority_set_direct(session, prioritycopy, &err);
625 free(prioritycopy);
626 }
627 }
628 if(rc != GNUTLS_E_SUCCESS) {
629 failf(data, "Error %d setting GnuTLS cipher list starting with %s",
630 rc, err);
631 return CURLE_SSL_CONNECT_ERROR;
632 }
633#endif
634
635#ifdef HAS_ALPN
636 if(data->set.ssl_enable_alpn) {
637 int cur = 0;
638 gnutls_datum_t protocols[2];
639
640#ifdef USE_NGHTTP2
641 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
642 protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
643 protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
644 cur++;
645 infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
646 }
647#endif
648
649 protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
650 protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
651 cur++;
652 infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
653
654 gnutls_alpn_set_protocols(session, protocols, cur, 0);
655 }
656#endif
657
658 if(data->set.str[STRING_CERT]) {
659 if(data->set.str[STRING_KEY_PASSWD]) {
660#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
661 const unsigned int supported_key_encryption_algorithms =
662 GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
663 GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
664 GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
665 GNUTLS_PKCS_USE_PBES2_AES_256;
666 rc = gnutls_certificate_set_x509_key_file2(
667 conn->ssl[sockindex].cred,
668 data->set.str[STRING_CERT],
669 data->set.str[STRING_KEY] ?
670 data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
671 do_file_type(data->set.str[STRING_CERT_TYPE]),
672 data->set.str[STRING_KEY_PASSWD],
673 supported_key_encryption_algorithms);
674 if(rc != GNUTLS_E_SUCCESS) {
675 failf(data,
676 "error reading X.509 potentially-encrypted key file: %s",
677 gnutls_strerror(rc));
678 return CURLE_SSL_CONNECT_ERROR;
679#else
680 failf(data, "gnutls lacks support for encrypted key files");
681 return CURLE_SSL_CONNECT_ERROR;
682#endif
683 }
684 }
685 else {
686 rc = gnutls_certificate_set_x509_key_file(
687 conn->ssl[sockindex].cred,
688 data->set.str[STRING_CERT],
689 data->set.str[STRING_KEY] ?
690 data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
691 do_file_type(data->set.str[STRING_CERT_TYPE]) );
692 if(rc != GNUTLS_E_SUCCESS) {
693 failf(data, "error reading X.509 key or certificate file: %s",
694 gnutls_strerror(rc));
695 return CURLE_SSL_CONNECT_ERROR;
696 }
697 }
698 }
699
700#ifdef USE_TLS_SRP
701 /* put the credentials to the current session */
702 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
703 rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
704 conn->ssl[sockindex].srp_client_cred);
705 if(rc != GNUTLS_E_SUCCESS) {
706 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
707 return CURLE_SSL_CONNECT_ERROR;
708 }
709 }
710 else
711#endif
712 {
713 rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
714 conn->ssl[sockindex].cred);
715 if(rc != GNUTLS_E_SUCCESS) {
716 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
717 return CURLE_SSL_CONNECT_ERROR;
718 }
719 }
720
721 /* set the connection handle (file descriptor for the socket) */
722 gnutls_transport_set_ptr(session,
723 GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
724
725 /* register callback functions to send and receive data. */
726 gnutls_transport_set_push_function(session, Curl_gtls_push);
727 gnutls_transport_set_pull_function(session, Curl_gtls_pull);
728
729 /* lowat must be set to zero when using custom push and pull functions. */
730 gnutls_transport_set_lowat(session, 0);
731
732#ifdef HAS_OCSP
733 if(data->set.ssl.verifystatus) {
734 rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
735 if(rc != GNUTLS_E_SUCCESS) {
736 failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
737 return CURLE_SSL_CONNECT_ERROR;
738 }
739 }
740#endif
741
742 /* This might be a reconnect, so we check for a session ID in the cache
743 to speed up things */
744
745 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
746 /* we got a session id, use it! */
747 gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
748
749 /* Informational message */
750 infof (data, "SSL re-using session ID\n");
751 }
752
753 return CURLE_OK;
754}
755
756static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data,
757 gnutls_x509_crt_t cert,
758 const char *pinnedpubkey)
759{
760 /* Scratch */
761 size_t len1 = 0, len2 = 0;
762 unsigned char *buff1 = NULL;
763
764 gnutls_pubkey_t key = NULL;
765
766 /* Result is returned to caller */
767 int ret = 0;
768 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
769
770 /* if a path wasn't specified, don't pin */
771 if(NULL == pinnedpubkey)
772 return CURLE_OK;
773
774 if(NULL == cert)
775 return result;
776
777 do {
778 /* Begin Gyrations to get the public key */
779 gnutls_pubkey_init(&key);
780
781 ret = gnutls_pubkey_import_x509(key, cert, 0);
782 if(ret < 0)
783 break; /* failed */
784
785 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
786 if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
787 break; /* failed */
788
789 buff1 = malloc(len1);
790 if(NULL == buff1)
791 break; /* failed */
792
793 len2 = len1;
794
795 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
796 if(ret < 0 || len1 != len2)
797 break; /* failed */
798
799 /* End Gyrations */
800
801 /* The one good exit point */
802 result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
803 } while(0);
804
805 if(NULL != key)
806 gnutls_pubkey_deinit(key);
807
808 Curl_safefree(buff1);
809
810 return result;
811}
812
813static Curl_recv gtls_recv;
814static Curl_send gtls_send;
815
816static CURLcode
817gtls_connect_step3(struct connectdata *conn,
818 int sockindex)
819{
820 unsigned int cert_list_size;
821 const gnutls_datum_t *chainp;
822 unsigned int verify_status = 0;
823 gnutls_x509_crt_t x509_cert, x509_issuer;
824 gnutls_datum_t issuerp;
825 char certbuf[256] = ""; /* big enough? */
826 size_t size;
827 unsigned int algo;
828 unsigned int bits;
829 time_t certclock;
830 const char *ptr;
831 struct SessionHandle *data = conn->data;
832 gnutls_session_t session = conn->ssl[sockindex].session;
833 int rc;
834 bool incache;
835 void *ssl_sessionid;
836#ifdef HAS_ALPN
837 gnutls_datum_t proto;
838#endif
839 CURLcode result = CURLE_OK;
840
841 gnutls_protocol_t version = gnutls_protocol_get_version(session);
842
843 /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
844 ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
845 gnutls_cipher_get(session),
846 gnutls_mac_get(session));
847
848 infof(data, "SSL connection using %s / %s\n",
849 gnutls_protocol_get_name(version), ptr);
850
851 /* This function will return the peer's raw certificate (chain) as sent by
852 the peer. These certificates are in raw format (DER encoded for
853 X.509). In case of a X.509 then a certificate list may be present. The
854 first certificate in the list is the peer's certificate, following the
855 issuer's certificate, then the issuer's issuer etc. */
856
857 chainp = gnutls_certificate_get_peers(session, &cert_list_size);
858 if(!chainp) {
859 if(data->set.ssl.verifypeer ||
860 data->set.ssl.verifyhost ||
861 data->set.ssl.issuercert) {
862#ifdef USE_TLS_SRP
863 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
864 && data->set.ssl.username != NULL
865 && !data->set.ssl.verifypeer
866 && gnutls_cipher_get(session)) {
867 /* no peer cert, but auth is ok if we have SRP user and cipher and no
868 peer verify */
869 }
870 else {
871#endif
872 failf(data, "failed to get server cert");
873 return CURLE_PEER_FAILED_VERIFICATION;
874#ifdef USE_TLS_SRP
875 }
876#endif
877 }
878 infof(data, "\t common name: WARNING couldn't obtain\n");
879 }
880
881 if(data->set.ssl.certinfo && chainp) {
882 unsigned int i;
883
884 result = Curl_ssl_init_certinfo(data, cert_list_size);
885 if(result)
886 return result;
887
888 for(i = 0; i < cert_list_size; i++) {
889 const char *beg = (const char *) chainp[i].data;
890 const char *end = beg + chainp[i].size;
891
892 result = Curl_extract_certinfo(conn, i, beg, end);
893 if(result)
894 return result;
895 }
896 }
897
898 if(data->set.ssl.verifypeer) {
899 /* This function will try to verify the peer's certificate and return its
900 status (trusted, invalid etc.). The value of status should be one or
901 more of the gnutls_certificate_status_t enumerated elements bitwise
902 or'd. To avoid denial of service attacks some default upper limits
903 regarding the certificate key size and chain size are set. To override
904 them use gnutls_certificate_set_verify_limits(). */
905
906 rc = gnutls_certificate_verify_peers2(session, &verify_status);
907 if(rc < 0) {
908 failf(data, "server cert verify failed: %d", rc);
909 return CURLE_SSL_CONNECT_ERROR;
910 }
911
912 /* verify_status is a bitmask of gnutls_certificate_status bits */
913 if(verify_status & GNUTLS_CERT_INVALID) {
914 if(data->set.ssl.verifypeer) {
915 failf(data, "server certificate verification failed. CAfile: %s "
916 "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
917 data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
918 return CURLE_SSL_CACERT;
919 }
920 else
921 infof(data, "\t server certificate verification FAILED\n");
922 }
923 else
924 infof(data, "\t server certificate verification OK\n");
925 }
926 else
927 infof(data, "\t server certificate verification SKIPPED\n");
928
929#ifdef HAS_OCSP
930 if(data->set.ssl.verifystatus) {
931 if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
932 gnutls_datum_t status_request;
933 gnutls_ocsp_resp_t ocsp_resp;
934
935 gnutls_ocsp_cert_status_t status;
936 gnutls_x509_crl_reason_t reason;
937
938 rc = gnutls_ocsp_status_request_get(session, &status_request);
939
940 infof(data, "\t server certificate status verification FAILED\n");
941
942 if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
943 failf(data, "No OCSP response received");
944 return CURLE_SSL_INVALIDCERTSTATUS;
945 }
946
947 if(rc < 0) {
948 failf(data, "Invalid OCSP response received");
949 return CURLE_SSL_INVALIDCERTSTATUS;
950 }
951
952 gnutls_ocsp_resp_init(&ocsp_resp);
953
954 rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
955 if(rc < 0) {
956 failf(data, "Invalid OCSP response received");
957 return CURLE_SSL_INVALIDCERTSTATUS;
958 }
959
960 rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
961 &status, NULL, NULL, NULL, &reason);
962
963 switch(status) {
964 case GNUTLS_OCSP_CERT_GOOD:
965 break;
966
967 case GNUTLS_OCSP_CERT_REVOKED: {
968 const char *crl_reason;
969
970 switch(reason) {
971 default:
972 case GNUTLS_X509_CRLREASON_UNSPECIFIED:
973 crl_reason = "unspecified reason";
974 break;
975
976 case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
977 crl_reason = "private key compromised";
978 break;
979
980 case GNUTLS_X509_CRLREASON_CACOMPROMISE:
981 crl_reason = "CA compromised";
982 break;
983
984 case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
985 crl_reason = "affiliation has changed";
986 break;
987
988 case GNUTLS_X509_CRLREASON_SUPERSEDED:
989 crl_reason = "certificate superseded";
990 break;
991
992 case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
993 crl_reason = "operation has ceased";
994 break;
995
996 case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
997 crl_reason = "certificate is on hold";
998 break;
999
1000 case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
1001 crl_reason = "will be removed from delta CRL";
1002 break;
1003
1004 case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
1005 crl_reason = "privilege withdrawn";
1006 break;
1007
1008 case GNUTLS_X509_CRLREASON_AACOMPROMISE:
1009 crl_reason = "AA compromised";
1010 break;
1011 }
1012
1013 failf(data, "Server certificate was revoked: %s", crl_reason);
1014 break;
1015 }
1016
1017 default:
1018 case GNUTLS_OCSP_CERT_UNKNOWN:
1019 failf(data, "Server certificate status is unknown");
1020 break;
1021 }
1022
1023 gnutls_ocsp_resp_deinit(ocsp_resp);
1024
1025 return CURLE_SSL_INVALIDCERTSTATUS;
1026 }
1027 else
1028 infof(data, "\t server certificate status verification OK\n");
1029 }
1030 else
1031 infof(data, "\t server certificate status verification SKIPPED\n");
1032#endif
1033
1034 /* initialize an X.509 certificate structure. */
1035 gnutls_x509_crt_init(&x509_cert);
1036
1037 if(chainp)
1038 /* convert the given DER or PEM encoded Certificate to the native
1039 gnutls_x509_crt_t format */
1040 gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
1041
1042 if(data->set.ssl.issuercert) {
1043 gnutls_x509_crt_init(&x509_issuer);
1044 issuerp = load_file(data->set.ssl.issuercert);
1045 gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
1046 rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
1047 gnutls_x509_crt_deinit(x509_issuer);
1048 unload_file(issuerp);
1049 if(rc <= 0) {
1050 failf(data, "server certificate issuer check failed (IssuerCert: %s)",
1051 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
1052 gnutls_x509_crt_deinit(x509_cert);
1053 return CURLE_SSL_ISSUER_ERROR;
1054 }
1055 infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
1056 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
1057 }
1058
1059 size=sizeof(certbuf);
1060 rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
1061 0, /* the first and only one */
1062 FALSE,
1063 certbuf,
1064 &size);
1065 if(rc) {
1066 infof(data, "error fetching CN from cert:%s\n",
1067 gnutls_strerror(rc));
1068 }
1069
1070 /* This function will check if the given certificate's subject matches the
1071 given hostname. This is a basic implementation of the matching described
1072 in RFC2818 (HTTPS), which takes into account wildcards, and the subject
1073 alternative name PKIX extension. Returns non zero on success, and zero on
1074 failure. */
1075 rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
1076#if GNUTLS_VERSION_NUMBER < 0x030306
1077 /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
1078 addresses. */
1079 if(!rc) {
1080#ifdef ENABLE_IPV6
1081 #define use_addr in6_addr
1082#else
1083 #define use_addr in_addr
1084#endif
1085 unsigned char addrbuf[sizeof(struct use_addr)];
1086 unsigned char certaddr[sizeof(struct use_addr)];
1087 size_t addrlen = 0, certaddrlen;
1088 int i;
1089 int ret = 0;
1090
1091 if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0)
1092 addrlen = 4;
1093#ifdef ENABLE_IPV6
1094 else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0)
1095 addrlen = 16;
1096#endif
1097
1098 if(addrlen) {
1099 for(i=0; ; i++) {
1100 certaddrlen = sizeof(certaddr);
1101 ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
1102 &certaddrlen, NULL);
1103 /* If this happens, it wasn't an IP address. */
1104 if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
1105 continue;
1106 if(ret < 0)
1107 break;
1108 if(ret != GNUTLS_SAN_IPADDRESS)
1109 continue;
1110 if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
1111 rc = 1;
1112 break;
1113 }
1114 }
1115 }
1116 }
1117#endif
1118 if(!rc) {
1119 if(data->set.ssl.verifyhost) {
1120 failf(data, "SSL: certificate subject name (%s) does not match "
1121 "target host name '%s'", certbuf, conn->host.dispname);
1122 gnutls_x509_crt_deinit(x509_cert);
1123 return CURLE_PEER_FAILED_VERIFICATION;
1124 }
1125 else
1126 infof(data, "\t common name: %s (does not match '%s')\n",
1127 certbuf, conn->host.dispname);
1128 }
1129 else
1130 infof(data, "\t common name: %s (matched)\n", certbuf);
1131
1132 /* Check for time-based validity */
1133 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
1134
1135 if(certclock == (time_t)-1) {
1136 if(data->set.ssl.verifypeer) {
1137 failf(data, "server cert expiration date verify failed");
1138 gnutls_x509_crt_deinit(x509_cert);
1139 return CURLE_SSL_CONNECT_ERROR;
1140 }
1141 else
1142 infof(data, "\t server certificate expiration date verify FAILED\n");
1143 }
1144 else {
1145 if(certclock < time(NULL)) {
1146 if(data->set.ssl.verifypeer) {
1147 failf(data, "server certificate expiration date has passed.");
1148 gnutls_x509_crt_deinit(x509_cert);
1149 return CURLE_PEER_FAILED_VERIFICATION;
1150 }
1151 else
1152 infof(data, "\t server certificate expiration date FAILED\n");
1153 }
1154 else
1155 infof(data, "\t server certificate expiration date OK\n");
1156 }
1157
1158 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
1159
1160 if(certclock == (time_t)-1) {
1161 if(data->set.ssl.verifypeer) {
1162 failf(data, "server cert activation date verify failed");
1163 gnutls_x509_crt_deinit(x509_cert);
1164 return CURLE_SSL_CONNECT_ERROR;
1165 }
1166 else
1167 infof(data, "\t server certificate activation date verify FAILED\n");
1168 }
1169 else {
1170 if(certclock > time(NULL)) {
1171 if(data->set.ssl.verifypeer) {
1172 failf(data, "server certificate not activated yet.");
1173 gnutls_x509_crt_deinit(x509_cert);
1174 return CURLE_PEER_FAILED_VERIFICATION;
1175 }
1176 else
1177 infof(data, "\t server certificate activation date FAILED\n");
1178 }
1179 else
1180 infof(data, "\t server certificate activation date OK\n");
1181 }
1182
1183 ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
1184 if(ptr) {
1185 result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
1186 if(result != CURLE_OK) {
1187 failf(data, "SSL: public key does not match pinned public key!");
1188 gnutls_x509_crt_deinit(x509_cert);
1189 return result;
1190 }
1191 }
1192
1193 /* Show:
1194
1195 - subject
1196 - start date
1197 - expire date
1198 - common name
1199 - issuer
1200
1201 */
1202
1203 /* public key algorithm's parameters */
1204 algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
1205 infof(data, "\t certificate public key: %s\n",
1206 gnutls_pk_algorithm_get_name(algo));
1207
1208 /* version of the X.509 certificate. */
1209 infof(data, "\t certificate version: #%d\n",
1210 gnutls_x509_crt_get_version(x509_cert));
1211
1212
1213 size = sizeof(certbuf);
1214 gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
1215 infof(data, "\t subject: %s\n", certbuf);
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 size = sizeof(certbuf);
1224 gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
1225 infof(data, "\t issuer: %s\n", certbuf);
1226
1227 gnutls_x509_crt_deinit(x509_cert);
1228
1229 /* compression algorithm (if any) */
1230 ptr = gnutls_compression_get_name(gnutls_compression_get(session));
1231 /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
1232 infof(data, "\t compression: %s\n", ptr);
1233
1234#ifdef HAS_ALPN
1235 if(data->set.ssl_enable_alpn) {
1236 rc = gnutls_alpn_get_selected_protocol(session, &proto);
1237 if(rc == 0) {
1238 infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
1239 proto.data);
1240
1241#ifdef USE_NGHTTP2
1242 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
1243 !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
1244 NGHTTP2_PROTO_VERSION_ID_LEN)) {
1245 conn->negnpn = CURL_HTTP_VERSION_2;
1246 }
1247 else
1248#endif
1249 if(proto.size == ALPN_HTTP_1_1_LENGTH &&
1250 !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
1251 conn->negnpn = CURL_HTTP_VERSION_1_1;
1252 }
1253 }
1254 else
1255 infof(data, "ALPN, server did not agree to a protocol\n");
1256 }
1257#endif
1258
1259 conn->ssl[sockindex].state = ssl_connection_complete;
1260 conn->recv[sockindex] = gtls_recv;
1261 conn->send[sockindex] = gtls_send;
1262
1263 {
1264 /* we always unconditionally get the session id here, as even if we
1265 already got it from the cache and asked to use it in the connection, it
1266 might've been rejected and then a new one is in use now and we need to
1267 detect that. */
1268 void *connect_sessionid;
1269 size_t connect_idsize = 0;
1270
1271 /* get the session ID data size */
1272 gnutls_session_get_data(session, NULL, &connect_idsize);
1273 connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
1274
1275 if(connect_sessionid) {
1276 /* extract session ID to the allocated buffer */
1277 gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
1278
1279 incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
1280 if(incache) {
1281 /* there was one before in the cache, so instead of risking that the
1282 previous one was rejected, we just kill that and store the new */
1283 Curl_ssl_delsessionid(conn, ssl_sessionid);
1284 }
1285
1286 /* store this session id */
1287 result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
1288 if(result) {
1289 free(connect_sessionid);
1290 result = CURLE_OUT_OF_MEMORY;
1291 }
1292 }
1293 else
1294 result = CURLE_OUT_OF_MEMORY;
1295 }
1296
1297 return result;
1298}
1299
1300
1301/*
1302 * This function is called after the TCP connect has completed. Setup the TLS
1303 * layer and do all necessary magic.
1304 */
1305/* We use connssl->connecting_state to keep track of the connection status;
1306 there are three states: 'ssl_connect_1' (not started yet or complete),
1307 'ssl_connect_2_reading' (waiting for data from server), and
1308 'ssl_connect_2_writing' (waiting to be able to write).
1309 */
1310static CURLcode
1311gtls_connect_common(struct connectdata *conn,
1312 int sockindex,
1313 bool nonblocking,
1314 bool *done)
1315{
1316 int rc;
1317 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1318
1319 /* Initiate the connection, if not already done */
1320 if(ssl_connect_1==connssl->connecting_state) {
1321 rc = gtls_connect_step1 (conn, sockindex);
1322 if(rc)
1323 return rc;
1324 }
1325
1326 rc = handshake(conn, sockindex, TRUE, nonblocking);
1327 if(rc)
1328 /* handshake() sets its own error message with failf() */
1329 return rc;
1330
1331 /* Finish connecting once the handshake is done */
1332 if(ssl_connect_1==connssl->connecting_state) {
1333 rc = gtls_connect_step3(conn, sockindex);
1334 if(rc)
1335 return rc;
1336 }
1337
1338 *done = ssl_connect_1==connssl->connecting_state;
1339
1340 return CURLE_OK;
1341}
1342
1343CURLcode
1344Curl_gtls_connect_nonblocking(struct connectdata *conn,
1345 int sockindex,
1346 bool *done)
1347{
1348 return gtls_connect_common(conn, sockindex, TRUE, done);
1349}
1350
1351CURLcode
1352Curl_gtls_connect(struct connectdata *conn,
1353 int sockindex)
1354
1355{
1356 CURLcode result;
1357 bool done = FALSE;
1358
1359 result = gtls_connect_common(conn, sockindex, FALSE, &done);
1360 if(result)
1361 return result;
1362
1363 DEBUGASSERT(done);
1364
1365 return CURLE_OK;
1366}
1367
1368static ssize_t gtls_send(struct connectdata *conn,
1369 int sockindex,
1370 const void *mem,
1371 size_t len,
1372 CURLcode *curlcode)
1373{
1374 ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
1375
1376 if(rc < 0 ) {
1377 *curlcode = (rc == GNUTLS_E_AGAIN)
1378 ? CURLE_AGAIN
1379 : CURLE_SEND_ERROR;
1380
1381 rc = -1;
1382 }
1383
1384 return rc;
1385}
1386
1387static void close_one(struct connectdata *conn,
1388 int idx)
1389{
1390 if(conn->ssl[idx].session) {
1391 gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
1392 gnutls_deinit(conn->ssl[idx].session);
1393 conn->ssl[idx].session = NULL;
1394 }
1395 if(conn->ssl[idx].cred) {
1396 gnutls_certificate_free_credentials(conn->ssl[idx].cred);
1397 conn->ssl[idx].cred = NULL;
1398 }
1399#ifdef USE_TLS_SRP
1400 if(conn->ssl[idx].srp_client_cred) {
1401 gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
1402 conn->ssl[idx].srp_client_cred = NULL;
1403 }
1404#endif
1405}
1406
1407void Curl_gtls_close(struct connectdata *conn, int sockindex)
1408{
1409 close_one(conn, sockindex);
1410}
1411
1412/*
1413 * This function is called to shut down the SSL layer but keep the
1414 * socket open (CCC - Clear Command Channel)
1415 */
1416int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
1417{
1418 ssize_t result;
1419 int retval = 0;
1420 struct SessionHandle *data = conn->data;
1421 int done = 0;
1422 char buf[120];
1423
1424 /* This has only been tested on the proftpd server, and the mod_tls code
1425 sends a close notify alert without waiting for a close notify alert in
1426 response. Thus we wait for a close notify alert from the server, but
1427 we do not send one. Let's hope other servers do the same... */
1428
1429 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
1430 gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
1431
1432 if(conn->ssl[sockindex].session) {
1433 while(!done) {
1434 int what = Curl_socket_ready(conn->sock[sockindex],
1435 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
1436 if(what > 0) {
1437 /* Something to read, let's do it and hope that it is the close
1438 notify alert from the server */
1439 result = gnutls_record_recv(conn->ssl[sockindex].session,
1440 buf, sizeof(buf));
1441 switch(result) {
1442 case 0:
1443 /* This is the expected response. There was no data but only
1444 the close notify alert */
1445 done = 1;
1446 break;
1447 case GNUTLS_E_AGAIN:
1448 case GNUTLS_E_INTERRUPTED:
1449 infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
1450 break;
1451 default:
1452 retval = -1;
1453 done = 1;
1454 break;
1455 }
1456 }
1457 else if(0 == what) {
1458 /* timeout */
1459 failf(data, "SSL shutdown timeout");
1460 done = 1;
1461 break;
1462 }
1463 else {
1464 /* anything that gets here is fatally bad */
1465 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1466 retval = -1;
1467 done = 1;
1468 }
1469 }
1470 gnutls_deinit(conn->ssl[sockindex].session);
1471 }
1472 gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
1473
1474#ifdef USE_TLS_SRP
1475 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
1476 && data->set.ssl.username != NULL)
1477 gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
1478#endif
1479
1480 conn->ssl[sockindex].cred = NULL;
1481 conn->ssl[sockindex].session = NULL;
1482
1483 return retval;
1484}
1485
1486static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
1487 int num, /* socketindex */
1488 char *buf, /* store read data here */
1489 size_t buffersize, /* max amount to read */
1490 CURLcode *curlcode)
1491{
1492 ssize_t ret;
1493
1494 ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
1495 if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
1496 *curlcode = CURLE_AGAIN;
1497 return -1;
1498 }
1499
1500 if(ret == GNUTLS_E_REHANDSHAKE) {
1501 /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
1502 proper way" takes a whole lot of work. */
1503 CURLcode result = handshake(conn, num, FALSE, FALSE);
1504 if(result)
1505 /* handshake() writes error message on its own */
1506 *curlcode = result;
1507 else
1508 *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
1509 return -1;
1510 }
1511
1512 if(ret < 0) {
1513 failf(conn->data, "GnuTLS recv error (%d): %s",
1514 (int)ret, gnutls_strerror((int)ret));
1515 *curlcode = CURLE_RECV_ERROR;
1516 return -1;
1517 }
1518
1519 return ret;
1520}
1521
1522void Curl_gtls_session_free(void *ptr)
1523{
1524 free(ptr);
1525}
1526
1527size_t Curl_gtls_version(char *buffer, size_t size)
1528{
1529 return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1530}
1531
1532#ifndef USE_GNUTLS_NETTLE
1533static int Curl_gtls_seed(struct SessionHandle *data)
1534{
1535 /* we have the "SSL is seeded" boolean static to prevent multiple
1536 time-consuming seedings in vain */
1537 static bool ssl_seeded = FALSE;
1538
1539 /* Quickly add a bit of entropy */
1540 gcry_fast_random_poll();
1541
1542 if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
1543 data->set.str[STRING_SSL_EGDSOCKET]) {
1544
1545 /* TODO: to a good job seeding the RNG
1546 This may involve the gcry_control function and these options:
1547 GCRYCTL_SET_RANDOM_SEED_FILE
1548 GCRYCTL_SET_RNDEGD_SOCKET
1549 */
1550 ssl_seeded = TRUE;
1551 }
1552 return 0;
1553}
1554#endif
1555
1556/* data might be NULL! */
1557int Curl_gtls_random(struct SessionHandle *data,
1558 unsigned char *entropy,
1559 size_t length)
1560{
1561#if defined(USE_GNUTLS_NETTLE)
1562 (void)data;
1563 gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
1564#elif defined(USE_GNUTLS)
1565 if(data)
1566 Curl_gtls_seed(data); /* Initiate the seed if not already done */
1567 gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
1568#endif
1569 return 0;
1570}
1571
1572void Curl_gtls_md5sum(unsigned char *tmp, /* input */
1573 size_t tmplen,
1574 unsigned char *md5sum, /* output */
1575 size_t md5len)
1576{
1577#if defined(USE_GNUTLS_NETTLE)
1578 struct md5_ctx MD5pw;
1579 md5_init(&MD5pw);
1580 md5_update(&MD5pw, (unsigned int)tmplen, tmp);
1581 md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
1582#elif defined(USE_GNUTLS)
1583 gcry_md_hd_t MD5pw;
1584 gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
1585 gcry_md_write(MD5pw, tmp, tmplen);
1586 memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len);
1587 gcry_md_close(MD5pw);
1588#endif
1589}
1590
1591void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
1592 size_t tmplen,
1593 unsigned char *sha256sum, /* output */
1594 size_t sha256len)
1595{
1596#if defined(USE_GNUTLS_NETTLE)
1597 struct sha256_ctx SHA256pw;
1598 sha256_init(&SHA256pw);
1599 sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
1600 sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
1601#elif defined(USE_GNUTLS)
1602 gcry_md_hd_t SHA256pw;
1603 gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
1604 gcry_md_write(SHA256pw, tmp, tmplen);
1605 memcpy(sha256sum, gcry_md_read (SHA256pw, 0), sha256len);
1606 gcry_md_close(SHA256pw);
1607#endif
1608}
1609
1610bool Curl_gtls_cert_status_request(void)
1611{
1612#ifdef HAS_OCSP
1613 return TRUE;
1614#else
1615 return FALSE;
1616#endif
1617}
1618
1619#endif /* USE_GNUTLS */
Note: See TracBrowser for help on using the repository browser.