Annotation of embedaddon/curl/lib/vtls/nss.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
        !             9:  *
        !            10:  * This software is licensed as described in the file COPYING, which
        !            11:  * you should have received as part of this distribution. The terms
        !            12:  * are also available at https://curl.haxx.se/docs/copyright.html.
        !            13:  *
        !            14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            15:  * copies of the Software, and permit persons to whom the Software is
        !            16:  * furnished to do so, under the terms of the COPYING file.
        !            17:  *
        !            18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            19:  * KIND, either express or implied.
        !            20:  *
        !            21:  ***************************************************************************/
        !            22: 
        !            23: /*
        !            24:  * Source file for all NSS-specific code for the TLS/SSL layer. No code
        !            25:  * but vtls.c should ever call or use these functions.
        !            26:  */
        !            27: 
        !            28: #include "curl_setup.h"
        !            29: 
        !            30: #ifdef USE_NSS
        !            31: 
        !            32: #include "urldata.h"
        !            33: #include "sendf.h"
        !            34: #include "formdata.h" /* for the boundary function */
        !            35: #include "url.h" /* for the ssl config check function */
        !            36: #include "connect.h"
        !            37: #include "strcase.h"
        !            38: #include "select.h"
        !            39: #include "vtls.h"
        !            40: #include "llist.h"
        !            41: #include "multiif.h"
        !            42: #include "curl_printf.h"
        !            43: #include "nssg.h"
        !            44: #include <nspr.h>
        !            45: #include <nss.h>
        !            46: #include <ssl.h>
        !            47: #include <sslerr.h>
        !            48: #include <secerr.h>
        !            49: #include <secmod.h>
        !            50: #include <sslproto.h>
        !            51: #include <prtypes.h>
        !            52: #include <pk11pub.h>
        !            53: #include <prio.h>
        !            54: #include <secitem.h>
        !            55: #include <secport.h>
        !            56: #include <certdb.h>
        !            57: #include <base64.h>
        !            58: #include <cert.h>
        !            59: #include <prerror.h>
        !            60: #include <keyhi.h>         /* for SECKEY_DestroyPublicKey() */
        !            61: #include <private/pprio.h> /* for PR_ImportTCPSocket */
        !            62: 
        !            63: #define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
        !            64: 
        !            65: #if NSSVERNUM >= 0x030f00 /* 3.15.0 */
        !            66: #include <ocsp.h>
        !            67: #endif
        !            68: 
        !            69: #include "strcase.h"
        !            70: #include "warnless.h"
        !            71: #include "x509asn1.h"
        !            72: 
        !            73: /* The last #include files should be: */
        !            74: #include "curl_memory.h"
        !            75: #include "memdebug.h"
        !            76: 
        !            77: #define SSL_DIR "/etc/pki/nssdb"
        !            78: 
        !            79: /* enough to fit the string "PEM Token #[0|1]" */
        !            80: #define SLOTSIZE 13
        !            81: 
        !            82: struct ssl_backend_data {
        !            83:   PRFileDesc *handle;
        !            84:   char *client_nickname;
        !            85:   struct Curl_easy *data;
        !            86:   struct curl_llist obj_list;
        !            87:   PK11GenericObject *obj_clicert;
        !            88: };
        !            89: 
        !            90: static PRLock *nss_initlock = NULL;
        !            91: static PRLock *nss_crllock = NULL;
        !            92: static PRLock *nss_findslot_lock = NULL;
        !            93: static PRLock *nss_trustload_lock = NULL;
        !            94: static struct curl_llist nss_crl_list;
        !            95: static NSSInitContext *nss_context = NULL;
        !            96: static volatile int initialized = 0;
        !            97: 
        !            98: /* type used to wrap pointers as list nodes */
        !            99: struct ptr_list_wrap {
        !           100:   void *ptr;
        !           101:   struct curl_llist_element node;
        !           102: };
        !           103: 
        !           104: typedef struct {
        !           105:   const char *name;
        !           106:   int num;
        !           107: } cipher_s;
        !           108: 
        !           109: #define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do {  \
        !           110:   CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++);                 \
        !           111:   ptr->type = (_type);                                      \
        !           112:   ptr->pValue = (_val);                                     \
        !           113:   ptr->ulValueLen = (_len);                                 \
        !           114: } while(0)
        !           115: 
        !           116: #define CERT_NewTempCertificate __CERT_NewTempCertificate
        !           117: 
        !           118: #define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
        !           119: static const cipher_s cipherlist[] = {
        !           120:   /* SSL2 cipher suites */
        !           121:   {"rc4",                        SSL_EN_RC4_128_WITH_MD5},
        !           122:   {"rc4-md5",                    SSL_EN_RC4_128_WITH_MD5},
        !           123:   {"rc4export",                  SSL_EN_RC4_128_EXPORT40_WITH_MD5},
        !           124:   {"rc2",                        SSL_EN_RC2_128_CBC_WITH_MD5},
        !           125:   {"rc2export",                  SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
        !           126:   {"des",                        SSL_EN_DES_64_CBC_WITH_MD5},
        !           127:   {"desede3",                    SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
        !           128:   /* SSL3/TLS cipher suites */
        !           129:   {"rsa_rc4_128_md5",            SSL_RSA_WITH_RC4_128_MD5},
        !           130:   {"rsa_rc4_128_sha",            SSL_RSA_WITH_RC4_128_SHA},
        !           131:   {"rsa_3des_sha",               SSL_RSA_WITH_3DES_EDE_CBC_SHA},
        !           132:   {"rsa_des_sha",                SSL_RSA_WITH_DES_CBC_SHA},
        !           133:   {"rsa_rc4_40_md5",             SSL_RSA_EXPORT_WITH_RC4_40_MD5},
        !           134:   {"rsa_rc2_40_md5",             SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
        !           135:   {"rsa_null_md5",               SSL_RSA_WITH_NULL_MD5},
        !           136:   {"rsa_null_sha",               SSL_RSA_WITH_NULL_SHA},
        !           137:   {"fips_3des_sha",              SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
        !           138:   {"fips_des_sha",               SSL_RSA_FIPS_WITH_DES_CBC_SHA},
        !           139:   {"fortezza",                   SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
        !           140:   {"fortezza_rc4_128_sha",       SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
        !           141:   {"fortezza_null",              SSL_FORTEZZA_DMS_WITH_NULL_SHA},
        !           142:   /* TLS 1.0: Exportable 56-bit Cipher Suites. */
        !           143:   {"rsa_des_56_sha",             TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
        !           144:   {"rsa_rc4_56_sha",             TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
        !           145:   /* AES ciphers. */
        !           146:   {"dhe_dss_aes_128_cbc_sha",    TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
        !           147:   {"dhe_dss_aes_256_cbc_sha",    TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
        !           148:   {"dhe_rsa_aes_128_cbc_sha",    TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
        !           149:   {"dhe_rsa_aes_256_cbc_sha",    TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
        !           150:   {"rsa_aes_128_sha",            TLS_RSA_WITH_AES_128_CBC_SHA},
        !           151:   {"rsa_aes_256_sha",            TLS_RSA_WITH_AES_256_CBC_SHA},
        !           152:   /* ECC ciphers. */
        !           153:   {"ecdh_ecdsa_null_sha",        TLS_ECDH_ECDSA_WITH_NULL_SHA},
        !           154:   {"ecdh_ecdsa_rc4_128_sha",     TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
        !           155:   {"ecdh_ecdsa_3des_sha",        TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
        !           156:   {"ecdh_ecdsa_aes_128_sha",     TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
        !           157:   {"ecdh_ecdsa_aes_256_sha",     TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
        !           158:   {"ecdhe_ecdsa_null_sha",       TLS_ECDHE_ECDSA_WITH_NULL_SHA},
        !           159:   {"ecdhe_ecdsa_rc4_128_sha",    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
        !           160:   {"ecdhe_ecdsa_3des_sha",       TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
        !           161:   {"ecdhe_ecdsa_aes_128_sha",    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
        !           162:   {"ecdhe_ecdsa_aes_256_sha",    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
        !           163:   {"ecdh_rsa_null_sha",          TLS_ECDH_RSA_WITH_NULL_SHA},
        !           164:   {"ecdh_rsa_128_sha",           TLS_ECDH_RSA_WITH_RC4_128_SHA},
        !           165:   {"ecdh_rsa_3des_sha",          TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
        !           166:   {"ecdh_rsa_aes_128_sha",       TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
        !           167:   {"ecdh_rsa_aes_256_sha",       TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
        !           168:   {"ecdhe_rsa_null",             TLS_ECDHE_RSA_WITH_NULL_SHA},
        !           169:   {"ecdhe_rsa_rc4_128_sha",      TLS_ECDHE_RSA_WITH_RC4_128_SHA},
        !           170:   {"ecdhe_rsa_3des_sha",         TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
        !           171:   {"ecdhe_rsa_aes_128_sha",      TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
        !           172:   {"ecdhe_rsa_aes_256_sha",      TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
        !           173:   {"ecdh_anon_null_sha",         TLS_ECDH_anon_WITH_NULL_SHA},
        !           174:   {"ecdh_anon_rc4_128sha",       TLS_ECDH_anon_WITH_RC4_128_SHA},
        !           175:   {"ecdh_anon_3des_sha",         TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
        !           176:   {"ecdh_anon_aes_128_sha",      TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
        !           177:   {"ecdh_anon_aes_256_sha",      TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
        !           178: #ifdef TLS_RSA_WITH_NULL_SHA256
        !           179:   /* new HMAC-SHA256 cipher suites specified in RFC */
        !           180:   {"rsa_null_sha_256",                TLS_RSA_WITH_NULL_SHA256},
        !           181:   {"rsa_aes_128_cbc_sha_256",         TLS_RSA_WITH_AES_128_CBC_SHA256},
        !           182:   {"rsa_aes_256_cbc_sha_256",         TLS_RSA_WITH_AES_256_CBC_SHA256},
        !           183:   {"dhe_rsa_aes_128_cbc_sha_256",     TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
        !           184:   {"dhe_rsa_aes_256_cbc_sha_256",     TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
        !           185:   {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
        !           186:   {"ecdhe_rsa_aes_128_cbc_sha_256",   TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
        !           187: #endif
        !           188: #ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
        !           189:   /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
        !           190:   {"rsa_aes_128_gcm_sha_256",         TLS_RSA_WITH_AES_128_GCM_SHA256},
        !           191:   {"dhe_rsa_aes_128_gcm_sha_256",     TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
        !           192:   {"dhe_dss_aes_128_gcm_sha_256",     TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
        !           193:   {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
        !           194:   {"ecdh_ecdsa_aes_128_gcm_sha_256",  TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
        !           195:   {"ecdhe_rsa_aes_128_gcm_sha_256",   TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
        !           196:   {"ecdh_rsa_aes_128_gcm_sha_256",    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
        !           197: #endif
        !           198: #ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        !           199:   /* cipher suites using SHA384 */
        !           200:   {"rsa_aes_256_gcm_sha_384",         TLS_RSA_WITH_AES_256_GCM_SHA384},
        !           201:   {"dhe_rsa_aes_256_gcm_sha_384",     TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
        !           202:   {"dhe_dss_aes_256_gcm_sha_384",     TLS_DHE_DSS_WITH_AES_256_GCM_SHA384},
        !           203:   {"ecdhe_ecdsa_aes_256_sha_384",     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
        !           204:   {"ecdhe_rsa_aes_256_sha_384",       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
        !           205:   {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
        !           206:   {"ecdhe_rsa_aes_256_gcm_sha_384",   TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
        !           207: #endif
        !           208: #ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        !           209:   /* chacha20-poly1305 cipher suites */
        !           210:  {"ecdhe_rsa_chacha20_poly1305_sha_256",
        !           211:      TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
        !           212:  {"ecdhe_ecdsa_chacha20_poly1305_sha_256",
        !           213:      TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
        !           214:  {"dhe_rsa_chacha20_poly1305_sha_256",
        !           215:      TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
        !           216: #endif
        !           217: #ifdef TLS_AES_256_GCM_SHA384
        !           218:  {"aes_128_gcm_sha_256",              TLS_AES_128_GCM_SHA256},
        !           219:  {"aes_256_gcm_sha_384",              TLS_AES_256_GCM_SHA384},
        !           220:  {"chacha20_poly1305_sha_256",        TLS_CHACHA20_POLY1305_SHA256},
        !           221: #endif
        !           222: };
        !           223: 
        !           224: #if defined(WIN32)
        !           225: static const char *pem_library = "nsspem.dll";
        !           226: static const char *trust_library = "nssckbi.dll";
        !           227: #elif defined(__APPLE__)
        !           228: static const char *pem_library = "libnsspem.dylib";
        !           229: static const char *trust_library = "libnssckbi.dylib";
        !           230: #else
        !           231: static const char *pem_library = "libnsspem.so";
        !           232: static const char *trust_library = "libnssckbi.so";
        !           233: #endif
        !           234: 
        !           235: static SECMODModule *pem_module = NULL;
        !           236: static SECMODModule *trust_module = NULL;
        !           237: 
        !           238: /* NSPR I/O layer we use to detect blocking direction during SSL handshake */
        !           239: static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
        !           240: static PRIOMethods nspr_io_methods;
        !           241: 
        !           242: static const char *nss_error_to_name(PRErrorCode code)
        !           243: {
        !           244:   const char *name = PR_ErrorToName(code);
        !           245:   if(name)
        !           246:     return name;
        !           247: 
        !           248:   return "unknown error";
        !           249: }
        !           250: 
        !           251: static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
        !           252: {
        !           253:   failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
        !           254: }
        !           255: 
        !           256: static char *nss_sslver_to_name(PRUint16 nssver)
        !           257: {
        !           258:   switch(nssver) {
        !           259:   case SSL_LIBRARY_VERSION_2:
        !           260:     return strdup("SSLv2");
        !           261:   case SSL_LIBRARY_VERSION_3_0:
        !           262:     return strdup("SSLv3");
        !           263:   case SSL_LIBRARY_VERSION_TLS_1_0:
        !           264:     return strdup("TLSv1.0");
        !           265: #ifdef SSL_LIBRARY_VERSION_TLS_1_1
        !           266:   case SSL_LIBRARY_VERSION_TLS_1_1:
        !           267:     return strdup("TLSv1.1");
        !           268: #endif
        !           269: #ifdef SSL_LIBRARY_VERSION_TLS_1_2
        !           270:   case SSL_LIBRARY_VERSION_TLS_1_2:
        !           271:     return strdup("TLSv1.2");
        !           272: #endif
        !           273: #ifdef SSL_LIBRARY_VERSION_TLS_1_3
        !           274:   case SSL_LIBRARY_VERSION_TLS_1_3:
        !           275:     return strdup("TLSv1.3");
        !           276: #endif
        !           277:   default:
        !           278:     return curl_maprintf("0x%04x", nssver);
        !           279:   }
        !           280: }
        !           281: 
        !           282: static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
        !           283:                              char *cipher_list)
        !           284: {
        !           285:   unsigned int i;
        !           286:   PRBool cipher_state[NUM_OF_CIPHERS];
        !           287:   PRBool found;
        !           288:   char *cipher;
        !           289: 
        !           290:   /* use accessors to avoid dynamic linking issues after an update of NSS */
        !           291:   const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
        !           292:   const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers();
        !           293:   if(!implemented_ciphers)
        !           294:     return SECFailure;
        !           295: 
        !           296:   /* First disable all ciphers. This uses a different max value in case
        !           297:    * NSS adds more ciphers later we don't want them available by
        !           298:    * accident
        !           299:    */
        !           300:   for(i = 0; i < num_implemented_ciphers; i++) {
        !           301:     SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
        !           302:   }
        !           303: 
        !           304:   /* Set every entry in our list to false */
        !           305:   for(i = 0; i < NUM_OF_CIPHERS; i++) {
        !           306:     cipher_state[i] = PR_FALSE;
        !           307:   }
        !           308: 
        !           309:   cipher = cipher_list;
        !           310: 
        !           311:   while(cipher_list && (cipher_list[0])) {
        !           312:     while((*cipher) && (ISSPACE(*cipher)))
        !           313:       ++cipher;
        !           314: 
        !           315:     cipher_list = strchr(cipher, ',');
        !           316:     if(cipher_list) {
        !           317:       *cipher_list++ = '\0';
        !           318:     }
        !           319: 
        !           320:     found = PR_FALSE;
        !           321: 
        !           322:     for(i = 0; i<NUM_OF_CIPHERS; i++) {
        !           323:       if(strcasecompare(cipher, cipherlist[i].name)) {
        !           324:         cipher_state[i] = PR_TRUE;
        !           325:         found = PR_TRUE;
        !           326:         break;
        !           327:       }
        !           328:     }
        !           329: 
        !           330:     if(found == PR_FALSE) {
        !           331:       failf(data, "Unknown cipher in list: %s", cipher);
        !           332:       return SECFailure;
        !           333:     }
        !           334: 
        !           335:     if(cipher_list) {
        !           336:       cipher = cipher_list;
        !           337:     }
        !           338:   }
        !           339: 
        !           340:   /* Finally actually enable the selected ciphers */
        !           341:   for(i = 0; i<NUM_OF_CIPHERS; i++) {
        !           342:     if(!cipher_state[i])
        !           343:       continue;
        !           344: 
        !           345:     if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
        !           346:       failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
        !           347:       return SECFailure;
        !           348:     }
        !           349:   }
        !           350: 
        !           351:   return SECSuccess;
        !           352: }
        !           353: 
        !           354: /*
        !           355:  * Return true if at least one cipher-suite is enabled. Used to determine
        !           356:  * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
        !           357:  */
        !           358: static bool any_cipher_enabled(void)
        !           359: {
        !           360:   unsigned int i;
        !           361: 
        !           362:   for(i = 0; i<NUM_OF_CIPHERS; i++) {
        !           363:     PRInt32 policy = 0;
        !           364:     SSL_CipherPolicyGet(cipherlist[i].num, &policy);
        !           365:     if(policy)
        !           366:       return TRUE;
        !           367:   }
        !           368: 
        !           369:   return FALSE;
        !           370: }
        !           371: 
        !           372: /*
        !           373:  * Determine whether the nickname passed in is a filename that needs to
        !           374:  * be loaded as a PEM or a regular NSS nickname.
        !           375:  *
        !           376:  * returns 1 for a file
        !           377:  * returns 0 for not a file (NSS nickname)
        !           378:  */
        !           379: static int is_file(const char *filename)
        !           380: {
        !           381:   struct_stat st;
        !           382: 
        !           383:   if(filename == NULL)
        !           384:     return 0;
        !           385: 
        !           386:   if(stat(filename, &st) == 0)
        !           387:     if(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
        !           388:       return 1;
        !           389: 
        !           390:   return 0;
        !           391: }
        !           392: 
        !           393: /* Check if the given string is filename or nickname of a certificate.  If the
        !           394:  * given string is recognized as filename, return NULL.  If the given string is
        !           395:  * recognized as nickname, return a duplicated string.  The returned string
        !           396:  * should be later deallocated using free().  If the OOM failure occurs, we
        !           397:  * return NULL, too.
        !           398:  */
        !           399: static char *dup_nickname(struct Curl_easy *data, const char *str)
        !           400: {
        !           401:   const char *n;
        !           402: 
        !           403:   if(!is_file(str))
        !           404:     /* no such file exists, use the string as nickname */
        !           405:     return strdup(str);
        !           406: 
        !           407:   /* search the first slash; we require at least one slash in a file name */
        !           408:   n = strchr(str, '/');
        !           409:   if(!n) {
        !           410:     infof(data, "warning: certificate file name \"%s\" handled as nickname; "
        !           411:           "please use \"./%s\" to force file name\n", str, str);
        !           412:     return strdup(str);
        !           413:   }
        !           414: 
        !           415:   /* we'll use the PEM reader to read the certificate from file */
        !           416:   return NULL;
        !           417: }
        !           418: 
        !           419: /* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition
        !           420:  * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN.  For more
        !           421:  * details, go to <https://bugzilla.mozilla.org/1297397>.
        !           422:  */
        !           423: static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
        !           424: {
        !           425:   PK11SlotInfo *slot;
        !           426:   PR_Lock(nss_findslot_lock);
        !           427:   slot = PK11_FindSlotByName(slot_name);
        !           428:   PR_Unlock(nss_findslot_lock);
        !           429:   return slot;
        !           430: }
        !           431: 
        !           432: /* wrap 'ptr' as list node and tail-insert into 'list' */
        !           433: static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
        !           434: {
        !           435:   struct ptr_list_wrap *wrap = malloc(sizeof(*wrap));
        !           436:   if(!wrap)
        !           437:     return CURLE_OUT_OF_MEMORY;
        !           438: 
        !           439:   wrap->ptr = ptr;
        !           440:   Curl_llist_insert_next(list, list->tail, wrap, &wrap->node);
        !           441:   return CURLE_OK;
        !           442: }
        !           443: 
        !           444: /* Call PK11_CreateGenericObject() with the given obj_class and filename.  If
        !           445:  * the call succeeds, append the object handle to the list of objects so that
        !           446:  * the object can be destroyed in Curl_nss_close(). */
        !           447: static CURLcode nss_create_object(struct ssl_connect_data *connssl,
        !           448:                                   CK_OBJECT_CLASS obj_class,
        !           449:                                   const char *filename, bool cacert)
        !           450: {
        !           451:   PK11SlotInfo *slot;
        !           452:   PK11GenericObject *obj;
        !           453:   CK_BBOOL cktrue = CK_TRUE;
        !           454:   CK_BBOOL ckfalse = CK_FALSE;
        !           455:   CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
        !           456:   int attr_cnt = 0;
        !           457:   CURLcode result = (cacert)
        !           458:     ? CURLE_SSL_CACERT_BADFILE
        !           459:     : CURLE_SSL_CERTPROBLEM;
        !           460: 
        !           461:   const int slot_id = (cacert) ? 0 : 1;
        !           462:   char *slot_name = aprintf("PEM Token #%d", slot_id);
        !           463:   struct ssl_backend_data *backend = connssl->backend;
        !           464:   if(!slot_name)
        !           465:     return CURLE_OUT_OF_MEMORY;
        !           466: 
        !           467:   slot = nss_find_slot_by_name(slot_name);
        !           468:   free(slot_name);
        !           469:   if(!slot)
        !           470:     return result;
        !           471: 
        !           472:   PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
        !           473:   PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
        !           474:   PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
        !           475:                 (CK_ULONG)strlen(filename) + 1);
        !           476: 
        !           477:   if(CKO_CERTIFICATE == obj_class) {
        !           478:     CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
        !           479:     PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
        !           480:   }
        !           481: 
        !           482:   /* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because
        !           483:    * PK11_DestroyGenericObject() does not release resources allocated by
        !           484:    * PK11_CreateGenericObject() early enough.  */
        !           485:   obj =
        !           486: #ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT
        !           487:     PK11_CreateManagedGenericObject
        !           488: #else
        !           489:     PK11_CreateGenericObject
        !           490: #endif
        !           491:     (slot, attrs, attr_cnt, PR_FALSE);
        !           492: 
        !           493:   PK11_FreeSlot(slot);
        !           494:   if(!obj)
        !           495:     return result;
        !           496: 
        !           497:   if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) {
        !           498:     PK11_DestroyGenericObject(obj);
        !           499:     return CURLE_OUT_OF_MEMORY;
        !           500:   }
        !           501: 
        !           502:   if(!cacert && CKO_CERTIFICATE == obj_class)
        !           503:     /* store reference to a client certificate */
        !           504:     backend->obj_clicert = obj;
        !           505: 
        !           506:   return CURLE_OK;
        !           507: }
        !           508: 
        !           509: /* Destroy the NSS object whose handle is given by ptr.  This function is
        !           510:  * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
        !           511:  * NSS objects in Curl_nss_close() */
        !           512: static void nss_destroy_object(void *user, void *ptr)
        !           513: {
        !           514:   struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
        !           515:   PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr;
        !           516:   (void) user;
        !           517:   PK11_DestroyGenericObject(obj);
        !           518:   free(wrap);
        !           519: }
        !           520: 
        !           521: /* same as nss_destroy_object() but for CRL items */
        !           522: static void nss_destroy_crl_item(void *user, void *ptr)
        !           523: {
        !           524:   struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
        !           525:   SECItem *crl_der = (SECItem *) wrap->ptr;
        !           526:   (void) user;
        !           527:   SECITEM_FreeItem(crl_der, PR_TRUE);
        !           528:   free(wrap);
        !           529: }
        !           530: 
        !           531: static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
        !           532:                               const char *filename, PRBool cacert)
        !           533: {
        !           534:   CURLcode result = (cacert)
        !           535:     ? CURLE_SSL_CACERT_BADFILE
        !           536:     : CURLE_SSL_CERTPROBLEM;
        !           537: 
        !           538:   /* libnsspem.so leaks memory if the requested file does not exist.  For more
        !           539:    * details, go to <https://bugzilla.redhat.com/734760>. */
        !           540:   if(is_file(filename))
        !           541:     result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
        !           542: 
        !           543:   if(!result && !cacert) {
        !           544:     /* we have successfully loaded a client certificate */
        !           545:     CERTCertificate *cert;
        !           546:     char *nickname = NULL;
        !           547:     char *n = strrchr(filename, '/');
        !           548:     if(n)
        !           549:       n++;
        !           550: 
        !           551:     /* The following undocumented magic helps to avoid a SIGSEGV on call
        !           552:      * of PK11_ReadRawAttribute() from SelectClientCert() when using an
        !           553:      * immature version of libnsspem.so.  For more details, go to
        !           554:      * <https://bugzilla.redhat.com/733685>. */
        !           555:     nickname = aprintf("PEM Token #1:%s", n);
        !           556:     if(nickname) {
        !           557:       cert = PK11_FindCertFromNickname(nickname, NULL);
        !           558:       if(cert)
        !           559:         CERT_DestroyCertificate(cert);
        !           560: 
        !           561:       free(nickname);
        !           562:     }
        !           563:   }
        !           564: 
        !           565:   return result;
        !           566: }
        !           567: 
        !           568: /* add given CRL to cache if it is not already there */
        !           569: static CURLcode nss_cache_crl(SECItem *crl_der)
        !           570: {
        !           571:   CERTCertDBHandle *db = CERT_GetDefaultCertDB();
        !           572:   CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
        !           573:   if(crl) {
        !           574:     /* CRL already cached */
        !           575:     SEC_DestroyCrl(crl);
        !           576:     SECITEM_FreeItem(crl_der, PR_TRUE);
        !           577:     return CURLE_OK;
        !           578:   }
        !           579: 
        !           580:   /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
        !           581:   PR_Lock(nss_crllock);
        !           582: 
        !           583:   if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
        !           584:     /* unable to cache CRL */
        !           585:     SECITEM_FreeItem(crl_der, PR_TRUE);
        !           586:     PR_Unlock(nss_crllock);
        !           587:     return CURLE_SSL_CRL_BADFILE;
        !           588:   }
        !           589: 
        !           590:   /* store the CRL item so that we can free it in Curl_nss_cleanup() */
        !           591:   if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
        !           592:     if(SECSuccess == CERT_UncacheCRL(db, crl_der))
        !           593:       SECITEM_FreeItem(crl_der, PR_TRUE);
        !           594:     PR_Unlock(nss_crllock);
        !           595:     return CURLE_OUT_OF_MEMORY;
        !           596:   }
        !           597: 
        !           598:   /* we need to clear session cache, so that the CRL could take effect */
        !           599:   SSL_ClearSessionCache();
        !           600:   PR_Unlock(nss_crllock);
        !           601:   return CURLE_OK;
        !           602: }
        !           603: 
        !           604: static CURLcode nss_load_crl(const char *crlfilename)
        !           605: {
        !           606:   PRFileDesc *infile;
        !           607:   PRFileInfo  info;
        !           608:   SECItem filedata = { 0, NULL, 0 };
        !           609:   SECItem *crl_der = NULL;
        !           610:   char *body;
        !           611: 
        !           612:   infile = PR_Open(crlfilename, PR_RDONLY, 0);
        !           613:   if(!infile)
        !           614:     return CURLE_SSL_CRL_BADFILE;
        !           615: 
        !           616:   if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
        !           617:     goto fail;
        !           618: 
        !           619:   if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
        !           620:     goto fail;
        !           621: 
        !           622:   if(info.size != PR_Read(infile, filedata.data, info.size))
        !           623:     goto fail;
        !           624: 
        !           625:   crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
        !           626:   if(!crl_der)
        !           627:     goto fail;
        !           628: 
        !           629:   /* place a trailing zero right after the visible data */
        !           630:   body = (char *)filedata.data;
        !           631:   body[--filedata.len] = '\0';
        !           632: 
        !           633:   body = strstr(body, "-----BEGIN");
        !           634:   if(body) {
        !           635:     /* assume ASCII */
        !           636:     char *trailer;
        !           637:     char *begin = PORT_Strchr(body, '\n');
        !           638:     if(!begin)
        !           639:       begin = PORT_Strchr(body, '\r');
        !           640:     if(!begin)
        !           641:       goto fail;
        !           642: 
        !           643:     trailer = strstr(++begin, "-----END");
        !           644:     if(!trailer)
        !           645:       goto fail;
        !           646: 
        !           647:     /* retrieve DER from ASCII */
        !           648:     *trailer = '\0';
        !           649:     if(ATOB_ConvertAsciiToItem(crl_der, begin))
        !           650:       goto fail;
        !           651: 
        !           652:     SECITEM_FreeItem(&filedata, PR_FALSE);
        !           653:   }
        !           654:   else
        !           655:     /* assume DER */
        !           656:     *crl_der = filedata;
        !           657: 
        !           658:   PR_Close(infile);
        !           659:   return nss_cache_crl(crl_der);
        !           660: 
        !           661: fail:
        !           662:   PR_Close(infile);
        !           663:   SECITEM_FreeItem(crl_der, PR_TRUE);
        !           664:   SECITEM_FreeItem(&filedata, PR_FALSE);
        !           665:   return CURLE_SSL_CRL_BADFILE;
        !           666: }
        !           667: 
        !           668: static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
        !           669:                              char *key_file)
        !           670: {
        !           671:   PK11SlotInfo *slot, *tmp;
        !           672:   SECStatus status;
        !           673:   CURLcode result;
        !           674:   struct ssl_connect_data *ssl = conn->ssl;
        !           675:   struct Curl_easy *data = conn->data;
        !           676: 
        !           677:   (void)sockindex; /* unused */
        !           678: 
        !           679:   result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
        !           680:   if(result) {
        !           681:     PR_SetError(SEC_ERROR_BAD_KEY, 0);
        !           682:     return result;
        !           683:   }
        !           684: 
        !           685:   slot = nss_find_slot_by_name("PEM Token #1");
        !           686:   if(!slot)
        !           687:     return CURLE_SSL_CERTPROBLEM;
        !           688: 
        !           689:   /* This will force the token to be seen as re-inserted */
        !           690:   tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
        !           691:   if(tmp)
        !           692:     PK11_FreeSlot(tmp);
        !           693:   if(!PK11_IsPresent(slot)) {
        !           694:     PK11_FreeSlot(slot);
        !           695:     return CURLE_SSL_CERTPROBLEM;
        !           696:   }
        !           697: 
        !           698:   status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
        !           699:   PK11_FreeSlot(slot);
        !           700: 
        !           701:   return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
        !           702: }
        !           703: 
        !           704: static int display_error(struct connectdata *conn, PRInt32 err,
        !           705:                          const char *filename)
        !           706: {
        !           707:   switch(err) {
        !           708:   case SEC_ERROR_BAD_PASSWORD:
        !           709:     failf(conn->data, "Unable to load client key: Incorrect password");
        !           710:     return 1;
        !           711:   case SEC_ERROR_UNKNOWN_CERT:
        !           712:     failf(conn->data, "Unable to load certificate %s", filename);
        !           713:     return 1;
        !           714:   default:
        !           715:     break;
        !           716:   }
        !           717:   return 0; /* The caller will print a generic error */
        !           718: }
        !           719: 
        !           720: static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
        !           721:                            char *cert_file, char *key_file)
        !           722: {
        !           723:   struct Curl_easy *data = conn->data;
        !           724:   CURLcode result;
        !           725: 
        !           726:   if(cert_file) {
        !           727:     result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
        !           728:     if(result) {
        !           729:       const PRErrorCode err = PR_GetError();
        !           730:       if(!display_error(conn, err, cert_file)) {
        !           731:         const char *err_name = nss_error_to_name(err);
        !           732:         failf(data, "unable to load client cert: %d (%s)", err, err_name);
        !           733:       }
        !           734: 
        !           735:       return result;
        !           736:     }
        !           737:   }
        !           738: 
        !           739:   if(key_file || (is_file(cert_file))) {
        !           740:     if(key_file)
        !           741:       result = nss_load_key(conn, sockindex, key_file);
        !           742:     else
        !           743:       /* In case the cert file also has the key */
        !           744:       result = nss_load_key(conn, sockindex, cert_file);
        !           745:     if(result) {
        !           746:       const PRErrorCode err = PR_GetError();
        !           747:       if(!display_error(conn, err, key_file)) {
        !           748:         const char *err_name = nss_error_to_name(err);
        !           749:         failf(data, "unable to load client key: %d (%s)", err, err_name);
        !           750:       }
        !           751: 
        !           752:       return result;
        !           753:     }
        !           754:   }
        !           755: 
        !           756:   return CURLE_OK;
        !           757: }
        !           758: 
        !           759: static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
        !           760: {
        !           761:   (void)slot; /* unused */
        !           762: 
        !           763:   if(retry || NULL == arg)
        !           764:     return NULL;
        !           765:   else
        !           766:     return (char *)PORT_Strdup((char *)arg);
        !           767: }
        !           768: 
        !           769: /* bypass the default SSL_AuthCertificate() hook in case we do not want to
        !           770:  * verify peer */
        !           771: static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
        !           772:                                     PRBool isServer)
        !           773: {
        !           774:   struct connectdata *conn = (struct connectdata *)arg;
        !           775: 
        !           776: #ifdef SSL_ENABLE_OCSP_STAPLING
        !           777:   if(SSL_CONN_CONFIG(verifystatus)) {
        !           778:     SECStatus cacheResult;
        !           779: 
        !           780:     const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
        !           781:     if(!csa) {
        !           782:       failf(conn->data, "Invalid OCSP response");
        !           783:       return SECFailure;
        !           784:     }
        !           785: 
        !           786:     if(csa->len == 0) {
        !           787:       failf(conn->data, "No OCSP response received");
        !           788:       return SECFailure;
        !           789:     }
        !           790: 
        !           791:     cacheResult = CERT_CacheOCSPResponseFromSideChannel(
        !           792:       CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd),
        !           793:       PR_Now(), &csa->items[0], arg
        !           794:     );
        !           795: 
        !           796:     if(cacheResult != SECSuccess) {
        !           797:       failf(conn->data, "Invalid OCSP response");
        !           798:       return cacheResult;
        !           799:     }
        !           800:   }
        !           801: #endif
        !           802: 
        !           803:   if(!SSL_CONN_CONFIG(verifypeer)) {
        !           804:     infof(conn->data, "skipping SSL peer certificate verification\n");
        !           805:     return SECSuccess;
        !           806:   }
        !           807: 
        !           808:   return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
        !           809: }
        !           810: 
        !           811: /**
        !           812:  * Inform the application that the handshake is complete.
        !           813:  */
        !           814: static void HandshakeCallback(PRFileDesc *sock, void *arg)
        !           815: {
        !           816:   struct connectdata *conn = (struct connectdata*) arg;
        !           817:   unsigned int buflenmax = 50;
        !           818:   unsigned char buf[50];
        !           819:   unsigned int buflen;
        !           820:   SSLNextProtoState state;
        !           821: 
        !           822:   if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) {
        !           823:     return;
        !           824:   }
        !           825: 
        !           826:   if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
        !           827: 
        !           828:     switch(state) {
        !           829: #if NSSVERNUM >= 0x031a00 /* 3.26.0 */
        !           830:     /* used by NSS internally to implement 0-RTT */
        !           831:     case SSL_NEXT_PROTO_EARLY_VALUE:
        !           832:       /* fall through! */
        !           833: #endif
        !           834:     case SSL_NEXT_PROTO_NO_SUPPORT:
        !           835:     case SSL_NEXT_PROTO_NO_OVERLAP:
        !           836:       infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n");
        !           837:       return;
        !           838: #ifdef SSL_ENABLE_ALPN
        !           839:     case SSL_NEXT_PROTO_SELECTED:
        !           840:       infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf);
        !           841:       break;
        !           842: #endif
        !           843:     case SSL_NEXT_PROTO_NEGOTIATED:
        !           844:       infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf);
        !           845:       break;
        !           846:     }
        !           847: 
        !           848: #ifdef USE_NGHTTP2
        !           849:     if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
        !           850:        !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) {
        !           851:       conn->negnpn = CURL_HTTP_VERSION_2;
        !           852:     }
        !           853:     else
        !           854: #endif
        !           855:     if(buflen == ALPN_HTTP_1_1_LENGTH &&
        !           856:        !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
        !           857:       conn->negnpn = CURL_HTTP_VERSION_1_1;
        !           858:     }
        !           859:     Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
        !           860:                         BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
        !           861:   }
        !           862: }
        !           863: 
        !           864: #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
        !           865: static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
        !           866:                                        PRBool *canFalseStart)
        !           867: {
        !           868:   struct connectdata *conn = client_data;
        !           869:   struct Curl_easy *data = conn->data;
        !           870: 
        !           871:   SSLChannelInfo channelInfo;
        !           872:   SSLCipherSuiteInfo cipherInfo;
        !           873: 
        !           874:   SECStatus rv;
        !           875:   PRBool negotiatedExtension;
        !           876: 
        !           877:   *canFalseStart = PR_FALSE;
        !           878: 
        !           879:   if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
        !           880:     return SECFailure;
        !           881: 
        !           882:   if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
        !           883:                             sizeof(cipherInfo)) != SECSuccess)
        !           884:     return SECFailure;
        !           885: 
        !           886:   /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
        !           887:    * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
        !           888:    */
        !           889:   if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
        !           890:     goto end;
        !           891: 
        !           892:   /* Only allow ECDHE key exchange algorithm.
        !           893:    * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
        !           894:   if(cipherInfo.keaType != ssl_kea_ecdh)
        !           895:     goto end;
        !           896: 
        !           897:   /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
        !           898:    * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
        !           899:    * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
        !           900:   if(cipherInfo.symCipher != ssl_calg_aes_gcm)
        !           901:     goto end;
        !           902: 
        !           903:   /* Enforce ALPN or NPN to do False Start, as an indicator of server
        !           904:    * compatibility. */
        !           905:   rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
        !           906:                                         &negotiatedExtension);
        !           907:   if(rv != SECSuccess || !negotiatedExtension) {
        !           908:     rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
        !           909:                                           &negotiatedExtension);
        !           910:   }
        !           911: 
        !           912:   if(rv != SECSuccess || !negotiatedExtension)
        !           913:     goto end;
        !           914: 
        !           915:   *canFalseStart = PR_TRUE;
        !           916: 
        !           917:   infof(data, "Trying TLS False Start\n");
        !           918: 
        !           919: end:
        !           920:   return SECSuccess;
        !           921: }
        !           922: #endif
        !           923: 
        !           924: static void display_cert_info(struct Curl_easy *data,
        !           925:                               CERTCertificate *cert)
        !           926: {
        !           927:   char *subject, *issuer, *common_name;
        !           928:   PRExplodedTime printableTime;
        !           929:   char timeString[256];
        !           930:   PRTime notBefore, notAfter;
        !           931: 
        !           932:   subject = CERT_NameToAscii(&cert->subject);
        !           933:   issuer = CERT_NameToAscii(&cert->issuer);
        !           934:   common_name = CERT_GetCommonName(&cert->subject);
        !           935:   infof(data, "\tsubject: %s\n", subject);
        !           936: 
        !           937:   CERT_GetCertTimes(cert, &notBefore, &notAfter);
        !           938:   PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
        !           939:   PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
        !           940:   infof(data, "\tstart date: %s\n", timeString);
        !           941:   PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
        !           942:   PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
        !           943:   infof(data, "\texpire date: %s\n", timeString);
        !           944:   infof(data, "\tcommon name: %s\n", common_name);
        !           945:   infof(data, "\tissuer: %s\n", issuer);
        !           946: 
        !           947:   PR_Free(subject);
        !           948:   PR_Free(issuer);
        !           949:   PR_Free(common_name);
        !           950: }
        !           951: 
        !           952: static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
        !           953: {
        !           954:   CURLcode result = CURLE_OK;
        !           955:   SSLChannelInfo channel;
        !           956:   SSLCipherSuiteInfo suite;
        !           957:   CERTCertificate *cert;
        !           958:   CERTCertificate *cert2;
        !           959:   CERTCertificate *cert3;
        !           960:   PRTime now;
        !           961:   int i;
        !           962: 
        !           963:   if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) ==
        !           964:      SECSuccess && channel.length == sizeof(channel) &&
        !           965:      channel.cipherSuite) {
        !           966:     if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
        !           967:                               &suite, sizeof(suite)) == SECSuccess) {
        !           968:       infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
        !           969:     }
        !           970:   }
        !           971: 
        !           972:   cert = SSL_PeerCertificate(sock);
        !           973:   if(cert) {
        !           974:     infof(conn->data, "Server certificate:\n");
        !           975: 
        !           976:     if(!conn->data->set.ssl.certinfo) {
        !           977:       display_cert_info(conn->data, cert);
        !           978:       CERT_DestroyCertificate(cert);
        !           979:     }
        !           980:     else {
        !           981:       /* Count certificates in chain. */
        !           982:       now = PR_Now();
        !           983:       i = 1;
        !           984:       if(!cert->isRoot) {
        !           985:         cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
        !           986:         while(cert2) {
        !           987:           i++;
        !           988:           if(cert2->isRoot) {
        !           989:             CERT_DestroyCertificate(cert2);
        !           990:             break;
        !           991:           }
        !           992:           cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
        !           993:           CERT_DestroyCertificate(cert2);
        !           994:           cert2 = cert3;
        !           995:         }
        !           996:       }
        !           997: 
        !           998:       result = Curl_ssl_init_certinfo(conn->data, i);
        !           999:       if(!result) {
        !          1000:         for(i = 0; cert; cert = cert2) {
        !          1001:           result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
        !          1002:                                          (char *)cert->derCert.data +
        !          1003:                                                  cert->derCert.len);
        !          1004:           if(result)
        !          1005:             break;
        !          1006: 
        !          1007:           if(cert->isRoot) {
        !          1008:             CERT_DestroyCertificate(cert);
        !          1009:             break;
        !          1010:           }
        !          1011: 
        !          1012:           cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
        !          1013:           CERT_DestroyCertificate(cert);
        !          1014:         }
        !          1015:       }
        !          1016:     }
        !          1017:   }
        !          1018: 
        !          1019:   return result;
        !          1020: }
        !          1021: 
        !          1022: static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
        !          1023: {
        !          1024:   struct connectdata *conn = (struct connectdata *)arg;
        !          1025:   struct Curl_easy *data = conn->data;
        !          1026:   PRErrorCode err = PR_GetError();
        !          1027:   CERTCertificate *cert;
        !          1028: 
        !          1029:   /* remember the cert verification result */
        !          1030:   if(SSL_IS_PROXY())
        !          1031:     data->set.proxy_ssl.certverifyresult = err;
        !          1032:   else
        !          1033:     data->set.ssl.certverifyresult = err;
        !          1034: 
        !          1035:   if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
        !          1036:     /* we are asked not to verify the host name */
        !          1037:     return SECSuccess;
        !          1038: 
        !          1039:   /* print only info about the cert, the error is printed off the callback */
        !          1040:   cert = SSL_PeerCertificate(sock);
        !          1041:   if(cert) {
        !          1042:     infof(data, "Server certificate:\n");
        !          1043:     display_cert_info(data, cert);
        !          1044:     CERT_DestroyCertificate(cert);
        !          1045:   }
        !          1046: 
        !          1047:   return SECFailure;
        !          1048: }
        !          1049: 
        !          1050: /**
        !          1051:  *
        !          1052:  * Check that the Peer certificate's issuer certificate matches the one found
        !          1053:  * by issuer_nickname.  This is not exactly the way OpenSSL and GNU TLS do the
        !          1054:  * issuer check, so we provide comments that mimic the OpenSSL
        !          1055:  * X509_check_issued function (in x509v3/v3_purp.c)
        !          1056:  */
        !          1057: static SECStatus check_issuer_cert(PRFileDesc *sock,
        !          1058:                                    char *issuer_nickname)
        !          1059: {
        !          1060:   CERTCertificate *cert, *cert_issuer, *issuer;
        !          1061:   SECStatus res = SECSuccess;
        !          1062:   void *proto_win = NULL;
        !          1063: 
        !          1064:   cert = SSL_PeerCertificate(sock);
        !          1065:   cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
        !          1066: 
        !          1067:   proto_win = SSL_RevealPinArg(sock);
        !          1068:   issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
        !          1069: 
        !          1070:   if((!cert_issuer) || (!issuer))
        !          1071:     res = SECFailure;
        !          1072:   else if(SECITEM_CompareItem(&cert_issuer->derCert,
        !          1073:                               &issuer->derCert) != SECEqual)
        !          1074:     res = SECFailure;
        !          1075: 
        !          1076:   CERT_DestroyCertificate(cert);
        !          1077:   CERT_DestroyCertificate(issuer);
        !          1078:   CERT_DestroyCertificate(cert_issuer);
        !          1079:   return res;
        !          1080: }
        !          1081: 
        !          1082: static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
        !          1083:                                 const char *pinnedpubkey)
        !          1084: {
        !          1085:   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
        !          1086:   struct ssl_backend_data *backend = connssl->backend;
        !          1087:   struct Curl_easy *data = backend->data;
        !          1088:   CERTCertificate *cert;
        !          1089: 
        !          1090:   if(!pinnedpubkey)
        !          1091:     /* no pinned public key specified */
        !          1092:     return CURLE_OK;
        !          1093: 
        !          1094:   /* get peer certificate */
        !          1095:   cert = SSL_PeerCertificate(backend->handle);
        !          1096:   if(cert) {
        !          1097:     /* extract public key from peer certificate */
        !          1098:     SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
        !          1099:     if(pubkey) {
        !          1100:       /* encode the public key as DER */
        !          1101:       SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
        !          1102:       if(cert_der) {
        !          1103:         /* compare the public key with the pinned public key */
        !          1104:         result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
        !          1105:                                       cert_der->len);
        !          1106:         SECITEM_FreeItem(cert_der, PR_TRUE);
        !          1107:       }
        !          1108:       SECKEY_DestroyPublicKey(pubkey);
        !          1109:     }
        !          1110:     CERT_DestroyCertificate(cert);
        !          1111:   }
        !          1112: 
        !          1113:   /* report the resulting status */
        !          1114:   switch(result) {
        !          1115:   case CURLE_OK:
        !          1116:     infof(data, "pinned public key verified successfully!\n");
        !          1117:     break;
        !          1118:   case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
        !          1119:     failf(data, "failed to verify pinned public key");
        !          1120:     break;
        !          1121:   default:
        !          1122:     /* OOM, etc. */
        !          1123:     break;
        !          1124:   }
        !          1125: 
        !          1126:   return result;
        !          1127: }
        !          1128: 
        !          1129: /**
        !          1130:  *
        !          1131:  * Callback to pick the SSL client certificate.
        !          1132:  */
        !          1133: static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
        !          1134:                                   struct CERTDistNamesStr *caNames,
        !          1135:                                   struct CERTCertificateStr **pRetCert,
        !          1136:                                   struct SECKEYPrivateKeyStr **pRetKey)
        !          1137: {
        !          1138:   struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
        !          1139:   struct ssl_backend_data *backend = connssl->backend;
        !          1140:   struct Curl_easy *data = backend->data;
        !          1141:   const char *nickname = backend->client_nickname;
        !          1142:   static const char pem_slotname[] = "PEM Token #1";
        !          1143: 
        !          1144:   if(backend->obj_clicert) {
        !          1145:     /* use the cert/key provided by PEM reader */
        !          1146:     SECItem cert_der = { 0, NULL, 0 };
        !          1147:     void *proto_win = SSL_RevealPinArg(sock);
        !          1148:     struct CERTCertificateStr *cert;
        !          1149:     struct SECKEYPrivateKeyStr *key;
        !          1150: 
        !          1151:     PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
        !          1152:     if(NULL == slot) {
        !          1153:       failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
        !          1154:       return SECFailure;
        !          1155:     }
        !          1156: 
        !          1157:     if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE,
        !          1158:                              &cert_der) != SECSuccess) {
        !          1159:       failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
        !          1160:       PK11_FreeSlot(slot);
        !          1161:       return SECFailure;
        !          1162:     }
        !          1163: 
        !          1164:     cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
        !          1165:     SECITEM_FreeItem(&cert_der, PR_FALSE);
        !          1166:     if(NULL == cert) {
        !          1167:       failf(data, "NSS: client certificate from file not found");
        !          1168:       PK11_FreeSlot(slot);
        !          1169:       return SECFailure;
        !          1170:     }
        !          1171: 
        !          1172:     key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
        !          1173:     PK11_FreeSlot(slot);
        !          1174:     if(NULL == key) {
        !          1175:       failf(data, "NSS: private key from file not found");
        !          1176:       CERT_DestroyCertificate(cert);
        !          1177:       return SECFailure;
        !          1178:     }
        !          1179: 
        !          1180:     infof(data, "NSS: client certificate from file\n");
        !          1181:     display_cert_info(data, cert);
        !          1182: 
        !          1183:     *pRetCert = cert;
        !          1184:     *pRetKey = key;
        !          1185:     return SECSuccess;
        !          1186:   }
        !          1187: 
        !          1188:   /* use the default NSS hook */
        !          1189:   if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
        !          1190:                                           pRetCert, pRetKey)
        !          1191:       || NULL == *pRetCert) {
        !          1192: 
        !          1193:     if(NULL == nickname)
        !          1194:       failf(data, "NSS: client certificate not found (nickname not "
        !          1195:             "specified)");
        !          1196:     else
        !          1197:       failf(data, "NSS: client certificate not found: %s", nickname);
        !          1198: 
        !          1199:     return SECFailure;
        !          1200:   }
        !          1201: 
        !          1202:   /* get certificate nickname if any */
        !          1203:   nickname = (*pRetCert)->nickname;
        !          1204:   if(NULL == nickname)
        !          1205:     nickname = "[unknown]";
        !          1206: 
        !          1207:   if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
        !          1208:     failf(data, "NSS: refusing previously loaded certificate from file: %s",
        !          1209:           nickname);
        !          1210:     return SECFailure;
        !          1211:   }
        !          1212: 
        !          1213:   if(NULL == *pRetKey) {
        !          1214:     failf(data, "NSS: private key not found for certificate: %s", nickname);
        !          1215:     return SECFailure;
        !          1216:   }
        !          1217: 
        !          1218:   infof(data, "NSS: using client certificate: %s\n", nickname);
        !          1219:   display_cert_info(data, *pRetCert);
        !          1220:   return SECSuccess;
        !          1221: }
        !          1222: 
        !          1223: /* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
        !          1224: static void nss_update_connecting_state(ssl_connect_state state, void *secret)
        !          1225: {
        !          1226:   struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
        !          1227:   if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
        !          1228:     /* an unrelated error is passing by */
        !          1229:     return;
        !          1230: 
        !          1231:   switch(connssl->connecting_state) {
        !          1232:   case ssl_connect_2:
        !          1233:   case ssl_connect_2_reading:
        !          1234:   case ssl_connect_2_writing:
        !          1235:     break;
        !          1236:   default:
        !          1237:     /* we are not called from an SSL handshake */
        !          1238:     return;
        !          1239:   }
        !          1240: 
        !          1241:   /* update the state accordingly */
        !          1242:   connssl->connecting_state = state;
        !          1243: }
        !          1244: 
        !          1245: /* recv() wrapper we use to detect blocking direction during SSL handshake */
        !          1246: static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
        !          1247:                             PRIntn flags, PRIntervalTime timeout)
        !          1248: {
        !          1249:   const PRRecvFN recv_fn = fd->lower->methods->recv;
        !          1250:   const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
        !          1251:   if(rv < 0)
        !          1252:     /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
        !          1253:     nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
        !          1254:   return rv;
        !          1255: }
        !          1256: 
        !          1257: /* send() wrapper we use to detect blocking direction during SSL handshake */
        !          1258: static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
        !          1259:                             PRIntn flags, PRIntervalTime timeout)
        !          1260: {
        !          1261:   const PRSendFN send_fn = fd->lower->methods->send;
        !          1262:   const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
        !          1263:   if(rv < 0)
        !          1264:     /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
        !          1265:     nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
        !          1266:   return rv;
        !          1267: }
        !          1268: 
        !          1269: /* close() wrapper to avoid assertion failure due to fd->secret != NULL */
        !          1270: static PRStatus nspr_io_close(PRFileDesc *fd)
        !          1271: {
        !          1272:   const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
        !          1273:   fd->secret = NULL;
        !          1274:   return close_fn(fd);
        !          1275: }
        !          1276: 
        !          1277: /* load a PKCS #11 module */
        !          1278: static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
        !          1279:                                 const char *name)
        !          1280: {
        !          1281:   char *config_string;
        !          1282:   SECMODModule *module = *pmod;
        !          1283:   if(module)
        !          1284:     /* already loaded */
        !          1285:     return CURLE_OK;
        !          1286: 
        !          1287:   config_string = aprintf("library=%s name=%s", library, name);
        !          1288:   if(!config_string)
        !          1289:     return CURLE_OUT_OF_MEMORY;
        !          1290: 
        !          1291:   module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
        !          1292:   free(config_string);
        !          1293: 
        !          1294:   if(module && module->loaded) {
        !          1295:     /* loaded successfully */
        !          1296:     *pmod = module;
        !          1297:     return CURLE_OK;
        !          1298:   }
        !          1299: 
        !          1300:   if(module)
        !          1301:     SECMOD_DestroyModule(module);
        !          1302:   return CURLE_FAILED_INIT;
        !          1303: }
        !          1304: 
        !          1305: /* unload a PKCS #11 module */
        !          1306: static void nss_unload_module(SECMODModule **pmod)
        !          1307: {
        !          1308:   SECMODModule *module = *pmod;
        !          1309:   if(!module)
        !          1310:     /* not loaded */
        !          1311:     return;
        !          1312: 
        !          1313:   if(SECMOD_UnloadUserModule(module) != SECSuccess)
        !          1314:     /* unload failed */
        !          1315:     return;
        !          1316: 
        !          1317:   SECMOD_DestroyModule(module);
        !          1318:   *pmod = NULL;
        !          1319: }
        !          1320: 
        !          1321: /* data might be NULL */
        !          1322: static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
        !          1323: {
        !          1324:   NSSInitParameters initparams;
        !          1325:   PRErrorCode err;
        !          1326:   const char *err_name;
        !          1327: 
        !          1328:   if(nss_context != NULL)
        !          1329:     return CURLE_OK;
        !          1330: 
        !          1331:   memset((void *) &initparams, '\0', sizeof(initparams));
        !          1332:   initparams.length = sizeof(initparams);
        !          1333: 
        !          1334:   if(cert_dir) {
        !          1335:     char *certpath = aprintf("sql:%s", cert_dir);
        !          1336:     if(!certpath)
        !          1337:       return CURLE_OUT_OF_MEMORY;
        !          1338: 
        !          1339:     infof(data, "Initializing NSS with certpath: %s\n", certpath);
        !          1340:     nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
        !          1341:             NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
        !          1342:     free(certpath);
        !          1343: 
        !          1344:     if(nss_context != NULL)
        !          1345:       return CURLE_OK;
        !          1346: 
        !          1347:     err = PR_GetError();
        !          1348:     err_name = nss_error_to_name(err);
        !          1349:     infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name);
        !          1350:   }
        !          1351: 
        !          1352:   infof(data, "Initializing NSS with certpath: none\n");
        !          1353:   nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
        !          1354:          | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
        !          1355:          | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
        !          1356:   if(nss_context != NULL)
        !          1357:     return CURLE_OK;
        !          1358: 
        !          1359:   err = PR_GetError();
        !          1360:   err_name = nss_error_to_name(err);
        !          1361:   failf(data, "Unable to initialize NSS: %d (%s)", err, err_name);
        !          1362:   return CURLE_SSL_CACERT_BADFILE;
        !          1363: }
        !          1364: 
        !          1365: /* data might be NULL */
        !          1366: static CURLcode nss_init(struct Curl_easy *data)
        !          1367: {
        !          1368:   char *cert_dir;
        !          1369:   struct_stat st;
        !          1370:   CURLcode result;
        !          1371: 
        !          1372:   if(initialized)
        !          1373:     return CURLE_OK;
        !          1374: 
        !          1375:   /* list of all CRL items we need to destroy in Curl_nss_cleanup() */
        !          1376:   Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
        !          1377: 
        !          1378:   /* First we check if $SSL_DIR points to a valid dir */
        !          1379:   cert_dir = getenv("SSL_DIR");
        !          1380:   if(cert_dir) {
        !          1381:     if((stat(cert_dir, &st) != 0) ||
        !          1382:         (!S_ISDIR(st.st_mode))) {
        !          1383:       cert_dir = NULL;
        !          1384:     }
        !          1385:   }
        !          1386: 
        !          1387:   /* Now we check if the default location is a valid dir */
        !          1388:   if(!cert_dir) {
        !          1389:     if((stat(SSL_DIR, &st) == 0) &&
        !          1390:         (S_ISDIR(st.st_mode))) {
        !          1391:       cert_dir = (char *)SSL_DIR;
        !          1392:     }
        !          1393:   }
        !          1394: 
        !          1395:   if(nspr_io_identity == PR_INVALID_IO_LAYER) {
        !          1396:     /* allocate an identity for our own NSPR I/O layer */
        !          1397:     nspr_io_identity = PR_GetUniqueIdentity("libcurl");
        !          1398:     if(nspr_io_identity == PR_INVALID_IO_LAYER)
        !          1399:       return CURLE_OUT_OF_MEMORY;
        !          1400: 
        !          1401:     /* the default methods just call down to the lower I/O layer */
        !          1402:     memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(),
        !          1403:            sizeof(nspr_io_methods));
        !          1404: 
        !          1405:     /* override certain methods in the table by our wrappers */
        !          1406:     nspr_io_methods.recv  = nspr_io_recv;
        !          1407:     nspr_io_methods.send  = nspr_io_send;
        !          1408:     nspr_io_methods.close = nspr_io_close;
        !          1409:   }
        !          1410: 
        !          1411:   result = nss_init_core(data, cert_dir);
        !          1412:   if(result)
        !          1413:     return result;
        !          1414: 
        !          1415:   if(!any_cipher_enabled())
        !          1416:     NSS_SetDomesticPolicy();
        !          1417: 
        !          1418:   initialized = 1;
        !          1419: 
        !          1420:   return CURLE_OK;
        !          1421: }
        !          1422: 
        !          1423: /**
        !          1424:  * Global SSL init
        !          1425:  *
        !          1426:  * @retval 0 error initializing SSL
        !          1427:  * @retval 1 SSL initialized successfully
        !          1428:  */
        !          1429: static int Curl_nss_init(void)
        !          1430: {
        !          1431:   /* curl_global_init() is not thread-safe so this test is ok */
        !          1432:   if(nss_initlock == NULL) {
        !          1433:     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
        !          1434:     nss_initlock = PR_NewLock();
        !          1435:     nss_crllock = PR_NewLock();
        !          1436:     nss_findslot_lock = PR_NewLock();
        !          1437:     nss_trustload_lock = PR_NewLock();
        !          1438:   }
        !          1439: 
        !          1440:   /* We will actually initialize NSS later */
        !          1441: 
        !          1442:   return 1;
        !          1443: }
        !          1444: 
        !          1445: /* data might be NULL */
        !          1446: CURLcode Curl_nss_force_init(struct Curl_easy *data)
        !          1447: {
        !          1448:   CURLcode result;
        !          1449:   if(!nss_initlock) {
        !          1450:     if(data)
        !          1451:       failf(data, "unable to initialize NSS, curl_global_init() should have "
        !          1452:                   "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
        !          1453:     return CURLE_FAILED_INIT;
        !          1454:   }
        !          1455: 
        !          1456:   PR_Lock(nss_initlock);
        !          1457:   result = nss_init(data);
        !          1458:   PR_Unlock(nss_initlock);
        !          1459: 
        !          1460:   return result;
        !          1461: }
        !          1462: 
        !          1463: /* Global cleanup */
        !          1464: static void Curl_nss_cleanup(void)
        !          1465: {
        !          1466:   /* This function isn't required to be threadsafe and this is only done
        !          1467:    * as a safety feature.
        !          1468:    */
        !          1469:   PR_Lock(nss_initlock);
        !          1470:   if(initialized) {
        !          1471:     /* Free references to client certificates held in the SSL session cache.
        !          1472:      * Omitting this hampers destruction of the security module owning
        !          1473:      * the certificates. */
        !          1474:     SSL_ClearSessionCache();
        !          1475: 
        !          1476:     nss_unload_module(&pem_module);
        !          1477:     nss_unload_module(&trust_module);
        !          1478:     NSS_ShutdownContext(nss_context);
        !          1479:     nss_context = NULL;
        !          1480:   }
        !          1481: 
        !          1482:   /* destroy all CRL items */
        !          1483:   Curl_llist_destroy(&nss_crl_list, NULL);
        !          1484: 
        !          1485:   PR_Unlock(nss_initlock);
        !          1486: 
        !          1487:   PR_DestroyLock(nss_initlock);
        !          1488:   PR_DestroyLock(nss_crllock);
        !          1489:   PR_DestroyLock(nss_findslot_lock);
        !          1490:   PR_DestroyLock(nss_trustload_lock);
        !          1491:   nss_initlock = NULL;
        !          1492: 
        !          1493:   initialized = 0;
        !          1494: }
        !          1495: 
        !          1496: /*
        !          1497:  * This function uses SSL_peek to determine connection status.
        !          1498:  *
        !          1499:  * Return codes:
        !          1500:  *     1 means the connection is still in place
        !          1501:  *     0 means the connection has been closed
        !          1502:  *    -1 means the connection status is unknown
        !          1503:  */
        !          1504: static int Curl_nss_check_cxn(struct connectdata *conn)
        !          1505: {
        !          1506:   struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
        !          1507:   struct ssl_backend_data *backend = connssl->backend;
        !          1508:   int rc;
        !          1509:   char buf;
        !          1510: 
        !          1511:   rc =
        !          1512:     PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
        !          1513:             PR_SecondsToInterval(1));
        !          1514:   if(rc > 0)
        !          1515:     return 1; /* connection still in place */
        !          1516: 
        !          1517:   if(rc == 0)
        !          1518:     return 0; /* connection has been closed */
        !          1519: 
        !          1520:   return -1;  /* connection status unknown */
        !          1521: }
        !          1522: 
        !          1523: static void nss_close(struct ssl_connect_data *connssl)
        !          1524: {
        !          1525:   /* before the cleanup, check whether we are using a client certificate */
        !          1526:   struct ssl_backend_data *backend = connssl->backend;
        !          1527:   const bool client_cert = (backend->client_nickname != NULL)
        !          1528:     || (backend->obj_clicert != NULL);
        !          1529: 
        !          1530:   free(backend->client_nickname);
        !          1531:   backend->client_nickname = NULL;
        !          1532: 
        !          1533:   /* destroy all NSS objects in order to avoid failure of NSS shutdown */
        !          1534:   Curl_llist_destroy(&backend->obj_list, NULL);
        !          1535:   backend->obj_clicert = NULL;
        !          1536: 
        !          1537:   if(backend->handle) {
        !          1538:     if(client_cert)
        !          1539:       /* A server might require different authentication based on the
        !          1540:        * particular path being requested by the client.  To support this
        !          1541:        * scenario, we must ensure that a connection will never reuse the
        !          1542:        * authentication data from a previous connection. */
        !          1543:       SSL_InvalidateSession(backend->handle);
        !          1544: 
        !          1545:     PR_Close(backend->handle);
        !          1546:     backend->handle = NULL;
        !          1547:   }
        !          1548: }
        !          1549: 
        !          1550: /*
        !          1551:  * This function is called when an SSL connection is closed.
        !          1552:  */
        !          1553: static void Curl_nss_close(struct connectdata *conn, int sockindex)
        !          1554: {
        !          1555:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !          1556:   struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
        !          1557:   struct ssl_backend_data *backend = connssl->backend;
        !          1558: 
        !          1559:   if(backend->handle || connssl_proxy->backend->handle) {
        !          1560:     /* NSS closes the socket we previously handed to it, so we must mark it
        !          1561:        as closed to avoid double close */
        !          1562:     fake_sclose(conn->sock[sockindex]);
        !          1563:     conn->sock[sockindex] = CURL_SOCKET_BAD;
        !          1564:   }
        !          1565: 
        !          1566:   if(backend->handle)
        !          1567:     /* nss_close(connssl) will transitively close also
        !          1568:        connssl_proxy->backend->handle if both are used. Clear it to avoid
        !          1569:        a double close leading to crash. */
        !          1570:     connssl_proxy->backend->handle = NULL;
        !          1571: 
        !          1572:   nss_close(connssl);
        !          1573:   nss_close(connssl_proxy);
        !          1574: }
        !          1575: 
        !          1576: /* return true if NSS can provide error code (and possibly msg) for the
        !          1577:    error */
        !          1578: static bool is_nss_error(CURLcode err)
        !          1579: {
        !          1580:   switch(err) {
        !          1581:   case CURLE_PEER_FAILED_VERIFICATION:
        !          1582:   case CURLE_SSL_CERTPROBLEM:
        !          1583:   case CURLE_SSL_CONNECT_ERROR:
        !          1584:   case CURLE_SSL_ISSUER_ERROR:
        !          1585:     return true;
        !          1586: 
        !          1587:   default:
        !          1588:     return false;
        !          1589:   }
        !          1590: }
        !          1591: 
        !          1592: /* return true if the given error code is related to a client certificate */
        !          1593: static bool is_cc_error(PRInt32 err)
        !          1594: {
        !          1595:   switch(err) {
        !          1596:   case SSL_ERROR_BAD_CERT_ALERT:
        !          1597:   case SSL_ERROR_EXPIRED_CERT_ALERT:
        !          1598:   case SSL_ERROR_REVOKED_CERT_ALERT:
        !          1599:     return true;
        !          1600: 
        !          1601:   default:
        !          1602:     return false;
        !          1603:   }
        !          1604: }
        !          1605: 
        !          1606: static Curl_recv nss_recv;
        !          1607: static Curl_send nss_send;
        !          1608: 
        !          1609: static CURLcode nss_load_ca_certificates(struct connectdata *conn,
        !          1610:                                          int sockindex)
        !          1611: {
        !          1612:   struct Curl_easy *data = conn->data;
        !          1613:   const char *cafile = SSL_CONN_CONFIG(CAfile);
        !          1614:   const char *capath = SSL_CONN_CONFIG(CApath);
        !          1615:   bool use_trust_module;
        !          1616:   CURLcode result = CURLE_OK;
        !          1617: 
        !          1618:   /* treat empty string as unset */
        !          1619:   if(cafile && !cafile[0])
        !          1620:     cafile = NULL;
        !          1621:   if(capath && !capath[0])
        !          1622:     capath = NULL;
        !          1623: 
        !          1624:   infof(data, "  CAfile: %s\n  CApath: %s\n",
        !          1625:       cafile ? cafile : "none",
        !          1626:       capath ? capath : "none");
        !          1627: 
        !          1628:   /* load libnssckbi.so if no other trust roots were specified */
        !          1629:   use_trust_module = !cafile && !capath;
        !          1630: 
        !          1631:   PR_Lock(nss_trustload_lock);
        !          1632:   if(use_trust_module && !trust_module) {
        !          1633:     /* libnssckbi.so needed but not yet loaded --> load it! */
        !          1634:     result = nss_load_module(&trust_module, trust_library, "trust");
        !          1635:     infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
        !          1636:           trust_library);
        !          1637:     if(result == CURLE_FAILED_INIT)
        !          1638:       /* If libnssckbi.so is not available (or fails to load), one can still
        !          1639:          use CA certificates stored in NSS database.  Ignore the failure. */
        !          1640:       result = CURLE_OK;
        !          1641:   }
        !          1642:   else if(!use_trust_module && trust_module) {
        !          1643:     /* libnssckbi.so not needed but already loaded --> unload it! */
        !          1644:     infof(data, "unloading %s\n", trust_library);
        !          1645:     nss_unload_module(&trust_module);
        !          1646:   }
        !          1647:   PR_Unlock(nss_trustload_lock);
        !          1648: 
        !          1649:   if(cafile)
        !          1650:     result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
        !          1651: 
        !          1652:   if(result)
        !          1653:     return result;
        !          1654: 
        !          1655:   if(capath) {
        !          1656:     struct_stat st;
        !          1657:     if(stat(capath, &st) == -1)
        !          1658:       return CURLE_SSL_CACERT_BADFILE;
        !          1659: 
        !          1660:     if(S_ISDIR(st.st_mode)) {
        !          1661:       PRDirEntry *entry;
        !          1662:       PRDir *dir = PR_OpenDir(capath);
        !          1663:       if(!dir)
        !          1664:         return CURLE_SSL_CACERT_BADFILE;
        !          1665: 
        !          1666:       while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
        !          1667:         char *fullpath = aprintf("%s/%s", capath, entry->name);
        !          1668:         if(!fullpath) {
        !          1669:           PR_CloseDir(dir);
        !          1670:           return CURLE_OUT_OF_MEMORY;
        !          1671:         }
        !          1672: 
        !          1673:         if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
        !          1674:           /* This is purposefully tolerant of errors so non-PEM files can
        !          1675:            * be in the same directory */
        !          1676:           infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
        !          1677: 
        !          1678:         free(fullpath);
        !          1679:       }
        !          1680: 
        !          1681:       PR_CloseDir(dir);
        !          1682:     }
        !          1683:     else
        !          1684:       infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
        !          1685:   }
        !          1686: 
        !          1687:   return CURLE_OK;
        !          1688: }
        !          1689: 
        !          1690: static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
        !          1691: {
        !          1692:   switch(version) {
        !          1693:   case CURL_SSLVERSION_SSLv2:
        !          1694:     *nssver = SSL_LIBRARY_VERSION_2;
        !          1695:     return CURLE_OK;
        !          1696: 
        !          1697:   case CURL_SSLVERSION_SSLv3:
        !          1698:     *nssver = SSL_LIBRARY_VERSION_3_0;
        !          1699:     return CURLE_OK;
        !          1700: 
        !          1701:   case CURL_SSLVERSION_TLSv1_0:
        !          1702:     *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
        !          1703:     return CURLE_OK;
        !          1704: 
        !          1705:   case CURL_SSLVERSION_TLSv1_1:
        !          1706: #ifdef SSL_LIBRARY_VERSION_TLS_1_1
        !          1707:     *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
        !          1708:     return CURLE_OK;
        !          1709: #else
        !          1710:     return CURLE_SSL_CONNECT_ERROR;
        !          1711: #endif
        !          1712: 
        !          1713:   case CURL_SSLVERSION_TLSv1_2:
        !          1714: #ifdef SSL_LIBRARY_VERSION_TLS_1_2
        !          1715:     *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
        !          1716:     return CURLE_OK;
        !          1717: #else
        !          1718:     return CURLE_SSL_CONNECT_ERROR;
        !          1719: #endif
        !          1720: 
        !          1721:   case CURL_SSLVERSION_TLSv1_3:
        !          1722: #ifdef SSL_LIBRARY_VERSION_TLS_1_3
        !          1723:     *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
        !          1724:     return CURLE_OK;
        !          1725: #else
        !          1726:     return CURLE_SSL_CONNECT_ERROR;
        !          1727: #endif
        !          1728: 
        !          1729:   default:
        !          1730:     return CURLE_SSL_CONNECT_ERROR;
        !          1731:   }
        !          1732: }
        !          1733: 
        !          1734: static CURLcode nss_init_sslver(SSLVersionRange *sslver,
        !          1735:                                 struct Curl_easy *data,
        !          1736:                                 struct connectdata *conn)
        !          1737: {
        !          1738:   CURLcode result;
        !          1739:   const long min = SSL_CONN_CONFIG(version);
        !          1740:   const long max = SSL_CONN_CONFIG(version_max);
        !          1741:   SSLVersionRange vrange;
        !          1742: 
        !          1743:   switch(min) {
        !          1744:   case CURL_SSLVERSION_TLSv1:
        !          1745:   case CURL_SSLVERSION_DEFAULT:
        !          1746:     /* Bump our minimum TLS version if NSS has stricter requirements. */
        !          1747:     if(SSL_VersionRangeGetDefault(ssl_variant_stream, &vrange) != SECSuccess)
        !          1748:       return CURLE_SSL_CONNECT_ERROR;
        !          1749:     if(sslver->min < vrange.min)
        !          1750:       sslver->min = vrange.min;
        !          1751:     break;
        !          1752:   default:
        !          1753:     result = nss_sslver_from_curl(&sslver->min, min);
        !          1754:     if(result) {
        !          1755:       failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
        !          1756:       return result;
        !          1757:     }
        !          1758:   }
        !          1759: 
        !          1760:   switch(max) {
        !          1761:   case CURL_SSLVERSION_MAX_NONE:
        !          1762:   case CURL_SSLVERSION_MAX_DEFAULT:
        !          1763:     break;
        !          1764:   default:
        !          1765:     result = nss_sslver_from_curl(&sslver->max, max >> 16);
        !          1766:     if(result) {
        !          1767:       failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
        !          1768:       return result;
        !          1769:     }
        !          1770:   }
        !          1771: 
        !          1772:   return CURLE_OK;
        !          1773: }
        !          1774: 
        !          1775: static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
        !          1776:                                  struct Curl_easy *data,
        !          1777:                                  CURLcode curlerr)
        !          1778: {
        !          1779:   PRErrorCode err = 0;
        !          1780:   struct ssl_backend_data *backend = connssl->backend;
        !          1781: 
        !          1782:   if(is_nss_error(curlerr)) {
        !          1783:     /* read NSPR error code */
        !          1784:     err = PR_GetError();
        !          1785:     if(is_cc_error(err))
        !          1786:       curlerr = CURLE_SSL_CERTPROBLEM;
        !          1787: 
        !          1788:     /* print the error number and error string */
        !          1789:     infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
        !          1790: 
        !          1791:     /* print a human-readable message describing the error if available */
        !          1792:     nss_print_error_message(data, err);
        !          1793:   }
        !          1794: 
        !          1795:   /* cleanup on connection failure */
        !          1796:   Curl_llist_destroy(&backend->obj_list, NULL);
        !          1797: 
        !          1798:   return curlerr;
        !          1799: }
        !          1800: 
        !          1801: /* Switch the SSL socket into blocking or non-blocking mode. */
        !          1802: static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
        !          1803:                                  struct Curl_easy *data,
        !          1804:                                  bool blocking)
        !          1805: {
        !          1806:   static PRSocketOptionData sock_opt;
        !          1807:   struct ssl_backend_data *backend = connssl->backend;
        !          1808:   sock_opt.option = PR_SockOpt_Nonblocking;
        !          1809:   sock_opt.value.non_blocking = !blocking;
        !          1810: 
        !          1811:   if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
        !          1812:     return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
        !          1813: 
        !          1814:   return CURLE_OK;
        !          1815: }
        !          1816: 
        !          1817: static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
        !          1818: {
        !          1819:   PRFileDesc *model = NULL;
        !          1820:   PRFileDesc *nspr_io = NULL;
        !          1821:   PRFileDesc *nspr_io_stub = NULL;
        !          1822:   PRBool ssl_no_cache;
        !          1823:   PRBool ssl_cbc_random_iv;
        !          1824:   struct Curl_easy *data = conn->data;
        !          1825:   curl_socket_t sockfd = conn->sock[sockindex];
        !          1826:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !          1827:   struct ssl_backend_data *backend = connssl->backend;
        !          1828:   CURLcode result;
        !          1829:   bool second_layer = FALSE;
        !          1830:   SSLVersionRange sslver_supported;
        !          1831: 
        !          1832:   SSLVersionRange sslver = {
        !          1833:     SSL_LIBRARY_VERSION_TLS_1_0,  /* min */
        !          1834: #ifdef SSL_LIBRARY_VERSION_TLS_1_3
        !          1835:     SSL_LIBRARY_VERSION_TLS_1_3   /* max */
        !          1836: #elif defined SSL_LIBRARY_VERSION_TLS_1_2
        !          1837:     SSL_LIBRARY_VERSION_TLS_1_2
        !          1838: #elif defined SSL_LIBRARY_VERSION_TLS_1_1
        !          1839:     SSL_LIBRARY_VERSION_TLS_1_1
        !          1840: #else
        !          1841:     SSL_LIBRARY_VERSION_TLS_1_0
        !          1842: #endif
        !          1843:   };
        !          1844: 
        !          1845:   backend->data = data;
        !          1846: 
        !          1847:   /* list of all NSS objects we need to destroy in Curl_nss_close() */
        !          1848:   Curl_llist_init(&backend->obj_list, nss_destroy_object);
        !          1849: 
        !          1850:   PR_Lock(nss_initlock);
        !          1851:   result = nss_init(conn->data);
        !          1852:   if(result) {
        !          1853:     PR_Unlock(nss_initlock);
        !          1854:     goto error;
        !          1855:   }
        !          1856: 
        !          1857:   PK11_SetPasswordFunc(nss_get_password);
        !          1858: 
        !          1859:   result = nss_load_module(&pem_module, pem_library, "PEM");
        !          1860:   PR_Unlock(nss_initlock);
        !          1861:   if(result == CURLE_FAILED_INIT)
        !          1862:     infof(data, "WARNING: failed to load NSS PEM library %s. Using "
        !          1863:                 "OpenSSL PEM certificates will not work.\n", pem_library);
        !          1864:   else if(result)
        !          1865:     goto error;
        !          1866: 
        !          1867:   result = CURLE_SSL_CONNECT_ERROR;
        !          1868: 
        !          1869:   model = PR_NewTCPSocket();
        !          1870:   if(!model)
        !          1871:     goto error;
        !          1872:   model = SSL_ImportFD(NULL, model);
        !          1873: 
        !          1874:   if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
        !          1875:     goto error;
        !          1876:   if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
        !          1877:     goto error;
        !          1878:   if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
        !          1879:     goto error;
        !          1880: 
        !          1881:   /* do not use SSL cache if disabled or we are not going to verify peer */
        !          1882:   ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
        !          1883:                   && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
        !          1884:   if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
        !          1885:     goto error;
        !          1886: 
        !          1887:   /* enable/disable the requested SSL version(s) */
        !          1888:   if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
        !          1889:     goto error;
        !          1890:   if(SSL_VersionRangeGetSupported(ssl_variant_stream,
        !          1891:                                   &sslver_supported) != SECSuccess)
        !          1892:     goto error;
        !          1893:   if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
        !          1894:     char *sslver_req_str, *sslver_supp_str;
        !          1895:     sslver_req_str = nss_sslver_to_name(sslver.max);
        !          1896:     sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
        !          1897:     if(sslver_req_str && sslver_supp_str)
        !          1898:       infof(data, "Falling back from %s to max supported SSL version (%s)\n",
        !          1899:                   sslver_req_str, sslver_supp_str);
        !          1900:     free(sslver_req_str);
        !          1901:     free(sslver_supp_str);
        !          1902:     sslver.max = sslver_supported.max;
        !          1903:   }
        !          1904:   if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
        !          1905:     goto error;
        !          1906: 
        !          1907:   ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
        !          1908: #ifdef SSL_CBC_RANDOM_IV
        !          1909:   /* unless the user explicitly asks to allow the protocol vulnerability, we
        !          1910:      use the work-around */
        !          1911:   if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
        !          1912:     infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
        !          1913:           ssl_cbc_random_iv);
        !          1914: #else
        !          1915:   if(ssl_cbc_random_iv)
        !          1916:     infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
        !          1917: #endif
        !          1918: 
        !          1919:   if(SSL_CONN_CONFIG(cipher_list)) {
        !          1920:     if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
        !          1921:       result = CURLE_SSL_CIPHER;
        !          1922:       goto error;
        !          1923:     }
        !          1924:   }
        !          1925: 
        !          1926:   if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
        !          1927:     infof(data, "warning: ignoring value of ssl.verifyhost\n");
        !          1928: 
        !          1929:   /* bypass the default SSL_AuthCertificate() hook in case we do not want to
        !          1930:    * verify peer */
        !          1931:   if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
        !          1932:     goto error;
        !          1933: 
        !          1934:   /* not checked yet */
        !          1935:   if(SSL_IS_PROXY())
        !          1936:     data->set.proxy_ssl.certverifyresult = 0;
        !          1937:   else
        !          1938:     data->set.ssl.certverifyresult = 0;
        !          1939: 
        !          1940:   if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
        !          1941:     goto error;
        !          1942: 
        !          1943:   if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
        !          1944:     goto error;
        !          1945: 
        !          1946:   {
        !          1947:     const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
        !          1948:     if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
        !          1949:       /* not a fatal error because we are not going to verify the peer */
        !          1950:       infof(data, "warning: CA certificates failed to load\n");
        !          1951:     else if(rv) {
        !          1952:       result = rv;
        !          1953:       goto error;
        !          1954:     }
        !          1955:   }
        !          1956: 
        !          1957:   if(SSL_SET_OPTION(CRLfile)) {
        !          1958:     const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile));
        !          1959:     if(rv) {
        !          1960:       result = rv;
        !          1961:       goto error;
        !          1962:     }
        !          1963:     infof(data, "  CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
        !          1964:   }
        !          1965: 
        !          1966:   if(SSL_SET_OPTION(cert)) {
        !          1967:     char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
        !          1968:     if(nickname) {
        !          1969:       /* we are not going to use libnsspem.so to read the client cert */
        !          1970:       backend->obj_clicert = NULL;
        !          1971:     }
        !          1972:     else {
        !          1973:       CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
        !          1974:                                SSL_SET_OPTION(key));
        !          1975:       if(rv) {
        !          1976:         /* failf() is already done in cert_stuff() */
        !          1977:         result = rv;
        !          1978:         goto error;
        !          1979:       }
        !          1980:     }
        !          1981: 
        !          1982:     /* store the nickname for SelectClientCert() called during handshake */
        !          1983:     backend->client_nickname = nickname;
        !          1984:   }
        !          1985:   else
        !          1986:     backend->client_nickname = NULL;
        !          1987: 
        !          1988:   if(SSL_GetClientAuthDataHook(model, SelectClientCert,
        !          1989:                                (void *)connssl) != SECSuccess) {
        !          1990:     result = CURLE_SSL_CERTPROBLEM;
        !          1991:     goto error;
        !          1992:   }
        !          1993: 
        !          1994:   if(conn->proxy_ssl[sockindex].use) {
        !          1995:     DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
        !          1996:     DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
        !          1997:     nspr_io = conn->proxy_ssl[sockindex].backend->handle;
        !          1998:     second_layer = TRUE;
        !          1999:   }
        !          2000:   else {
        !          2001:     /* wrap OS file descriptor by NSPR's file descriptor abstraction */
        !          2002:     nspr_io = PR_ImportTCPSocket(sockfd);
        !          2003:     if(!nspr_io)
        !          2004:       goto error;
        !          2005:   }
        !          2006: 
        !          2007:   /* create our own NSPR I/O layer */
        !          2008:   nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
        !          2009:   if(!nspr_io_stub) {
        !          2010:     if(!second_layer)
        !          2011:       PR_Close(nspr_io);
        !          2012:     goto error;
        !          2013:   }
        !          2014: 
        !          2015:   /* make the per-connection data accessible from NSPR I/O callbacks */
        !          2016:   nspr_io_stub->secret = (void *)connssl;
        !          2017: 
        !          2018:   /* push our new layer to the NSPR I/O stack */
        !          2019:   if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
        !          2020:     if(!second_layer)
        !          2021:       PR_Close(nspr_io);
        !          2022:     PR_Close(nspr_io_stub);
        !          2023:     goto error;
        !          2024:   }
        !          2025: 
        !          2026:   /* import our model socket onto the current I/O stack */
        !          2027:   backend->handle = SSL_ImportFD(model, nspr_io);
        !          2028:   if(!backend->handle) {
        !          2029:     if(!second_layer)
        !          2030:       PR_Close(nspr_io);
        !          2031:     goto error;
        !          2032:   }
        !          2033: 
        !          2034:   PR_Close(model); /* We don't need this any more */
        !          2035:   model = NULL;
        !          2036: 
        !          2037:   /* This is the password associated with the cert that we're using */
        !          2038:   if(SSL_SET_OPTION(key_passwd)) {
        !          2039:     SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
        !          2040:   }
        !          2041: 
        !          2042: #ifdef SSL_ENABLE_OCSP_STAPLING
        !          2043:   if(SSL_CONN_CONFIG(verifystatus)) {
        !          2044:     if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
        !          2045:         != SECSuccess)
        !          2046:       goto error;
        !          2047:   }
        !          2048: #endif
        !          2049: 
        !          2050: #ifdef SSL_ENABLE_NPN
        !          2051:   if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
        !          2052:                    ? PR_TRUE : PR_FALSE) != SECSuccess)
        !          2053:     goto error;
        !          2054: #endif
        !          2055: 
        !          2056: #ifdef SSL_ENABLE_ALPN
        !          2057:   if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
        !          2058:                    ? PR_TRUE : PR_FALSE) != SECSuccess)
        !          2059:     goto error;
        !          2060: #endif
        !          2061: 
        !          2062: #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
        !          2063:   if(data->set.ssl.falsestart) {
        !          2064:     if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
        !          2065:         != SECSuccess)
        !          2066:       goto error;
        !          2067: 
        !          2068:     if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
        !          2069:         conn) != SECSuccess)
        !          2070:       goto error;
        !          2071:   }
        !          2072: #endif
        !          2073: 
        !          2074: #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
        !          2075:   if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
        !          2076:     int cur = 0;
        !          2077:     unsigned char protocols[128];
        !          2078: 
        !          2079: #ifdef USE_NGHTTP2
        !          2080:     if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
        !          2081:        (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
        !          2082:       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
        !          2083:       memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
        !          2084:           NGHTTP2_PROTO_VERSION_ID_LEN);
        !          2085:       cur += NGHTTP2_PROTO_VERSION_ID_LEN;
        !          2086:     }
        !          2087: #endif
        !          2088:     protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
        !          2089:     memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
        !          2090:     cur += ALPN_HTTP_1_1_LENGTH;
        !          2091: 
        !          2092:     if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
        !          2093:       goto error;
        !          2094:   }
        !          2095: #endif
        !          2096: 
        !          2097: 
        !          2098:   /* Force handshake on next I/O */
        !          2099:   if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
        !          2100:       != SECSuccess)
        !          2101:     goto error;
        !          2102: 
        !          2103:   /* propagate hostname to the TLS layer */
        !          2104:   if(SSL_SetURL(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
        !          2105:                 conn->host.name) != SECSuccess)
        !          2106:     goto error;
        !          2107: 
        !          2108:   /* prevent NSS from re-using the session for a different hostname */
        !          2109:   if(SSL_SetSockPeerID(backend->handle, SSL_IS_PROXY() ?
        !          2110:                        conn->http_proxy.host.name : conn->host.name)
        !          2111:      != SECSuccess)
        !          2112:     goto error;
        !          2113: 
        !          2114:   return CURLE_OK;
        !          2115: 
        !          2116: error:
        !          2117:   if(model)
        !          2118:     PR_Close(model);
        !          2119: 
        !          2120:   return nss_fail_connect(connssl, data, result);
        !          2121: }
        !          2122: 
        !          2123: static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
        !          2124: {
        !          2125:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !          2126:   struct ssl_backend_data *backend = connssl->backend;
        !          2127:   struct Curl_easy *data = conn->data;
        !          2128:   CURLcode result = CURLE_SSL_CONNECT_ERROR;
        !          2129:   PRUint32 timeout;
        !          2130:   long * const certverifyresult = SSL_IS_PROXY() ?
        !          2131:     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
        !          2132:   const char * const pinnedpubkey = SSL_IS_PROXY() ?
        !          2133:               data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
        !          2134:               data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
        !          2135: 
        !          2136: 
        !          2137:   /* check timeout situation */
        !          2138:   const timediff_t time_left = Curl_timeleft(data, NULL, TRUE);
        !          2139:   if(time_left < 0) {
        !          2140:     failf(data, "timed out before SSL handshake");
        !          2141:     result = CURLE_OPERATION_TIMEDOUT;
        !          2142:     goto error;
        !          2143:   }
        !          2144: 
        !          2145:   /* Force the handshake now */
        !          2146:   timeout = PR_MillisecondsToInterval((PRUint32) time_left);
        !          2147:   if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) {
        !          2148:     if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
        !          2149:       /* blocking direction is updated by nss_update_connecting_state() */
        !          2150:       return CURLE_AGAIN;
        !          2151:     else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
        !          2152:       result = CURLE_PEER_FAILED_VERIFICATION;
        !          2153:     else if(*certverifyresult != 0)
        !          2154:       result = CURLE_PEER_FAILED_VERIFICATION;
        !          2155:     goto error;
        !          2156:   }
        !          2157: 
        !          2158:   result = display_conn_info(conn, backend->handle);
        !          2159:   if(result)
        !          2160:     goto error;
        !          2161: 
        !          2162:   if(SSL_SET_OPTION(issuercert)) {
        !          2163:     SECStatus ret = SECFailure;
        !          2164:     char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
        !          2165:     if(nickname) {
        !          2166:       /* we support only nicknames in case of issuercert for now */
        !          2167:       ret = check_issuer_cert(backend->handle, nickname);
        !          2168:       free(nickname);
        !          2169:     }
        !          2170: 
        !          2171:     if(SECFailure == ret) {
        !          2172:       infof(data, "SSL certificate issuer check failed\n");
        !          2173:       result = CURLE_SSL_ISSUER_ERROR;
        !          2174:       goto error;
        !          2175:     }
        !          2176:     else {
        !          2177:       infof(data, "SSL certificate issuer check ok\n");
        !          2178:     }
        !          2179:   }
        !          2180: 
        !          2181:   result = cmp_peer_pubkey(connssl, pinnedpubkey);
        !          2182:   if(result)
        !          2183:     /* status already printed */
        !          2184:     goto error;
        !          2185: 
        !          2186:   return CURLE_OK;
        !          2187: 
        !          2188: error:
        !          2189:   return nss_fail_connect(connssl, data, result);
        !          2190: }
        !          2191: 
        !          2192: static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
        !          2193:                                    bool *done)
        !          2194: {
        !          2195:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !          2196:   struct Curl_easy *data = conn->data;
        !          2197:   const bool blocking = (done == NULL);
        !          2198:   CURLcode result;
        !          2199: 
        !          2200:   if(connssl->state == ssl_connection_complete) {
        !          2201:     if(!blocking)
        !          2202:       *done = TRUE;
        !          2203:     return CURLE_OK;
        !          2204:   }
        !          2205: 
        !          2206:   if(connssl->connecting_state == ssl_connect_1) {
        !          2207:     result = nss_setup_connect(conn, sockindex);
        !          2208:     if(result)
        !          2209:       /* we do not expect CURLE_AGAIN from nss_setup_connect() */
        !          2210:       return result;
        !          2211: 
        !          2212:     connssl->connecting_state = ssl_connect_2;
        !          2213:   }
        !          2214: 
        !          2215:   /* enable/disable blocking mode before handshake */
        !          2216:   result = nss_set_blocking(connssl, data, blocking);
        !          2217:   if(result)
        !          2218:     return result;
        !          2219: 
        !          2220:   result = nss_do_connect(conn, sockindex);
        !          2221:   switch(result) {
        !          2222:   case CURLE_OK:
        !          2223:     break;
        !          2224:   case CURLE_AGAIN:
        !          2225:     if(!blocking)
        !          2226:       /* CURLE_AGAIN in non-blocking mode is not an error */
        !          2227:       return CURLE_OK;
        !          2228:     /* FALLTHROUGH */
        !          2229:   default:
        !          2230:     return result;
        !          2231:   }
        !          2232: 
        !          2233:   if(blocking) {
        !          2234:     /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
        !          2235:     result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
        !          2236:     if(result)
        !          2237:       return result;
        !          2238:   }
        !          2239:   else
        !          2240:     /* signal completed SSL handshake */
        !          2241:     *done = TRUE;
        !          2242: 
        !          2243:   connssl->state = ssl_connection_complete;
        !          2244:   conn->recv[sockindex] = nss_recv;
        !          2245:   conn->send[sockindex] = nss_send;
        !          2246: 
        !          2247:   /* ssl_connect_done is never used outside, go back to the initial state */
        !          2248:   connssl->connecting_state = ssl_connect_1;
        !          2249: 
        !          2250:   return CURLE_OK;
        !          2251: }
        !          2252: 
        !          2253: static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
        !          2254: {
        !          2255:   return nss_connect_common(conn, sockindex, /* blocking */ NULL);
        !          2256: }
        !          2257: 
        !          2258: static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
        !          2259:                                              int sockindex, bool *done)
        !          2260: {
        !          2261:   return nss_connect_common(conn, sockindex, done);
        !          2262: }
        !          2263: 
        !          2264: static ssize_t nss_send(struct connectdata *conn,  /* connection data */
        !          2265:                         int sockindex,             /* socketindex */
        !          2266:                         const void *mem,           /* send this data */
        !          2267:                         size_t len,                /* amount to write */
        !          2268:                         CURLcode *curlcode)
        !          2269: {
        !          2270:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !          2271:   struct ssl_backend_data *backend = connssl->backend;
        !          2272:   ssize_t rc;
        !          2273: 
        !          2274:   /* The SelectClientCert() hook uses this for infof() and failf() but the
        !          2275:      handle stored in nss_setup_connect() could have already been freed. */
        !          2276:   backend->data = conn->data;
        !          2277: 
        !          2278:   rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
        !          2279:   if(rc < 0) {
        !          2280:     PRInt32 err = PR_GetError();
        !          2281:     if(err == PR_WOULD_BLOCK_ERROR)
        !          2282:       *curlcode = CURLE_AGAIN;
        !          2283:     else {
        !          2284:       /* print the error number and error string */
        !          2285:       const char *err_name = nss_error_to_name(err);
        !          2286:       infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
        !          2287: 
        !          2288:       /* print a human-readable message describing the error if available */
        !          2289:       nss_print_error_message(conn->data, err);
        !          2290: 
        !          2291:       *curlcode = (is_cc_error(err))
        !          2292:         ? CURLE_SSL_CERTPROBLEM
        !          2293:         : CURLE_SEND_ERROR;
        !          2294:     }
        !          2295: 
        !          2296:     return -1;
        !          2297:   }
        !          2298: 
        !          2299:   return rc; /* number of bytes */
        !          2300: }
        !          2301: 
        !          2302: static ssize_t nss_recv(struct connectdata *conn,  /* connection data */
        !          2303:                         int sockindex,             /* socketindex */
        !          2304:                         char *buf,                 /* store read data here */
        !          2305:                         size_t buffersize,         /* max amount to read */
        !          2306:                         CURLcode *curlcode)
        !          2307: {
        !          2308:   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
        !          2309:   struct ssl_backend_data *backend = connssl->backend;
        !          2310:   ssize_t nread;
        !          2311: 
        !          2312:   /* The SelectClientCert() hook uses this for infof() and failf() but the
        !          2313:      handle stored in nss_setup_connect() could have already been freed. */
        !          2314:   backend->data = conn->data;
        !          2315: 
        !          2316:   nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
        !          2317:                   PR_INTERVAL_NO_WAIT);
        !          2318:   if(nread < 0) {
        !          2319:     /* failed SSL read */
        !          2320:     PRInt32 err = PR_GetError();
        !          2321: 
        !          2322:     if(err == PR_WOULD_BLOCK_ERROR)
        !          2323:       *curlcode = CURLE_AGAIN;
        !          2324:     else {
        !          2325:       /* print the error number and error string */
        !          2326:       const char *err_name = nss_error_to_name(err);
        !          2327:       infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
        !          2328: 
        !          2329:       /* print a human-readable message describing the error if available */
        !          2330:       nss_print_error_message(conn->data, err);
        !          2331: 
        !          2332:       *curlcode = (is_cc_error(err))
        !          2333:         ? CURLE_SSL_CERTPROBLEM
        !          2334:         : CURLE_RECV_ERROR;
        !          2335:     }
        !          2336: 
        !          2337:     return -1;
        !          2338:   }
        !          2339: 
        !          2340:   return nread;
        !          2341: }
        !          2342: 
        !          2343: static size_t Curl_nss_version(char *buffer, size_t size)
        !          2344: {
        !          2345:   return msnprintf(buffer, size, "NSS/%s", NSS_VERSION);
        !          2346: }
        !          2347: 
        !          2348: /* data might be NULL */
        !          2349: static int Curl_nss_seed(struct Curl_easy *data)
        !          2350: {
        !          2351:   /* make sure that NSS is initialized */
        !          2352:   return !!Curl_nss_force_init(data);
        !          2353: }
        !          2354: 
        !          2355: /* data might be NULL */
        !          2356: static CURLcode Curl_nss_random(struct Curl_easy *data,
        !          2357:                                 unsigned char *entropy,
        !          2358:                                 size_t length)
        !          2359: {
        !          2360:   Curl_nss_seed(data);  /* Initiate the seed if not already done */
        !          2361: 
        !          2362:   if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
        !          2363:     /* signal a failure */
        !          2364:     return CURLE_FAILED_INIT;
        !          2365: 
        !          2366:   return CURLE_OK;
        !          2367: }
        !          2368: 
        !          2369: static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */
        !          2370:                                 size_t tmplen,
        !          2371:                                 unsigned char *md5sum, /* output */
        !          2372:                                 size_t md5len)
        !          2373: {
        !          2374:   PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
        !          2375:   unsigned int MD5out;
        !          2376: 
        !          2377:   if(!MD5pw)
        !          2378:     return CURLE_NOT_BUILT_IN;
        !          2379: 
        !          2380:   PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
        !          2381:   PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
        !          2382:   PK11_DestroyContext(MD5pw, PR_TRUE);
        !          2383: 
        !          2384:   return CURLE_OK;
        !          2385: }
        !          2386: 
        !          2387: static CURLcode Curl_nss_sha256sum(const unsigned char *tmp, /* input */
        !          2388:                                size_t tmplen,
        !          2389:                                unsigned char *sha256sum, /* output */
        !          2390:                                size_t sha256len)
        !          2391: {
        !          2392:   PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
        !          2393:   unsigned int SHA256out;
        !          2394: 
        !          2395:   if(!SHA256pw)
        !          2396:     return CURLE_NOT_BUILT_IN;
        !          2397: 
        !          2398:   PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
        !          2399:   PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
        !          2400:   PK11_DestroyContext(SHA256pw, PR_TRUE);
        !          2401: 
        !          2402:   return CURLE_OK;
        !          2403: }
        !          2404: 
        !          2405: static bool Curl_nss_cert_status_request(void)
        !          2406: {
        !          2407: #ifdef SSL_ENABLE_OCSP_STAPLING
        !          2408:   return TRUE;
        !          2409: #else
        !          2410:   return FALSE;
        !          2411: #endif
        !          2412: }
        !          2413: 
        !          2414: static bool Curl_nss_false_start(void)
        !          2415: {
        !          2416: #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
        !          2417:   return TRUE;
        !          2418: #else
        !          2419:   return FALSE;
        !          2420: #endif
        !          2421: }
        !          2422: 
        !          2423: static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
        !          2424:                                     CURLINFO info UNUSED_PARAM)
        !          2425: {
        !          2426:   struct ssl_backend_data *backend = connssl->backend;
        !          2427:   (void)info;
        !          2428:   return backend->handle;
        !          2429: }
        !          2430: 
        !          2431: const struct Curl_ssl Curl_ssl_nss = {
        !          2432:   { CURLSSLBACKEND_NSS, "nss" }, /* info */
        !          2433: 
        !          2434:   SSLSUPP_CA_PATH |
        !          2435:   SSLSUPP_CERTINFO |
        !          2436:   SSLSUPP_PINNEDPUBKEY |
        !          2437:   SSLSUPP_HTTPS_PROXY,
        !          2438: 
        !          2439:   sizeof(struct ssl_backend_data),
        !          2440: 
        !          2441:   Curl_nss_init,                /* init */
        !          2442:   Curl_nss_cleanup,             /* cleanup */
        !          2443:   Curl_nss_version,             /* version */
        !          2444:   Curl_nss_check_cxn,           /* check_cxn */
        !          2445:   /* NSS has no shutdown function provided and thus always fail */
        !          2446:   Curl_none_shutdown,           /* shutdown */
        !          2447:   Curl_none_data_pending,       /* data_pending */
        !          2448:   Curl_nss_random,              /* random */
        !          2449:   Curl_nss_cert_status_request, /* cert_status_request */
        !          2450:   Curl_nss_connect,             /* connect */
        !          2451:   Curl_nss_connect_nonblocking, /* connect_nonblocking */
        !          2452:   Curl_nss_get_internals,       /* get_internals */
        !          2453:   Curl_nss_close,               /* close_one */
        !          2454:   Curl_none_close_all,          /* close_all */
        !          2455:   /* NSS has its own session ID cache */
        !          2456:   Curl_none_session_free,       /* session_free */
        !          2457:   Curl_none_set_engine,         /* set_engine */
        !          2458:   Curl_none_set_engine_default, /* set_engine_default */
        !          2459:   Curl_none_engines_list,       /* engines_list */
        !          2460:   Curl_nss_false_start,         /* false_start */
        !          2461:   Curl_nss_md5sum,              /* md5sum */
        !          2462:   Curl_nss_sha256sum            /* sha256sum */
        !          2463: };
        !          2464: 
        !          2465: #endif /* USE_NSS */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>