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

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