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