1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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 http://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 sslgen.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 "setup.h"
32 #ifdef USE_GNUTLS
33 #include <gnutls/gnutls.h>
34 #include <gnutls/x509.h>
35 #include <gcrypt.h>
36
37 #include <string.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
42 #endif
43
44 #include "urldata.h"
45 #include "sendf.h"
46 #include "inet_pton.h"
47 #include "gtls.h"
48 #include "sslgen.h"
49 #include "parsedate.h"
50 #include "connect.h" /* for the connect timeout */
51 #include "select.h"
52 #include "rawstr.h"
53
54 #define _MPRINTF_REPLACE /* use our functions only */
55 #include <curl/mprintf.h>
56 #include "curl_memory.h"
57 /* The last #include file should be: */
58 #include "memdebug.h"
59
60 /*
61 Some hackish cast macros based on:
62 http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
63 */
64 #ifndef GNUTLS_POINTER_TO_INT_CAST
65 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
66 #endif
67 #ifndef GNUTLS_INT_TO_POINTER_CAST
68 #define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
69 #endif
70
71 /* Enable GnuTLS debugging by defining GTLSDEBUG */
72 /*#define GTLSDEBUG */
73
74 #ifdef GTLSDEBUG
tls_log_func(int level,const char * str)75 static void tls_log_func(int level, const char *str)
76 {
77 fprintf(stderr, "|<%d>| %s", level, str);
78 }
79 #endif
80 static bool gtls_inited = FALSE;
81
82 /*
83 * Custom push and pull callback functions used by GNU TLS to read and write
84 * to the socket. These functions are simple wrappers to send() and recv()
85 * (although here using the sread/swrite macros as defined by setup_once.h).
86 * We use custom functions rather than the GNU TLS defaults because it allows
87 * us to get specific about the fourth "flags" argument, and to use arbitrary
88 * private data with gnutls_transport_set_ptr if we wish.
89 *
90 * When these custom push and pull callbacks fail, GNU TLS checks its own
91 * session-specific error variable, and when not set also its own global
92 * errno variable, in order to take appropriate action. GNU TLS does not
93 * require that the transport is actually a socket. This implies that for
94 * Windows builds these callbacks should ideally set the session-specific
95 * error variable using function gnutls_transport_set_errno or as a last
96 * resort global errno variable using gnutls_transport_set_global_errno,
97 * with a transport agnostic error value. This implies that some winsock
98 * error translation must take place in these callbacks.
99 */
100
101 #ifdef USE_WINSOCK
102 # define gtls_EINTR 4
103 # define gtls_EIO 5
104 # define gtls_EAGAIN 11
gtls_mapped_sockerrno(void)105 static int gtls_mapped_sockerrno(void)
106 {
107 switch(SOCKERRNO) {
108 case WSAEWOULDBLOCK:
109 return gtls_EAGAIN;
110 case WSAEINTR:
111 return gtls_EINTR;
112 default:
113 break;
114 }
115 return gtls_EIO;
116 }
117 #endif
118
Curl_gtls_push(void * s,const void * buf,size_t len)119 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
120 {
121 ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
122 #ifdef USE_WINSOCK
123 if(ret < 0)
124 gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
125 #endif
126 return ret;
127 }
128
Curl_gtls_pull(void * s,void * buf,size_t len)129 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
130 {
131 ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
132 #ifdef USE_WINSOCK
133 if(ret < 0)
134 gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
135 #endif
136 return ret;
137 }
138
139 /* Curl_gtls_init()
140 *
141 * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
142 * are not thread-safe and thus this function itself is not thread-safe and
143 * must only be called from within curl_global_init() to keep the thread
144 * situation under control!
145 */
Curl_gtls_init(void)146 int Curl_gtls_init(void)
147 {
148 int ret = 1;
149 if(!gtls_inited) {
150 ret = gnutls_global_init()?0:1;
151 #ifdef GTLSDEBUG
152 gnutls_global_set_log_function(tls_log_func);
153 gnutls_global_set_log_level(2);
154 #endif
155 gtls_inited = TRUE;
156 }
157 return ret;
158 }
159
Curl_gtls_cleanup(void)160 int Curl_gtls_cleanup(void)
161 {
162 if(gtls_inited) {
163 gnutls_global_deinit();
164 gtls_inited = FALSE;
165 }
166 return 1;
167 }
168
showtime(struct SessionHandle * data,const char * text,time_t stamp)169 static void showtime(struct SessionHandle *data,
170 const char *text,
171 time_t stamp)
172 {
173 struct tm buffer;
174 const struct tm *tm = &buffer;
175 CURLcode result = Curl_gmtime(stamp, &buffer);
176 if(result)
177 return;
178
179 snprintf(data->state.buffer,
180 BUFSIZE,
181 "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
182 text,
183 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
184 tm->tm_mday,
185 Curl_month[tm->tm_mon],
186 tm->tm_year + 1900,
187 tm->tm_hour,
188 tm->tm_min,
189 tm->tm_sec);
190 infof(data, "%s", data->state.buffer);
191 }
192
load_file(const char * file)193 static gnutls_datum load_file (const char *file)
194 {
195 FILE *f;
196 gnutls_datum loaded_file = { NULL, 0 };
197 long filelen;
198 void *ptr;
199
200 if (!(f = fopen(file, "r")))
201 return loaded_file;
202 if (fseek(f, 0, SEEK_END) != 0
203 || (filelen = ftell(f)) < 0
204 || fseek(f, 0, SEEK_SET) != 0
205 || !(ptr = malloc((size_t)filelen)))
206 goto out;
207 if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
208 free(ptr);
209 goto out;
210 }
211
212 loaded_file.data = ptr;
213 loaded_file.size = (unsigned int)filelen;
214 out:
215 fclose(f);
216 return loaded_file;
217 }
218
unload_file(gnutls_datum data)219 static void unload_file(gnutls_datum data) {
220 free(data.data);
221 }
222
223
224 /* this function does a SSL/TLS (re-)handshake */
handshake(struct connectdata * conn,int sockindex,bool duringconnect,bool nonblocking)225 static CURLcode handshake(struct connectdata *conn,
226 int sockindex,
227 bool duringconnect,
228 bool nonblocking)
229 {
230 struct SessionHandle *data = conn->data;
231 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
232 gnutls_session session = conn->ssl[sockindex].session;
233 curl_socket_t sockfd = conn->sock[sockindex];
234 long timeout_ms;
235 int rc;
236 int what;
237
238 for(;;) {
239 /* check allowed time left */
240 timeout_ms = Curl_timeleft(data, NULL, duringconnect);
241
242 if(timeout_ms < 0) {
243 /* no need to continue if time already is up */
244 failf(data, "SSL connection timeout");
245 return CURLE_OPERATION_TIMEDOUT;
246 }
247
248 /* if ssl is expecting something, check if it's available. */
249 if(connssl->connecting_state == ssl_connect_2_reading
250 || connssl->connecting_state == ssl_connect_2_writing) {
251
252 curl_socket_t writefd = ssl_connect_2_writing==
253 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
254 curl_socket_t readfd = ssl_connect_2_reading==
255 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
256
257 what = Curl_socket_ready(readfd, writefd,
258 nonblocking?0:(int)timeout_ms?1000:timeout_ms);
259 if(what < 0) {
260 /* fatal error */
261 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
262 return CURLE_SSL_CONNECT_ERROR;
263 }
264 else if(0 == what) {
265 if(nonblocking)
266 return CURLE_OK;
267 else if(timeout_ms) {
268 /* timeout */
269 failf(data, "SSL connection timeout at %ld", timeout_ms);
270 return CURLE_OPERATION_TIMEDOUT;
271 }
272 }
273 /* socket is readable or writable */
274 }
275
276 rc = gnutls_handshake(session);
277
278 if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
279 connssl->connecting_state =
280 gnutls_record_get_direction(session)?
281 ssl_connect_2_writing:ssl_connect_2_reading;
282 if(nonblocking)
283 return CURLE_OK;
284 }
285 else if (rc < 0) {
286 failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
287 return CURLE_SSL_CONNECT_ERROR;
288 }
289 else {
290 /* Reset our connect state machine */
291 connssl->connecting_state = ssl_connect_1;
292 return CURLE_OK;
293 }
294 }
295 }
296
do_file_type(const char * type)297 static gnutls_x509_crt_fmt do_file_type(const char *type)
298 {
299 if(!type || !type[0])
300 return GNUTLS_X509_FMT_PEM;
301 if(Curl_raw_equal(type, "PEM"))
302 return GNUTLS_X509_FMT_PEM;
303 if(Curl_raw_equal(type, "DER"))
304 return GNUTLS_X509_FMT_DER;
305 return -1;
306 }
307
308 static CURLcode
gtls_connect_step1(struct connectdata * conn,int sockindex)309 gtls_connect_step1(struct connectdata *conn,
310 int sockindex)
311 {
312 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
313 struct SessionHandle *data = conn->data;
314 gnutls_session session;
315 int rc;
316 void *ssl_sessionid;
317 size_t ssl_idsize;
318 bool sni = TRUE; /* default is SNI enabled */
319 #ifdef ENABLE_IPV6
320 struct in6_addr addr;
321 #else
322 struct in_addr addr;
323 #endif
324
325 if(conn->ssl[sockindex].state == ssl_connection_complete)
326 /* to make us tolerant against being called more than once for the
327 same connection */
328 return CURLE_OK;
329
330 if(!gtls_inited)
331 Curl_gtls_init();
332
333 /* GnuTLS only supports SSLv3 and TLSv1 */
334 if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
335 failf(data, "GnuTLS does not support SSLv2");
336 return CURLE_SSL_CONNECT_ERROR;
337 }
338 else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
339 sni = FALSE; /* SSLv3 has no SNI */
340
341 /* allocate a cred struct */
342 rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
343 if(rc != GNUTLS_E_SUCCESS) {
344 failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
345 return CURLE_SSL_CONNECT_ERROR;
346 }
347
348 #ifdef USE_TLS_SRP
349 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
350 infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
351
352 rc = gnutls_srp_allocate_client_credentials(
353 &conn->ssl[sockindex].srp_client_cred);
354 if(rc != GNUTLS_E_SUCCESS) {
355 failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
356 gnutls_strerror(rc));
357 return CURLE_OUT_OF_MEMORY;
358 }
359
360 rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].srp_client_cred,
361 data->set.ssl.username,
362 data->set.ssl.password);
363 if(rc != GNUTLS_E_SUCCESS) {
364 failf(data, "gnutls_srp_set_client_cred() failed: %s",
365 gnutls_strerror(rc));
366 return CURLE_BAD_FUNCTION_ARGUMENT;
367 }
368 }
369 #endif
370
371 if(data->set.ssl.CAfile) {
372 /* set the trusted CA cert bundle file */
373 gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
374 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
375
376 rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
377 data->set.ssl.CAfile,
378 GNUTLS_X509_FMT_PEM);
379 if(rc < 0) {
380 infof(data, "error reading ca cert file %s (%s)\n",
381 data->set.ssl.CAfile, gnutls_strerror(rc));
382 if(data->set.ssl.verifypeer)
383 return CURLE_SSL_CACERT_BADFILE;
384 }
385 else
386 infof(data, "found %d certificates in %s\n",
387 rc, data->set.ssl.CAfile);
388 }
389
390 if(data->set.ssl.CRLfile) {
391 /* set the CRL list file */
392 rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
393 data->set.ssl.CRLfile,
394 GNUTLS_X509_FMT_PEM);
395 if(rc < 0) {
396 failf(data, "error reading crl file %s (%s)\n",
397 data->set.ssl.CRLfile, gnutls_strerror(rc));
398 return CURLE_SSL_CRL_BADFILE;
399 }
400 else
401 infof(data, "found %d CRL in %s\n",
402 rc, data->set.ssl.CRLfile);
403 }
404
405 /* Initialize TLS session as a client */
406 rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
407 if(rc != GNUTLS_E_SUCCESS) {
408 failf(data, "gnutls_init() failed: %d", rc);
409 return CURLE_SSL_CONNECT_ERROR;
410 }
411
412 /* convenient assign */
413 session = conn->ssl[sockindex].session;
414
415 if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
416 #ifdef ENABLE_IPV6
417 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
418 #endif
419 sni &&
420 (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
421 strlen(conn->host.name)) < 0))
422 infof(data, "WARNING: failed to configure server name indication (SNI) "
423 "TLS extension\n");
424
425 /* Use default priorities */
426 rc = gnutls_set_default_priority(session);
427 if(rc != GNUTLS_E_SUCCESS)
428 return CURLE_SSL_CONNECT_ERROR;
429
430 if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) {
431 static const int protocol_priority[] = { GNUTLS_SSL3, 0 };
432 gnutls_protocol_set_priority(session, protocol_priority);
433 if(rc != GNUTLS_E_SUCCESS)
434 return CURLE_SSL_CONNECT_ERROR;
435 }
436
437 /* Sets the priority on the certificate types supported by gnutls. Priority
438 is higher for types specified before others. After specifying the types
439 you want, you must append a 0. */
440 rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
441 if(rc != GNUTLS_E_SUCCESS)
442 return CURLE_SSL_CONNECT_ERROR;
443
444 if(data->set.str[STRING_CERT]) {
445 if( gnutls_certificate_set_x509_key_file(
446 conn->ssl[sockindex].cred,
447 data->set.str[STRING_CERT],
448 data->set.str[STRING_KEY] ?
449 data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
450 do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) {
451 failf(data, "error reading X.509 key or certificate file");
452 return CURLE_SSL_CONNECT_ERROR;
453 }
454 }
455
456 #ifdef USE_TLS_SRP
457 /* put the credentials to the current session */
458 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
459 rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
460 conn->ssl[sockindex].srp_client_cred);
461 if (rc != GNUTLS_E_SUCCESS) {
462 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
463 }
464 } else
465 #endif
466 rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
467 conn->ssl[sockindex].cred);
468
469 /* set the connection handle (file descriptor for the socket) */
470 gnutls_transport_set_ptr(session,
471 GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
472
473 /* register callback functions to send and receive data. */
474 gnutls_transport_set_push_function(session, Curl_gtls_push);
475 gnutls_transport_set_pull_function(session, Curl_gtls_pull);
476
477 /* lowat must be set to zero when using custom push and pull functions. */
478 gnutls_transport_set_lowat(session, 0);
479
480 /* This might be a reconnect, so we check for a session ID in the cache
481 to speed up things */
482
483 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
484 /* we got a session id, use it! */
485 gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
486
487 /* Informational message */
488 infof (data, "SSL re-using session ID\n");
489 }
490
491 return CURLE_OK;
492 }
493
494 static Curl_recv gtls_recv;
495 static Curl_send gtls_send;
496
497 static CURLcode
gtls_connect_step3(struct connectdata * conn,int sockindex)498 gtls_connect_step3(struct connectdata *conn,
499 int sockindex)
500 {
501 unsigned int cert_list_size;
502 const gnutls_datum *chainp;
503 unsigned int verify_status;
504 gnutls_x509_crt x509_cert,x509_issuer;
505 gnutls_datum issuerp;
506 char certbuf[256]; /* big enough? */
507 size_t size;
508 unsigned int algo;
509 unsigned int bits;
510 time_t certclock;
511 const char *ptr;
512 struct SessionHandle *data = conn->data;
513 gnutls_session session = conn->ssl[sockindex].session;
514 int rc;
515 int incache;
516 void *ssl_sessionid;
517 CURLcode result = CURLE_OK;
518
519 /* This function will return the peer's raw certificate (chain) as sent by
520 the peer. These certificates are in raw format (DER encoded for
521 X.509). In case of a X.509 then a certificate list may be present. The
522 first certificate in the list is the peer's certificate, following the
523 issuer's certificate, then the issuer's issuer etc. */
524
525 chainp = gnutls_certificate_get_peers(session, &cert_list_size);
526 if(!chainp) {
527 if(data->set.ssl.verifypeer ||
528 data->set.ssl.verifyhost ||
529 data->set.ssl.issuercert) {
530 #ifdef USE_TLS_SRP
531 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
532 && data->set.ssl.username != NULL
533 && !data->set.ssl.verifypeer
534 && gnutls_cipher_get(session)) {
535 /* no peer cert, but auth is ok if we have SRP user and cipher and no
536 peer verify */
537 }
538 else {
539 #endif
540 failf(data, "failed to get server cert");
541 return CURLE_PEER_FAILED_VERIFICATION;
542 #ifdef USE_TLS_SRP
543 }
544 #endif
545 }
546 infof(data, "\t common name: WARNING couldn't obtain\n");
547 }
548
549 if(data->set.ssl.verifypeer) {
550 /* This function will try to verify the peer's certificate and return its
551 status (trusted, invalid etc.). The value of status should be one or
552 more of the gnutls_certificate_status_t enumerated elements bitwise
553 or'd. To avoid denial of service attacks some default upper limits
554 regarding the certificate key size and chain size are set. To override
555 them use gnutls_certificate_set_verify_limits(). */
556
557 rc = gnutls_certificate_verify_peers2(session, &verify_status);
558 if(rc < 0) {
559 failf(data, "server cert verify failed: %d", rc);
560 return CURLE_SSL_CONNECT_ERROR;
561 }
562
563 /* verify_status is a bitmask of gnutls_certificate_status bits */
564 if(verify_status & GNUTLS_CERT_INVALID) {
565 if(data->set.ssl.verifypeer) {
566 failf(data, "server certificate verification failed. CAfile: %s "
567 "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
568 data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
569 return CURLE_SSL_CACERT;
570 }
571 else
572 infof(data, "\t server certificate verification FAILED\n");
573 }
574 else
575 infof(data, "\t server certificate verification OK\n");
576 }
577 else {
578 infof(data, "\t server certificate verification SKIPPED\n");
579 goto after_server_cert_verification;
580 }
581
582 /* initialize an X.509 certificate structure. */
583 gnutls_x509_crt_init(&x509_cert);
584
585 /* convert the given DER or PEM encoded Certificate to the native
586 gnutls_x509_crt_t format */
587 gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
588
589 if (data->set.ssl.issuercert) {
590 gnutls_x509_crt_init(&x509_issuer);
591 issuerp = load_file(data->set.ssl.issuercert);
592 gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
593 rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
594 unload_file(issuerp);
595 if (rc <= 0) {
596 failf(data, "server certificate issuer check failed (IssuerCert: %s)",
597 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
598 return CURLE_SSL_ISSUER_ERROR;
599 }
600 infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
601 data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
602 }
603
604 size=sizeof(certbuf);
605 rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
606 0, /* the first and only one */
607 FALSE,
608 certbuf,
609 &size);
610 if(rc) {
611 infof(data, "error fetching CN from cert:%s\n",
612 gnutls_strerror(rc));
613 }
614
615 /* This function will check if the given certificate's subject matches the
616 given hostname. This is a basic implementation of the matching described
617 in RFC2818 (HTTPS), which takes into account wildcards, and the subject
618 alternative name PKIX extension. Returns non zero on success, and zero on
619 failure. */
620 rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
621
622 if(!rc) {
623 if(data->set.ssl.verifyhost > 1) {
624 failf(data, "SSL: certificate subject name (%s) does not match "
625 "target host name '%s'", certbuf, conn->host.dispname);
626 gnutls_x509_crt_deinit(x509_cert);
627 return CURLE_PEER_FAILED_VERIFICATION;
628 }
629 else
630 infof(data, "\t common name: %s (does not match '%s')\n",
631 certbuf, conn->host.dispname);
632 }
633 else
634 infof(data, "\t common name: %s (matched)\n", certbuf);
635
636 /* Check for time-based validity */
637 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
638
639 if(certclock == (time_t)-1) {
640 failf(data, "server cert expiration date verify failed");
641 return CURLE_SSL_CONNECT_ERROR;
642 }
643
644 if(certclock < time(NULL)) {
645 if(data->set.ssl.verifypeer) {
646 failf(data, "server certificate expiration date has passed.");
647 return CURLE_PEER_FAILED_VERIFICATION;
648 }
649 else
650 infof(data, "\t server certificate expiration date FAILED\n");
651 }
652 else
653 infof(data, "\t server certificate expiration date OK\n");
654
655 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
656
657 if(certclock == (time_t)-1) {
658 failf(data, "server cert activation date verify failed");
659 return CURLE_SSL_CONNECT_ERROR;
660 }
661
662 if(certclock > time(NULL)) {
663 if(data->set.ssl.verifypeer) {
664 failf(data, "server certificate not activated yet.");
665 return CURLE_PEER_FAILED_VERIFICATION;
666 }
667 else
668 infof(data, "\t server certificate activation date FAILED\n");
669 }
670 else
671 infof(data, "\t server certificate activation date OK\n");
672
673 /* Show:
674
675 - ciphers used
676 - subject
677 - start date
678 - expire date
679 - common name
680 - issuer
681
682 */
683
684 /* public key algorithm's parameters */
685 algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
686 infof(data, "\t certificate public key: %s\n",
687 gnutls_pk_algorithm_get_name(algo));
688
689 /* version of the X.509 certificate. */
690 infof(data, "\t certificate version: #%d\n",
691 gnutls_x509_crt_get_version(x509_cert));
692
693
694 size = sizeof(certbuf);
695 gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
696 infof(data, "\t subject: %s\n", certbuf);
697
698 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
699 showtime(data, "start date", certclock);
700
701 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
702 showtime(data, "expire date", certclock);
703
704 size = sizeof(certbuf);
705 gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
706 infof(data, "\t issuer: %s\n", certbuf);
707
708 gnutls_x509_crt_deinit(x509_cert);
709
710 after_server_cert_verification:
711
712 /* compression algorithm (if any) */
713 ptr = gnutls_compression_get_name(gnutls_compression_get(session));
714 /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
715 infof(data, "\t compression: %s\n", ptr);
716
717 /* the name of the cipher used. ie 3DES. */
718 ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
719 infof(data, "\t cipher: %s\n", ptr);
720
721 /* the MAC algorithms name. ie SHA1 */
722 ptr = gnutls_mac_get_name(gnutls_mac_get(session));
723 infof(data, "\t MAC: %s\n", ptr);
724
725 conn->ssl[sockindex].state = ssl_connection_complete;
726 conn->recv[sockindex] = gtls_recv;
727 conn->send[sockindex] = gtls_send;
728
729 {
730 /* we always unconditionally get the session id here, as even if we
731 already got it from the cache and asked to use it in the connection, it
732 might've been rejected and then a new one is in use now and we need to
733 detect that. */
734 void *connect_sessionid;
735 size_t connect_idsize;
736
737 /* get the session ID data size */
738 gnutls_session_get_data(session, NULL, &connect_idsize);
739 connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
740
741 if(connect_sessionid) {
742 /* extract session ID to the allocated buffer */
743 gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
744
745 incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
746 if (incache) {
747 /* there was one before in the cache, so instead of risking that the
748 previous one was rejected, we just kill that and store the new */
749 Curl_ssl_delsessionid(conn, ssl_sessionid);
750 }
751
752 /* store this session id */
753 result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
754 if(result) {
755 free(connect_sessionid);
756 result = CURLE_OUT_OF_MEMORY;
757 }
758 }
759 else
760 result = CURLE_OUT_OF_MEMORY;
761 }
762
763 return result;
764 }
765
766
767 /*
768 * This function is called after the TCP connect has completed. Setup the TLS
769 * layer and do all necessary magic.
770 */
771 /* We use connssl->connecting_state to keep track of the connection status;
772 there are three states: 'ssl_connect_1' (not started yet or complete),
773 'ssl_connect_2_reading' (waiting for data from server), and
774 'ssl_connect_2_writing' (waiting to be able to write).
775 */
776 static CURLcode
gtls_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)777 gtls_connect_common(struct connectdata *conn,
778 int sockindex,
779 bool nonblocking,
780 bool *done)
781 {
782 int rc;
783 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
784
785 /* Initiate the connection, if not already done */
786 if(ssl_connect_1==connssl->connecting_state) {
787 rc = gtls_connect_step1 (conn, sockindex);
788 if(rc)
789 return rc;
790 }
791
792 rc = handshake(conn, sockindex, TRUE, nonblocking);
793 if(rc)
794 /* handshake() sets its own error message with failf() */
795 return rc;
796
797 /* Finish connecting once the handshake is done */
798 if(ssl_connect_1==connssl->connecting_state) {
799 rc = gtls_connect_step3(conn, sockindex);
800 if(rc)
801 return rc;
802 }
803
804 *done = ssl_connect_1==connssl->connecting_state;
805
806 return CURLE_OK;
807 }
808
809 CURLcode
Curl_gtls_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)810 Curl_gtls_connect_nonblocking(struct connectdata *conn,
811 int sockindex,
812 bool *done)
813 {
814 return gtls_connect_common(conn, sockindex, TRUE, done);
815 }
816
817 CURLcode
Curl_gtls_connect(struct connectdata * conn,int sockindex)818 Curl_gtls_connect(struct connectdata *conn,
819 int sockindex)
820
821 {
822 CURLcode retcode;
823 bool done = FALSE;
824
825 retcode = gtls_connect_common(conn, sockindex, FALSE, &done);
826 if(retcode)
827 return retcode;
828
829 DEBUGASSERT(done);
830
831 return CURLE_OK;
832 }
833
gtls_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * curlcode)834 static ssize_t gtls_send(struct connectdata *conn,
835 int sockindex,
836 const void *mem,
837 size_t len,
838 CURLcode *curlcode)
839 {
840 ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
841
842 if(rc < 0 ) {
843 *curlcode = (rc == GNUTLS_E_AGAIN)
844 ? CURLE_AGAIN
845 : CURLE_SEND_ERROR;
846
847 rc = -1;
848 }
849
850 return rc;
851 }
852
Curl_gtls_close_all(struct SessionHandle * data)853 void Curl_gtls_close_all(struct SessionHandle *data)
854 {
855 /* FIX: make the OpenSSL code more generic and use parts of it here */
856 (void)data;
857 }
858
close_one(struct connectdata * conn,int idx)859 static void close_one(struct connectdata *conn,
860 int idx)
861 {
862 if(conn->ssl[idx].session) {
863 gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
864 gnutls_deinit(conn->ssl[idx].session);
865 conn->ssl[idx].session = NULL;
866 }
867 if(conn->ssl[idx].cred) {
868 gnutls_certificate_free_credentials(conn->ssl[idx].cred);
869 conn->ssl[idx].cred = NULL;
870 }
871 #ifdef USE_TLS_SRP
872 if (conn->ssl[idx].srp_client_cred) {
873 gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
874 conn->ssl[idx].srp_client_cred = NULL;
875 }
876 #endif
877 }
878
Curl_gtls_close(struct connectdata * conn,int sockindex)879 void Curl_gtls_close(struct connectdata *conn, int sockindex)
880 {
881 close_one(conn, sockindex);
882 }
883
884 /*
885 * This function is called to shut down the SSL layer but keep the
886 * socket open (CCC - Clear Command Channel)
887 */
Curl_gtls_shutdown(struct connectdata * conn,int sockindex)888 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
889 {
890 ssize_t result;
891 int retval = 0;
892 struct SessionHandle *data = conn->data;
893 int done = 0;
894 char buf[120];
895
896 /* This has only been tested on the proftpd server, and the mod_tls code
897 sends a close notify alert without waiting for a close notify alert in
898 response. Thus we wait for a close notify alert from the server, but
899 we do not send one. Let's hope other servers do the same... */
900
901 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
902 gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
903
904 if(conn->ssl[sockindex].session) {
905 while(!done) {
906 int what = Curl_socket_ready(conn->sock[sockindex],
907 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
908 if(what > 0) {
909 /* Something to read, let's do it and hope that it is the close
910 notify alert from the server */
911 result = gnutls_record_recv(conn->ssl[sockindex].session,
912 buf, sizeof(buf));
913 switch(result) {
914 case 0:
915 /* This is the expected response. There was no data but only
916 the close notify alert */
917 done = 1;
918 break;
919 case GNUTLS_E_AGAIN:
920 case GNUTLS_E_INTERRUPTED:
921 infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
922 break;
923 default:
924 retval = -1;
925 done = 1;
926 break;
927 }
928 }
929 else if(0 == what) {
930 /* timeout */
931 failf(data, "SSL shutdown timeout");
932 done = 1;
933 break;
934 }
935 else {
936 /* anything that gets here is fatally bad */
937 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
938 retval = -1;
939 done = 1;
940 }
941 }
942 gnutls_deinit(conn->ssl[sockindex].session);
943 }
944 gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
945
946 #ifdef USE_TLS_SRP
947 if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
948 && data->set.ssl.username != NULL)
949 gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
950 #endif
951
952 conn->ssl[sockindex].cred = NULL;
953 conn->ssl[sockindex].session = NULL;
954
955 return retval;
956 }
957
gtls_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,CURLcode * curlcode)958 static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
959 int num, /* socketindex */
960 char *buf, /* store read data here */
961 size_t buffersize, /* max amount to read */
962 CURLcode *curlcode)
963 {
964 ssize_t ret;
965
966 ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
967 if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
968 *curlcode = CURLE_AGAIN;
969 return -1;
970 }
971
972 if(ret == GNUTLS_E_REHANDSHAKE) {
973 /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
974 proper way" takes a whole lot of work. */
975 CURLcode rc = handshake(conn, num, FALSE, FALSE);
976 if(rc)
977 /* handshake() writes error message on its own */
978 *curlcode = rc;
979 else
980 *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
981 return -1;
982 }
983
984 if(ret < 0) {
985 failf(conn->data, "GnuTLS recv error (%d): %s",
986 (int)ret, gnutls_strerror((int)ret));
987 *curlcode = CURLE_RECV_ERROR;
988 return -1;
989 }
990
991 return ret;
992 }
993
Curl_gtls_session_free(void * ptr)994 void Curl_gtls_session_free(void *ptr)
995 {
996 free(ptr);
997 }
998
Curl_gtls_version(char * buffer,size_t size)999 size_t Curl_gtls_version(char *buffer, size_t size)
1000 {
1001 return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
1002 }
1003
Curl_gtls_seed(struct SessionHandle * data)1004 int Curl_gtls_seed(struct SessionHandle *data)
1005 {
1006 /* we have the "SSL is seeded" boolean static to prevent multiple
1007 time-consuming seedings in vain */
1008 static bool ssl_seeded = FALSE;
1009
1010 /* Quickly add a bit of entropy */
1011 gcry_fast_random_poll();
1012
1013 if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
1014 data->set.str[STRING_SSL_EGDSOCKET]) {
1015
1016 /* TODO: to a good job seeding the RNG
1017 This may involve the gcry_control function and these options:
1018 GCRYCTL_SET_RANDOM_SEED_FILE
1019 GCRYCTL_SET_RNDEGD_SOCKET
1020 */
1021 ssl_seeded = TRUE;
1022 }
1023 return 0;
1024 }
1025
1026 #endif /* USE_GNUTLS */
1027