00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "curl_setup.h"
00032
00033 #ifdef USE_GNUTLS
00034
00035 #include <gnutls/abstract.h>
00036 #include <gnutls/gnutls.h>
00037 #include <gnutls/x509.h>
00038
00039 #ifdef USE_GNUTLS_NETTLE
00040 #include <gnutls/crypto.h>
00041 #include <nettle/md5.h>
00042 #include <nettle/sha2.h>
00043 #else
00044 #include <gcrypt.h>
00045 #endif
00046
00047 #include "urldata.h"
00048 #include "sendf.h"
00049 #include "inet_pton.h"
00050 #include "gtls.h"
00051 #include "vtls.h"
00052 #include "parsedate.h"
00053 #include "connect.h"
00054 #include "select.h"
00055 #include "strcase.h"
00056 #include "warnless.h"
00057 #include "x509asn1.h"
00058 #include "curl_printf.h"
00059 #include "curl_memory.h"
00060
00061 #include "memdebug.h"
00062
00063
00064
00065
00066
00067 #ifndef GNUTLS_POINTER_TO_INT_CAST
00068 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
00069 #endif
00070 #ifndef GNUTLS_INT_TO_POINTER_CAST
00071 #define GNUTLS_INT_TO_POINTER_CAST(i) ((void *) (long) (i))
00072 #endif
00073
00074
00075
00076
00077 #ifdef GTLSDEBUG
00078 static void tls_log_func(int level, const char *str)
00079 {
00080 fprintf(stderr, "|<%d>| %s", level, str);
00081 }
00082 #endif
00083 static bool gtls_inited = FALSE;
00084
00085 #if defined(GNUTLS_VERSION_NUMBER)
00086 # if (GNUTLS_VERSION_NUMBER >= 0x020c00)
00087 # undef gnutls_transport_set_lowat
00088 # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
00089 # define USE_GNUTLS_PRIORITY_SET_DIRECT 1
00090 # endif
00091 # if (GNUTLS_VERSION_NUMBER >= 0x020c03)
00092 # define GNUTLS_MAPS_WINSOCK_ERRORS 1
00093 # endif
00094
00095 # if (GNUTLS_VERSION_NUMBER >= 0x030200)
00096 # define HAS_ALPN
00097 # endif
00098
00099 # if (GNUTLS_VERSION_NUMBER >= 0x03020d)
00100 # define HAS_OCSP
00101 # endif
00102
00103 # if (GNUTLS_VERSION_NUMBER >= 0x030306)
00104 # define HAS_CAPATH
00105 # endif
00106 #endif
00107
00108 #ifdef HAS_OCSP
00109 # include <gnutls/ocsp.h>
00110 #endif
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
00137 # define gtls_EINTR 4
00138 # define gtls_EIO 5
00139 # define gtls_EAGAIN 11
00140 static int gtls_mapped_sockerrno(void)
00141 {
00142 switch(SOCKERRNO) {
00143 case WSAEWOULDBLOCK:
00144 return gtls_EAGAIN;
00145 case WSAEINTR:
00146 return gtls_EINTR;
00147 default:
00148 break;
00149 }
00150 return gtls_EIO;
00151 }
00152 #endif
00153
00154 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
00155 {
00156 ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
00157 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
00158 if(ret < 0)
00159 gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
00160 #endif
00161 return ret;
00162 }
00163
00164 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
00165 {
00166 ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
00167 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
00168 if(ret < 0)
00169 gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
00170 #endif
00171 return ret;
00172 }
00173
00174 static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
00175 {
00176 return gnutls_record_send((gnutls_session_t) s, buf, len);
00177 }
00178
00179 static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
00180 {
00181 return gnutls_record_recv((gnutls_session_t) s, buf, len);
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191 int Curl_gtls_init(void)
00192 {
00193 int ret = 1;
00194 if(!gtls_inited) {
00195 ret = gnutls_global_init()?0:1;
00196 #ifdef GTLSDEBUG
00197 gnutls_global_set_log_function(tls_log_func);
00198 gnutls_global_set_log_level(2);
00199 #endif
00200 gtls_inited = TRUE;
00201 }
00202 return ret;
00203 }
00204
00205 int Curl_gtls_cleanup(void)
00206 {
00207 if(gtls_inited) {
00208 gnutls_global_deinit();
00209 gtls_inited = FALSE;
00210 }
00211 return 1;
00212 }
00213
00214 static void showtime(struct Curl_easy *data,
00215 const char *text,
00216 time_t stamp)
00217 {
00218 struct tm buffer;
00219 const struct tm *tm = &buffer;
00220 CURLcode result = Curl_gmtime(stamp, &buffer);
00221 if(result)
00222 return;
00223
00224 snprintf(data->state.buffer,
00225 BUFSIZE,
00226 "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
00227 text,
00228 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
00229 tm->tm_mday,
00230 Curl_month[tm->tm_mon],
00231 tm->tm_year + 1900,
00232 tm->tm_hour,
00233 tm->tm_min,
00234 tm->tm_sec);
00235 infof(data, "%s\n", data->state.buffer);
00236 }
00237
00238 static gnutls_datum_t load_file(const char *file)
00239 {
00240 FILE *f;
00241 gnutls_datum_t loaded_file = { NULL, 0 };
00242 long filelen;
00243 void *ptr;
00244
00245 f = fopen(file, "rb");
00246 if(!f)
00247 return loaded_file;
00248 if(fseek(f, 0, SEEK_END) != 0
00249 || (filelen = ftell(f)) < 0
00250 || fseek(f, 0, SEEK_SET) != 0
00251 || !(ptr = malloc((size_t)filelen)))
00252 goto out;
00253 if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
00254 free(ptr);
00255 goto out;
00256 }
00257
00258 loaded_file.data = ptr;
00259 loaded_file.size = (unsigned int)filelen;
00260 out:
00261 fclose(f);
00262 return loaded_file;
00263 }
00264
00265 static void unload_file(gnutls_datum_t data)
00266 {
00267 free(data.data);
00268 }
00269
00270
00271
00272 static CURLcode handshake(struct connectdata *conn,
00273 int sockindex,
00274 bool duringconnect,
00275 bool nonblocking)
00276 {
00277 struct Curl_easy *data = conn->data;
00278 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00279 gnutls_session_t session = conn->ssl[sockindex].session;
00280 curl_socket_t sockfd = conn->sock[sockindex];
00281 long timeout_ms;
00282 int rc;
00283 int what;
00284
00285 for(;;) {
00286
00287 timeout_ms = Curl_timeleft(data, NULL, duringconnect);
00288
00289 if(timeout_ms < 0) {
00290
00291 failf(data, "SSL connection timeout");
00292 return CURLE_OPERATION_TIMEDOUT;
00293 }
00294
00295
00296 if(connssl->connecting_state == ssl_connect_2_reading
00297 || connssl->connecting_state == ssl_connect_2_writing) {
00298
00299 curl_socket_t writefd = ssl_connect_2_writing==
00300 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
00301 curl_socket_t readfd = ssl_connect_2_reading==
00302 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
00303
00304 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
00305 nonblocking?0:
00306 timeout_ms?timeout_ms:1000);
00307 if(what < 0) {
00308
00309 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
00310 return CURLE_SSL_CONNECT_ERROR;
00311 }
00312 else if(0 == what) {
00313 if(nonblocking)
00314 return CURLE_OK;
00315 else if(timeout_ms) {
00316
00317 failf(data, "SSL connection timeout at %ld", timeout_ms);
00318 return CURLE_OPERATION_TIMEDOUT;
00319 }
00320 }
00321
00322 }
00323
00324 rc = gnutls_handshake(session);
00325
00326 if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
00327 connssl->connecting_state =
00328 gnutls_record_get_direction(session)?
00329 ssl_connect_2_writing:ssl_connect_2_reading;
00330 continue;
00331 }
00332 else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
00333 const char *strerr = NULL;
00334
00335 if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
00336 int alert = gnutls_alert_get(session);
00337 strerr = gnutls_alert_get_name(alert);
00338 }
00339
00340 if(strerr == NULL)
00341 strerr = gnutls_strerror(rc);
00342
00343 infof(data, "gnutls_handshake() warning: %s\n", strerr);
00344 continue;
00345 }
00346 else if(rc < 0) {
00347 const char *strerr = NULL;
00348
00349 if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
00350 int alert = gnutls_alert_get(session);
00351 strerr = gnutls_alert_get_name(alert);
00352 }
00353
00354 if(strerr == NULL)
00355 strerr = gnutls_strerror(rc);
00356
00357 failf(data, "gnutls_handshake() failed: %s", strerr);
00358 return CURLE_SSL_CONNECT_ERROR;
00359 }
00360
00361
00362 connssl->connecting_state = ssl_connect_1;
00363 return CURLE_OK;
00364 }
00365 }
00366
00367 static gnutls_x509_crt_fmt_t do_file_type(const char *type)
00368 {
00369 if(!type || !type[0])
00370 return GNUTLS_X509_FMT_PEM;
00371 if(strcasecompare(type, "PEM"))
00372 return GNUTLS_X509_FMT_PEM;
00373 if(strcasecompare(type, "DER"))
00374 return GNUTLS_X509_FMT_DER;
00375 return -1;
00376 }
00377
00378 static CURLcode
00379 gtls_connect_step1(struct connectdata *conn,
00380 int sockindex)
00381 {
00382 struct Curl_easy *data = conn->data;
00383 gnutls_session_t session;
00384 int rc;
00385 bool sni = TRUE;
00386 void *transport_ptr = NULL;
00387 gnutls_push_func gnutls_transport_push = NULL;
00388 gnutls_pull_func gnutls_transport_pull = NULL;
00389 #ifdef ENABLE_IPV6
00390 struct in6_addr addr;
00391 #else
00392 struct in_addr addr;
00393 #endif
00394 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
00395 static const int cipher_priority[] = {
00396
00397
00398
00399
00400
00401 GNUTLS_CIPHER_AES_128_CBC,
00402 GNUTLS_CIPHER_AES_256_CBC,
00403 GNUTLS_CIPHER_CAMELLIA_128_CBC,
00404 GNUTLS_CIPHER_CAMELLIA_256_CBC,
00405 GNUTLS_CIPHER_3DES_CBC,
00406 };
00407 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
00408 static int protocol_priority[] = { 0, 0, 0, 0 };
00409 #else
00410 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
00411
00412
00413
00414 #define GNUTLS_SRP "+SRP"
00415 const char *prioritylist;
00416 const char *err = NULL;
00417 #endif
00418
00419 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00420 conn->host.name;
00421
00422 if(conn->ssl[sockindex].state == ssl_connection_complete)
00423
00424
00425 return CURLE_OK;
00426
00427 if(!gtls_inited)
00428 Curl_gtls_init();
00429
00430 if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
00431 failf(data, "GnuTLS does not support SSLv2");
00432 return CURLE_SSL_CONNECT_ERROR;
00433 }
00434 else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
00435 sni = FALSE;
00436
00437
00438 rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
00439 if(rc != GNUTLS_E_SUCCESS) {
00440 failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
00441 return CURLE_SSL_CONNECT_ERROR;
00442 }
00443
00444 #ifdef USE_TLS_SRP
00445 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
00446 infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
00447
00448 rc = gnutls_srp_allocate_client_credentials(
00449 &conn->ssl[sockindex].srp_client_cred);
00450 if(rc != GNUTLS_E_SUCCESS) {
00451 failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
00452 gnutls_strerror(rc));
00453 return CURLE_OUT_OF_MEMORY;
00454 }
00455
00456 rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
00457 srp_client_cred,
00458 SSL_SET_OPTION(username),
00459 SSL_SET_OPTION(password));
00460 if(rc != GNUTLS_E_SUCCESS) {
00461 failf(data, "gnutls_srp_set_client_cred() failed: %s",
00462 gnutls_strerror(rc));
00463 return CURLE_BAD_FUNCTION_ARGUMENT;
00464 }
00465 }
00466 #endif
00467
00468 if(SSL_CONN_CONFIG(CAfile)) {
00469
00470 gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
00471 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
00472
00473 rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
00474 SSL_CONN_CONFIG(CAfile),
00475 GNUTLS_X509_FMT_PEM);
00476 if(rc < 0) {
00477 infof(data, "error reading ca cert file %s (%s)\n",
00478 SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
00479 if(SSL_CONN_CONFIG(verifypeer))
00480 return CURLE_SSL_CACERT_BADFILE;
00481 }
00482 else
00483 infof(data, "found %d certificates in %s\n", rc,
00484 SSL_CONN_CONFIG(CAfile));
00485 }
00486
00487 #ifdef HAS_CAPATH
00488 if(SSL_CONN_CONFIG(CApath)) {
00489
00490 rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
00491 SSL_CONN_CONFIG(CApath),
00492 GNUTLS_X509_FMT_PEM);
00493 if(rc < 0) {
00494 infof(data, "error reading ca cert file %s (%s)\n",
00495 SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
00496 if(SSL_CONN_CONFIG(verifypeer))
00497 return CURLE_SSL_CACERT_BADFILE;
00498 }
00499 else
00500 infof(data, "found %d certificates in %s\n",
00501 rc, SSL_CONN_CONFIG(CApath));
00502 }
00503 #endif
00504
00505 #ifdef CURL_CA_FALLBACK
00506
00507 if(SSL_CONN_CONFIG(verifypeer) &&
00508 !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
00509 gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
00510 }
00511 #endif
00512
00513 if(SSL_SET_OPTION(CRLfile)) {
00514
00515 rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
00516 SSL_SET_OPTION(CRLfile),
00517 GNUTLS_X509_FMT_PEM);
00518 if(rc < 0) {
00519 failf(data, "error reading crl file %s (%s)",
00520 SSL_SET_OPTION(CRLfile), gnutls_strerror(rc));
00521 return CURLE_SSL_CRL_BADFILE;
00522 }
00523 else
00524 infof(data, "found %d CRL in %s\n",
00525 rc, SSL_SET_OPTION(CRLfile));
00526 }
00527
00528
00529 rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
00530 if(rc != GNUTLS_E_SUCCESS) {
00531 failf(data, "gnutls_init() failed: %d", rc);
00532 return CURLE_SSL_CONNECT_ERROR;
00533 }
00534
00535
00536 session = conn->ssl[sockindex].session;
00537
00538 if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
00539 #ifdef ENABLE_IPV6
00540 (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
00541 #endif
00542 sni &&
00543 (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
00544 strlen(hostname)) < 0))
00545 infof(data, "WARNING: failed to configure server name indication (SNI) "
00546 "TLS extension\n");
00547
00548
00549 rc = gnutls_set_default_priority(session);
00550 if(rc != GNUTLS_E_SUCCESS)
00551 return CURLE_SSL_CONNECT_ERROR;
00552
00553 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
00554 rc = gnutls_cipher_set_priority(session, cipher_priority);
00555 if(rc != GNUTLS_E_SUCCESS)
00556 return CURLE_SSL_CONNECT_ERROR;
00557
00558
00559
00560
00561 rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
00562 if(rc != GNUTLS_E_SUCCESS)
00563 return CURLE_SSL_CONNECT_ERROR;
00564
00565 if(SSL_CONN_CONFIG(cipher_list) != NULL) {
00566 failf(data, "can't pass a custom cipher list to older GnuTLS"
00567 " versions");
00568 return CURLE_SSL_CONNECT_ERROR;
00569 }
00570
00571 switch(SSL_CONN_CONFIG(version) {
00572 case CURL_SSLVERSION_SSLv3:
00573 protocol_priority[0] = GNUTLS_SSL3;
00574 break;
00575 case CURL_SSLVERSION_DEFAULT:
00576 case CURL_SSLVERSION_TLSv1:
00577 protocol_priority[0] = GNUTLS_TLS1_0;
00578 protocol_priority[1] = GNUTLS_TLS1_1;
00579 protocol_priority[2] = GNUTLS_TLS1_2;
00580 break;
00581 case CURL_SSLVERSION_TLSv1_0:
00582 protocol_priority[0] = GNUTLS_TLS1_0;
00583 break;
00584 case CURL_SSLVERSION_TLSv1_1:
00585 protocol_priority[0] = GNUTLS_TLS1_1;
00586 break;
00587 case CURL_SSLVERSION_TLSv1_2:
00588 protocol_priority[0] = GNUTLS_TLS1_2;
00589 break;
00590 case CURL_SSLVERSION_TLSv1_3:
00591 failf(data, "GnuTLS: TLS 1.3 is not yet supported");
00592 return CURLE_SSL_CONNECT_ERROR;
00593 case CURL_SSLVERSION_SSLv2:
00594 failf(data, "GnuTLS does not support SSLv2");
00595 return CURLE_SSL_CONNECT_ERROR;
00596 default:
00597 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
00598 return CURLE_SSL_CONNECT_ERROR;
00599 }
00600 rc = gnutls_protocol_set_priority(session, protocol_priority);
00601 if(rc != GNUTLS_E_SUCCESS) {
00602 failf(data, "Did you pass a valid GnuTLS cipher list?");
00603 return CURLE_SSL_CONNECT_ERROR;
00604 }
00605
00606 #else
00607
00608
00609
00610 switch(SSL_CONN_CONFIG(version)) {
00611 case CURL_SSLVERSION_SSLv3:
00612 prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
00613 sni = false;
00614 break;
00615 case CURL_SSLVERSION_DEFAULT:
00616 case CURL_SSLVERSION_TLSv1:
00617 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
00618 break;
00619 case CURL_SSLVERSION_TLSv1_0:
00620 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
00621 "+VERS-TLS1.0:" GNUTLS_SRP;
00622 break;
00623 case CURL_SSLVERSION_TLSv1_1:
00624 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
00625 "+VERS-TLS1.1:" GNUTLS_SRP;
00626 break;
00627 case CURL_SSLVERSION_TLSv1_2:
00628 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
00629 "+VERS-TLS1.2:" GNUTLS_SRP;
00630 break;
00631 case CURL_SSLVERSION_TLSv1_3:
00632 failf(data, "GnuTLS: TLS 1.3 is not yet supported");
00633 return CURLE_SSL_CONNECT_ERROR;
00634 case CURL_SSLVERSION_SSLv2:
00635 failf(data, "GnuTLS does not support SSLv2");
00636 return CURLE_SSL_CONNECT_ERROR;
00637 default:
00638 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
00639 return CURLE_SSL_CONNECT_ERROR;
00640 }
00641 rc = gnutls_priority_set_direct(session, prioritylist, &err);
00642 if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
00643 if(!strcmp(err, GNUTLS_SRP)) {
00644
00645
00646 int validprioritylen = curlx_uztosi(err - prioritylist);
00647 char *prioritycopy = strdup(prioritylist);
00648 if(!prioritycopy)
00649 return CURLE_OUT_OF_MEMORY;
00650
00651 infof(data, "This GnuTLS does not support SRP\n");
00652 if(validprioritylen)
00653
00654 prioritycopy[validprioritylen - 1] = 0;
00655 rc = gnutls_priority_set_direct(session, prioritycopy, &err);
00656 free(prioritycopy);
00657 }
00658 }
00659 if(rc != GNUTLS_E_SUCCESS) {
00660 failf(data, "Error %d setting GnuTLS cipher list starting with %s",
00661 rc, err);
00662 return CURLE_SSL_CONNECT_ERROR;
00663 }
00664 #endif
00665
00666 #ifdef HAS_ALPN
00667 if(conn->bits.tls_enable_alpn) {
00668 int cur = 0;
00669 gnutls_datum_t protocols[2];
00670
00671 #ifdef USE_NGHTTP2
00672 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
00673 protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
00674 protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
00675 cur++;
00676 infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
00677 }
00678 #endif
00679
00680 protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
00681 protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
00682 cur++;
00683 infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
00684
00685 gnutls_alpn_set_protocols(session, protocols, cur, 0);
00686 }
00687 #endif
00688
00689 if(SSL_SET_OPTION(cert)) {
00690 if(SSL_SET_OPTION(key_passwd)) {
00691 #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
00692 const unsigned int supported_key_encryption_algorithms =
00693 GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
00694 GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
00695 GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
00696 GNUTLS_PKCS_USE_PBES2_AES_256;
00697 rc = gnutls_certificate_set_x509_key_file2(
00698 conn->ssl[sockindex].cred,
00699 SSL_SET_OPTION(cert),
00700 SSL_SET_OPTION(key) ?
00701 SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
00702 do_file_type(SSL_SET_OPTION(cert_type)),
00703 SSL_SET_OPTION(key_passwd),
00704 supported_key_encryption_algorithms);
00705 if(rc != GNUTLS_E_SUCCESS) {
00706 failf(data,
00707 "error reading X.509 potentially-encrypted key file: %s",
00708 gnutls_strerror(rc));
00709 return CURLE_SSL_CONNECT_ERROR;
00710 }
00711 #else
00712 failf(data, "gnutls lacks support for encrypted key files");
00713 return CURLE_SSL_CONNECT_ERROR;
00714 #endif
00715 }
00716 else {
00717 if(gnutls_certificate_set_x509_key_file(
00718 conn->ssl[sockindex].cred,
00719 SSL_SET_OPTION(cert),
00720 SSL_SET_OPTION(key) ?
00721 SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
00722 do_file_type(SSL_SET_OPTION(cert_type)) ) !=
00723 GNUTLS_E_SUCCESS) {
00724 failf(data, "error reading X.509 key or certificate file");
00725 return CURLE_SSL_CONNECT_ERROR;
00726 }
00727 }
00728 }
00729
00730 #ifdef USE_TLS_SRP
00731
00732 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
00733 rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
00734 conn->ssl[sockindex].srp_client_cred);
00735 if(rc != GNUTLS_E_SUCCESS) {
00736 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
00737 return CURLE_SSL_CONNECT_ERROR;
00738 }
00739 }
00740 else
00741 #endif
00742 {
00743 rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
00744 conn->ssl[sockindex].cred);
00745 if(rc != GNUTLS_E_SUCCESS) {
00746 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
00747 return CURLE_SSL_CONNECT_ERROR;
00748 }
00749 }
00750
00751 if(conn->proxy_ssl[sockindex].use) {
00752 transport_ptr = conn->proxy_ssl[sockindex].session;
00753 gnutls_transport_push = Curl_gtls_push_ssl;
00754 gnutls_transport_pull = Curl_gtls_pull_ssl;
00755 }
00756 else {
00757
00758 transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]);
00759 gnutls_transport_push = Curl_gtls_push;
00760 gnutls_transport_pull = Curl_gtls_pull;
00761 }
00762
00763
00764 gnutls_transport_set_ptr(session, transport_ptr);
00765
00766
00767 gnutls_transport_set_push_function(session, gnutls_transport_push);
00768 gnutls_transport_set_pull_function(session, gnutls_transport_pull);
00769
00770
00771 gnutls_transport_set_lowat(session, 0);
00772
00773 #ifdef HAS_OCSP
00774 if(SSL_CONN_CONFIG(verifystatus)) {
00775 rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
00776 if(rc != GNUTLS_E_SUCCESS) {
00777 failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
00778 return CURLE_SSL_CONNECT_ERROR;
00779 }
00780 }
00781 #endif
00782
00783
00784
00785 if(data->set.general_ssl.sessionid) {
00786 void *ssl_sessionid;
00787 size_t ssl_idsize;
00788
00789 Curl_ssl_sessionid_lock(conn);
00790 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) {
00791
00792 gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
00793
00794
00795 infof(data, "SSL re-using session ID\n");
00796 }
00797 Curl_ssl_sessionid_unlock(conn);
00798 }
00799
00800 return CURLE_OK;
00801 }
00802
00803 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
00804 gnutls_x509_crt_t cert,
00805 const char *pinnedpubkey)
00806 {
00807
00808 size_t len1 = 0, len2 = 0;
00809 unsigned char *buff1 = NULL;
00810
00811 gnutls_pubkey_t key = NULL;
00812
00813
00814 int ret = 0;
00815 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
00816
00817
00818 if(NULL == pinnedpubkey)
00819 return CURLE_OK;
00820
00821 if(NULL == cert)
00822 return result;
00823
00824 do {
00825
00826 gnutls_pubkey_init(&key);
00827
00828 ret = gnutls_pubkey_import_x509(key, cert, 0);
00829 if(ret < 0)
00830 break;
00831
00832 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
00833 if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
00834 break;
00835
00836 buff1 = malloc(len1);
00837 if(NULL == buff1)
00838 break;
00839
00840 len2 = len1;
00841
00842 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
00843 if(ret < 0 || len1 != len2)
00844 break;
00845
00846
00847
00848
00849 result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
00850 } while(0);
00851
00852 if(NULL != key)
00853 gnutls_pubkey_deinit(key);
00854
00855 Curl_safefree(buff1);
00856
00857 return result;
00858 }
00859
00860 static Curl_recv gtls_recv;
00861 static Curl_send gtls_send;
00862
00863 static CURLcode
00864 gtls_connect_step3(struct connectdata *conn,
00865 int sockindex)
00866 {
00867 unsigned int cert_list_size;
00868 const gnutls_datum_t *chainp;
00869 unsigned int verify_status = 0;
00870 gnutls_x509_crt_t x509_cert, x509_issuer;
00871 gnutls_datum_t issuerp;
00872 char certbuf[256] = "";
00873 size_t size;
00874 unsigned int algo;
00875 unsigned int bits;
00876 time_t certclock;
00877 const char *ptr;
00878 struct Curl_easy *data = conn->data;
00879 gnutls_session_t session = conn->ssl[sockindex].session;
00880 int rc;
00881 #ifdef HAS_ALPN
00882 gnutls_datum_t proto;
00883 #endif
00884 CURLcode result = CURLE_OK;
00885 gnutls_protocol_t version = gnutls_protocol_get_version(session);
00886 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00887 conn->host.name;
00888
00889
00890 ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
00891 gnutls_cipher_get(session),
00892 gnutls_mac_get(session));
00893
00894 infof(data, "SSL connection using %s / %s\n",
00895 gnutls_protocol_get_name(version), ptr);
00896
00897
00898
00899
00900
00901
00902
00903 chainp = gnutls_certificate_get_peers(session, &cert_list_size);
00904 if(!chainp) {
00905 if(SSL_CONN_CONFIG(verifypeer) ||
00906 SSL_CONN_CONFIG(verifyhost) ||
00907 SSL_SET_OPTION(issuercert)) {
00908 #ifdef USE_TLS_SRP
00909 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
00910 && SSL_SET_OPTION(username) != NULL
00911 && !SSL_CONN_CONFIG(verifypeer)
00912 && gnutls_cipher_get(session)) {
00913
00914
00915 }
00916 else {
00917 #endif
00918 failf(data, "failed to get server cert");
00919 return CURLE_PEER_FAILED_VERIFICATION;
00920 #ifdef USE_TLS_SRP
00921 }
00922 #endif
00923 }
00924 infof(data, "\t common name: WARNING couldn't obtain\n");
00925 }
00926
00927 if(data->set.ssl.certinfo && chainp) {
00928 unsigned int i;
00929
00930 result = Curl_ssl_init_certinfo(data, cert_list_size);
00931 if(result)
00932 return result;
00933
00934 for(i = 0; i < cert_list_size; i++) {
00935 const char *beg = (const char *) chainp[i].data;
00936 const char *end = beg + chainp[i].size;
00937
00938 result = Curl_extract_certinfo(conn, i, beg, end);
00939 if(result)
00940 return result;
00941 }
00942 }
00943
00944 if(SSL_CONN_CONFIG(verifypeer)) {
00945
00946
00947
00948
00949
00950
00951
00952 rc = gnutls_certificate_verify_peers2(session, &verify_status);
00953 if(rc < 0) {
00954 failf(data, "server cert verify failed: %d", rc);
00955 return CURLE_SSL_CONNECT_ERROR;
00956 }
00957
00958
00959 if(verify_status & GNUTLS_CERT_INVALID) {
00960 if(SSL_CONN_CONFIG(verifypeer)) {
00961 failf(data, "server certificate verification failed. CAfile: %s "
00962 "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
00963 "none",
00964 SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
00965 return CURLE_SSL_CACERT;
00966 }
00967 else
00968 infof(data, "\t server certificate verification FAILED\n");
00969 }
00970 else
00971 infof(data, "\t server certificate verification OK\n");
00972 }
00973 else
00974 infof(data, "\t server certificate verification SKIPPED\n");
00975
00976 #ifdef HAS_OCSP
00977 if(SSL_CONN_CONFIG(verifystatus)) {
00978 if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
00979 gnutls_datum_t status_request;
00980 gnutls_ocsp_resp_t ocsp_resp;
00981
00982 gnutls_ocsp_cert_status_t status;
00983 gnutls_x509_crl_reason_t reason;
00984
00985 rc = gnutls_ocsp_status_request_get(session, &status_request);
00986
00987 infof(data, "\t server certificate status verification FAILED\n");
00988
00989 if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
00990 failf(data, "No OCSP response received");
00991 return CURLE_SSL_INVALIDCERTSTATUS;
00992 }
00993
00994 if(rc < 0) {
00995 failf(data, "Invalid OCSP response received");
00996 return CURLE_SSL_INVALIDCERTSTATUS;
00997 }
00998
00999 gnutls_ocsp_resp_init(&ocsp_resp);
01000
01001 rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
01002 if(rc < 0) {
01003 failf(data, "Invalid OCSP response received");
01004 return CURLE_SSL_INVALIDCERTSTATUS;
01005 }
01006
01007 rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
01008 &status, NULL, NULL, NULL, &reason);
01009
01010 switch(status) {
01011 case GNUTLS_OCSP_CERT_GOOD:
01012 break;
01013
01014 case GNUTLS_OCSP_CERT_REVOKED: {
01015 const char *crl_reason;
01016
01017 switch(reason) {
01018 default:
01019 case GNUTLS_X509_CRLREASON_UNSPECIFIED:
01020 crl_reason = "unspecified reason";
01021 break;
01022
01023 case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
01024 crl_reason = "private key compromised";
01025 break;
01026
01027 case GNUTLS_X509_CRLREASON_CACOMPROMISE:
01028 crl_reason = "CA compromised";
01029 break;
01030
01031 case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
01032 crl_reason = "affiliation has changed";
01033 break;
01034
01035 case GNUTLS_X509_CRLREASON_SUPERSEDED:
01036 crl_reason = "certificate superseded";
01037 break;
01038
01039 case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
01040 crl_reason = "operation has ceased";
01041 break;
01042
01043 case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
01044 crl_reason = "certificate is on hold";
01045 break;
01046
01047 case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
01048 crl_reason = "will be removed from delta CRL";
01049 break;
01050
01051 case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
01052 crl_reason = "privilege withdrawn";
01053 break;
01054
01055 case GNUTLS_X509_CRLREASON_AACOMPROMISE:
01056 crl_reason = "AA compromised";
01057 break;
01058 }
01059
01060 failf(data, "Server certificate was revoked: %s", crl_reason);
01061 break;
01062 }
01063
01064 default:
01065 case GNUTLS_OCSP_CERT_UNKNOWN:
01066 failf(data, "Server certificate status is unknown");
01067 break;
01068 }
01069
01070 gnutls_ocsp_resp_deinit(ocsp_resp);
01071
01072 return CURLE_SSL_INVALIDCERTSTATUS;
01073 }
01074 else
01075 infof(data, "\t server certificate status verification OK\n");
01076 }
01077 else
01078 infof(data, "\t server certificate status verification SKIPPED\n");
01079 #endif
01080
01081
01082 gnutls_x509_crt_init(&x509_cert);
01083
01084 if(chainp)
01085
01086
01087 gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
01088
01089 if(SSL_SET_OPTION(issuercert)) {
01090 gnutls_x509_crt_init(&x509_issuer);
01091 issuerp = load_file(SSL_SET_OPTION(issuercert));
01092 gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
01093 rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
01094 gnutls_x509_crt_deinit(x509_issuer);
01095 unload_file(issuerp);
01096 if(rc <= 0) {
01097 failf(data, "server certificate issuer check failed (IssuerCert: %s)",
01098 SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
01099 gnutls_x509_crt_deinit(x509_cert);
01100 return CURLE_SSL_ISSUER_ERROR;
01101 }
01102 infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
01103 SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
01104 }
01105
01106 size=sizeof(certbuf);
01107 rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
01108 0,
01109 FALSE,
01110 certbuf,
01111 &size);
01112 if(rc) {
01113 infof(data, "error fetching CN from cert:%s\n",
01114 gnutls_strerror(rc));
01115 }
01116
01117
01118
01119
01120
01121
01122 rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
01123 #if GNUTLS_VERSION_NUMBER < 0x030306
01124
01125
01126 if(!rc) {
01127 #ifdef ENABLE_IPV6
01128 #define use_addr in6_addr
01129 #else
01130 #define use_addr in_addr
01131 #endif
01132 unsigned char addrbuf[sizeof(struct use_addr)];
01133 unsigned char certaddr[sizeof(struct use_addr)];
01134 size_t addrlen = 0, certaddrlen;
01135 int i;
01136 int ret = 0;
01137
01138 if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
01139 addrlen = 4;
01140 #ifdef ENABLE_IPV6
01141 else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
01142 addrlen = 16;
01143 #endif
01144
01145 if(addrlen) {
01146 for(i=0; ; i++) {
01147 certaddrlen = sizeof(certaddr);
01148 ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
01149 &certaddrlen, NULL);
01150
01151 if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
01152 continue;
01153 if(ret < 0)
01154 break;
01155 if(ret != GNUTLS_SAN_IPADDRESS)
01156 continue;
01157 if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
01158 rc = 1;
01159 break;
01160 }
01161 }
01162 }
01163 }
01164 #endif
01165 if(!rc) {
01166 const char * const dispname = SSL_IS_PROXY() ?
01167 conn->http_proxy.host.dispname : conn->host.dispname;
01168
01169 if(SSL_CONN_CONFIG(verifyhost)) {
01170 failf(data, "SSL: certificate subject name (%s) does not match "
01171 "target host name '%s'", certbuf, dispname);
01172 gnutls_x509_crt_deinit(x509_cert);
01173 return CURLE_PEER_FAILED_VERIFICATION;
01174 }
01175 else
01176 infof(data, "\t common name: %s (does not match '%s')\n",
01177 certbuf, dispname);
01178 }
01179 else
01180 infof(data, "\t common name: %s (matched)\n", certbuf);
01181
01182
01183 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
01184
01185 if(certclock == (time_t)-1) {
01186 if(SSL_CONN_CONFIG(verifypeer)) {
01187 failf(data, "server cert expiration date verify failed");
01188 gnutls_x509_crt_deinit(x509_cert);
01189 return CURLE_SSL_CONNECT_ERROR;
01190 }
01191 else
01192 infof(data, "\t server certificate expiration date verify FAILED\n");
01193 }
01194 else {
01195 if(certclock < time(NULL)) {
01196 if(SSL_CONN_CONFIG(verifypeer)) {
01197 failf(data, "server certificate expiration date has passed.");
01198 gnutls_x509_crt_deinit(x509_cert);
01199 return CURLE_PEER_FAILED_VERIFICATION;
01200 }
01201 else
01202 infof(data, "\t server certificate expiration date FAILED\n");
01203 }
01204 else
01205 infof(data, "\t server certificate expiration date OK\n");
01206 }
01207
01208 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
01209
01210 if(certclock == (time_t)-1) {
01211 if(SSL_CONN_CONFIG(verifypeer)) {
01212 failf(data, "server cert activation date verify failed");
01213 gnutls_x509_crt_deinit(x509_cert);
01214 return CURLE_SSL_CONNECT_ERROR;
01215 }
01216 else
01217 infof(data, "\t server certificate activation date verify FAILED\n");
01218 }
01219 else {
01220 if(certclock > time(NULL)) {
01221 if(SSL_CONN_CONFIG(verifypeer)) {
01222 failf(data, "server certificate not activated yet.");
01223 gnutls_x509_crt_deinit(x509_cert);
01224 return CURLE_PEER_FAILED_VERIFICATION;
01225 }
01226 else
01227 infof(data, "\t server certificate activation date FAILED\n");
01228 }
01229 else
01230 infof(data, "\t server certificate activation date OK\n");
01231 }
01232
01233 ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
01234 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
01235 if(ptr) {
01236 result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
01237 if(result != CURLE_OK) {
01238 failf(data, "SSL: public key does not match pinned public key!");
01239 gnutls_x509_crt_deinit(x509_cert);
01240 return result;
01241 }
01242 }
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
01256 infof(data, "\t certificate public key: %s\n",
01257 gnutls_pk_algorithm_get_name(algo));
01258
01259
01260 infof(data, "\t certificate version: #%d\n",
01261 gnutls_x509_crt_get_version(x509_cert));
01262
01263
01264 size = sizeof(certbuf);
01265 gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
01266 infof(data, "\t subject: %s\n", certbuf);
01267
01268 certclock = gnutls_x509_crt_get_activation_time(x509_cert);
01269 showtime(data, "start date", certclock);
01270
01271 certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
01272 showtime(data, "expire date", certclock);
01273
01274 size = sizeof(certbuf);
01275 gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
01276 infof(data, "\t issuer: %s\n", certbuf);
01277
01278 gnutls_x509_crt_deinit(x509_cert);
01279
01280
01281 ptr = gnutls_compression_get_name(gnutls_compression_get(session));
01282
01283 infof(data, "\t compression: %s\n", ptr);
01284
01285 #ifdef HAS_ALPN
01286 if(conn->bits.tls_enable_alpn) {
01287 rc = gnutls_alpn_get_selected_protocol(session, &proto);
01288 if(rc == 0) {
01289 infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
01290 proto.data);
01291
01292 #ifdef USE_NGHTTP2
01293 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
01294 !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
01295 NGHTTP2_PROTO_VERSION_ID_LEN)) {
01296 conn->negnpn = CURL_HTTP_VERSION_2;
01297 }
01298 else
01299 #endif
01300 if(proto.size == ALPN_HTTP_1_1_LENGTH &&
01301 !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
01302 conn->negnpn = CURL_HTTP_VERSION_1_1;
01303 }
01304 }
01305 else
01306 infof(data, "ALPN, server did not agree to a protocol\n");
01307 }
01308 #endif
01309
01310 conn->ssl[sockindex].state = ssl_connection_complete;
01311 conn->recv[sockindex] = gtls_recv;
01312 conn->send[sockindex] = gtls_send;
01313
01314 if(data->set.general_ssl.sessionid) {
01315
01316
01317
01318
01319 bool incache;
01320 void *ssl_sessionid;
01321 void *connect_sessionid;
01322 size_t connect_idsize = 0;
01323
01324
01325 gnutls_session_get_data(session, NULL, &connect_idsize);
01326 connect_sessionid = malloc(connect_idsize);
01327
01328 if(connect_sessionid) {
01329
01330 gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
01331
01332 Curl_ssl_sessionid_lock(conn);
01333 incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL,
01334 sockindex));
01335 if(incache) {
01336
01337
01338 Curl_ssl_delsessionid(conn, ssl_sessionid);
01339 }
01340
01341
01342 result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize,
01343 sockindex);
01344 Curl_ssl_sessionid_unlock(conn);
01345 if(result) {
01346 free(connect_sessionid);
01347 result = CURLE_OUT_OF_MEMORY;
01348 }
01349 }
01350 else
01351 result = CURLE_OUT_OF_MEMORY;
01352 }
01353
01354 return result;
01355 }
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 static CURLcode
01368 gtls_connect_common(struct connectdata *conn,
01369 int sockindex,
01370 bool nonblocking,
01371 bool *done)
01372 {
01373 int rc;
01374 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
01375
01376
01377 if(ssl_connect_1==connssl->connecting_state) {
01378 rc = gtls_connect_step1(conn, sockindex);
01379 if(rc)
01380 return rc;
01381 }
01382
01383 rc = handshake(conn, sockindex, TRUE, nonblocking);
01384 if(rc)
01385
01386 return rc;
01387
01388
01389 if(ssl_connect_1==connssl->connecting_state) {
01390 rc = gtls_connect_step3(conn, sockindex);
01391 if(rc)
01392 return rc;
01393 }
01394
01395 *done = ssl_connect_1==connssl->connecting_state;
01396
01397 return CURLE_OK;
01398 }
01399
01400 CURLcode
01401 Curl_gtls_connect_nonblocking(struct connectdata *conn,
01402 int sockindex,
01403 bool *done)
01404 {
01405 return gtls_connect_common(conn, sockindex, TRUE, done);
01406 }
01407
01408 CURLcode
01409 Curl_gtls_connect(struct connectdata *conn,
01410 int sockindex)
01411
01412 {
01413 CURLcode result;
01414 bool done = FALSE;
01415
01416 result = gtls_connect_common(conn, sockindex, FALSE, &done);
01417 if(result)
01418 return result;
01419
01420 DEBUGASSERT(done);
01421
01422 return CURLE_OK;
01423 }
01424
01425 bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex)
01426 {
01427 bool res = FALSE;
01428 if(conn->ssl[connindex].session &&
01429 0 != gnutls_record_check_pending(conn->ssl[connindex].session))
01430 res = TRUE;
01431
01432 if(conn->proxy_ssl[connindex].session &&
01433 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session))
01434 res = TRUE;
01435
01436 return res;
01437 }
01438
01439 static ssize_t gtls_send(struct connectdata *conn,
01440 int sockindex,
01441 const void *mem,
01442 size_t len,
01443 CURLcode *curlcode)
01444 {
01445 ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
01446
01447 if(rc < 0) {
01448 *curlcode = (rc == GNUTLS_E_AGAIN)
01449 ? CURLE_AGAIN
01450 : CURLE_SEND_ERROR;
01451
01452 rc = -1;
01453 }
01454
01455 return rc;
01456 }
01457
01458 static void close_one(struct ssl_connect_data *ssl)
01459 {
01460 if(ssl->session) {
01461 gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
01462 gnutls_deinit(ssl->session);
01463 ssl->session = NULL;
01464 }
01465 if(ssl->cred) {
01466 gnutls_certificate_free_credentials(ssl->cred);
01467 ssl->cred = NULL;
01468 }
01469 #ifdef USE_TLS_SRP
01470 if(ssl->srp_client_cred) {
01471 gnutls_srp_free_client_credentials(ssl->srp_client_cred);
01472 ssl->srp_client_cred = NULL;
01473 }
01474 #endif
01475 }
01476
01477 void Curl_gtls_close(struct connectdata *conn, int sockindex)
01478 {
01479 close_one(&conn->ssl[sockindex]);
01480 close_one(&conn->proxy_ssl[sockindex]);
01481 }
01482
01483
01484
01485
01486
01487 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
01488 {
01489 ssize_t result;
01490 int retval = 0;
01491 struct Curl_easy *data = conn->data;
01492 int done = 0;
01493 char buf[120];
01494
01495
01496
01497
01498
01499
01500 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
01501 gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
01502
01503 if(conn->ssl[sockindex].session) {
01504 while(!done) {
01505 int what = SOCKET_READABLE(conn->sock[sockindex],
01506 SSL_SHUTDOWN_TIMEOUT);
01507 if(what > 0) {
01508
01509
01510 result = gnutls_record_recv(conn->ssl[sockindex].session,
01511 buf, sizeof(buf));
01512 switch(result) {
01513 case 0:
01514
01515
01516 done = 1;
01517 break;
01518 case GNUTLS_E_AGAIN:
01519 case GNUTLS_E_INTERRUPTED:
01520 infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
01521 break;
01522 default:
01523 retval = -1;
01524 done = 1;
01525 break;
01526 }
01527 }
01528 else if(0 == what) {
01529
01530 failf(data, "SSL shutdown timeout");
01531 done = 1;
01532 break;
01533 }
01534 else {
01535
01536 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
01537 retval = -1;
01538 done = 1;
01539 }
01540 }
01541 gnutls_deinit(conn->ssl[sockindex].session);
01542 }
01543 gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
01544
01545 #ifdef USE_TLS_SRP
01546 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
01547 && SSL_SET_OPTION(username) != NULL)
01548 gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
01549 #endif
01550
01551 conn->ssl[sockindex].cred = NULL;
01552 conn->ssl[sockindex].session = NULL;
01553
01554 return retval;
01555 }
01556
01557 static ssize_t gtls_recv(struct connectdata *conn,
01558 int num,
01559 char *buf,
01560 size_t buffersize,
01561 CURLcode *curlcode)
01562 {
01563 ssize_t ret;
01564
01565 ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
01566 if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
01567 *curlcode = CURLE_AGAIN;
01568 return -1;
01569 }
01570
01571 if(ret == GNUTLS_E_REHANDSHAKE) {
01572
01573
01574 CURLcode result = handshake(conn, num, FALSE, FALSE);
01575 if(result)
01576
01577 *curlcode = result;
01578 else
01579 *curlcode = CURLE_AGAIN;
01580 return -1;
01581 }
01582
01583 if(ret < 0) {
01584 failf(conn->data, "GnuTLS recv error (%d): %s",
01585 (int)ret, gnutls_strerror((int)ret));
01586 *curlcode = CURLE_RECV_ERROR;
01587 return -1;
01588 }
01589
01590 return ret;
01591 }
01592
01593 void Curl_gtls_session_free(void *ptr)
01594 {
01595 free(ptr);
01596 }
01597
01598 size_t Curl_gtls_version(char *buffer, size_t size)
01599 {
01600 return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
01601 }
01602
01603 #ifndef USE_GNUTLS_NETTLE
01604 static int Curl_gtls_seed(struct Curl_easy *data)
01605 {
01606
01607
01608 static bool ssl_seeded = FALSE;
01609
01610
01611 gcry_fast_random_poll();
01612
01613 if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
01614 data->set.str[STRING_SSL_EGDSOCKET]) {
01615
01616
01617
01618
01619
01620
01621 ssl_seeded = TRUE;
01622 }
01623 return 0;
01624 }
01625 #endif
01626
01627
01628 int Curl_gtls_random(struct Curl_easy *data,
01629 unsigned char *entropy,
01630 size_t length)
01631 {
01632 #if defined(USE_GNUTLS_NETTLE)
01633 (void)data;
01634 gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
01635 #elif defined(USE_GNUTLS)
01636 if(data)
01637 Curl_gtls_seed(data);
01638 gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
01639 #endif
01640 return 0;
01641 }
01642
01643 void Curl_gtls_md5sum(unsigned char *tmp,
01644 size_t tmplen,
01645 unsigned char *md5sum,
01646 size_t md5len)
01647 {
01648 #if defined(USE_GNUTLS_NETTLE)
01649 struct md5_ctx MD5pw;
01650 md5_init(&MD5pw);
01651 md5_update(&MD5pw, (unsigned int)tmplen, tmp);
01652 md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
01653 #elif defined(USE_GNUTLS)
01654 gcry_md_hd_t MD5pw;
01655 gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
01656 gcry_md_write(MD5pw, tmp, tmplen);
01657 memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
01658 gcry_md_close(MD5pw);
01659 #endif
01660 }
01661
01662 void Curl_gtls_sha256sum(const unsigned char *tmp,
01663 size_t tmplen,
01664 unsigned char *sha256sum,
01665 size_t sha256len)
01666 {
01667 #if defined(USE_GNUTLS_NETTLE)
01668 struct sha256_ctx SHA256pw;
01669 sha256_init(&SHA256pw);
01670 sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
01671 sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
01672 #elif defined(USE_GNUTLS)
01673 gcry_md_hd_t SHA256pw;
01674 gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
01675 gcry_md_write(SHA256pw, tmp, tmplen);
01676 memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
01677 gcry_md_close(SHA256pw);
01678 #endif
01679 }
01680
01681 bool Curl_gtls_cert_status_request(void)
01682 {
01683 #ifdef HAS_OCSP
01684 return TRUE;
01685 #else
01686 return FALSE;
01687 #endif
01688 }
01689
01690 #endif