File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vtls / vtls.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>