Annotation of embedaddon/curl/lib/vtls/vtls.c, revision 1.1.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>