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>