Annotation of embedaddon/curl/lib/vtls/vtls.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: /* This file is for implementing all "generic" SSL functions that all libcurl
! 24: internals should use. It is then responsible for calling the proper
! 25: "backend" function.
! 26:
! 27: SSL-functions in libcurl should call functions in this source file, and not
! 28: to any specific SSL-layer.
! 29:
! 30: Curl_ssl_ - prefix for generic ones
! 31:
! 32: Note that this source code uses the functions of the configured SSL
! 33: backend via the global Curl_ssl instance.
! 34:
! 35: "SSL/TLS Strong Encryption: An Introduction"
! 36: https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
! 37: */
! 38:
! 39: #include "curl_setup.h"
! 40:
! 41: #ifdef HAVE_SYS_TYPES_H
! 42: #include <sys/types.h>
! 43: #endif
! 44: #ifdef HAVE_SYS_STAT_H
! 45: #include <sys/stat.h>
! 46: #endif
! 47: #ifdef HAVE_FCNTL_H
! 48: #include <fcntl.h>
! 49: #endif
! 50:
! 51: #include "urldata.h"
! 52:
! 53: #include "vtls.h" /* generic SSL protos etc */
! 54: #include "slist.h"
! 55: #include "sendf.h"
! 56: #include "strcase.h"
! 57: #include "url.h"
! 58: #include "progress.h"
! 59: #include "share.h"
! 60: #include "multiif.h"
! 61: #include "timeval.h"
! 62: #include "curl_md5.h"
! 63: #include "warnless.h"
! 64: #include "curl_base64.h"
! 65: #include "curl_printf.h"
! 66:
! 67: /* The last #include files should be: */
! 68: #include "curl_memory.h"
! 69: #include "memdebug.h"
! 70:
! 71: /* convenience macro to check if this handle is using a shared SSL session */
! 72: #define SSLSESSION_SHARED(data) (data->share && \
! 73: (data->share->specifier & \
! 74: (1<<CURL_LOCK_DATA_SSL_SESSION)))
! 75:
! 76: #define CLONE_STRING(var) \
! 77: if(source->var) { \
! 78: dest->var = strdup(source->var); \
! 79: if(!dest->var) \
! 80: return FALSE; \
! 81: } \
! 82: else \
! 83: dest->var = NULL;
! 84:
! 85: bool
! 86: Curl_ssl_config_matches(struct ssl_primary_config* data,
! 87: struct ssl_primary_config* needle)
! 88: {
! 89: if((data->version == needle->version) &&
! 90: (data->version_max == needle->version_max) &&
! 91: (data->verifypeer == needle->verifypeer) &&
! 92: (data->verifyhost == needle->verifyhost) &&
! 93: (data->verifystatus == needle->verifystatus) &&
! 94: Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
! 95: Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
! 96: Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
! 97: Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
! 98: Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
! 99: Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
! 100: Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
! 101: Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key))
! 102: return TRUE;
! 103:
! 104: return FALSE;
! 105: }
! 106:
! 107: bool
! 108: Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
! 109: struct ssl_primary_config *dest)
! 110: {
! 111: dest->version = source->version;
! 112: dest->version_max = source->version_max;
! 113: dest->verifypeer = source->verifypeer;
! 114: dest->verifyhost = source->verifyhost;
! 115: dest->verifystatus = source->verifystatus;
! 116: dest->sessionid = source->sessionid;
! 117:
! 118: CLONE_STRING(CApath);
! 119: CLONE_STRING(CAfile);
! 120: CLONE_STRING(clientcert);
! 121: CLONE_STRING(random_file);
! 122: CLONE_STRING(egdsocket);
! 123: CLONE_STRING(cipher_list);
! 124: CLONE_STRING(cipher_list13);
! 125: CLONE_STRING(pinned_key);
! 126:
! 127: return TRUE;
! 128: }
! 129:
! 130: void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
! 131: {
! 132: Curl_safefree(sslc->CApath);
! 133: Curl_safefree(sslc->CAfile);
! 134: Curl_safefree(sslc->clientcert);
! 135: Curl_safefree(sslc->random_file);
! 136: Curl_safefree(sslc->egdsocket);
! 137: Curl_safefree(sslc->cipher_list);
! 138: Curl_safefree(sslc->cipher_list13);
! 139: Curl_safefree(sslc->pinned_key);
! 140: }
! 141:
! 142: #ifdef USE_SSL
! 143: static int multissl_init(const struct Curl_ssl *backend);
! 144: #endif
! 145:
! 146: int Curl_ssl_backend(void)
! 147: {
! 148: #ifdef USE_SSL
! 149: multissl_init(NULL);
! 150: return Curl_ssl->info.id;
! 151: #else
! 152: return (int)CURLSSLBACKEND_NONE;
! 153: #endif
! 154: }
! 155:
! 156: #ifdef USE_SSL
! 157:
! 158: /* "global" init done? */
! 159: static bool init_ssl = FALSE;
! 160:
! 161: /**
! 162: * Global SSL init
! 163: *
! 164: * @retval 0 error initializing SSL
! 165: * @retval 1 SSL initialized successfully
! 166: */
! 167: int Curl_ssl_init(void)
! 168: {
! 169: /* make sure this is only done once */
! 170: if(init_ssl)
! 171: return 1;
! 172: init_ssl = TRUE; /* never again */
! 173:
! 174: return Curl_ssl->init();
! 175: }
! 176:
! 177: #if defined(CURL_WITH_MULTI_SSL)
! 178: static const struct Curl_ssl Curl_ssl_multi;
! 179: #endif
! 180:
! 181: /* Global cleanup */
! 182: void Curl_ssl_cleanup(void)
! 183: {
! 184: if(init_ssl) {
! 185: /* only cleanup if we did a previous init */
! 186: Curl_ssl->cleanup();
! 187: #if defined(CURL_WITH_MULTI_SSL)
! 188: Curl_ssl = &Curl_ssl_multi;
! 189: #endif
! 190: init_ssl = FALSE;
! 191: }
! 192: }
! 193:
! 194: static bool ssl_prefs_check(struct Curl_easy *data)
! 195: {
! 196: /* check for CURLOPT_SSLVERSION invalid parameter value */
! 197: const long sslver = data->set.ssl.primary.version;
! 198: if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) {
! 199: failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
! 200: return FALSE;
! 201: }
! 202:
! 203: switch(data->set.ssl.primary.version_max) {
! 204: case CURL_SSLVERSION_MAX_NONE:
! 205: case CURL_SSLVERSION_MAX_DEFAULT:
! 206: break;
! 207:
! 208: default:
! 209: if((data->set.ssl.primary.version_max >> 16) < sslver) {
! 210: failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
! 211: return FALSE;
! 212: }
! 213: }
! 214:
! 215: return TRUE;
! 216: }
! 217:
! 218: static CURLcode
! 219: ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
! 220: {
! 221: DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
! 222: if(ssl_connection_complete == conn->ssl[sockindex].state &&
! 223: !conn->proxy_ssl[sockindex].use) {
! 224: struct ssl_backend_data *pbdata;
! 225:
! 226: if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
! 227: return CURLE_NOT_BUILT_IN;
! 228:
! 229: /* The pointers to the ssl backend data, which is opaque here, are swapped
! 230: rather than move the contents. */
! 231: pbdata = conn->proxy_ssl[sockindex].backend;
! 232: conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
! 233:
! 234: memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
! 235: memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data);
! 236:
! 237: conn->ssl[sockindex].backend = pbdata;
! 238: }
! 239: return CURLE_OK;
! 240: }
! 241:
! 242: CURLcode
! 243: Curl_ssl_connect(struct connectdata *conn, int sockindex)
! 244: {
! 245: CURLcode result;
! 246:
! 247: if(conn->bits.proxy_ssl_connected[sockindex]) {
! 248: result = ssl_connect_init_proxy(conn, sockindex);
! 249: if(result)
! 250: return result;
! 251: }
! 252:
! 253: if(!ssl_prefs_check(conn->data))
! 254: return CURLE_SSL_CONNECT_ERROR;
! 255:
! 256: /* mark this is being ssl-enabled from here on. */
! 257: conn->ssl[sockindex].use = TRUE;
! 258: conn->ssl[sockindex].state = ssl_connection_negotiating;
! 259:
! 260: result = Curl_ssl->connect_blocking(conn, sockindex);
! 261:
! 262: if(!result)
! 263: Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
! 264:
! 265: return result;
! 266: }
! 267:
! 268: CURLcode
! 269: Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
! 270: bool *done)
! 271: {
! 272: CURLcode result;
! 273: if(conn->bits.proxy_ssl_connected[sockindex]) {
! 274: result = ssl_connect_init_proxy(conn, sockindex);
! 275: if(result)
! 276: return result;
! 277: }
! 278:
! 279: if(!ssl_prefs_check(conn->data))
! 280: return CURLE_SSL_CONNECT_ERROR;
! 281:
! 282: /* mark this is being ssl requested from here on. */
! 283: conn->ssl[sockindex].use = TRUE;
! 284: result = Curl_ssl->connect_nonblocking(conn, sockindex, done);
! 285: if(!result && *done)
! 286: Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
! 287: return result;
! 288: }
! 289:
! 290: /*
! 291: * Lock shared SSL session data
! 292: */
! 293: void Curl_ssl_sessionid_lock(struct connectdata *conn)
! 294: {
! 295: if(SSLSESSION_SHARED(conn->data))
! 296: Curl_share_lock(conn->data,
! 297: CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
! 298: }
! 299:
! 300: /*
! 301: * Unlock shared SSL session data
! 302: */
! 303: void Curl_ssl_sessionid_unlock(struct connectdata *conn)
! 304: {
! 305: if(SSLSESSION_SHARED(conn->data))
! 306: Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
! 307: }
! 308:
! 309: /*
! 310: * Check if there's a session ID for the given connection in the cache, and if
! 311: * there's one suitable, it is provided. Returns TRUE when no entry matched.
! 312: */
! 313: bool Curl_ssl_getsessionid(struct connectdata *conn,
! 314: void **ssl_sessionid,
! 315: size_t *idsize, /* set 0 if unknown */
! 316: int sockindex)
! 317: {
! 318: struct curl_ssl_session *check;
! 319: struct Curl_easy *data = conn->data;
! 320: size_t i;
! 321: long *general_age;
! 322: bool no_match = TRUE;
! 323:
! 324: const bool isProxy = CONNECT_PROXY_SSL();
! 325: struct ssl_primary_config * const ssl_config = isProxy ?
! 326: &conn->proxy_ssl_config :
! 327: &conn->ssl_config;
! 328: const char * const name = isProxy ? conn->http_proxy.host.name :
! 329: conn->host.name;
! 330: int port = isProxy ? (int)conn->port : conn->remote_port;
! 331: *ssl_sessionid = NULL;
! 332:
! 333: DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
! 334:
! 335: if(!SSL_SET_OPTION(primary.sessionid))
! 336: /* session ID re-use is disabled */
! 337: return TRUE;
! 338:
! 339: /* Lock if shared */
! 340: if(SSLSESSION_SHARED(data))
! 341: general_age = &data->share->sessionage;
! 342: else
! 343: general_age = &data->state.sessionage;
! 344:
! 345: for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
! 346: check = &data->state.session[i];
! 347: if(!check->sessionid)
! 348: /* not session ID means blank entry */
! 349: continue;
! 350: if(strcasecompare(name, check->name) &&
! 351: ((!conn->bits.conn_to_host && !check->conn_to_host) ||
! 352: (conn->bits.conn_to_host && check->conn_to_host &&
! 353: strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
! 354: ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
! 355: (conn->bits.conn_to_port && check->conn_to_port != -1 &&
! 356: conn->conn_to_port == check->conn_to_port)) &&
! 357: (port == check->remote_port) &&
! 358: strcasecompare(conn->handler->scheme, check->scheme) &&
! 359: Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
! 360: /* yes, we have a session ID! */
! 361: (*general_age)++; /* increase general age */
! 362: check->age = *general_age; /* set this as used in this age */
! 363: *ssl_sessionid = check->sessionid;
! 364: if(idsize)
! 365: *idsize = check->idsize;
! 366: no_match = FALSE;
! 367: break;
! 368: }
! 369: }
! 370:
! 371: return no_match;
! 372: }
! 373:
! 374: /*
! 375: * Kill a single session ID entry in the cache.
! 376: */
! 377: void Curl_ssl_kill_session(struct curl_ssl_session *session)
! 378: {
! 379: if(session->sessionid) {
! 380: /* defensive check */
! 381:
! 382: /* free the ID the SSL-layer specific way */
! 383: Curl_ssl->session_free(session->sessionid);
! 384:
! 385: session->sessionid = NULL;
! 386: session->age = 0; /* fresh */
! 387:
! 388: Curl_free_primary_ssl_config(&session->ssl_config);
! 389:
! 390: Curl_safefree(session->name);
! 391: Curl_safefree(session->conn_to_host);
! 392: }
! 393: }
! 394:
! 395: /*
! 396: * Delete the given session ID from the cache.
! 397: */
! 398: void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
! 399: {
! 400: size_t i;
! 401: struct Curl_easy *data = conn->data;
! 402:
! 403: for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
! 404: struct curl_ssl_session *check = &data->state.session[i];
! 405:
! 406: if(check->sessionid == ssl_sessionid) {
! 407: Curl_ssl_kill_session(check);
! 408: break;
! 409: }
! 410: }
! 411: }
! 412:
! 413: /*
! 414: * Store session id in the session cache. The ID passed on to this function
! 415: * must already have been extracted and allocated the proper way for the SSL
! 416: * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
! 417: * later on.
! 418: */
! 419: CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
! 420: void *ssl_sessionid,
! 421: size_t idsize,
! 422: int sockindex)
! 423: {
! 424: size_t i;
! 425: struct Curl_easy *data = conn->data; /* the mother of all structs */
! 426: struct curl_ssl_session *store = &data->state.session[0];
! 427: long oldest_age = data->state.session[0].age; /* zero if unused */
! 428: char *clone_host;
! 429: char *clone_conn_to_host;
! 430: int conn_to_port;
! 431: long *general_age;
! 432: const bool isProxy = CONNECT_PROXY_SSL();
! 433: struct ssl_primary_config * const ssl_config = isProxy ?
! 434: &conn->proxy_ssl_config :
! 435: &conn->ssl_config;
! 436:
! 437: DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
! 438:
! 439: clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
! 440: if(!clone_host)
! 441: return CURLE_OUT_OF_MEMORY; /* bail out */
! 442:
! 443: if(conn->bits.conn_to_host) {
! 444: clone_conn_to_host = strdup(conn->conn_to_host.name);
! 445: if(!clone_conn_to_host) {
! 446: free(clone_host);
! 447: return CURLE_OUT_OF_MEMORY; /* bail out */
! 448: }
! 449: }
! 450: else
! 451: clone_conn_to_host = NULL;
! 452:
! 453: if(conn->bits.conn_to_port)
! 454: conn_to_port = conn->conn_to_port;
! 455: else
! 456: conn_to_port = -1;
! 457:
! 458: /* Now we should add the session ID and the host name to the cache, (remove
! 459: the oldest if necessary) */
! 460:
! 461: /* If using shared SSL session, lock! */
! 462: if(SSLSESSION_SHARED(data)) {
! 463: general_age = &data->share->sessionage;
! 464: }
! 465: else {
! 466: general_age = &data->state.sessionage;
! 467: }
! 468:
! 469: /* find an empty slot for us, or find the oldest */
! 470: for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
! 471: data->state.session[i].sessionid; i++) {
! 472: if(data->state.session[i].age < oldest_age) {
! 473: oldest_age = data->state.session[i].age;
! 474: store = &data->state.session[i];
! 475: }
! 476: }
! 477: if(i == data->set.general_ssl.max_ssl_sessions)
! 478: /* cache is full, we must "kill" the oldest entry! */
! 479: Curl_ssl_kill_session(store);
! 480: else
! 481: store = &data->state.session[i]; /* use this slot */
! 482:
! 483: /* now init the session struct wisely */
! 484: store->sessionid = ssl_sessionid;
! 485: store->idsize = idsize;
! 486: store->age = *general_age; /* set current age */
! 487: /* free it if there's one already present */
! 488: free(store->name);
! 489: free(store->conn_to_host);
! 490: store->name = clone_host; /* clone host name */
! 491: store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
! 492: store->conn_to_port = conn_to_port; /* connect to port number */
! 493: /* port number */
! 494: store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
! 495: store->scheme = conn->handler->scheme;
! 496:
! 497: if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
! 498: Curl_free_primary_ssl_config(&store->ssl_config);
! 499: store->sessionid = NULL; /* let caller free sessionid */
! 500: free(clone_host);
! 501: free(clone_conn_to_host);
! 502: return CURLE_OUT_OF_MEMORY;
! 503: }
! 504:
! 505: return CURLE_OK;
! 506: }
! 507:
! 508:
! 509: void Curl_ssl_close_all(struct Curl_easy *data)
! 510: {
! 511: /* kill the session ID cache if not shared */
! 512: if(data->state.session && !SSLSESSION_SHARED(data)) {
! 513: size_t i;
! 514: for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
! 515: /* the single-killer function handles empty table slots */
! 516: Curl_ssl_kill_session(&data->state.session[i]);
! 517:
! 518: /* free the cache data */
! 519: Curl_safefree(data->state.session);
! 520: }
! 521:
! 522: Curl_ssl->close_all(data);
! 523: }
! 524:
! 525: #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
! 526: defined(USE_SECTRANSP) || defined(USE_NSS) || \
! 527: defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL)
! 528: int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks)
! 529: {
! 530: struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
! 531:
! 532: if(connssl->connecting_state == ssl_connect_2_writing) {
! 533: /* write mode */
! 534: socks[0] = conn->sock[FIRSTSOCKET];
! 535: return GETSOCK_WRITESOCK(0);
! 536: }
! 537: if(connssl->connecting_state == ssl_connect_2_reading) {
! 538: /* read mode */
! 539: socks[0] = conn->sock[FIRSTSOCKET];
! 540: return GETSOCK_READSOCK(0);
! 541: }
! 542:
! 543: return GETSOCK_BLANK;
! 544: }
! 545: #else
! 546: int Curl_ssl_getsock(struct connectdata *conn,
! 547: curl_socket_t *socks)
! 548: {
! 549: (void)conn;
! 550: (void)socks;
! 551: return GETSOCK_BLANK;
! 552: }
! 553: /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_SECTRANSP || USE_NSS */
! 554: #endif
! 555:
! 556: void Curl_ssl_close(struct connectdata *conn, int sockindex)
! 557: {
! 558: DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
! 559: Curl_ssl->close_one(conn, sockindex);
! 560: }
! 561:
! 562: CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
! 563: {
! 564: if(Curl_ssl->shut_down(conn, sockindex))
! 565: return CURLE_SSL_SHUTDOWN_FAILED;
! 566:
! 567: conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
! 568: conn->ssl[sockindex].state = ssl_connection_none;
! 569:
! 570: conn->recv[sockindex] = Curl_recv_plain;
! 571: conn->send[sockindex] = Curl_send_plain;
! 572:
! 573: return CURLE_OK;
! 574: }
! 575:
! 576: /* Selects an SSL crypto engine
! 577: */
! 578: CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
! 579: {
! 580: return Curl_ssl->set_engine(data, engine);
! 581: }
! 582:
! 583: /* Selects the default SSL crypto engine
! 584: */
! 585: CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
! 586: {
! 587: return Curl_ssl->set_engine_default(data);
! 588: }
! 589:
! 590: /* Return list of OpenSSL crypto engine names. */
! 591: struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
! 592: {
! 593: return Curl_ssl->engines_list(data);
! 594: }
! 595:
! 596: /*
! 597: * This sets up a session ID cache to the specified size. Make sure this code
! 598: * is agnostic to what underlying SSL technology we use.
! 599: */
! 600: CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
! 601: {
! 602: struct curl_ssl_session *session;
! 603:
! 604: if(data->state.session)
! 605: /* this is just a precaution to prevent multiple inits */
! 606: return CURLE_OK;
! 607:
! 608: session = calloc(amount, sizeof(struct curl_ssl_session));
! 609: if(!session)
! 610: return CURLE_OUT_OF_MEMORY;
! 611:
! 612: /* store the info in the SSL section */
! 613: data->set.general_ssl.max_ssl_sessions = amount;
! 614: data->state.session = session;
! 615: data->state.sessionage = 1; /* this is brand new */
! 616: return CURLE_OK;
! 617: }
! 618:
! 619: static size_t Curl_multissl_version(char *buffer, size_t size);
! 620:
! 621: size_t Curl_ssl_version(char *buffer, size_t size)
! 622: {
! 623: #ifdef CURL_WITH_MULTI_SSL
! 624: return Curl_multissl_version(buffer, size);
! 625: #else
! 626: return Curl_ssl->version(buffer, size);
! 627: #endif
! 628: }
! 629:
! 630: /*
! 631: * This function tries to determine connection status.
! 632: *
! 633: * Return codes:
! 634: * 1 means the connection is still in place
! 635: * 0 means the connection has been closed
! 636: * -1 means the connection status is unknown
! 637: */
! 638: int Curl_ssl_check_cxn(struct connectdata *conn)
! 639: {
! 640: return Curl_ssl->check_cxn(conn);
! 641: }
! 642:
! 643: bool Curl_ssl_data_pending(const struct connectdata *conn,
! 644: int connindex)
! 645: {
! 646: return Curl_ssl->data_pending(conn, connindex);
! 647: }
! 648:
! 649: void Curl_ssl_free_certinfo(struct Curl_easy *data)
! 650: {
! 651: struct curl_certinfo *ci = &data->info.certs;
! 652:
! 653: if(ci->num_of_certs) {
! 654: /* free all individual lists used */
! 655: int i;
! 656: for(i = 0; i<ci->num_of_certs; i++) {
! 657: curl_slist_free_all(ci->certinfo[i]);
! 658: ci->certinfo[i] = NULL;
! 659: }
! 660:
! 661: free(ci->certinfo); /* free the actual array too */
! 662: ci->certinfo = NULL;
! 663: ci->num_of_certs = 0;
! 664: }
! 665: }
! 666:
! 667: CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
! 668: {
! 669: struct curl_certinfo *ci = &data->info.certs;
! 670: struct curl_slist **table;
! 671:
! 672: /* Free any previous certificate information structures */
! 673: Curl_ssl_free_certinfo(data);
! 674:
! 675: /* Allocate the required certificate information structures */
! 676: table = calloc((size_t) num, sizeof(struct curl_slist *));
! 677: if(!table)
! 678: return CURLE_OUT_OF_MEMORY;
! 679:
! 680: ci->num_of_certs = num;
! 681: ci->certinfo = table;
! 682:
! 683: return CURLE_OK;
! 684: }
! 685:
! 686: /*
! 687: * 'value' is NOT a zero terminated string
! 688: */
! 689: CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
! 690: int certnum,
! 691: const char *label,
! 692: const char *value,
! 693: size_t valuelen)
! 694: {
! 695: struct curl_certinfo *ci = &data->info.certs;
! 696: char *output;
! 697: struct curl_slist *nl;
! 698: CURLcode result = CURLE_OK;
! 699: size_t labellen = strlen(label);
! 700: size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
! 701:
! 702: output = malloc(outlen);
! 703: if(!output)
! 704: return CURLE_OUT_OF_MEMORY;
! 705:
! 706: /* sprintf the label and colon */
! 707: msnprintf(output, outlen, "%s:", label);
! 708:
! 709: /* memcpy the value (it might not be zero terminated) */
! 710: memcpy(&output[labellen + 1], value, valuelen);
! 711:
! 712: /* zero terminate the output */
! 713: output[labellen + 1 + valuelen] = 0;
! 714:
! 715: nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
! 716: if(!nl) {
! 717: free(output);
! 718: curl_slist_free_all(ci->certinfo[certnum]);
! 719: result = CURLE_OUT_OF_MEMORY;
! 720: }
! 721:
! 722: ci->certinfo[certnum] = nl;
! 723: return result;
! 724: }
! 725:
! 726: /*
! 727: * This is a convenience function for push_certinfo_len that takes a zero
! 728: * terminated value.
! 729: */
! 730: CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
! 731: int certnum,
! 732: const char *label,
! 733: const char *value)
! 734: {
! 735: size_t valuelen = strlen(value);
! 736:
! 737: return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
! 738: }
! 739:
! 740: CURLcode Curl_ssl_random(struct Curl_easy *data,
! 741: unsigned char *entropy,
! 742: size_t length)
! 743: {
! 744: return Curl_ssl->random(data, entropy, length);
! 745: }
! 746:
! 747: /*
! 748: * Public key pem to der conversion
! 749: */
! 750:
! 751: static CURLcode pubkey_pem_to_der(const char *pem,
! 752: unsigned char **der, size_t *der_len)
! 753: {
! 754: char *stripped_pem, *begin_pos, *end_pos;
! 755: size_t pem_count, stripped_pem_count = 0, pem_len;
! 756: CURLcode result;
! 757:
! 758: /* if no pem, exit. */
! 759: if(!pem)
! 760: return CURLE_BAD_CONTENT_ENCODING;
! 761:
! 762: begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
! 763: if(!begin_pos)
! 764: return CURLE_BAD_CONTENT_ENCODING;
! 765:
! 766: pem_count = begin_pos - pem;
! 767: /* Invalid if not at beginning AND not directly following \n */
! 768: if(0 != pem_count && '\n' != pem[pem_count - 1])
! 769: return CURLE_BAD_CONTENT_ENCODING;
! 770:
! 771: /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
! 772: pem_count += 26;
! 773:
! 774: /* Invalid if not directly following \n */
! 775: end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
! 776: if(!end_pos)
! 777: return CURLE_BAD_CONTENT_ENCODING;
! 778:
! 779: pem_len = end_pos - pem;
! 780:
! 781: stripped_pem = malloc(pem_len - pem_count + 1);
! 782: if(!stripped_pem)
! 783: return CURLE_OUT_OF_MEMORY;
! 784:
! 785: /*
! 786: * Here we loop through the pem array one character at a time between the
! 787: * correct indices, and place each character that is not '\n' or '\r'
! 788: * into the stripped_pem array, which should represent the raw base64 string
! 789: */
! 790: while(pem_count < pem_len) {
! 791: if('\n' != pem[pem_count] && '\r' != pem[pem_count])
! 792: stripped_pem[stripped_pem_count++] = pem[pem_count];
! 793: ++pem_count;
! 794: }
! 795: /* Place the null terminator in the correct place */
! 796: stripped_pem[stripped_pem_count] = '\0';
! 797:
! 798: result = Curl_base64_decode(stripped_pem, der, der_len);
! 799:
! 800: Curl_safefree(stripped_pem);
! 801:
! 802: return result;
! 803: }
! 804:
! 805: /*
! 806: * Generic pinned public key check.
! 807: */
! 808:
! 809: CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
! 810: const char *pinnedpubkey,
! 811: const unsigned char *pubkey, size_t pubkeylen)
! 812: {
! 813: FILE *fp;
! 814: unsigned char *buf = NULL, *pem_ptr = NULL;
! 815: CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
! 816:
! 817: /* if a path wasn't specified, don't pin */
! 818: if(!pinnedpubkey)
! 819: return CURLE_OK;
! 820: if(!pubkey || !pubkeylen)
! 821: return result;
! 822:
! 823: /* only do this if pinnedpubkey starts with "sha256//", length 8 */
! 824: if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
! 825: CURLcode encode;
! 826: size_t encodedlen, pinkeylen;
! 827: char *encoded, *pinkeycopy, *begin_pos, *end_pos;
! 828: unsigned char *sha256sumdigest;
! 829:
! 830: if(!Curl_ssl->sha256sum) {
! 831: /* without sha256 support, this cannot match */
! 832: return result;
! 833: }
! 834:
! 835: /* compute sha256sum of public key */
! 836: sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
! 837: if(!sha256sumdigest)
! 838: return CURLE_OUT_OF_MEMORY;
! 839: encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
! 840: sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
! 841:
! 842: if(encode != CURLE_OK)
! 843: return encode;
! 844:
! 845: encode = Curl_base64_encode(data, (char *)sha256sumdigest,
! 846: CURL_SHA256_DIGEST_LENGTH, &encoded,
! 847: &encodedlen);
! 848: Curl_safefree(sha256sumdigest);
! 849:
! 850: if(encode)
! 851: return encode;
! 852:
! 853: infof(data, "\t public key hash: sha256//%s\n", encoded);
! 854:
! 855: /* it starts with sha256//, copy so we can modify it */
! 856: pinkeylen = strlen(pinnedpubkey) + 1;
! 857: pinkeycopy = malloc(pinkeylen);
! 858: if(!pinkeycopy) {
! 859: Curl_safefree(encoded);
! 860: return CURLE_OUT_OF_MEMORY;
! 861: }
! 862: memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
! 863: /* point begin_pos to the copy, and start extracting keys */
! 864: begin_pos = pinkeycopy;
! 865: do {
! 866: end_pos = strstr(begin_pos, ";sha256//");
! 867: /*
! 868: * if there is an end_pos, null terminate,
! 869: * otherwise it'll go to the end of the original string
! 870: */
! 871: if(end_pos)
! 872: end_pos[0] = '\0';
! 873:
! 874: /* compare base64 sha256 digests, 8 is the length of "sha256//" */
! 875: if(encodedlen == strlen(begin_pos + 8) &&
! 876: !memcmp(encoded, begin_pos + 8, encodedlen)) {
! 877: result = CURLE_OK;
! 878: break;
! 879: }
! 880:
! 881: /*
! 882: * change back the null-terminator we changed earlier,
! 883: * and look for next begin
! 884: */
! 885: if(end_pos) {
! 886: end_pos[0] = ';';
! 887: begin_pos = strstr(end_pos, "sha256//");
! 888: }
! 889: } while(end_pos && begin_pos);
! 890: Curl_safefree(encoded);
! 891: Curl_safefree(pinkeycopy);
! 892: return result;
! 893: }
! 894:
! 895: fp = fopen(pinnedpubkey, "rb");
! 896: if(!fp)
! 897: return result;
! 898:
! 899: do {
! 900: long filesize;
! 901: size_t size, pem_len;
! 902: CURLcode pem_read;
! 903:
! 904: /* Determine the file's size */
! 905: if(fseek(fp, 0, SEEK_END))
! 906: break;
! 907: filesize = ftell(fp);
! 908: if(fseek(fp, 0, SEEK_SET))
! 909: break;
! 910: if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
! 911: break;
! 912:
! 913: /*
! 914: * if the size of our certificate is bigger than the file
! 915: * size then it can't match
! 916: */
! 917: size = curlx_sotouz((curl_off_t) filesize);
! 918: if(pubkeylen > size)
! 919: break;
! 920:
! 921: /*
! 922: * Allocate buffer for the pinned key
! 923: * With 1 additional byte for null terminator in case of PEM key
! 924: */
! 925: buf = malloc(size + 1);
! 926: if(!buf)
! 927: break;
! 928:
! 929: /* Returns number of elements read, which should be 1 */
! 930: if((int) fread(buf, size, 1, fp) != 1)
! 931: break;
! 932:
! 933: /* If the sizes are the same, it can't be base64 encoded, must be der */
! 934: if(pubkeylen == size) {
! 935: if(!memcmp(pubkey, buf, pubkeylen))
! 936: result = CURLE_OK;
! 937: break;
! 938: }
! 939:
! 940: /*
! 941: * Otherwise we will assume it's PEM and try to decode it
! 942: * after placing null terminator
! 943: */
! 944: buf[size] = '\0';
! 945: pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
! 946: /* if it wasn't read successfully, exit */
! 947: if(pem_read)
! 948: break;
! 949:
! 950: /*
! 951: * if the size of our certificate doesn't match the size of
! 952: * the decoded file, they can't be the same, otherwise compare
! 953: */
! 954: if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
! 955: result = CURLE_OK;
! 956: } while(0);
! 957:
! 958: Curl_safefree(buf);
! 959: Curl_safefree(pem_ptr);
! 960: fclose(fp);
! 961:
! 962: return result;
! 963: }
! 964:
! 965: #ifndef CURL_DISABLE_CRYPTO_AUTH
! 966: CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
! 967: size_t tmplen,
! 968: unsigned char *md5sum, /* output */
! 969: size_t md5len)
! 970: {
! 971: return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len);
! 972: }
! 973: #endif
! 974:
! 975: /*
! 976: * Check whether the SSL backend supports the status_request extension.
! 977: */
! 978: bool Curl_ssl_cert_status_request(void)
! 979: {
! 980: return Curl_ssl->cert_status_request();
! 981: }
! 982:
! 983: /*
! 984: * Check whether the SSL backend supports false start.
! 985: */
! 986: bool Curl_ssl_false_start(void)
! 987: {
! 988: return Curl_ssl->false_start();
! 989: }
! 990:
! 991: /*
! 992: * Check whether the SSL backend supports setting TLS 1.3 cipher suites
! 993: */
! 994: bool Curl_ssl_tls13_ciphersuites(void)
! 995: {
! 996: return Curl_ssl->supports & SSLSUPP_TLS13_CIPHERSUITES;
! 997: }
! 998:
! 999: /*
! 1000: * Default implementations for unsupported functions.
! 1001: */
! 1002:
! 1003: int Curl_none_init(void)
! 1004: {
! 1005: return 1;
! 1006: }
! 1007:
! 1008: void Curl_none_cleanup(void)
! 1009: { }
! 1010:
! 1011: int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM,
! 1012: int sockindex UNUSED_PARAM)
! 1013: {
! 1014: (void)conn;
! 1015: (void)sockindex;
! 1016: return 0;
! 1017: }
! 1018:
! 1019: int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM)
! 1020: {
! 1021: (void)conn;
! 1022: return -1;
! 1023: }
! 1024:
! 1025: CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
! 1026: unsigned char *entropy UNUSED_PARAM,
! 1027: size_t length UNUSED_PARAM)
! 1028: {
! 1029: (void)data;
! 1030: (void)entropy;
! 1031: (void)length;
! 1032: return CURLE_NOT_BUILT_IN;
! 1033: }
! 1034:
! 1035: void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
! 1036: {
! 1037: (void)data;
! 1038: }
! 1039:
! 1040: void Curl_none_session_free(void *ptr UNUSED_PARAM)
! 1041: {
! 1042: (void)ptr;
! 1043: }
! 1044:
! 1045: bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM,
! 1046: int connindex UNUSED_PARAM)
! 1047: {
! 1048: (void)conn;
! 1049: (void)connindex;
! 1050: return 0;
! 1051: }
! 1052:
! 1053: bool Curl_none_cert_status_request(void)
! 1054: {
! 1055: return FALSE;
! 1056: }
! 1057:
! 1058: CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM,
! 1059: const char *engine UNUSED_PARAM)
! 1060: {
! 1061: (void)data;
! 1062: (void)engine;
! 1063: return CURLE_NOT_BUILT_IN;
! 1064: }
! 1065:
! 1066: CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM)
! 1067: {
! 1068: (void)data;
! 1069: return CURLE_NOT_BUILT_IN;
! 1070: }
! 1071:
! 1072: struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM)
! 1073: {
! 1074: (void)data;
! 1075: return (struct curl_slist *)NULL;
! 1076: }
! 1077:
! 1078: bool Curl_none_false_start(void)
! 1079: {
! 1080: return FALSE;
! 1081: }
! 1082:
! 1083: #ifndef CURL_DISABLE_CRYPTO_AUTH
! 1084: CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
! 1085: unsigned char *md5sum, size_t md5len UNUSED_PARAM)
! 1086: {
! 1087: MD5_context *MD5pw;
! 1088:
! 1089: (void)md5len;
! 1090:
! 1091: MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
! 1092: if(!MD5pw)
! 1093: return CURLE_OUT_OF_MEMORY;
! 1094: Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen));
! 1095: Curl_MD5_final(MD5pw, md5sum);
! 1096: return CURLE_OK;
! 1097: }
! 1098: #else
! 1099: CURLcode Curl_none_md5sum(unsigned char *input UNUSED_PARAM,
! 1100: size_t inputlen UNUSED_PARAM,
! 1101: unsigned char *md5sum UNUSED_PARAM,
! 1102: size_t md5len UNUSED_PARAM)
! 1103: {
! 1104: (void)input;
! 1105: (void)inputlen;
! 1106: (void)md5sum;
! 1107: (void)md5len;
! 1108: return CURLE_NOT_BUILT_IN;
! 1109: }
! 1110: #endif
! 1111:
! 1112: static int Curl_multissl_init(void)
! 1113: {
! 1114: if(multissl_init(NULL))
! 1115: return 1;
! 1116: return Curl_ssl->init();
! 1117: }
! 1118:
! 1119: static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex)
! 1120: {
! 1121: if(multissl_init(NULL))
! 1122: return CURLE_FAILED_INIT;
! 1123: return Curl_ssl->connect_blocking(conn, sockindex);
! 1124: }
! 1125:
! 1126: static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn,
! 1127: int sockindex, bool *done)
! 1128: {
! 1129: if(multissl_init(NULL))
! 1130: return CURLE_FAILED_INIT;
! 1131: return Curl_ssl->connect_nonblocking(conn, sockindex, done);
! 1132: }
! 1133:
! 1134: static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl,
! 1135: CURLINFO info)
! 1136: {
! 1137: if(multissl_init(NULL))
! 1138: return NULL;
! 1139: return Curl_ssl->get_internals(connssl, info);
! 1140: }
! 1141:
! 1142: static void Curl_multissl_close(struct connectdata *conn, int sockindex)
! 1143: {
! 1144: if(multissl_init(NULL))
! 1145: return;
! 1146: Curl_ssl->close_one(conn, sockindex);
! 1147: }
! 1148:
! 1149: static const struct Curl_ssl Curl_ssl_multi = {
! 1150: { CURLSSLBACKEND_NONE, "multi" }, /* info */
! 1151: 0, /* supports nothing */
! 1152: (size_t)-1, /* something insanely large to be on the safe side */
! 1153:
! 1154: Curl_multissl_init, /* init */
! 1155: Curl_none_cleanup, /* cleanup */
! 1156: Curl_multissl_version, /* version */
! 1157: Curl_none_check_cxn, /* check_cxn */
! 1158: Curl_none_shutdown, /* shutdown */
! 1159: Curl_none_data_pending, /* data_pending */
! 1160: Curl_none_random, /* random */
! 1161: Curl_none_cert_status_request, /* cert_status_request */
! 1162: Curl_multissl_connect, /* connect */
! 1163: Curl_multissl_connect_nonblocking, /* connect_nonblocking */
! 1164: Curl_multissl_get_internals, /* get_internals */
! 1165: Curl_multissl_close, /* close_one */
! 1166: Curl_none_close_all, /* close_all */
! 1167: Curl_none_session_free, /* session_free */
! 1168: Curl_none_set_engine, /* set_engine */
! 1169: Curl_none_set_engine_default, /* set_engine_default */
! 1170: Curl_none_engines_list, /* engines_list */
! 1171: Curl_none_false_start, /* false_start */
! 1172: Curl_none_md5sum, /* md5sum */
! 1173: NULL /* sha256sum */
! 1174: };
! 1175:
! 1176: const struct Curl_ssl *Curl_ssl =
! 1177: #if defined(CURL_WITH_MULTI_SSL)
! 1178: &Curl_ssl_multi;
! 1179: #elif defined(USE_WOLFSSL)
! 1180: &Curl_ssl_wolfssl;
! 1181: #elif defined(USE_SECTRANSP)
! 1182: &Curl_ssl_sectransp;
! 1183: #elif defined(USE_GNUTLS)
! 1184: &Curl_ssl_gnutls;
! 1185: #elif defined(USE_GSKIT)
! 1186: &Curl_ssl_gskit;
! 1187: #elif defined(USE_MBEDTLS)
! 1188: &Curl_ssl_mbedtls;
! 1189: #elif defined(USE_NSS)
! 1190: &Curl_ssl_nss;
! 1191: #elif defined(USE_OPENSSL)
! 1192: &Curl_ssl_openssl;
! 1193: #elif defined(USE_SCHANNEL)
! 1194: &Curl_ssl_schannel;
! 1195: #elif defined(USE_MESALINK)
! 1196: &Curl_ssl_mesalink;
! 1197: #elif defined(USE_BEARSSL)
! 1198: &Curl_ssl_bearssl;
! 1199: #else
! 1200: #error "Missing struct Curl_ssl for selected SSL backend"
! 1201: #endif
! 1202:
! 1203: static const struct Curl_ssl *available_backends[] = {
! 1204: #if defined(USE_WOLFSSL)
! 1205: &Curl_ssl_wolfssl,
! 1206: #endif
! 1207: #if defined(USE_SECTRANSP)
! 1208: &Curl_ssl_sectransp,
! 1209: #endif
! 1210: #if defined(USE_GNUTLS)
! 1211: &Curl_ssl_gnutls,
! 1212: #endif
! 1213: #if defined(USE_GSKIT)
! 1214: &Curl_ssl_gskit,
! 1215: #endif
! 1216: #if defined(USE_MBEDTLS)
! 1217: &Curl_ssl_mbedtls,
! 1218: #endif
! 1219: #if defined(USE_NSS)
! 1220: &Curl_ssl_nss,
! 1221: #endif
! 1222: #if defined(USE_OPENSSL)
! 1223: &Curl_ssl_openssl,
! 1224: #endif
! 1225: #if defined(USE_SCHANNEL)
! 1226: &Curl_ssl_schannel,
! 1227: #endif
! 1228: #if defined(USE_MESALINK)
! 1229: &Curl_ssl_mesalink,
! 1230: #endif
! 1231: #if defined(USE_BEARSSL)
! 1232: &Curl_ssl_bearssl,
! 1233: #endif
! 1234: NULL
! 1235: };
! 1236:
! 1237: static size_t Curl_multissl_version(char *buffer, size_t size)
! 1238: {
! 1239: static const struct Curl_ssl *selected;
! 1240: static char backends[200];
! 1241: static size_t backends_len;
! 1242: const struct Curl_ssl *current;
! 1243:
! 1244: current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
! 1245:
! 1246: if(current != selected) {
! 1247: char *p = backends;
! 1248: char *end = backends + sizeof(backends);
! 1249: int i;
! 1250:
! 1251: selected = current;
! 1252:
! 1253: backends[0] = '\0';
! 1254:
! 1255: for(i = 0; available_backends[i]; ++i) {
! 1256: char vb[200];
! 1257: bool paren = (selected != available_backends[i]);
! 1258:
! 1259: if(available_backends[i]->version(vb, sizeof(vb))) {
! 1260: p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""),
! 1261: (paren ? "(" : ""), vb, (paren ? ")" : ""));
! 1262: }
! 1263: }
! 1264:
! 1265: backends_len = p - backends;
! 1266: }
! 1267:
! 1268: if(!size)
! 1269: return 0;
! 1270:
! 1271: if(size <= backends_len) {
! 1272: strncpy(buffer, backends, size - 1);
! 1273: buffer[size - 1] = '\0';
! 1274: return size - 1;
! 1275: }
! 1276:
! 1277: strcpy(buffer, backends);
! 1278: return backends_len;
! 1279: }
! 1280:
! 1281: static int multissl_init(const struct Curl_ssl *backend)
! 1282: {
! 1283: const char *env;
! 1284: char *env_tmp;
! 1285:
! 1286: if(Curl_ssl != &Curl_ssl_multi)
! 1287: return 1;
! 1288:
! 1289: if(backend) {
! 1290: Curl_ssl = backend;
! 1291: return 0;
! 1292: }
! 1293:
! 1294: if(!available_backends[0])
! 1295: return 1;
! 1296:
! 1297: env = env_tmp = curl_getenv("CURL_SSL_BACKEND");
! 1298: #ifdef CURL_DEFAULT_SSL_BACKEND
! 1299: if(!env)
! 1300: env = CURL_DEFAULT_SSL_BACKEND;
! 1301: #endif
! 1302: if(env) {
! 1303: int i;
! 1304: for(i = 0; available_backends[i]; i++) {
! 1305: if(strcasecompare(env, available_backends[i]->info.name)) {
! 1306: Curl_ssl = available_backends[i];
! 1307: curl_free(env_tmp);
! 1308: return 0;
! 1309: }
! 1310: }
! 1311: }
! 1312:
! 1313: /* Fall back to first available backend */
! 1314: Curl_ssl = available_backends[0];
! 1315: curl_free(env_tmp);
! 1316: return 0;
! 1317: }
! 1318:
! 1319: CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
! 1320: const curl_ssl_backend ***avail)
! 1321: {
! 1322: int i;
! 1323:
! 1324: if(avail)
! 1325: *avail = (const curl_ssl_backend **)&available_backends;
! 1326:
! 1327: if(Curl_ssl != &Curl_ssl_multi)
! 1328: return id == Curl_ssl->info.id ||
! 1329: (name && strcasecompare(name, Curl_ssl->info.name)) ?
! 1330: CURLSSLSET_OK :
! 1331: #if defined(CURL_WITH_MULTI_SSL)
! 1332: CURLSSLSET_TOO_LATE;
! 1333: #else
! 1334: CURLSSLSET_UNKNOWN_BACKEND;
! 1335: #endif
! 1336:
! 1337: for(i = 0; available_backends[i]; i++) {
! 1338: if(available_backends[i]->info.id == id ||
! 1339: (name && strcasecompare(available_backends[i]->info.name, name))) {
! 1340: multissl_init(available_backends[i]);
! 1341: return CURLSSLSET_OK;
! 1342: }
! 1343: }
! 1344:
! 1345: return CURLSSLSET_UNKNOWN_BACKEND;
! 1346: }
! 1347:
! 1348: #else /* USE_SSL */
! 1349: CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
! 1350: const curl_ssl_backend ***avail)
! 1351: {
! 1352: (void)id;
! 1353: (void)name;
! 1354: (void)avail;
! 1355: return CURLSSLSET_NO_BACKENDS;
! 1356: }
! 1357:
! 1358: #endif /* !USE_SSL */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>