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