Annotation of embedaddon/curl/lib/vtls/gtls.c, revision 1.1
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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>