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

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
                      9:  *
                     10:  * This software is licensed as described in the file COPYING, which
                     11:  * you should have received as part of this distribution. The terms
                     12:  * are also available at https://curl.haxx.se/docs/copyright.html.
                     13:  *
                     14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
                     15:  * copies of the Software, and permit persons to whom the Software is
                     16:  * furnished to do so, under the terms of the COPYING file.
                     17:  *
                     18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
                     19:  * KIND, either express or implied.
                     20:  *
                     21:  ***************************************************************************/
                     22: 
                     23: /*
                     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>