Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/vtls/gtls.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /*************************************************************************** | |
| 2 * _ _ ____ _ | |
| 3 * Project ___| | | | _ \| | | |
| 4 * / __| | | | |_) | | | |
| 5 * | (__| |_| | _ <| |___ | |
| 6 * \___|\___/|_| \_\_____| | |
| 7 * | |
| 8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. | |
| 9 * | |
| 10 * This software is licensed as described in the file COPYING, which | |
| 11 * you should have received as part of this distribution. The terms | |
| 12 * are also available at https://curl.haxx.se/docs/copyright.html. | |
| 13 * | |
| 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell | |
| 15 * copies of the Software, and permit persons to whom the Software is | |
| 16 * furnished to do so, under the terms of the COPYING file. | |
| 17 * | |
| 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | |
| 19 * KIND, either express or implied. | |
| 20 * | |
| 21 ***************************************************************************/ | |
| 22 | |
| 23 /* | |
| 24 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code | |
| 25 * but vtls.c should ever call or use these functions. | |
| 26 * | |
| 27 * Note: don't use the GnuTLS' *_t variable type names in this source code, | |
| 28 * since they were not present in 1.0.X. | |
| 29 */ | |
| 30 | |
| 31 #include "curl_setup.h" | |
| 32 | |
| 33 #ifdef USE_GNUTLS | |
| 34 | |
| 35 #include <gnutls/abstract.h> | |
| 36 #include <gnutls/gnutls.h> | |
| 37 #include <gnutls/x509.h> | |
| 38 | |
| 39 #ifdef USE_GNUTLS_NETTLE | |
| 40 #include <gnutls/crypto.h> | |
| 41 #include <nettle/md5.h> | |
| 42 #include <nettle/sha2.h> | |
| 43 #else | |
| 44 #include <gcrypt.h> | |
| 45 #endif | |
| 46 | |
| 47 #include "urldata.h" | |
| 48 #include "sendf.h" | |
| 49 #include "inet_pton.h" | |
| 50 #include "gtls.h" | |
| 51 #include "vtls.h" | |
| 52 #include "parsedate.h" | |
| 53 #include "connect.h" /* for the connect timeout */ | |
| 54 #include "select.h" | |
| 55 #include "strcase.h" | |
| 56 #include "warnless.h" | |
| 57 #include "x509asn1.h" | |
| 58 #include "multiif.h" | |
| 59 #include "curl_printf.h" | |
| 60 #include "curl_memory.h" | |
| 61 /* The last #include file should be: */ | |
| 62 #include "memdebug.h" | |
| 63 | |
| 64 /* Enable GnuTLS debugging by defining GTLSDEBUG */ | |
| 65 /*#define GTLSDEBUG */ | |
| 66 | |
| 67 #ifdef GTLSDEBUG | |
| 68 static void tls_log_func(int level, const char *str) | |
| 69 { | |
| 70 fprintf(stderr, "|<%d>| %s", level, str); | |
| 71 } | |
| 72 #endif | |
| 73 static bool gtls_inited = FALSE; | |
| 74 | |
| 75 #if defined(GNUTLS_VERSION_NUMBER) | |
| 76 # if (GNUTLS_VERSION_NUMBER >= 0x020c00) | |
| 77 # undef gnutls_transport_set_lowat | |
| 78 # define gnutls_transport_set_lowat(A,B) Curl_nop_stmt | |
| 79 # define USE_GNUTLS_PRIORITY_SET_DIRECT 1 | |
| 80 # endif | |
| 81 # if (GNUTLS_VERSION_NUMBER >= 0x020c03) | |
| 82 # define GNUTLS_MAPS_WINSOCK_ERRORS 1 | |
| 83 # endif | |
| 84 | |
| 85 # if HAVE_GNUTLS_ALPN_SET_PROTOCOLS | |
| 86 # define HAS_ALPN | |
| 87 # endif | |
| 88 | |
| 89 # if HAVE_GNUTLS_OCSP_REQ_INIT | |
| 90 # define HAS_OCSP | |
| 91 # endif | |
| 92 | |
| 93 # if (GNUTLS_VERSION_NUMBER >= 0x030306) | |
| 94 # define HAS_CAPATH | |
| 95 # endif | |
| 96 #endif | |
| 97 | |
| 98 #if (GNUTLS_VERSION_NUMBER >= 0x030603) | |
| 99 #define HAS_TLS13 | |
| 100 #endif | |
| 101 | |
| 102 #ifdef HAS_OCSP | |
| 103 # include <gnutls/ocsp.h> | |
| 104 #endif | |
| 105 | |
| 106 struct ssl_backend_data { | |
| 107 gnutls_session_t session; | |
| 108 gnutls_certificate_credentials_t cred; | |
| 109 #ifdef USE_TLS_SRP | |
| 110 gnutls_srp_client_credentials_t srp_client_cred; | |
| 111 #endif | |
| 112 }; | |
| 113 | |
| 114 #define BACKEND connssl->backend | |
| 115 | |
| 116 /* | |
| 117 * Custom push and pull callback functions used by GNU TLS to read and write | |
| 118 * to the socket. These functions are simple wrappers to send() and recv() | |
| 119 * (although here using the sread/swrite macros as defined by | |
| 120 * curl_setup_once.h). | |
| 121 * We use custom functions rather than the GNU TLS defaults because it allows | |
| 122 * us to get specific about the fourth "flags" argument, and to use arbitrary | |
| 123 * private data with gnutls_transport_set_ptr if we wish. | |
| 124 * | |
| 125 * When these custom push and pull callbacks fail, GNU TLS checks its own | |
| 126 * session-specific error variable, and when not set also its own global | |
| 127 * errno variable, in order to take appropriate action. GNU TLS does not | |
| 128 * require that the transport is actually a socket. This implies that for | |
| 129 * Windows builds these callbacks should ideally set the session-specific | |
| 130 * error variable using function gnutls_transport_set_errno or as a last | |
| 131 * resort global errno variable using gnutls_transport_set_global_errno, | |
| 132 * with a transport agnostic error value. This implies that some winsock | |
| 133 * error translation must take place in these callbacks. | |
| 134 * | |
| 135 * Paragraph above applies to GNU TLS versions older than 2.12.3, since | |
| 136 * this version GNU TLS does its own internal winsock error translation | |
| 137 * using system_errno() function. | |
| 138 */ | |
| 139 | |
| 140 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) | |
| 141 # define gtls_EINTR 4 | |
| 142 # define gtls_EIO 5 | |
| 143 # define gtls_EAGAIN 11 | |
| 144 static int gtls_mapped_sockerrno(void) | |
| 145 { | |
| 146 switch(SOCKERRNO) { | |
| 147 case WSAEWOULDBLOCK: | |
| 148 return gtls_EAGAIN; | |
| 149 case WSAEINTR: | |
| 150 return gtls_EINTR; | |
| 151 default: | |
| 152 break; | |
| 153 } | |
| 154 return gtls_EIO; | |
| 155 } | |
| 156 #endif | |
| 157 | |
| 158 static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len) | |
| 159 { | |
| 160 curl_socket_t sock = *(curl_socket_t *)s; | |
| 161 ssize_t ret = swrite(sock, buf, len); | |
| 162 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) | |
| 163 if(ret < 0) | |
| 164 gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); | |
| 165 #endif | |
| 166 return ret; | |
| 167 } | |
| 168 | |
| 169 static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) | |
| 170 { | |
| 171 curl_socket_t sock = *(curl_socket_t *)s; | |
| 172 ssize_t ret = sread(sock, buf, len); | |
| 173 #if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS) | |
| 174 if(ret < 0) | |
| 175 gnutls_transport_set_global_errno(gtls_mapped_sockerrno()); | |
| 176 #endif | |
| 177 return ret; | |
| 178 } | |
| 179 | |
| 180 static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len) | |
| 181 { | |
| 182 return gnutls_record_send((gnutls_session_t) s, buf, len); | |
| 183 } | |
| 184 | |
| 185 static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len) | |
| 186 { | |
| 187 return gnutls_record_recv((gnutls_session_t) s, buf, len); | |
| 188 } | |
| 189 | |
| 190 /* Curl_gtls_init() | |
| 191 * | |
| 192 * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that | |
| 193 * are not thread-safe and thus this function itself is not thread-safe and | |
| 194 * must only be called from within curl_global_init() to keep the thread | |
| 195 * situation under control! | |
| 196 */ | |
| 197 static int Curl_gtls_init(void) | |
| 198 { | |
| 199 int ret = 1; | |
| 200 if(!gtls_inited) { | |
| 201 ret = gnutls_global_init()?0:1; | |
| 202 #ifdef GTLSDEBUG | |
| 203 gnutls_global_set_log_function(tls_log_func); | |
| 204 gnutls_global_set_log_level(2); | |
| 205 #endif | |
| 206 gtls_inited = TRUE; | |
| 207 } | |
| 208 return ret; | |
| 209 } | |
| 210 | |
| 211 static void Curl_gtls_cleanup(void) | |
| 212 { | |
| 213 if(gtls_inited) { | |
| 214 gnutls_global_deinit(); | |
| 215 gtls_inited = FALSE; | |
| 216 } | |
| 217 } | |
| 218 | |
| 219 #ifndef CURL_DISABLE_VERBOSE_STRINGS | |
| 220 static void showtime(struct Curl_easy *data, | |
| 221 const char *text, | |
| 222 time_t stamp) | |
| 223 { | |
| 224 struct tm buffer; | |
| 225 const struct tm *tm = &buffer; | |
| 226 char str[96]; | |
| 227 CURLcode result = Curl_gmtime(stamp, &buffer); | |
| 228 if(result) | |
| 229 return; | |
| 230 | |
| 231 msnprintf(str, | |
| 232 sizeof(str), | |
| 233 "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", | |
| 234 text, | |
| 235 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], | |
| 236 tm->tm_mday, | |
| 237 Curl_month[tm->tm_mon], | |
| 238 tm->tm_year + 1900, | |
| 239 tm->tm_hour, | |
| 240 tm->tm_min, | |
| 241 tm->tm_sec); | |
| 242 infof(data, "%s\n", str); | |
| 243 } | |
| 244 #endif | |
| 245 | |
| 246 static gnutls_datum_t load_file(const char *file) | |
| 247 { | |
| 248 FILE *f; | |
| 249 gnutls_datum_t loaded_file = { NULL, 0 }; | |
| 250 long filelen; | |
| 251 void *ptr; | |
| 252 | |
| 253 f = fopen(file, "rb"); | |
| 254 if(!f) | |
| 255 return loaded_file; | |
| 256 if(fseek(f, 0, SEEK_END) != 0 | |
| 257 || (filelen = ftell(f)) < 0 | |
| 258 || fseek(f, 0, SEEK_SET) != 0 | |
| 259 || !(ptr = malloc((size_t)filelen))) | |
| 260 goto out; | |
| 261 if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) { | |
| 262 free(ptr); | |
| 263 goto out; | |
| 264 } | |
| 265 | |
| 266 loaded_file.data = ptr; | |
| 267 loaded_file.size = (unsigned int)filelen; | |
| 268 out: | |
| 269 fclose(f); | |
| 270 return loaded_file; | |
| 271 } | |
| 272 | |
| 273 static void unload_file(gnutls_datum_t data) | |
| 274 { | |
| 275 free(data.data); | |
| 276 } | |
| 277 | |
| 278 | |
| 279 /* this function does a SSL/TLS (re-)handshake */ | |
| 280 static CURLcode handshake(struct connectdata *conn, | |
| 281 int sockindex, | |
| 282 bool duringconnect, | |
| 283 bool nonblocking) | |
| 284 { | |
| 285 struct Curl_easy *data = conn->data; | |
| 286 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 287 gnutls_session_t session = BACKEND->session; | |
| 288 curl_socket_t sockfd = conn->sock[sockindex]; | |
| 289 | |
| 290 for(;;) { | |
| 291 time_t timeout_ms; | |
| 292 int rc; | |
| 293 | |
| 294 /* check allowed time left */ | |
| 295 timeout_ms = Curl_timeleft(data, NULL, duringconnect); | |
| 296 | |
| 297 if(timeout_ms < 0) { | |
| 298 /* no need to continue if time already is up */ | |
| 299 failf(data, "SSL connection timeout"); | |
| 300 return CURLE_OPERATION_TIMEDOUT; | |
| 301 } | |
| 302 | |
| 303 /* if ssl is expecting something, check if it's available. */ | |
| 304 if(connssl->connecting_state == ssl_connect_2_reading | |
| 305 || connssl->connecting_state == ssl_connect_2_writing) { | |
| 306 int what; | |
| 307 curl_socket_t writefd = ssl_connect_2_writing == | |
| 308 connssl->connecting_state?sockfd:CURL_SOCKET_BAD; | |
| 309 curl_socket_t readfd = ssl_connect_2_reading == | |
| 310 connssl->connecting_state?sockfd:CURL_SOCKET_BAD; | |
| 311 | |
| 312 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, | |
| 313 nonblocking?0: | |
| 314 timeout_ms?timeout_ms:1000); | |
| 315 if(what < 0) { | |
| 316 /* fatal error */ | |
| 317 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); | |
| 318 return CURLE_SSL_CONNECT_ERROR; | |
| 319 } | |
| 320 else if(0 == what) { | |
| 321 if(nonblocking) | |
| 322 return CURLE_OK; | |
| 323 else if(timeout_ms) { | |
| 324 /* timeout */ | |
| 325 failf(data, "SSL connection timeout at %ld", (long)timeout_ms); | |
| 326 return CURLE_OPERATION_TIMEDOUT; | |
| 327 } | |
| 328 } | |
| 329 /* socket is readable or writable */ | |
| 330 } | |
| 331 | |
| 332 rc = gnutls_handshake(session); | |
| 333 | |
| 334 if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { | |
| 335 connssl->connecting_state = | |
| 336 gnutls_record_get_direction(session)? | |
| 337 ssl_connect_2_writing:ssl_connect_2_reading; | |
| 338 continue; | |
| 339 } | |
| 340 else if((rc < 0) && !gnutls_error_is_fatal(rc)) { | |
| 341 const char *strerr = NULL; | |
| 342 | |
| 343 if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { | |
| 344 int alert = gnutls_alert_get(session); | |
| 345 strerr = gnutls_alert_get_name(alert); | |
| 346 } | |
| 347 | |
| 348 if(strerr == NULL) | |
| 349 strerr = gnutls_strerror(rc); | |
| 350 | |
| 351 infof(data, "gnutls_handshake() warning: %s\n", strerr); | |
| 352 continue; | |
| 353 } | |
| 354 else if(rc < 0) { | |
| 355 const char *strerr = NULL; | |
| 356 | |
| 357 if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { | |
| 358 int alert = gnutls_alert_get(session); | |
| 359 strerr = gnutls_alert_get_name(alert); | |
| 360 } | |
| 361 | |
| 362 if(strerr == NULL) | |
| 363 strerr = gnutls_strerror(rc); | |
| 364 | |
| 365 failf(data, "gnutls_handshake() failed: %s", strerr); | |
| 366 return CURLE_SSL_CONNECT_ERROR; | |
| 367 } | |
| 368 | |
| 369 /* Reset our connect state machine */ | |
| 370 connssl->connecting_state = ssl_connect_1; | |
| 371 return CURLE_OK; | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 static gnutls_x509_crt_fmt_t do_file_type(const char *type) | |
| 376 { | |
| 377 if(!type || !type[0]) | |
| 378 return GNUTLS_X509_FMT_PEM; | |
| 379 if(strcasecompare(type, "PEM")) | |
| 380 return GNUTLS_X509_FMT_PEM; | |
| 381 if(strcasecompare(type, "DER")) | |
| 382 return GNUTLS_X509_FMT_DER; | |
| 383 return -1; | |
| 384 } | |
| 385 | |
| 386 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT | |
| 387 static CURLcode | |
| 388 set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn) | |
| 389 { | |
| 390 struct Curl_easy *data = conn->data; | |
| 391 long ssl_version = SSL_CONN_CONFIG(version); | |
| 392 long ssl_version_max = SSL_CONN_CONFIG(version_max); | |
| 393 long i = ssl_version; | |
| 394 long protocol_priority_idx = 0; | |
| 395 | |
| 396 switch(ssl_version_max) { | |
| 397 case CURL_SSLVERSION_MAX_NONE: | |
| 398 case CURL_SSLVERSION_MAX_DEFAULT: | |
| 399 #ifdef HAS_TLS13 | |
| 400 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; | |
| 401 #endif | |
| 402 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; | |
| 403 break; | |
| 404 } | |
| 405 | |
| 406 for(; i <= (ssl_version_max >> 16) && | |
| 407 protocol_priority_idx < list_size; ++i) { | |
| 408 switch(i) { | |
| 409 case CURL_SSLVERSION_TLSv1_0: | |
| 410 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0; | |
| 411 break; | |
| 412 case CURL_SSLVERSION_TLSv1_1: | |
| 413 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1; | |
| 414 break; | |
| 415 case CURL_SSLVERSION_TLSv1_2: | |
| 416 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2; | |
| 417 break; | |
| 418 case CURL_SSLVERSION_TLSv1_3: | |
| 419 #ifdef HAS_TLS13 | |
| 420 protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_3; | |
| 421 break; | |
| 422 #else | |
| 423 failf(data, "GnuTLS: TLS 1.3 is not yet supported"); | |
| 424 return CURLE_SSL_CONNECT_ERROR; | |
| 425 #endif | |
| 426 } | |
| 427 } | |
| 428 return CURLE_OK; | |
| 429 } | |
| 430 #else | |
| 431 #define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" | |
| 432 /* If GnuTLS was compiled without support for SRP it will error out if SRP is | |
| 433 requested in the priority string, so treat it specially | |
| 434 */ | |
| 435 #define GNUTLS_SRP "+SRP" | |
| 436 | |
| 437 static CURLcode | |
| 438 set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn) | |
| 439 { | |
| 440 struct Curl_easy *data = conn->data; | |
| 441 long ssl_version = SSL_CONN_CONFIG(version); | |
| 442 long ssl_version_max = SSL_CONN_CONFIG(version_max); | |
| 443 | |
| 444 if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { | |
| 445 ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; | |
| 446 } | |
| 447 switch(ssl_version | ssl_version_max) { | |
| 448 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: | |
| 449 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 450 "+VERS-TLS1.0:" GNUTLS_SRP; | |
| 451 return CURLE_OK; | |
| 452 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: | |
| 453 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 454 "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; | |
| 455 return CURLE_OK; | |
| 456 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: | |
| 457 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 458 "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; | |
| 459 return CURLE_OK; | |
| 460 case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: | |
| 461 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 462 "+VERS-TLS1.1:" GNUTLS_SRP; | |
| 463 return CURLE_OK; | |
| 464 case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: | |
| 465 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 466 "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; | |
| 467 return CURLE_OK; | |
| 468 case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: | |
| 469 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 470 "+VERS-TLS1.2:" GNUTLS_SRP; | |
| 471 return CURLE_OK; | |
| 472 case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3: | |
| 473 #ifdef HAS_TLS13 | |
| 474 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 475 "+VERS-TLS1.3:" GNUTLS_SRP; | |
| 476 return CURLE_OK; | |
| 477 #else | |
| 478 failf(data, "GnuTLS: TLS 1.3 is not yet supported"); | |
| 479 return CURLE_SSL_CONNECT_ERROR; | |
| 480 #endif | |
| 481 case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: | |
| 482 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 483 "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" | |
| 484 #ifdef HAS_TLS13 | |
| 485 "+VERS-TLS1.3:" | |
| 486 #endif | |
| 487 GNUTLS_SRP; | |
| 488 return CURLE_OK; | |
| 489 case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: | |
| 490 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 491 "+VERS-TLS1.1:+VERS-TLS1.2:" | |
| 492 #ifdef HAS_TLS13 | |
| 493 "+VERS-TLS1.3:" | |
| 494 #endif | |
| 495 GNUTLS_SRP; | |
| 496 return CURLE_OK; | |
| 497 case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: | |
| 498 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 499 "+VERS-TLS1.2:" | |
| 500 #ifdef HAS_TLS13 | |
| 501 "+VERS-TLS1.3:" | |
| 502 #endif | |
| 503 GNUTLS_SRP; | |
| 504 return CURLE_OK; | |
| 505 case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: | |
| 506 *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" | |
| 507 "+VERS-TLS1.2:" | |
| 508 #ifdef HAS_TLS13 | |
| 509 "+VERS-TLS1.3:" | |
| 510 #endif | |
| 511 GNUTLS_SRP; | |
| 512 return CURLE_OK; | |
| 513 } | |
| 514 | |
| 515 failf(data, "GnuTLS: cannot set ssl protocol"); | |
| 516 return CURLE_SSL_CONNECT_ERROR; | |
| 517 } | |
| 518 #endif | |
| 519 | |
| 520 static CURLcode | |
| 521 gtls_connect_step1(struct connectdata *conn, | |
| 522 int sockindex) | |
| 523 { | |
| 524 struct Curl_easy *data = conn->data; | |
| 525 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 526 unsigned int init_flags; | |
| 527 gnutls_session_t session; | |
| 528 int rc; | |
| 529 bool sni = TRUE; /* default is SNI enabled */ | |
| 530 void *transport_ptr = NULL; | |
| 531 gnutls_push_func gnutls_transport_push = NULL; | |
| 532 gnutls_pull_func gnutls_transport_pull = NULL; | |
| 533 #ifdef ENABLE_IPV6 | |
| 534 struct in6_addr addr; | |
| 535 #else | |
| 536 struct in_addr addr; | |
| 537 #endif | |
| 538 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT | |
| 539 static const int cipher_priority[] = { | |
| 540 /* These two ciphers were added to GnuTLS as late as ver. 3.0.1, | |
| 541 but this code path is only ever used for ver. < 2.12.0. | |
| 542 GNUTLS_CIPHER_AES_128_GCM, | |
| 543 GNUTLS_CIPHER_AES_256_GCM, | |
| 544 */ | |
| 545 GNUTLS_CIPHER_AES_128_CBC, | |
| 546 GNUTLS_CIPHER_AES_256_CBC, | |
| 547 GNUTLS_CIPHER_CAMELLIA_128_CBC, | |
| 548 GNUTLS_CIPHER_CAMELLIA_256_CBC, | |
| 549 GNUTLS_CIPHER_3DES_CBC, | |
| 550 }; | |
| 551 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; | |
| 552 int protocol_priority[] = { 0, 0, 0, 0 }; | |
| 553 #else | |
| 554 const char *prioritylist; | |
| 555 const char *err = NULL; | |
| 556 #endif | |
| 557 | |
| 558 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : | |
| 559 conn->host.name; | |
| 560 | |
| 561 if(connssl->state == ssl_connection_complete) | |
| 562 /* to make us tolerant against being called more than once for the | |
| 563 same connection */ | |
| 564 return CURLE_OK; | |
| 565 | |
| 566 if(!gtls_inited) | |
| 567 Curl_gtls_init(); | |
| 568 | |
| 569 if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { | |
| 570 failf(data, "GnuTLS does not support SSLv2"); | |
| 571 return CURLE_SSL_CONNECT_ERROR; | |
| 572 } | |
| 573 else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) | |
| 574 sni = FALSE; /* SSLv3 has no SNI */ | |
| 575 | |
| 576 /* allocate a cred struct */ | |
| 577 rc = gnutls_certificate_allocate_credentials(&BACKEND->cred); | |
| 578 if(rc != GNUTLS_E_SUCCESS) { | |
| 579 failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc)); | |
| 580 return CURLE_SSL_CONNECT_ERROR; | |
| 581 } | |
| 582 | |
| 583 #ifdef USE_TLS_SRP | |
| 584 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { | |
| 585 infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); | |
| 586 | |
| 587 rc = gnutls_srp_allocate_client_credentials( | |
| 588 &BACKEND->srp_client_cred); | |
| 589 if(rc != GNUTLS_E_SUCCESS) { | |
| 590 failf(data, "gnutls_srp_allocate_client_cred() failed: %s", | |
| 591 gnutls_strerror(rc)); | |
| 592 return CURLE_OUT_OF_MEMORY; | |
| 593 } | |
| 594 | |
| 595 rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred, | |
| 596 SSL_SET_OPTION(username), | |
| 597 SSL_SET_OPTION(password)); | |
| 598 if(rc != GNUTLS_E_SUCCESS) { | |
| 599 failf(data, "gnutls_srp_set_client_cred() failed: %s", | |
| 600 gnutls_strerror(rc)); | |
| 601 return CURLE_BAD_FUNCTION_ARGUMENT; | |
| 602 } | |
| 603 } | |
| 604 #endif | |
| 605 | |
| 606 if(SSL_CONN_CONFIG(CAfile)) { | |
| 607 /* set the trusted CA cert bundle file */ | |
| 608 gnutls_certificate_set_verify_flags(BACKEND->cred, | |
| 609 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); | |
| 610 | |
| 611 rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred, | |
| 612 SSL_CONN_CONFIG(CAfile), | |
| 613 GNUTLS_X509_FMT_PEM); | |
| 614 if(rc < 0) { | |
| 615 infof(data, "error reading ca cert file %s (%s)\n", | |
| 616 SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); | |
| 617 if(SSL_CONN_CONFIG(verifypeer)) | |
| 618 return CURLE_SSL_CACERT_BADFILE; | |
| 619 } | |
| 620 else | |
| 621 infof(data, "found %d certificates in %s\n", rc, | |
| 622 SSL_CONN_CONFIG(CAfile)); | |
| 623 } | |
| 624 | |
| 625 #ifdef HAS_CAPATH | |
| 626 if(SSL_CONN_CONFIG(CApath)) { | |
| 627 /* set the trusted CA cert directory */ | |
| 628 rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred, | |
| 629 SSL_CONN_CONFIG(CApath), | |
| 630 GNUTLS_X509_FMT_PEM); | |
| 631 if(rc < 0) { | |
| 632 infof(data, "error reading ca cert file %s (%s)\n", | |
| 633 SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); | |
| 634 if(SSL_CONN_CONFIG(verifypeer)) | |
| 635 return CURLE_SSL_CACERT_BADFILE; | |
| 636 } | |
| 637 else | |
| 638 infof(data, "found %d certificates in %s\n", | |
| 639 rc, SSL_CONN_CONFIG(CApath)); | |
| 640 } | |
| 641 #endif | |
| 642 | |
| 643 #ifdef CURL_CA_FALLBACK | |
| 644 /* use system ca certificate store as fallback */ | |
| 645 if(SSL_CONN_CONFIG(verifypeer) && | |
| 646 !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { | |
| 647 gnutls_certificate_set_x509_system_trust(BACKEND->cred); | |
| 648 } | |
| 649 #endif | |
| 650 | |
| 651 if(SSL_SET_OPTION(CRLfile)) { | |
| 652 /* set the CRL list file */ | |
| 653 rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred, | |
| 654 SSL_SET_OPTION(CRLfile), | |
| 655 GNUTLS_X509_FMT_PEM); | |
| 656 if(rc < 0) { | |
| 657 failf(data, "error reading crl file %s (%s)", | |
| 658 SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); | |
| 659 return CURLE_SSL_CRL_BADFILE; | |
| 660 } | |
| 661 else | |
| 662 infof(data, "found %d CRL in %s\n", | |
| 663 rc, SSL_SET_OPTION(CRLfile)); | |
| 664 } | |
| 665 | |
| 666 /* Initialize TLS session as a client */ | |
| 667 init_flags = GNUTLS_CLIENT; | |
| 668 | |
| 669 #if defined(GNUTLS_NO_TICKETS) | |
| 670 /* Disable TLS session tickets */ | |
| 671 init_flags |= GNUTLS_NO_TICKETS; | |
| 672 #endif | |
| 673 | |
| 674 rc = gnutls_init(&BACKEND->session, init_flags); | |
| 675 if(rc != GNUTLS_E_SUCCESS) { | |
| 676 failf(data, "gnutls_init() failed: %d", rc); | |
| 677 return CURLE_SSL_CONNECT_ERROR; | |
| 678 } | |
| 679 | |
| 680 /* convenient assign */ | |
| 681 session = BACKEND->session; | |
| 682 | |
| 683 if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && | |
| 684 #ifdef ENABLE_IPV6 | |
| 685 (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && | |
| 686 #endif | |
| 687 sni && | |
| 688 (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, | |
| 689 strlen(hostname)) < 0)) | |
| 690 infof(data, "WARNING: failed to configure server name indication (SNI) " | |
| 691 "TLS extension\n"); | |
| 692 | |
| 693 /* Use default priorities */ | |
| 694 rc = gnutls_set_default_priority(session); | |
| 695 if(rc != GNUTLS_E_SUCCESS) | |
| 696 return CURLE_SSL_CONNECT_ERROR; | |
| 697 | |
| 698 #ifndef USE_GNUTLS_PRIORITY_SET_DIRECT | |
| 699 rc = gnutls_cipher_set_priority(session, cipher_priority); | |
| 700 if(rc != GNUTLS_E_SUCCESS) | |
| 701 return CURLE_SSL_CONNECT_ERROR; | |
| 702 | |
| 703 /* Sets the priority on the certificate types supported by gnutls. Priority | |
| 704 is higher for types specified before others. After specifying the types | |
| 705 you want, you must append a 0. */ | |
| 706 rc = gnutls_certificate_type_set_priority(session, cert_type_priority); | |
| 707 if(rc != GNUTLS_E_SUCCESS) | |
| 708 return CURLE_SSL_CONNECT_ERROR; | |
| 709 | |
| 710 if(SSL_CONN_CONFIG(cipher_list) != NULL) { | |
| 711 failf(data, "can't pass a custom cipher list to older GnuTLS" | |
| 712 " versions"); | |
| 713 return CURLE_SSL_CONNECT_ERROR; | |
| 714 } | |
| 715 | |
| 716 switch(SSL_CONN_CONFIG(version)) { | |
| 717 case CURL_SSLVERSION_SSLv3: | |
| 718 protocol_priority[0] = GNUTLS_SSL3; | |
| 719 break; | |
| 720 case CURL_SSLVERSION_DEFAULT: | |
| 721 case CURL_SSLVERSION_TLSv1: | |
| 722 protocol_priority[0] = GNUTLS_TLS1_0; | |
| 723 protocol_priority[1] = GNUTLS_TLS1_1; | |
| 724 protocol_priority[2] = GNUTLS_TLS1_2; | |
| 725 #ifdef HAS_TLS13 | |
| 726 protocol_priority[3] = GNUTLS_TLS1_3; | |
| 727 #endif | |
| 728 break; | |
| 729 case CURL_SSLVERSION_TLSv1_0: | |
| 730 case CURL_SSLVERSION_TLSv1_1: | |
| 731 case CURL_SSLVERSION_TLSv1_2: | |
| 732 case CURL_SSLVERSION_TLSv1_3: | |
| 733 { | |
| 734 CURLcode result = set_ssl_version_min_max(protocol_priority, | |
| 735 sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn); | |
| 736 if(result != CURLE_OK) | |
| 737 return result; | |
| 738 break; | |
| 739 } | |
| 740 case CURL_SSLVERSION_SSLv2: | |
| 741 failf(data, "GnuTLS does not support SSLv2"); | |
| 742 return CURLE_SSL_CONNECT_ERROR; | |
| 743 default: | |
| 744 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); | |
| 745 return CURLE_SSL_CONNECT_ERROR; | |
| 746 } | |
| 747 rc = gnutls_protocol_set_priority(session, protocol_priority); | |
| 748 if(rc != GNUTLS_E_SUCCESS) { | |
| 749 failf(data, "Did you pass a valid GnuTLS cipher list?"); | |
| 750 return CURLE_SSL_CONNECT_ERROR; | |
| 751 } | |
| 752 | |
| 753 #else | |
| 754 /* Ensure +SRP comes at the *end* of all relevant strings so that it can be | |
| 755 * removed if a run-time error indicates that SRP is not supported by this | |
| 756 * GnuTLS version */ | |
| 757 switch(SSL_CONN_CONFIG(version)) { | |
| 758 case CURL_SSLVERSION_SSLv3: | |
| 759 prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; | |
| 760 break; | |
| 761 case CURL_SSLVERSION_DEFAULT: | |
| 762 case CURL_SSLVERSION_TLSv1: | |
| 763 prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" | |
| 764 #ifdef HAS_TLS13 | |
| 765 "+VERS-TLS1.3:" | |
| 766 #endif | |
| 767 GNUTLS_SRP; | |
| 768 break; | |
| 769 case CURL_SSLVERSION_TLSv1_0: | |
| 770 case CURL_SSLVERSION_TLSv1_1: | |
| 771 case CURL_SSLVERSION_TLSv1_2: | |
| 772 case CURL_SSLVERSION_TLSv1_3: | |
| 773 { | |
| 774 CURLcode result = set_ssl_version_min_max(&prioritylist, conn); | |
| 775 if(result != CURLE_OK) | |
| 776 return result; | |
| 777 break; | |
| 778 } | |
| 779 case CURL_SSLVERSION_SSLv2: | |
| 780 failf(data, "GnuTLS does not support SSLv2"); | |
| 781 return CURLE_SSL_CONNECT_ERROR; | |
| 782 default: | |
| 783 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); | |
| 784 return CURLE_SSL_CONNECT_ERROR; | |
| 785 } | |
| 786 rc = gnutls_priority_set_direct(session, prioritylist, &err); | |
| 787 if((rc == GNUTLS_E_INVALID_REQUEST) && err) { | |
| 788 if(!strcmp(err, GNUTLS_SRP)) { | |
| 789 /* This GnuTLS was probably compiled without support for SRP. | |
| 790 * Note that fact and try again without it. */ | |
| 791 int validprioritylen = curlx_uztosi(err - prioritylist); | |
| 792 char *prioritycopy = strdup(prioritylist); | |
| 793 if(!prioritycopy) | |
| 794 return CURLE_OUT_OF_MEMORY; | |
| 795 | |
| 796 infof(data, "This GnuTLS does not support SRP\n"); | |
| 797 if(validprioritylen) | |
| 798 /* Remove the :+SRP */ | |
| 799 prioritycopy[validprioritylen - 1] = 0; | |
| 800 rc = gnutls_priority_set_direct(session, prioritycopy, &err); | |
| 801 free(prioritycopy); | |
| 802 } | |
| 803 } | |
| 804 if(rc != GNUTLS_E_SUCCESS) { | |
| 805 failf(data, "Error %d setting GnuTLS cipher list starting with %s", | |
| 806 rc, err); | |
| 807 return CURLE_SSL_CONNECT_ERROR; | |
| 808 } | |
| 809 #endif | |
| 810 | |
| 811 #ifdef HAS_ALPN | |
| 812 if(conn->bits.tls_enable_alpn) { | |
| 813 int cur = 0; | |
| 814 gnutls_datum_t protocols[2]; | |
| 815 | |
| 816 #ifdef USE_NGHTTP2 | |
| 817 if(data->set.httpversion >= CURL_HTTP_VERSION_2 && | |
| 818 (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { | |
| 819 protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID; | |
| 820 protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN; | |
| 821 cur++; | |
| 822 infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); | |
| 823 } | |
| 824 #endif | |
| 825 | |
| 826 protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; | |
| 827 protocols[cur].size = ALPN_HTTP_1_1_LENGTH; | |
| 828 cur++; | |
| 829 infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); | |
| 830 | |
| 831 gnutls_alpn_set_protocols(session, protocols, cur, 0); | |
| 832 } | |
| 833 #endif | |
| 834 | |
| 835 if(SSL_SET_OPTION(cert)) { | |
| 836 if(SSL_SET_OPTION(key_passwd)) { | |
| 837 #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 | |
| 838 const unsigned int supported_key_encryption_algorithms = | |
| 839 GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | | |
| 840 GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES | | |
| 841 GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 | | |
| 842 GNUTLS_PKCS_USE_PBES2_AES_256; | |
| 843 rc = gnutls_certificate_set_x509_key_file2( | |
| 844 BACKEND->cred, | |
| 845 SSL_SET_OPTION(cert), | |
| 846 SSL_SET_OPTION(key) ? | |
| 847 SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), | |
| 848 do_file_type(SSL_SET_OPTION(cert_type)), | |
| 849 SSL_SET_OPTION(key_passwd), | |
| 850 supported_key_encryption_algorithms); | |
| 851 if(rc != GNUTLS_E_SUCCESS) { | |
| 852 failf(data, | |
| 853 "error reading X.509 potentially-encrypted key file: %s", | |
| 854 gnutls_strerror(rc)); | |
| 855 return CURLE_SSL_CONNECT_ERROR; | |
| 856 } | |
| 857 #else | |
| 858 failf(data, "gnutls lacks support for encrypted key files"); | |
| 859 return CURLE_SSL_CONNECT_ERROR; | |
| 860 #endif | |
| 861 } | |
| 862 else { | |
| 863 if(gnutls_certificate_set_x509_key_file( | |
| 864 BACKEND->cred, | |
| 865 SSL_SET_OPTION(cert), | |
| 866 SSL_SET_OPTION(key) ? | |
| 867 SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), | |
| 868 do_file_type(SSL_SET_OPTION(cert_type)) ) != | |
| 869 GNUTLS_E_SUCCESS) { | |
| 870 failf(data, "error reading X.509 key or certificate file"); | |
| 871 return CURLE_SSL_CONNECT_ERROR; | |
| 872 } | |
| 873 } | |
| 874 } | |
| 875 | |
| 876 #ifdef USE_TLS_SRP | |
| 877 /* put the credentials to the current session */ | |
| 878 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { | |
| 879 rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, | |
| 880 BACKEND->srp_client_cred); | |
| 881 if(rc != GNUTLS_E_SUCCESS) { | |
| 882 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); | |
| 883 return CURLE_SSL_CONNECT_ERROR; | |
| 884 } | |
| 885 } | |
| 886 else | |
| 887 #endif | |
| 888 { | |
| 889 rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, | |
| 890 BACKEND->cred); | |
| 891 if(rc != GNUTLS_E_SUCCESS) { | |
| 892 failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc)); | |
| 893 return CURLE_SSL_CONNECT_ERROR; | |
| 894 } | |
| 895 } | |
| 896 | |
| 897 if(conn->proxy_ssl[sockindex].use) { | |
| 898 transport_ptr = conn->proxy_ssl[sockindex].backend->session; | |
| 899 gnutls_transport_push = Curl_gtls_push_ssl; | |
| 900 gnutls_transport_pull = Curl_gtls_pull_ssl; | |
| 901 } | |
| 902 else { | |
| 903 /* file descriptor for the socket */ | |
| 904 transport_ptr = &conn->sock[sockindex]; | |
| 905 gnutls_transport_push = Curl_gtls_push; | |
| 906 gnutls_transport_pull = Curl_gtls_pull; | |
| 907 } | |
| 908 | |
| 909 /* set the connection handle */ | |
| 910 gnutls_transport_set_ptr(session, transport_ptr); | |
| 911 | |
| 912 /* register callback functions to send and receive data. */ | |
| 913 gnutls_transport_set_push_function(session, gnutls_transport_push); | |
| 914 gnutls_transport_set_pull_function(session, gnutls_transport_pull); | |
| 915 | |
| 916 /* lowat must be set to zero when using custom push and pull functions. */ | |
| 917 gnutls_transport_set_lowat(session, 0); | |
| 918 | |
| 919 #ifdef HAS_OCSP | |
| 920 if(SSL_CONN_CONFIG(verifystatus)) { | |
| 921 rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); | |
| 922 if(rc != GNUTLS_E_SUCCESS) { | |
| 923 failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); | |
| 924 return CURLE_SSL_CONNECT_ERROR; | |
| 925 } | |
| 926 } | |
| 927 #endif | |
| 928 | |
| 929 /* This might be a reconnect, so we check for a session ID in the cache | |
| 930 to speed up things */ | |
| 931 if(SSL_SET_OPTION(primary.sessionid)) { | |
| 932 void *ssl_sessionid; | |
| 933 size_t ssl_idsize; | |
| 934 | |
| 935 Curl_ssl_sessionid_lock(conn); | |
| 936 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { | |
| 937 /* we got a session id, use it! */ | |
| 938 gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); | |
| 939 | |
| 940 /* Informational message */ | |
| 941 infof(data, "SSL re-using session ID\n"); | |
| 942 } | |
| 943 Curl_ssl_sessionid_unlock(conn); | |
| 944 } | |
| 945 | |
| 946 return CURLE_OK; | |
| 947 } | |
| 948 | |
| 949 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, | |
| 950 gnutls_x509_crt_t cert, | |
| 951 const char *pinnedpubkey) | |
| 952 { | |
| 953 /* Scratch */ | |
| 954 size_t len1 = 0, len2 = 0; | |
| 955 unsigned char *buff1 = NULL; | |
| 956 | |
| 957 gnutls_pubkey_t key = NULL; | |
| 958 | |
| 959 /* Result is returned to caller */ | |
| 960 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; | |
| 961 | |
| 962 /* if a path wasn't specified, don't pin */ | |
| 963 if(NULL == pinnedpubkey) | |
| 964 return CURLE_OK; | |
| 965 | |
| 966 if(NULL == cert) | |
| 967 return result; | |
| 968 | |
| 969 do { | |
| 970 int ret; | |
| 971 | |
| 972 /* Begin Gyrations to get the public key */ | |
| 973 gnutls_pubkey_init(&key); | |
| 974 | |
| 975 ret = gnutls_pubkey_import_x509(key, cert, 0); | |
| 976 if(ret < 0) | |
| 977 break; /* failed */ | |
| 978 | |
| 979 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1); | |
| 980 if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0) | |
| 981 break; /* failed */ | |
| 982 | |
| 983 buff1 = malloc(len1); | |
| 984 if(NULL == buff1) | |
| 985 break; /* failed */ | |
| 986 | |
| 987 len2 = len1; | |
| 988 | |
| 989 ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2); | |
| 990 if(ret < 0 || len1 != len2) | |
| 991 break; /* failed */ | |
| 992 | |
| 993 /* End Gyrations */ | |
| 994 | |
| 995 /* The one good exit point */ | |
| 996 result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); | |
| 997 } while(0); | |
| 998 | |
| 999 if(NULL != key) | |
| 1000 gnutls_pubkey_deinit(key); | |
| 1001 | |
| 1002 Curl_safefree(buff1); | |
| 1003 | |
| 1004 return result; | |
| 1005 } | |
| 1006 | |
| 1007 static Curl_recv gtls_recv; | |
| 1008 static Curl_send gtls_send; | |
| 1009 | |
| 1010 static CURLcode | |
| 1011 gtls_connect_step3(struct connectdata *conn, | |
| 1012 int sockindex) | |
| 1013 { | |
| 1014 unsigned int cert_list_size; | |
| 1015 const gnutls_datum_t *chainp; | |
| 1016 unsigned int verify_status = 0; | |
| 1017 gnutls_x509_crt_t x509_cert, x509_issuer; | |
| 1018 gnutls_datum_t issuerp; | |
| 1019 char certbuf[256] = ""; /* big enough? */ | |
| 1020 size_t size; | |
| 1021 time_t certclock; | |
| 1022 const char *ptr; | |
| 1023 struct Curl_easy *data = conn->data; | |
| 1024 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1025 gnutls_session_t session = BACKEND->session; | |
| 1026 int rc; | |
| 1027 #ifdef HAS_ALPN | |
| 1028 gnutls_datum_t proto; | |
| 1029 #endif | |
| 1030 CURLcode result = CURLE_OK; | |
| 1031 #ifndef CURL_DISABLE_VERBOSE_STRINGS | |
| 1032 unsigned int algo; | |
| 1033 unsigned int bits; | |
| 1034 gnutls_protocol_t version = gnutls_protocol_get_version(session); | |
| 1035 #endif | |
| 1036 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : | |
| 1037 conn->host.name; | |
| 1038 | |
| 1039 /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ | |
| 1040 ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), | |
| 1041 gnutls_cipher_get(session), | |
| 1042 gnutls_mac_get(session)); | |
| 1043 | |
| 1044 infof(data, "SSL connection using %s / %s\n", | |
| 1045 gnutls_protocol_get_name(version), ptr); | |
| 1046 | |
| 1047 /* This function will return the peer's raw certificate (chain) as sent by | |
| 1048 the peer. These certificates are in raw format (DER encoded for | |
| 1049 X.509). In case of a X.509 then a certificate list may be present. The | |
| 1050 first certificate in the list is the peer's certificate, following the | |
| 1051 issuer's certificate, then the issuer's issuer etc. */ | |
| 1052 | |
| 1053 chainp = gnutls_certificate_get_peers(session, &cert_list_size); | |
| 1054 if(!chainp) { | |
| 1055 if(SSL_CONN_CONFIG(verifypeer) || | |
| 1056 SSL_CONN_CONFIG(verifyhost) || | |
| 1057 SSL_SET_OPTION(issuercert)) { | |
| 1058 #ifdef USE_TLS_SRP | |
| 1059 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP | |
| 1060 && SSL_SET_OPTION(username) != NULL | |
| 1061 && !SSL_CONN_CONFIG(verifypeer) | |
| 1062 && gnutls_cipher_get(session)) { | |
| 1063 /* no peer cert, but auth is ok if we have SRP user and cipher and no | |
| 1064 peer verify */ | |
| 1065 } | |
| 1066 else { | |
| 1067 #endif | |
| 1068 failf(data, "failed to get server cert"); | |
| 1069 return CURLE_PEER_FAILED_VERIFICATION; | |
| 1070 #ifdef USE_TLS_SRP | |
| 1071 } | |
| 1072 #endif | |
| 1073 } | |
| 1074 infof(data, "\t common name: WARNING couldn't obtain\n"); | |
| 1075 } | |
| 1076 | |
| 1077 if(data->set.ssl.certinfo && chainp) { | |
| 1078 unsigned int i; | |
| 1079 | |
| 1080 result = Curl_ssl_init_certinfo(data, cert_list_size); | |
| 1081 if(result) | |
| 1082 return result; | |
| 1083 | |
| 1084 for(i = 0; i < cert_list_size; i++) { | |
| 1085 const char *beg = (const char *) chainp[i].data; | |
| 1086 const char *end = beg + chainp[i].size; | |
| 1087 | |
| 1088 result = Curl_extract_certinfo(conn, i, beg, end); | |
| 1089 if(result) | |
| 1090 return result; | |
| 1091 } | |
| 1092 } | |
| 1093 | |
| 1094 if(SSL_CONN_CONFIG(verifypeer)) { | |
| 1095 /* This function will try to verify the peer's certificate and return its | |
| 1096 status (trusted, invalid etc.). The value of status should be one or | |
| 1097 more of the gnutls_certificate_status_t enumerated elements bitwise | |
| 1098 or'd. To avoid denial of service attacks some default upper limits | |
| 1099 regarding the certificate key size and chain size are set. To override | |
| 1100 them use gnutls_certificate_set_verify_limits(). */ | |
| 1101 | |
| 1102 rc = gnutls_certificate_verify_peers2(session, &verify_status); | |
| 1103 if(rc < 0) { | |
| 1104 failf(data, "server cert verify failed: %d", rc); | |
| 1105 return CURLE_SSL_CONNECT_ERROR; | |
| 1106 } | |
| 1107 | |
| 1108 /* verify_status is a bitmask of gnutls_certificate_status bits */ | |
| 1109 if(verify_status & GNUTLS_CERT_INVALID) { | |
| 1110 if(SSL_CONN_CONFIG(verifypeer)) { | |
| 1111 failf(data, "server certificate verification failed. CAfile: %s " | |
| 1112 "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): | |
| 1113 "none", | |
| 1114 SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); | |
| 1115 return CURLE_PEER_FAILED_VERIFICATION; | |
| 1116 } | |
| 1117 else | |
| 1118 infof(data, "\t server certificate verification FAILED\n"); | |
| 1119 } | |
| 1120 else | |
| 1121 infof(data, "\t server certificate verification OK\n"); | |
| 1122 } | |
| 1123 else | |
| 1124 infof(data, "\t server certificate verification SKIPPED\n"); | |
| 1125 | |
| 1126 #ifdef HAS_OCSP | |
| 1127 if(SSL_CONN_CONFIG(verifystatus)) { | |
| 1128 if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { | |
| 1129 gnutls_datum_t status_request; | |
| 1130 gnutls_ocsp_resp_t ocsp_resp; | |
| 1131 | |
| 1132 gnutls_ocsp_cert_status_t status; | |
| 1133 gnutls_x509_crl_reason_t reason; | |
| 1134 | |
| 1135 rc = gnutls_ocsp_status_request_get(session, &status_request); | |
| 1136 | |
| 1137 infof(data, "\t server certificate status verification FAILED\n"); | |
| 1138 | |
| 1139 if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { | |
| 1140 failf(data, "No OCSP response received"); | |
| 1141 return CURLE_SSL_INVALIDCERTSTATUS; | |
| 1142 } | |
| 1143 | |
| 1144 if(rc < 0) { | |
| 1145 failf(data, "Invalid OCSP response received"); | |
| 1146 return CURLE_SSL_INVALIDCERTSTATUS; | |
| 1147 } | |
| 1148 | |
| 1149 gnutls_ocsp_resp_init(&ocsp_resp); | |
| 1150 | |
| 1151 rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); | |
| 1152 if(rc < 0) { | |
| 1153 failf(data, "Invalid OCSP response received"); | |
| 1154 return CURLE_SSL_INVALIDCERTSTATUS; | |
| 1155 } | |
| 1156 | |
| 1157 (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, | |
| 1158 &status, NULL, NULL, NULL, &reason); | |
| 1159 | |
| 1160 switch(status) { | |
| 1161 case GNUTLS_OCSP_CERT_GOOD: | |
| 1162 break; | |
| 1163 | |
| 1164 case GNUTLS_OCSP_CERT_REVOKED: { | |
| 1165 const char *crl_reason; | |
| 1166 | |
| 1167 switch(reason) { | |
| 1168 default: | |
| 1169 case GNUTLS_X509_CRLREASON_UNSPECIFIED: | |
| 1170 crl_reason = "unspecified reason"; | |
| 1171 break; | |
| 1172 | |
| 1173 case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: | |
| 1174 crl_reason = "private key compromised"; | |
| 1175 break; | |
| 1176 | |
| 1177 case GNUTLS_X509_CRLREASON_CACOMPROMISE: | |
| 1178 crl_reason = "CA compromised"; | |
| 1179 break; | |
| 1180 | |
| 1181 case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: | |
| 1182 crl_reason = "affiliation has changed"; | |
| 1183 break; | |
| 1184 | |
| 1185 case GNUTLS_X509_CRLREASON_SUPERSEDED: | |
| 1186 crl_reason = "certificate superseded"; | |
| 1187 break; | |
| 1188 | |
| 1189 case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: | |
| 1190 crl_reason = "operation has ceased"; | |
| 1191 break; | |
| 1192 | |
| 1193 case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: | |
| 1194 crl_reason = "certificate is on hold"; | |
| 1195 break; | |
| 1196 | |
| 1197 case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: | |
| 1198 crl_reason = "will be removed from delta CRL"; | |
| 1199 break; | |
| 1200 | |
| 1201 case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: | |
| 1202 crl_reason = "privilege withdrawn"; | |
| 1203 break; | |
| 1204 | |
| 1205 case GNUTLS_X509_CRLREASON_AACOMPROMISE: | |
| 1206 crl_reason = "AA compromised"; | |
| 1207 break; | |
| 1208 } | |
| 1209 | |
| 1210 failf(data, "Server certificate was revoked: %s", crl_reason); | |
| 1211 break; | |
| 1212 } | |
| 1213 | |
| 1214 default: | |
| 1215 case GNUTLS_OCSP_CERT_UNKNOWN: | |
| 1216 failf(data, "Server certificate status is unknown"); | |
| 1217 break; | |
| 1218 } | |
| 1219 | |
| 1220 gnutls_ocsp_resp_deinit(ocsp_resp); | |
| 1221 | |
| 1222 return CURLE_SSL_INVALIDCERTSTATUS; | |
| 1223 } | |
| 1224 else | |
| 1225 infof(data, "\t server certificate status verification OK\n"); | |
| 1226 } | |
| 1227 else | |
| 1228 infof(data, "\t server certificate status verification SKIPPED\n"); | |
| 1229 #endif | |
| 1230 | |
| 1231 /* initialize an X.509 certificate structure. */ | |
| 1232 gnutls_x509_crt_init(&x509_cert); | |
| 1233 | |
| 1234 if(chainp) | |
| 1235 /* convert the given DER or PEM encoded Certificate to the native | |
| 1236 gnutls_x509_crt_t format */ | |
| 1237 gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); | |
| 1238 | |
| 1239 if(SSL_SET_OPTION(issuercert)) { | |
| 1240 gnutls_x509_crt_init(&x509_issuer); | |
| 1241 issuerp = load_file(SSL_SET_OPTION(issuercert)); | |
| 1242 gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); | |
| 1243 rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); | |
| 1244 gnutls_x509_crt_deinit(x509_issuer); | |
| 1245 unload_file(issuerp); | |
| 1246 if(rc <= 0) { | |
| 1247 failf(data, "server certificate issuer check failed (IssuerCert: %s)", | |
| 1248 SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); | |
| 1249 gnutls_x509_crt_deinit(x509_cert); | |
| 1250 return CURLE_SSL_ISSUER_ERROR; | |
| 1251 } | |
| 1252 infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", | |
| 1253 SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); | |
| 1254 } | |
| 1255 | |
| 1256 size = sizeof(certbuf); | |
| 1257 rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, | |
| 1258 0, /* the first and only one */ | |
| 1259 FALSE, | |
| 1260 certbuf, | |
| 1261 &size); | |
| 1262 if(rc) { | |
| 1263 infof(data, "error fetching CN from cert:%s\n", | |
| 1264 gnutls_strerror(rc)); | |
| 1265 } | |
| 1266 | |
| 1267 /* This function will check if the given certificate's subject matches the | |
| 1268 given hostname. This is a basic implementation of the matching described | |
| 1269 in RFC2818 (HTTPS), which takes into account wildcards, and the subject | |
| 1270 alternative name PKIX extension. Returns non zero on success, and zero on | |
| 1271 failure. */ | |
| 1272 rc = gnutls_x509_crt_check_hostname(x509_cert, hostname); | |
| 1273 #if GNUTLS_VERSION_NUMBER < 0x030306 | |
| 1274 /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP | |
| 1275 addresses. */ | |
| 1276 if(!rc) { | |
| 1277 #ifdef ENABLE_IPV6 | |
| 1278 #define use_addr in6_addr | |
| 1279 #else | |
| 1280 #define use_addr in_addr | |
| 1281 #endif | |
| 1282 unsigned char addrbuf[sizeof(struct use_addr)]; | |
| 1283 size_t addrlen = 0; | |
| 1284 | |
| 1285 if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0) | |
| 1286 addrlen = 4; | |
| 1287 #ifdef ENABLE_IPV6 | |
| 1288 else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0) | |
| 1289 addrlen = 16; | |
| 1290 #endif | |
| 1291 | |
| 1292 if(addrlen) { | |
| 1293 unsigned char certaddr[sizeof(struct use_addr)]; | |
| 1294 int i; | |
| 1295 | |
| 1296 for(i = 0; ; i++) { | |
| 1297 size_t certaddrlen = sizeof(certaddr); | |
| 1298 int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr, | |
| 1299 &certaddrlen, NULL); | |
| 1300 /* If this happens, it wasn't an IP address. */ | |
| 1301 if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) | |
| 1302 continue; | |
| 1303 if(ret < 0) | |
| 1304 break; | |
| 1305 if(ret != GNUTLS_SAN_IPADDRESS) | |
| 1306 continue; | |
| 1307 if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) { | |
| 1308 rc = 1; | |
| 1309 break; | |
| 1310 } | |
| 1311 } | |
| 1312 } | |
| 1313 } | |
| 1314 #endif | |
| 1315 if(!rc) { | |
| 1316 const char * const dispname = SSL_IS_PROXY() ? | |
| 1317 conn->http_proxy.host.dispname : conn->host.dispname; | |
| 1318 | |
| 1319 if(SSL_CONN_CONFIG(verifyhost)) { | |
| 1320 failf(data, "SSL: certificate subject name (%s) does not match " | |
| 1321 "target host name '%s'", certbuf, dispname); | |
| 1322 gnutls_x509_crt_deinit(x509_cert); | |
| 1323 return CURLE_PEER_FAILED_VERIFICATION; | |
| 1324 } | |
| 1325 else | |
| 1326 infof(data, "\t common name: %s (does not match '%s')\n", | |
| 1327 certbuf, dispname); | |
| 1328 } | |
| 1329 else | |
| 1330 infof(data, "\t common name: %s (matched)\n", certbuf); | |
| 1331 | |
| 1332 /* Check for time-based validity */ | |
| 1333 certclock = gnutls_x509_crt_get_expiration_time(x509_cert); | |
| 1334 | |
| 1335 if(certclock == (time_t)-1) { | |
| 1336 if(SSL_CONN_CONFIG(verifypeer)) { | |
| 1337 failf(data, "server cert expiration date verify failed"); | |
| 1338 gnutls_x509_crt_deinit(x509_cert); | |
| 1339 return CURLE_SSL_CONNECT_ERROR; | |
| 1340 } | |
| 1341 else | |
| 1342 infof(data, "\t server certificate expiration date verify FAILED\n"); | |
| 1343 } | |
| 1344 else { | |
| 1345 if(certclock < time(NULL)) { | |
| 1346 if(SSL_CONN_CONFIG(verifypeer)) { | |
| 1347 failf(data, "server certificate expiration date has passed."); | |
| 1348 gnutls_x509_crt_deinit(x509_cert); | |
| 1349 return CURLE_PEER_FAILED_VERIFICATION; | |
| 1350 } | |
| 1351 else | |
| 1352 infof(data, "\t server certificate expiration date FAILED\n"); | |
| 1353 } | |
| 1354 else | |
| 1355 infof(data, "\t server certificate expiration date OK\n"); | |
| 1356 } | |
| 1357 | |
| 1358 certclock = gnutls_x509_crt_get_activation_time(x509_cert); | |
| 1359 | |
| 1360 if(certclock == (time_t)-1) { | |
| 1361 if(SSL_CONN_CONFIG(verifypeer)) { | |
| 1362 failf(data, "server cert activation date verify failed"); | |
| 1363 gnutls_x509_crt_deinit(x509_cert); | |
| 1364 return CURLE_SSL_CONNECT_ERROR; | |
| 1365 } | |
| 1366 else | |
| 1367 infof(data, "\t server certificate activation date verify FAILED\n"); | |
| 1368 } | |
| 1369 else { | |
| 1370 if(certclock > time(NULL)) { | |
| 1371 if(SSL_CONN_CONFIG(verifypeer)) { | |
| 1372 failf(data, "server certificate not activated yet."); | |
| 1373 gnutls_x509_crt_deinit(x509_cert); | |
| 1374 return CURLE_PEER_FAILED_VERIFICATION; | |
| 1375 } | |
| 1376 else | |
| 1377 infof(data, "\t server certificate activation date FAILED\n"); | |
| 1378 } | |
| 1379 else | |
| 1380 infof(data, "\t server certificate activation date OK\n"); | |
| 1381 } | |
| 1382 | |
| 1383 ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : | |
| 1384 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; | |
| 1385 if(ptr) { | |
| 1386 result = pkp_pin_peer_pubkey(data, x509_cert, ptr); | |
| 1387 if(result != CURLE_OK) { | |
| 1388 failf(data, "SSL: public key does not match pinned public key!"); | |
| 1389 gnutls_x509_crt_deinit(x509_cert); | |
| 1390 return result; | |
| 1391 } | |
| 1392 } | |
| 1393 | |
| 1394 /* Show: | |
| 1395 | |
| 1396 - subject | |
| 1397 - start date | |
| 1398 - expire date | |
| 1399 - common name | |
| 1400 - issuer | |
| 1401 | |
| 1402 */ | |
| 1403 | |
| 1404 #ifndef CURL_DISABLE_VERBOSE_STRINGS | |
| 1405 /* public key algorithm's parameters */ | |
| 1406 algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); | |
| 1407 infof(data, "\t certificate public key: %s\n", | |
| 1408 gnutls_pk_algorithm_get_name(algo)); | |
| 1409 | |
| 1410 /* version of the X.509 certificate. */ | |
| 1411 infof(data, "\t certificate version: #%d\n", | |
| 1412 gnutls_x509_crt_get_version(x509_cert)); | |
| 1413 | |
| 1414 | |
| 1415 size = sizeof(certbuf); | |
| 1416 gnutls_x509_crt_get_dn(x509_cert, certbuf, &size); | |
| 1417 infof(data, "\t subject: %s\n", certbuf); | |
| 1418 | |
| 1419 certclock = gnutls_x509_crt_get_activation_time(x509_cert); | |
| 1420 showtime(data, "start date", certclock); | |
| 1421 | |
| 1422 certclock = gnutls_x509_crt_get_expiration_time(x509_cert); | |
| 1423 showtime(data, "expire date", certclock); | |
| 1424 | |
| 1425 size = sizeof(certbuf); | |
| 1426 gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size); | |
| 1427 infof(data, "\t issuer: %s\n", certbuf); | |
| 1428 #endif | |
| 1429 | |
| 1430 gnutls_x509_crt_deinit(x509_cert); | |
| 1431 | |
| 1432 #ifdef HAS_ALPN | |
| 1433 if(conn->bits.tls_enable_alpn) { | |
| 1434 rc = gnutls_alpn_get_selected_protocol(session, &proto); | |
| 1435 if(rc == 0) { | |
| 1436 infof(data, "ALPN, server accepted to use %.*s\n", proto.size, | |
| 1437 proto.data); | |
| 1438 | |
| 1439 #ifdef USE_NGHTTP2 | |
| 1440 if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN && | |
| 1441 !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data, | |
| 1442 NGHTTP2_PROTO_VERSION_ID_LEN)) { | |
| 1443 conn->negnpn = CURL_HTTP_VERSION_2; | |
| 1444 } | |
| 1445 else | |
| 1446 #endif | |
| 1447 if(proto.size == ALPN_HTTP_1_1_LENGTH && | |
| 1448 !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { | |
| 1449 conn->negnpn = CURL_HTTP_VERSION_1_1; | |
| 1450 } | |
| 1451 } | |
| 1452 else | |
| 1453 infof(data, "ALPN, server did not agree to a protocol\n"); | |
| 1454 | |
| 1455 Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? | |
| 1456 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); | |
| 1457 } | |
| 1458 #endif | |
| 1459 | |
| 1460 conn->ssl[sockindex].state = ssl_connection_complete; | |
| 1461 conn->recv[sockindex] = gtls_recv; | |
| 1462 conn->send[sockindex] = gtls_send; | |
| 1463 | |
| 1464 if(SSL_SET_OPTION(primary.sessionid)) { | |
| 1465 /* we always unconditionally get the session id here, as even if we | |
| 1466 already got it from the cache and asked to use it in the connection, it | |
| 1467 might've been rejected and then a new one is in use now and we need to | |
| 1468 detect that. */ | |
| 1469 void *connect_sessionid; | |
| 1470 size_t connect_idsize = 0; | |
| 1471 | |
| 1472 /* get the session ID data size */ | |
| 1473 gnutls_session_get_data(session, NULL, &connect_idsize); | |
| 1474 connect_sessionid = malloc(connect_idsize); /* get a buffer for it */ | |
| 1475 | |
| 1476 if(connect_sessionid) { | |
| 1477 bool incache; | |
| 1478 void *ssl_sessionid; | |
| 1479 | |
| 1480 /* extract session ID to the allocated buffer */ | |
| 1481 gnutls_session_get_data(session, connect_sessionid, &connect_idsize); | |
| 1482 | |
| 1483 Curl_ssl_sessionid_lock(conn); | |
| 1484 incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, | |
| 1485 sockindex)); | |
| 1486 if(incache) { | |
| 1487 /* there was one before in the cache, so instead of risking that the | |
| 1488 previous one was rejected, we just kill that and store the new */ | |
| 1489 Curl_ssl_delsessionid(conn, ssl_sessionid); | |
| 1490 } | |
| 1491 | |
| 1492 /* store this session id */ | |
| 1493 result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, | |
| 1494 sockindex); | |
| 1495 Curl_ssl_sessionid_unlock(conn); | |
| 1496 if(result) { | |
| 1497 free(connect_sessionid); | |
| 1498 result = CURLE_OUT_OF_MEMORY; | |
| 1499 } | |
| 1500 } | |
| 1501 else | |
| 1502 result = CURLE_OUT_OF_MEMORY; | |
| 1503 } | |
| 1504 | |
| 1505 return result; | |
| 1506 } | |
| 1507 | |
| 1508 | |
| 1509 /* | |
| 1510 * This function is called after the TCP connect has completed. Setup the TLS | |
| 1511 * layer and do all necessary magic. | |
| 1512 */ | |
| 1513 /* We use connssl->connecting_state to keep track of the connection status; | |
| 1514 there are three states: 'ssl_connect_1' (not started yet or complete), | |
| 1515 'ssl_connect_2_reading' (waiting for data from server), and | |
| 1516 'ssl_connect_2_writing' (waiting to be able to write). | |
| 1517 */ | |
| 1518 static CURLcode | |
| 1519 gtls_connect_common(struct connectdata *conn, | |
| 1520 int sockindex, | |
| 1521 bool nonblocking, | |
| 1522 bool *done) | |
| 1523 { | |
| 1524 int rc; | |
| 1525 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1526 | |
| 1527 /* Initiate the connection, if not already done */ | |
| 1528 if(ssl_connect_1 == connssl->connecting_state) { | |
| 1529 rc = gtls_connect_step1(conn, sockindex); | |
| 1530 if(rc) | |
| 1531 return rc; | |
| 1532 } | |
| 1533 | |
| 1534 rc = handshake(conn, sockindex, TRUE, nonblocking); | |
| 1535 if(rc) | |
| 1536 /* handshake() sets its own error message with failf() */ | |
| 1537 return rc; | |
| 1538 | |
| 1539 /* Finish connecting once the handshake is done */ | |
| 1540 if(ssl_connect_1 == connssl->connecting_state) { | |
| 1541 rc = gtls_connect_step3(conn, sockindex); | |
| 1542 if(rc) | |
| 1543 return rc; | |
| 1544 } | |
| 1545 | |
| 1546 *done = ssl_connect_1 == connssl->connecting_state; | |
| 1547 | |
| 1548 return CURLE_OK; | |
| 1549 } | |
| 1550 | |
| 1551 static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, | |
| 1552 int sockindex, bool *done) | |
| 1553 { | |
| 1554 return gtls_connect_common(conn, sockindex, TRUE, done); | |
| 1555 } | |
| 1556 | |
| 1557 static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex) | |
| 1558 { | |
| 1559 CURLcode result; | |
| 1560 bool done = FALSE; | |
| 1561 | |
| 1562 result = gtls_connect_common(conn, sockindex, FALSE, &done); | |
| 1563 if(result) | |
| 1564 return result; | |
| 1565 | |
| 1566 DEBUGASSERT(done); | |
| 1567 | |
| 1568 return CURLE_OK; | |
| 1569 } | |
| 1570 | |
| 1571 static bool Curl_gtls_data_pending(const struct connectdata *conn, | |
| 1572 int connindex) | |
| 1573 { | |
| 1574 const struct ssl_connect_data *connssl = &conn->ssl[connindex]; | |
| 1575 bool res = FALSE; | |
| 1576 if(BACKEND->session && | |
| 1577 0 != gnutls_record_check_pending(BACKEND->session)) | |
| 1578 res = TRUE; | |
| 1579 | |
| 1580 connssl = &conn->proxy_ssl[connindex]; | |
| 1581 if(BACKEND->session && | |
| 1582 0 != gnutls_record_check_pending(BACKEND->session)) | |
| 1583 res = TRUE; | |
| 1584 | |
| 1585 return res; | |
| 1586 } | |
| 1587 | |
| 1588 static ssize_t gtls_send(struct connectdata *conn, | |
| 1589 int sockindex, | |
| 1590 const void *mem, | |
| 1591 size_t len, | |
| 1592 CURLcode *curlcode) | |
| 1593 { | |
| 1594 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1595 ssize_t rc = gnutls_record_send(BACKEND->session, mem, len); | |
| 1596 | |
| 1597 if(rc < 0) { | |
| 1598 *curlcode = (rc == GNUTLS_E_AGAIN) | |
| 1599 ? CURLE_AGAIN | |
| 1600 : CURLE_SEND_ERROR; | |
| 1601 | |
| 1602 rc = -1; | |
| 1603 } | |
| 1604 | |
| 1605 return rc; | |
| 1606 } | |
| 1607 | |
| 1608 static void close_one(struct ssl_connect_data *connssl) | |
| 1609 { | |
| 1610 if(BACKEND->session) { | |
| 1611 gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR); | |
| 1612 gnutls_deinit(BACKEND->session); | |
| 1613 BACKEND->session = NULL; | |
| 1614 } | |
| 1615 if(BACKEND->cred) { | |
| 1616 gnutls_certificate_free_credentials(BACKEND->cred); | |
| 1617 BACKEND->cred = NULL; | |
| 1618 } | |
| 1619 #ifdef USE_TLS_SRP | |
| 1620 if(BACKEND->srp_client_cred) { | |
| 1621 gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); | |
| 1622 BACKEND->srp_client_cred = NULL; | |
| 1623 } | |
| 1624 #endif | |
| 1625 } | |
| 1626 | |
| 1627 static void Curl_gtls_close(struct connectdata *conn, int sockindex) | |
| 1628 { | |
| 1629 close_one(&conn->ssl[sockindex]); | |
| 1630 close_one(&conn->proxy_ssl[sockindex]); | |
| 1631 } | |
| 1632 | |
| 1633 /* | |
| 1634 * This function is called to shut down the SSL layer but keep the | |
| 1635 * socket open (CCC - Clear Command Channel) | |
| 1636 */ | |
| 1637 static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) | |
| 1638 { | |
| 1639 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | |
| 1640 int retval = 0; | |
| 1641 struct Curl_easy *data = conn->data; | |
| 1642 | |
| 1643 #ifndef CURL_DISABLE_FTP | |
| 1644 /* This has only been tested on the proftpd server, and the mod_tls code | |
| 1645 sends a close notify alert without waiting for a close notify alert in | |
| 1646 response. Thus we wait for a close notify alert from the server, but | |
| 1647 we do not send one. Let's hope other servers do the same... */ | |
| 1648 | |
| 1649 if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) | |
| 1650 gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR); | |
| 1651 #endif | |
| 1652 | |
| 1653 if(BACKEND->session) { | |
| 1654 ssize_t result; | |
| 1655 bool done = FALSE; | |
| 1656 char buf[120]; | |
| 1657 | |
| 1658 while(!done) { | |
| 1659 int what = SOCKET_READABLE(conn->sock[sockindex], | |
| 1660 SSL_SHUTDOWN_TIMEOUT); | |
| 1661 if(what > 0) { | |
| 1662 /* Something to read, let's do it and hope that it is the close | |
| 1663 notify alert from the server */ | |
| 1664 result = gnutls_record_recv(BACKEND->session, | |
| 1665 buf, sizeof(buf)); | |
| 1666 switch(result) { | |
| 1667 case 0: | |
| 1668 /* This is the expected response. There was no data but only | |
| 1669 the close notify alert */ | |
| 1670 done = TRUE; | |
| 1671 break; | |
| 1672 case GNUTLS_E_AGAIN: | |
| 1673 case GNUTLS_E_INTERRUPTED: | |
| 1674 infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); | |
| 1675 break; | |
| 1676 default: | |
| 1677 retval = -1; | |
| 1678 done = TRUE; | |
| 1679 break; | |
| 1680 } | |
| 1681 } | |
| 1682 else if(0 == what) { | |
| 1683 /* timeout */ | |
| 1684 failf(data, "SSL shutdown timeout"); | |
| 1685 done = TRUE; | |
| 1686 } | |
| 1687 else { | |
| 1688 /* anything that gets here is fatally bad */ | |
| 1689 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); | |
| 1690 retval = -1; | |
| 1691 done = TRUE; | |
| 1692 } | |
| 1693 } | |
| 1694 gnutls_deinit(BACKEND->session); | |
| 1695 } | |
| 1696 gnutls_certificate_free_credentials(BACKEND->cred); | |
| 1697 | |
| 1698 #ifdef USE_TLS_SRP | |
| 1699 if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP | |
| 1700 && SSL_SET_OPTION(username) != NULL) | |
| 1701 gnutls_srp_free_client_credentials(BACKEND->srp_client_cred); | |
| 1702 #endif | |
| 1703 | |
| 1704 BACKEND->cred = NULL; | |
| 1705 BACKEND->session = NULL; | |
| 1706 | |
| 1707 return retval; | |
| 1708 } | |
| 1709 | |
| 1710 static ssize_t gtls_recv(struct connectdata *conn, /* connection data */ | |
| 1711 int num, /* socketindex */ | |
| 1712 char *buf, /* store read data here */ | |
| 1713 size_t buffersize, /* max amount to read */ | |
| 1714 CURLcode *curlcode) | |
| 1715 { | |
| 1716 struct ssl_connect_data *connssl = &conn->ssl[num]; | |
| 1717 ssize_t ret; | |
| 1718 | |
| 1719 ret = gnutls_record_recv(BACKEND->session, buf, buffersize); | |
| 1720 if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { | |
| 1721 *curlcode = CURLE_AGAIN; | |
| 1722 return -1; | |
| 1723 } | |
| 1724 | |
| 1725 if(ret == GNUTLS_E_REHANDSHAKE) { | |
| 1726 /* BLOCKING call, this is bad but a work-around for now. Fixing this "the | |
| 1727 proper way" takes a whole lot of work. */ | |
| 1728 CURLcode result = handshake(conn, num, FALSE, FALSE); | |
| 1729 if(result) | |
| 1730 /* handshake() writes error message on its own */ | |
| 1731 *curlcode = result; | |
| 1732 else | |
| 1733 *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ | |
| 1734 return -1; | |
| 1735 } | |
| 1736 | |
| 1737 if(ret < 0) { | |
| 1738 failf(conn->data, "GnuTLS recv error (%d): %s", | |
| 1739 | |
| 1740 (int)ret, gnutls_strerror((int)ret)); | |
| 1741 *curlcode = CURLE_RECV_ERROR; | |
| 1742 return -1; | |
| 1743 } | |
| 1744 | |
| 1745 return ret; | |
| 1746 } | |
| 1747 | |
| 1748 static void Curl_gtls_session_free(void *ptr) | |
| 1749 { | |
| 1750 free(ptr); | |
| 1751 } | |
| 1752 | |
| 1753 static size_t Curl_gtls_version(char *buffer, size_t size) | |
| 1754 { | |
| 1755 return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL)); | |
| 1756 } | |
| 1757 | |
| 1758 #ifndef USE_GNUTLS_NETTLE | |
| 1759 static int Curl_gtls_seed(struct Curl_easy *data) | |
| 1760 { | |
| 1761 /* we have the "SSL is seeded" boolean static to prevent multiple | |
| 1762 time-consuming seedings in vain */ | |
| 1763 static bool ssl_seeded = FALSE; | |
| 1764 | |
| 1765 /* Quickly add a bit of entropy */ | |
| 1766 gcry_fast_random_poll(); | |
| 1767 | |
| 1768 if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || | |
| 1769 data->set.str[STRING_SSL_EGDSOCKET]) { | |
| 1770 ssl_seeded = TRUE; | |
| 1771 } | |
| 1772 return 0; | |
| 1773 } | |
| 1774 #endif | |
| 1775 | |
| 1776 /* data might be NULL! */ | |
| 1777 static CURLcode Curl_gtls_random(struct Curl_easy *data, | |
| 1778 unsigned char *entropy, size_t length) | |
| 1779 { | |
| 1780 #if defined(USE_GNUTLS_NETTLE) | |
| 1781 int rc; | |
| 1782 (void)data; | |
| 1783 rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); | |
| 1784 return rc?CURLE_FAILED_INIT:CURLE_OK; | |
| 1785 #elif defined(USE_GNUTLS) | |
| 1786 if(data) | |
| 1787 Curl_gtls_seed(data); /* Initiate the seed if not already done */ | |
| 1788 gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); | |
| 1789 #endif | |
| 1790 return CURLE_OK; | |
| 1791 } | |
| 1792 | |
| 1793 static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */ | |
| 1794 size_t tmplen, | |
| 1795 unsigned char *md5sum, /* output */ | |
| 1796 size_t md5len) | |
| 1797 { | |
| 1798 #if defined(USE_GNUTLS_NETTLE) | |
| 1799 struct md5_ctx MD5pw; | |
| 1800 md5_init(&MD5pw); | |
| 1801 md5_update(&MD5pw, (unsigned int)tmplen, tmp); | |
| 1802 md5_digest(&MD5pw, (unsigned int)md5len, md5sum); | |
| 1803 #elif defined(USE_GNUTLS) | |
| 1804 gcry_md_hd_t MD5pw; | |
| 1805 gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); | |
| 1806 gcry_md_write(MD5pw, tmp, tmplen); | |
| 1807 memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len); | |
| 1808 gcry_md_close(MD5pw); | |
| 1809 #endif | |
| 1810 return CURLE_OK; | |
| 1811 } | |
| 1812 | |
| 1813 static CURLcode Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ | |
| 1814 size_t tmplen, | |
| 1815 unsigned char *sha256sum, /* output */ | |
| 1816 size_t sha256len) | |
| 1817 { | |
| 1818 #if defined(USE_GNUTLS_NETTLE) | |
| 1819 struct sha256_ctx SHA256pw; | |
| 1820 sha256_init(&SHA256pw); | |
| 1821 sha256_update(&SHA256pw, (unsigned int)tmplen, tmp); | |
| 1822 sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum); | |
| 1823 #elif defined(USE_GNUTLS) | |
| 1824 gcry_md_hd_t SHA256pw; | |
| 1825 gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0); | |
| 1826 gcry_md_write(SHA256pw, tmp, tmplen); | |
| 1827 memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len); | |
| 1828 gcry_md_close(SHA256pw); | |
| 1829 #endif | |
| 1830 return CURLE_OK; | |
| 1831 } | |
| 1832 | |
| 1833 static bool Curl_gtls_cert_status_request(void) | |
| 1834 { | |
| 1835 #ifdef HAS_OCSP | |
| 1836 return TRUE; | |
| 1837 #else | |
| 1838 return FALSE; | |
| 1839 #endif | |
| 1840 } | |
| 1841 | |
| 1842 static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl, | |
| 1843 CURLINFO info UNUSED_PARAM) | |
| 1844 { | |
| 1845 (void)info; | |
| 1846 return BACKEND->session; | |
| 1847 } | |
| 1848 | |
| 1849 const struct Curl_ssl Curl_ssl_gnutls = { | |
| 1850 { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */ | |
| 1851 | |
| 1852 SSLSUPP_CA_PATH | | |
| 1853 SSLSUPP_CERTINFO | | |
| 1854 SSLSUPP_PINNEDPUBKEY | | |
| 1855 SSLSUPP_HTTPS_PROXY, | |
| 1856 | |
| 1857 sizeof(struct ssl_backend_data), | |
| 1858 | |
| 1859 Curl_gtls_init, /* init */ | |
| 1860 Curl_gtls_cleanup, /* cleanup */ | |
| 1861 Curl_gtls_version, /* version */ | |
| 1862 Curl_none_check_cxn, /* check_cxn */ | |
| 1863 Curl_gtls_shutdown, /* shutdown */ | |
| 1864 Curl_gtls_data_pending, /* data_pending */ | |
| 1865 Curl_gtls_random, /* random */ | |
| 1866 Curl_gtls_cert_status_request, /* cert_status_request */ | |
| 1867 Curl_gtls_connect, /* connect */ | |
| 1868 Curl_gtls_connect_nonblocking, /* connect_nonblocking */ | |
| 1869 Curl_gtls_get_internals, /* get_internals */ | |
| 1870 Curl_gtls_close, /* close_one */ | |
| 1871 Curl_none_close_all, /* close_all */ | |
| 1872 Curl_gtls_session_free, /* session_free */ | |
| 1873 Curl_none_set_engine, /* set_engine */ | |
| 1874 Curl_none_set_engine_default, /* set_engine_default */ | |
| 1875 Curl_none_engines_list, /* engines_list */ | |
| 1876 Curl_none_false_start, /* false_start */ | |
| 1877 Curl_gtls_md5sum, /* md5sum */ | |
| 1878 Curl_gtls_sha256sum /* sha256sum */ | |
| 1879 }; | |
| 1880 | |
| 1881 #endif /* USE_GNUTLS */ |
