1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsCrypto.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2939 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 +#include "nsCrypto.h" 1.10 +#include "nsNSSComponent.h" 1.11 +#include "secmod.h" 1.12 + 1.13 +#include "nsReadableUtils.h" 1.14 +#include "nsCRT.h" 1.15 +#include "nsXPIDLString.h" 1.16 +#include "nsISaveAsCharset.h" 1.17 +#include "nsNativeCharsetUtils.h" 1.18 +#include "nsServiceManagerUtils.h" 1.19 + 1.20 +#ifndef MOZ_DISABLE_CRYPTOLEGACY 1.21 +#include "nsKeygenHandler.h" 1.22 +#include "nsKeygenThread.h" 1.23 +#include "nsNSSCertificate.h" 1.24 +#include "nsNSSCertificateDB.h" 1.25 +#include "nsPKCS12Blob.h" 1.26 +#include "nsPK11TokenDB.h" 1.27 +#include "nsThreadUtils.h" 1.28 +#include "nsIServiceManager.h" 1.29 +#include "nsIMemory.h" 1.30 +#include "nsAlgorithm.h" 1.31 +#include "prprf.h" 1.32 +#include "nsDOMCID.h" 1.33 +#include "nsIDOMWindow.h" 1.34 +#include "nsIDOMClassInfo.h" 1.35 +#include "nsIDOMDocument.h" 1.36 +#include "nsIDocument.h" 1.37 +#include "nsIScriptObjectPrincipal.h" 1.38 +#include "nsIScriptContext.h" 1.39 +#include "nsIScriptGlobalObject.h" 1.40 +#include "nsContentUtils.h" 1.41 +#include "nsCxPusher.h" 1.42 +#include "nsDOMJSUtils.h" 1.43 +#include "nsJSUtils.h" 1.44 +#include "nsIXPConnect.h" 1.45 +#include "nsIRunnable.h" 1.46 +#include "nsIWindowWatcher.h" 1.47 +#include "nsIPrompt.h" 1.48 +#include "nsIFilePicker.h" 1.49 +#include "nsJSPrincipals.h" 1.50 +#include "nsJSUtils.h" 1.51 +#include "nsIPrincipal.h" 1.52 +#include "nsIScriptSecurityManager.h" 1.53 +#include "nsIGenKeypairInfoDlg.h" 1.54 +#include "nsIDOMCryptoDialogs.h" 1.55 +#include "nsIFormSigningDialog.h" 1.56 +#include "nsIContentSecurityPolicy.h" 1.57 +#include "nsIURI.h" 1.58 +#include "jsapi.h" 1.59 +#include "js/OldDebugAPI.h" 1.60 +#include <ctype.h> 1.61 +#include "pk11func.h" 1.62 +#include "keyhi.h" 1.63 +#include "cryptohi.h" 1.64 +#include "seccomon.h" 1.65 +#include "secerr.h" 1.66 +#include "sechash.h" 1.67 +#include "crmf.h" 1.68 +#include "pk11pqg.h" 1.69 +#include "cmmf.h" 1.70 +#include "nssb64.h" 1.71 +#include "base64.h" 1.72 +#include "cert.h" 1.73 +#include "certdb.h" 1.74 +#include "secmod.h" 1.75 +#include "ScopedNSSTypes.h" 1.76 +#include "pkix/pkixtypes.h" 1.77 + 1.78 +#include "ssl.h" // For SSL_ClearSessionCache 1.79 + 1.80 +#include "nsNSSCleaner.h" 1.81 + 1.82 +#include "nsNSSCertHelper.h" 1.83 +#include <algorithm> 1.84 +#include "nsWrapperCacheInlines.h" 1.85 +#endif 1.86 +#ifndef MOZ_DISABLE_CRYPTOLEGACY 1.87 +#include "mozilla/dom/CRMFObjectBinding.h" 1.88 +#endif 1.89 + 1.90 +using namespace mozilla; 1.91 +using namespace mozilla::dom; 1.92 + 1.93 +/* 1.94 + * These are the most common error strings that are returned 1.95 + * by the JavaScript methods in case of error. 1.96 + */ 1.97 + 1.98 +#define JS_ERROR "error:" 1.99 +#define JS_ERROR_INTERNAL JS_ERROR"internalError" 1.100 + 1.101 +#undef REPORT_INCORRECT_NUM_ARGS 1.102 + 1.103 +#define JS_OK_ADD_MOD 3 1.104 +#define JS_OK_DEL_EXTERNAL_MOD 2 1.105 +#define JS_OK_DEL_INTERNAL_MOD 1 1.106 + 1.107 +#define JS_ERR_INTERNAL -1 1.108 +#define JS_ERR_USER_CANCEL_ACTION -2 1.109 +#define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3 1.110 +#define JS_ERR_DEL_MOD -4 1.111 +#define JS_ERR_ADD_MOD -5 1.112 +#define JS_ERR_BAD_MODULE_NAME -6 1.113 +#define JS_ERR_BAD_DLL_NAME -7 1.114 +#define JS_ERR_BAD_MECHANISM_FLAGS -8 1.115 +#define JS_ERR_BAD_CIPHER_ENABLE_FLAGS -9 1.116 +#define JS_ERR_ADD_DUPLICATE_MOD -10 1.117 + 1.118 +#ifndef MOZ_DISABLE_CRYPTOLEGACY 1.119 + 1.120 +NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true) 1.121 + 1.122 +/* 1.123 + * This structure is used to store information for one key generation. 1.124 + * The nsCrypto::GenerateCRMFRequest method parses the inputs and then 1.125 + * stores one of these structures for every key generation that happens. 1.126 + * The information stored in this structure is then used to set some 1.127 + * values in the CRMF request. 1.128 + */ 1.129 +typedef enum { 1.130 + rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation, 1.131 + ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation, 1.132 + dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen 1.133 +} nsKeyGenType; 1.134 + 1.135 +bool isECKeyGenType(nsKeyGenType kgt) 1.136 +{ 1.137 + switch (kgt) 1.138 + { 1.139 + case ecEnc: 1.140 + case ecDualUse: 1.141 + case ecSign: 1.142 + case ecNonrepudiation: 1.143 + case ecSignNonrepudiation: 1.144 + return true; 1.145 + 1.146 + default: 1.147 + break; 1.148 + } 1.149 + 1.150 + return false; 1.151 +} 1.152 + 1.153 +typedef struct nsKeyPairInfoStr { 1.154 + SECKEYPublicKey *pubKey; /* The putlic key associated with gen'd 1.155 + priv key. */ 1.156 + SECKEYPrivateKey *privKey; /* The private key we generated */ 1.157 + nsKeyGenType keyGenType; /* What type of key gen are we doing.*/ 1.158 + 1.159 + CERTCertificate *ecPopCert; 1.160 + /* null: use signing for pop 1.161 + other than null: a cert that defines EC keygen params 1.162 + and will be used for dhMac PoP. */ 1.163 + 1.164 + SECKEYPublicKey *ecPopPubKey; 1.165 + /* extracted public key from ecPopCert */ 1.166 +} nsKeyPairInfo; 1.167 + 1.168 + 1.169 +//This class is just used to pass arguments 1.170 +//to the nsCryptoRunnable event. 1.171 +class nsCryptoRunArgs : public nsISupports { 1.172 +public: 1.173 + nsCryptoRunArgs(JSContext *aCx); 1.174 + virtual ~nsCryptoRunArgs(); 1.175 + nsCOMPtr<nsISupports> m_kungFuDeathGrip; 1.176 + JSContext *m_cx; 1.177 + JS::PersistentRooted<JSObject*> m_scope; 1.178 + nsCOMPtr<nsIPrincipal> m_principals; 1.179 + nsXPIDLCString m_jsCallback; 1.180 + NS_DECL_ISUPPORTS 1.181 +}; 1.182 + 1.183 +//This class is used to run the callback code 1.184 +//passed to crypto.generateCRMFRequest 1.185 +//We have to do that for backwards compatibility 1.186 +//reasons w/ PSM 1.x and Communciator 4.x 1.187 +class nsCryptoRunnable : public nsIRunnable { 1.188 +public: 1.189 + nsCryptoRunnable(nsCryptoRunArgs *args); 1.190 + virtual ~nsCryptoRunnable(); 1.191 + 1.192 + NS_IMETHOD Run (); 1.193 + NS_DECL_ISUPPORTS 1.194 +private: 1.195 + nsCryptoRunArgs *m_args; 1.196 +}; 1.197 + 1.198 + 1.199 +//We're going to inherit the memory passed 1.200 +//into us. 1.201 +//This class backs up an array of certificates 1.202 +//as an event. 1.203 +class nsP12Runnable : public nsIRunnable { 1.204 +public: 1.205 + nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts, nsIPK11Token *token); 1.206 + virtual ~nsP12Runnable(); 1.207 + 1.208 + NS_IMETHOD Run(); 1.209 + NS_DECL_ISUPPORTS 1.210 +private: 1.211 + nsCOMPtr<nsIPK11Token> mToken; 1.212 + nsIX509Cert **mCertArr; 1.213 + int32_t mNumCerts; 1.214 +}; 1.215 + 1.216 +// QueryInterface implementation for nsCrypto 1.217 +NS_INTERFACE_MAP_BEGIN(nsCrypto) 1.218 + NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto) 1.219 +NS_INTERFACE_MAP_END_INHERITING(mozilla::dom::Crypto) 1.220 + 1.221 +NS_IMPL_ADDREF_INHERITED(nsCrypto, mozilla::dom::Crypto) 1.222 +NS_IMPL_RELEASE_INHERITED(nsCrypto, mozilla::dom::Crypto) 1.223 + 1.224 +// QueryInterface implementation for nsPkcs11 1.225 +#endif // MOZ_DISABLE_CRYPTOLEGACY 1.226 + 1.227 +NS_INTERFACE_MAP_BEGIN(nsPkcs11) 1.228 + NS_INTERFACE_MAP_ENTRY(nsIPKCS11) 1.229 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.230 +NS_INTERFACE_MAP_END 1.231 + 1.232 +NS_IMPL_ADDREF(nsPkcs11) 1.233 +NS_IMPL_RELEASE(nsPkcs11) 1.234 + 1.235 +#ifndef MOZ_DISABLE_CRYPTOLEGACY 1.236 + 1.237 +// ISupports implementation for nsCryptoRunnable 1.238 +NS_IMPL_ISUPPORTS(nsCryptoRunnable, nsIRunnable) 1.239 + 1.240 +// ISupports implementation for nsP12Runnable 1.241 +NS_IMPL_ISUPPORTS(nsP12Runnable, nsIRunnable) 1.242 + 1.243 +// ISupports implementation for nsCryptoRunArgs 1.244 +NS_IMPL_ISUPPORTS0(nsCryptoRunArgs) 1.245 + 1.246 +nsCrypto::nsCrypto() : 1.247 + mEnableSmartCardEvents(false) 1.248 +{ 1.249 +} 1.250 + 1.251 +nsCrypto::~nsCrypto() 1.252 +{ 1.253 +} 1.254 + 1.255 +void 1.256 +nsCrypto::Init(nsIDOMWindow* aWindow) 1.257 +{ 1.258 + mozilla::dom::Crypto::Init(aWindow); 1.259 +} 1.260 + 1.261 +void 1.262 +nsCrypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv) 1.263 +{ 1.264 + NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.265 + 1.266 + nsresult rv = NS_OK; 1.267 + 1.268 + // this has the side effect of starting the nssComponent (and initializing 1.269 + // NSS) even if it isn't already going. Starting the nssComponent is a 1.270 + // prerequisite for getting smartCard events. 1.271 + if (aEnable) { 1.272 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.273 + } 1.274 + 1.275 + if (NS_FAILED(rv)) { 1.276 + aRv.Throw(rv); 1.277 + return; 1.278 + } 1.279 + 1.280 + mEnableSmartCardEvents = aEnable; 1.281 +} 1.282 + 1.283 +NS_IMETHODIMP 1.284 +nsCrypto::SetEnableSmartCardEvents(bool aEnable) 1.285 +{ 1.286 + ErrorResult rv; 1.287 + SetEnableSmartCardEvents(aEnable, rv); 1.288 + return rv.ErrorCode(); 1.289 +} 1.290 + 1.291 +bool 1.292 +nsCrypto::EnableSmartCardEvents() 1.293 +{ 1.294 + return mEnableSmartCardEvents; 1.295 +} 1.296 + 1.297 +NS_IMETHODIMP 1.298 +nsCrypto::GetEnableSmartCardEvents(bool *aEnable) 1.299 +{ 1.300 + *aEnable = EnableSmartCardEvents(); 1.301 + return NS_OK; 1.302 +} 1.303 + 1.304 +//A quick function to let us know if the key we're trying to generate 1.305 +//can be escrowed. 1.306 +static bool 1.307 +ns_can_escrow(nsKeyGenType keyGenType) 1.308 +{ 1.309 + /* For now, we only escrow rsa-encryption and ec-encryption keys. */ 1.310 + return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc); 1.311 +} 1.312 + 1.313 +//Retrieve crypto.version so that callers know what 1.314 +//version of PSM this is. 1.315 +void 1.316 +nsCrypto::GetVersion(nsString& aVersion) 1.317 +{ 1.318 + aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING)); 1.319 +} 1.320 + 1.321 +/* 1.322 + * Given an nsKeyGenType, return the PKCS11 mechanism that will 1.323 + * perform the correct key generation. 1.324 + */ 1.325 +static uint32_t 1.326 +cryptojs_convert_to_mechanism(nsKeyGenType keyGenType) 1.327 +{ 1.328 + uint32_t retMech; 1.329 + 1.330 + switch (keyGenType) { 1.331 + case rsaEnc: 1.332 + case rsaDualUse: 1.333 + case rsaSign: 1.334 + case rsaNonrepudiation: 1.335 + case rsaSignNonrepudiation: 1.336 + retMech = CKM_RSA_PKCS_KEY_PAIR_GEN; 1.337 + break; 1.338 + case ecEnc: 1.339 + case ecDualUse: 1.340 + case ecSign: 1.341 + case ecNonrepudiation: 1.342 + case ecSignNonrepudiation: 1.343 + retMech = CKM_EC_KEY_PAIR_GEN; 1.344 + break; 1.345 + case dhEx: 1.346 + retMech = CKM_DH_PKCS_KEY_PAIR_GEN; 1.347 + break; 1.348 + case dsaSign: 1.349 + case dsaSignNonrepudiation: 1.350 + case dsaNonrepudiation: 1.351 + retMech = CKM_DSA_KEY_PAIR_GEN; 1.352 + break; 1.353 + default: 1.354 + retMech = CKM_INVALID_MECHANISM; 1.355 + } 1.356 + return retMech; 1.357 +} 1.358 + 1.359 +/* 1.360 + * This function takes a string read through JavaScript parameters 1.361 + * and translates it to the internal enumeration representing the 1.362 + * key gen type. Leading and trailing whitespace must be already removed. 1.363 + */ 1.364 +static nsKeyGenType 1.365 +cryptojs_interpret_key_gen_type(const nsAString& keyAlg) 1.366 +{ 1.367 + if (keyAlg.EqualsLiteral("rsa-ex")) { 1.368 + return rsaEnc; 1.369 + } 1.370 + if (keyAlg.EqualsLiteral("rsa-dual-use")) { 1.371 + return rsaDualUse; 1.372 + } 1.373 + if (keyAlg.EqualsLiteral("rsa-sign")) { 1.374 + return rsaSign; 1.375 + } 1.376 + if (keyAlg.EqualsLiteral("rsa-sign-nonrepudiation")) { 1.377 + return rsaSignNonrepudiation; 1.378 + } 1.379 + if (keyAlg.EqualsLiteral("rsa-nonrepudiation")) { 1.380 + return rsaNonrepudiation; 1.381 + } 1.382 + if (keyAlg.EqualsLiteral("ec-ex")) { 1.383 + return ecEnc; 1.384 + } 1.385 + if (keyAlg.EqualsLiteral("ec-dual-use")) { 1.386 + return ecDualUse; 1.387 + } 1.388 + if (keyAlg.EqualsLiteral("ec-sign")) { 1.389 + return ecSign; 1.390 + } 1.391 + if (keyAlg.EqualsLiteral("ec-sign-nonrepudiation")) { 1.392 + return ecSignNonrepudiation; 1.393 + } 1.394 + if (keyAlg.EqualsLiteral("ec-nonrepudiation")) { 1.395 + return ecNonrepudiation; 1.396 + } 1.397 + if (keyAlg.EqualsLiteral("dsa-sign-nonrepudiation")) { 1.398 + return dsaSignNonrepudiation; 1.399 + } 1.400 + if (keyAlg.EqualsLiteral("dsa-sign")) { 1.401 + return dsaSign; 1.402 + } 1.403 + if (keyAlg.EqualsLiteral("dsa-nonrepudiation")) { 1.404 + return dsaNonrepudiation; 1.405 + } 1.406 + if (keyAlg.EqualsLiteral("dh-ex")) { 1.407 + return dhEx; 1.408 + } 1.409 + return invalidKeyGen; 1.410 +} 1.411 + 1.412 +/* 1.413 + * input: null terminated char* pointing to (the remainder of) an 1.414 + * EC key param string. 1.415 + * 1.416 + * bool return value, false means "no more name=value pair found", 1.417 + * true means "found, see out params" 1.418 + * 1.419 + * out param name: char * pointing to name (not zero terminated) 1.420 + * out param name_len: length of found name 1.421 + * out param value: char * pointing to value (not zero terminated) 1.422 + * out param value_len: length of found value 1.423 + * out param next_pair: to be used for a follow up call to this function 1.424 + */ 1.425 + 1.426 +bool getNextNameValueFromECKeygenParamString(char *input, 1.427 + char *&name, 1.428 + int &name_len, 1.429 + char *&value, 1.430 + int &value_len, 1.431 + char *&next_call) 1.432 +{ 1.433 + if (!input || !*input) 1.434 + return false; 1.435 + 1.436 + // we allow leading ; and leading space in front of each name value pair 1.437 + 1.438 + while (*input && *input == ';') 1.439 + ++input; 1.440 + 1.441 + while (*input && *input == ' ') 1.442 + ++input; 1.443 + 1.444 + name = input; 1.445 + 1.446 + while (*input && *input != '=') 1.447 + ++input; 1.448 + 1.449 + if (*input != '=') 1.450 + return false; 1.451 + 1.452 + name_len = input - name; 1.453 + ++input; 1.454 + 1.455 + value = input; 1.456 + 1.457 + while (*input && *input != ';') 1.458 + ++input; 1.459 + 1.460 + value_len = input - value; 1.461 + next_call = input; 1.462 + 1.463 + return true; 1.464 +} 1.465 + 1.466 +//Take the string passed into us via crypto.generateCRMFRequest 1.467 +//as the keygen type parameter and convert it to parameters 1.468 +//we can actually pass to the PKCS#11 layer. 1.469 +static void* 1.470 +nsConvertToActualKeyGenParams(uint32_t keyGenMech, char *params, 1.471 + uint32_t paramLen, int32_t keySize, 1.472 + nsKeyPairInfo *keyPairInfo) 1.473 +{ 1.474 + void *returnParams = nullptr; 1.475 + 1.476 + 1.477 + switch (keyGenMech) { 1.478 + case CKM_RSA_PKCS_KEY_PAIR_GEN: 1.479 + { 1.480 + // For RSA, we don't support passing in key generation arguments from 1.481 + // the JS code just yet. 1.482 + if (params) 1.483 + return nullptr; 1.484 + 1.485 + PK11RSAGenParams *rsaParams; 1.486 + rsaParams = static_cast<PK11RSAGenParams*> 1.487 + (nsMemory::Alloc(sizeof(PK11RSAGenParams))); 1.488 + 1.489 + if (!rsaParams) { 1.490 + return nullptr; 1.491 + } 1.492 + /* I'm just taking the same parameters used in 1.493 + * certdlgs.c:GenKey 1.494 + */ 1.495 + if (keySize > 0) { 1.496 + rsaParams->keySizeInBits = keySize; 1.497 + } else { 1.498 + rsaParams->keySizeInBits = 1024; 1.499 + } 1.500 + rsaParams->pe = DEFAULT_RSA_KEYGEN_PE; 1.501 + returnParams = rsaParams; 1.502 + break; 1.503 + } 1.504 + case CKM_EC_KEY_PAIR_GEN: 1.505 + { 1.506 + /* 1.507 + * keygen params for generating EC keys must be composed of name=value pairs, 1.508 + * multiple pairs allowed, separated using semicolon ; 1.509 + * 1.510 + * Either param "curve" or param "popcert" must be specified. 1.511 + * curve=name-of-curve 1.512 + * popcert=base64-encoded-cert 1.513 + * 1.514 + * When both params are specified, popcert will be used. 1.515 + * If no popcert param is given, or if popcert can not be decoded, 1.516 + * we will fall back to the curve param. 1.517 + * 1.518 + * Additional name=value pairs may be defined in the future. 1.519 + * 1.520 + * If param popcert is present and valid, the given certificate will be used 1.521 + * to determine the key generation params. In addition the certificate 1.522 + * will be used to produce a dhMac based Proof of Posession, 1.523 + * using the cert's public key, subject and issuer names, 1.524 + * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A. 1.525 + * 1.526 + * If neither param popcert nor param curve could be used, 1.527 + * tse a curve based on the keysize param. 1.528 + * NOTE: Here keysize is used only as an indication of 1.529 + * High/Medium/Low strength; elliptic curve 1.530 + * cryptography uses smaller keys than RSA to provide 1.531 + * equivalent security. 1.532 + */ 1.533 + 1.534 + char *curve = nullptr; 1.535 + 1.536 + { 1.537 + // extract components of name=value list 1.538 + 1.539 + char *next_input = params; 1.540 + char *name = nullptr; 1.541 + char *value = nullptr; 1.542 + int name_len = 0; 1.543 + int value_len = 0; 1.544 + 1.545 + while (getNextNameValueFromECKeygenParamString( 1.546 + next_input, name, name_len, value, value_len, 1.547 + next_input)) 1.548 + { 1.549 + // use only the first specified curve 1.550 + if (!curve && PL_strncmp(name, "curve", std::min(name_len, 5)) == 0) 1.551 + { 1.552 + curve = PL_strndup(value, value_len); 1.553 + } 1.554 + // use only the first specified popcert 1.555 + else if (!keyPairInfo->ecPopCert && 1.556 + PL_strncmp(name, "popcert", std::min(name_len, 7)) == 0) 1.557 + { 1.558 + char *certstr = PL_strndup(value, value_len); 1.559 + if (certstr) { 1.560 + keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr); 1.561 + PL_strfree(certstr); 1.562 + 1.563 + if (keyPairInfo->ecPopCert) 1.564 + { 1.565 + keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert); 1.566 + } 1.567 + } 1.568 + } 1.569 + } 1.570 + } 1.571 + 1.572 + // first try to use the params of the provided CA cert 1.573 + if (keyPairInfo->ecPopPubKey && keyPairInfo->ecPopPubKey->keyType == ecKey) 1.574 + { 1.575 + returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams); 1.576 + } 1.577 + 1.578 + // if we did not yet find good params, do we have a curve name? 1.579 + if (!returnParams && curve) 1.580 + { 1.581 + returnParams = decode_ec_params(curve); 1.582 + } 1.583 + 1.584 + // if we did not yet find good params, do something based on keysize 1.585 + if (!returnParams) 1.586 + { 1.587 + switch (keySize) { 1.588 + case 512: 1.589 + case 1024: 1.590 + returnParams = decode_ec_params("secp256r1"); 1.591 + break; 1.592 + case 2048: 1.593 + default: 1.594 + returnParams = decode_ec_params("secp384r1"); 1.595 + break; 1.596 + } 1.597 + } 1.598 + 1.599 + if (curve) 1.600 + PL_strfree(curve); 1.601 + 1.602 + break; 1.603 + } 1.604 + case CKM_DSA_KEY_PAIR_GEN: 1.605 + { 1.606 + // For DSA, we don't support passing in key generation arguments from 1.607 + // the JS code just yet. 1.608 + if (params) 1.609 + return nullptr; 1.610 + 1.611 + PQGParams *pqgParams = nullptr; 1.612 + PQGVerify *vfy = nullptr; 1.613 + SECStatus rv; 1.614 + int index; 1.615 + 1.616 + index = PQG_PBITS_TO_INDEX(keySize); 1.617 + if (index == -1) { 1.618 + returnParams = nullptr; 1.619 + break; 1.620 + } 1.621 + rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy); 1.622 + if (vfy) { 1.623 + PK11_PQG_DestroyVerify(vfy); 1.624 + } 1.625 + if (rv != SECSuccess) { 1.626 + if (pqgParams) { 1.627 + PK11_PQG_DestroyParams(pqgParams); 1.628 + } 1.629 + return nullptr; 1.630 + } 1.631 + returnParams = pqgParams; 1.632 + break; 1.633 + } 1.634 + default: 1.635 + returnParams = nullptr; 1.636 + } 1.637 + return returnParams; 1.638 +} 1.639 + 1.640 +//We need to choose which PKCS11 slot we're going to generate 1.641 +//the key on. Calls the default implementation provided by 1.642 +//nsKeygenHandler.cpp 1.643 +static PK11SlotInfo* 1.644 +nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx) 1.645 +{ 1.646 + nsNSSShutDownPreventionLock locker; 1.647 + uint32_t mechanism = cryptojs_convert_to_mechanism(keyGenType); 1.648 + PK11SlotInfo *slot = nullptr; 1.649 + nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot); 1.650 + if (NS_FAILED(rv)) { 1.651 + if (slot) 1.652 + PK11_FreeSlot(slot); 1.653 + slot = nullptr; 1.654 + } 1.655 + return slot; 1.656 +} 1.657 + 1.658 +//Free the parameters that were passed into PK11_GenerateKeyPair 1.659 +//depending on the mechanism type used. 1.660 +static void 1.661 +nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params) 1.662 +{ 1.663 + switch (keyGenMechanism) { 1.664 + case CKM_RSA_PKCS_KEY_PAIR_GEN: 1.665 + nsMemory::Free(params); 1.666 + break; 1.667 + case CKM_EC_KEY_PAIR_GEN: 1.668 + SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true); 1.669 + break; 1.670 + case CKM_DSA_KEY_PAIR_GEN: 1.671 + PK11_PQG_DestroyParams(static_cast<PQGParams*>(params)); 1.672 + break; 1.673 + } 1.674 +} 1.675 + 1.676 +//Function that is used to generate a single key pair. 1.677 +//Once all the arguments have been parsed and processed, this 1.678 +//function gets called and takes care of actually generating 1.679 +//the key pair passing the appopriate parameters to the NSS 1.680 +//functions. 1.681 +static nsresult 1.682 +cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo, 1.683 + int32_t keySize, char *params, 1.684 + nsIInterfaceRequestor *uiCxt, 1.685 + PK11SlotInfo *slot, bool willEscrow) 1.686 + 1.687 +{ 1.688 + const PK11AttrFlags sensitiveFlags = (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE); 1.689 + const PK11AttrFlags temporarySessionFlags = PK11_ATTR_SESSION; 1.690 + const PK11AttrFlags permanentTokenFlags = PK11_ATTR_TOKEN; 1.691 + const PK11AttrFlags extractableFlags = PK11_ATTR_EXTRACTABLE; 1.692 + 1.693 + nsIGeneratingKeypairInfoDialogs * dialogs; 1.694 + nsKeygenThread *KeygenRunnable = 0; 1.695 + nsCOMPtr<nsIKeygenThread> runnable; 1.696 + 1.697 + uint32_t mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType); 1.698 + void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params, 1.699 + (params) ? strlen(params):0, 1.700 + keySize, keyPairInfo); 1.701 + 1.702 + if (!keyGenParams || !slot) { 1.703 + return NS_ERROR_INVALID_ARG; 1.704 + } 1.705 + 1.706 + // Make sure the token has password already set on it before trying 1.707 + // to generate the key. 1.708 + 1.709 + nsresult rv = setPassword(slot, uiCxt); 1.710 + if (NS_FAILED(rv)) 1.711 + return rv; 1.712 + 1.713 + if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess) 1.714 + return NS_ERROR_FAILURE; 1.715 + 1.716 + // Smart cards will not let you extract a private key once 1.717 + // it is on the smart card. If we've been told to escrow 1.718 + // a private key that will be stored on a smart card, 1.719 + // then we'll use the following strategy to ensure we can escrow it. 1.720 + // We'll attempt to generate the key on our internal token, 1.721 + // because this is expected to avoid some problems. 1.722 + // If it works, we'll escrow, move the key to the smartcard, done. 1.723 + // If it didn't work (or the internal key doesn't support the desired 1.724 + // mechanism), then we'll attempt to generate the key on 1.725 + // the destination token, with the EXTRACTABLE flag set. 1.726 + // If it works, we'll extract, escrow, done. 1.727 + // If it failed, then we're unable to escrow and return failure. 1.728 + // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot 1.729 + // so that the key has zero chance of being store in the 1.730 + // user's key3.db file. Which the slot returned by 1.731 + // PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot 1.732 + // does not. 1.733 + ScopedPK11SlotInfo intSlot; 1.734 + 1.735 + if (willEscrow && !PK11_IsInternal(slot)) { 1.736 + intSlot = PK11_GetInternalSlot(); 1.737 + NS_ASSERTION(intSlot,"Couldn't get the internal slot"); 1.738 + 1.739 + if (!PK11_DoesMechanism(intSlot, mechanism)) { 1.740 + // Set to null, and the subsequent code will not attempt to use it. 1.741 + intSlot = nullptr; 1.742 + } 1.743 + } 1.744 + 1.745 + rv = getNSSDialogs((void**)&dialogs, 1.746 + NS_GET_IID(nsIGeneratingKeypairInfoDialogs), 1.747 + NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID); 1.748 + 1.749 + if (NS_SUCCEEDED(rv)) { 1.750 + KeygenRunnable = new nsKeygenThread(); 1.751 + if (KeygenRunnable) { 1.752 + NS_ADDREF(KeygenRunnable); 1.753 + } 1.754 + } 1.755 + 1.756 + // "firstAttemptSlot" and "secondAttemptSlot" are alternative names 1.757 + // for better code readability, we don't increase the reference counts. 1.758 + 1.759 + PK11SlotInfo *firstAttemptSlot = nullptr; 1.760 + PK11AttrFlags firstAttemptFlags = 0; 1.761 + 1.762 + PK11SlotInfo *secondAttemptSlot = slot; 1.763 + PK11AttrFlags secondAttemptFlags = sensitiveFlags | permanentTokenFlags; 1.764 + 1.765 + if (willEscrow) { 1.766 + secondAttemptFlags |= extractableFlags; 1.767 + } 1.768 + 1.769 + if (!intSlot || PK11_IsInternal(slot)) { 1.770 + // if we cannot use the internal slot, then there is only one attempt 1.771 + // if the destination slot is the internal slot, then there is only one attempt 1.772 + firstAttemptSlot = secondAttemptSlot; 1.773 + firstAttemptFlags = secondAttemptFlags; 1.774 + secondAttemptSlot = nullptr; 1.775 + secondAttemptFlags = 0; 1.776 + } 1.777 + else { 1.778 + firstAttemptSlot = intSlot; 1.779 + firstAttemptFlags = sensitiveFlags | temporarySessionFlags; 1.780 + 1.781 + // We always need the extractable flag on the first attempt, 1.782 + // because we want to move the key to another slot - ### is this correct? 1.783 + firstAttemptFlags |= extractableFlags; 1.784 + } 1.785 + 1.786 + bool mustMoveKey = false; 1.787 + 1.788 + if (NS_FAILED(rv) || !KeygenRunnable) { 1.789 + /* execute key generation on this thread */ 1.790 + rv = NS_OK; 1.791 + 1.792 + keyPairInfo->privKey = 1.793 + PK11_GenerateKeyPairWithFlags(firstAttemptSlot, mechanism, 1.794 + keyGenParams, &keyPairInfo->pubKey, 1.795 + firstAttemptFlags, uiCxt); 1.796 + 1.797 + if (keyPairInfo->privKey) { 1.798 + // success on first attempt 1.799 + if (secondAttemptSlot) { 1.800 + mustMoveKey = true; 1.801 + } 1.802 + } 1.803 + else { 1.804 + keyPairInfo->privKey = 1.805 + PK11_GenerateKeyPairWithFlags(secondAttemptSlot, mechanism, 1.806 + keyGenParams, &keyPairInfo->pubKey, 1.807 + secondAttemptFlags, uiCxt); 1.808 + } 1.809 + 1.810 + } else { 1.811 + /* execute key generation on separate thread */ 1.812 + KeygenRunnable->SetParams( firstAttemptSlot, firstAttemptFlags, 1.813 + secondAttemptSlot, secondAttemptFlags, 1.814 + mechanism, keyGenParams, uiCxt ); 1.815 + 1.816 + runnable = do_QueryInterface(KeygenRunnable); 1.817 + 1.818 + if (runnable) { 1.819 + { 1.820 + nsPSMUITracker tracker; 1.821 + if (tracker.isUIForbidden()) { 1.822 + rv = NS_ERROR_NOT_AVAILABLE; 1.823 + } 1.824 + else { 1.825 + rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable); 1.826 + // We call join on the thread, 1.827 + // so we can be sure that no simultaneous access to the passed parameters will happen. 1.828 + KeygenRunnable->Join(); 1.829 + } 1.830 + } 1.831 + 1.832 + NS_RELEASE(dialogs); 1.833 + if (NS_SUCCEEDED(rv)) { 1.834 + PK11SlotInfo *used_slot = nullptr; 1.835 + rv = KeygenRunnable->ConsumeResult(&used_slot, 1.836 + &keyPairInfo->privKey, &keyPairInfo->pubKey); 1.837 + 1.838 + if (NS_SUCCEEDED(rv)) { 1.839 + if ((used_slot == firstAttemptSlot) && secondAttemptSlot) { 1.840 + mustMoveKey = true; 1.841 + } 1.842 + 1.843 + if (used_slot) { 1.844 + PK11_FreeSlot(used_slot); 1.845 + } 1.846 + } 1.847 + } 1.848 + } 1.849 + } 1.850 + 1.851 + firstAttemptSlot = nullptr; 1.852 + secondAttemptSlot = nullptr; 1.853 + 1.854 + nsFreeKeyGenParams(mechanism, keyGenParams); 1.855 + 1.856 + if (KeygenRunnable) { 1.857 + NS_RELEASE(KeygenRunnable); 1.858 + } 1.859 + 1.860 + if (!keyPairInfo->privKey || !keyPairInfo->pubKey) { 1.861 + return NS_ERROR_FAILURE; 1.862 + } 1.863 + 1.864 + //If we generated the key pair on the internal slot because the 1.865 + // keys were going to be escrowed, move the keys over right now. 1.866 + if (mustMoveKey) { 1.867 + ScopedSECKEYPrivateKey newPrivKey(PK11_LoadPrivKey(slot, 1.868 + keyPairInfo->privKey, 1.869 + keyPairInfo->pubKey, 1.870 + true, true)); 1.871 + if (!newPrivKey) 1.872 + return NS_ERROR_FAILURE; 1.873 + 1.874 + // The private key is stored on the selected slot now, and the copy we 1.875 + // ultimately use for escrowing when the time comes lives 1.876 + // in the internal slot. We will delete it from that slot 1.877 + // after the requests are made. 1.878 + } 1.879 + 1.880 + return NS_OK; 1.881 +} 1.882 + 1.883 +/* 1.884 + * FUNCTION: cryptojs_ReadArgsAndGenerateKey 1.885 + * ------------------------------------- 1.886 + * INPUTS: 1.887 + * cx 1.888 + * The JSContext associated with the execution of the corresponging 1.889 + * crypto.generateCRMFRequest call 1.890 + * argv 1.891 + * A pointer to an array of JavaScript parameters passed to the 1.892 + * method crypto.generateCRMFRequest. The array should have the 1.893 + * 3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in 1.894 + * the definition of crypto.generateCRMFRequest at the following 1.895 + * document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 1.896 + * keyGenType 1.897 + * A structure used to store the information about the newly created 1.898 + * key pair. 1.899 + * uiCxt 1.900 + * An interface requestor that would be used to get an nsIPrompt 1.901 + * if we need to ask the user for a password. 1.902 + * slotToUse 1.903 + * The PKCS11 slot to use for generating the key pair. If nullptr, then 1.904 + * this function should select a slot that can do the key generation 1.905 + * from the keytype associted with the keyPairInfo, and pass it back to 1.906 + * the caller so that subsequence key generations can use the same slot. 1.907 + * willEscrow 1.908 + * If true, then that means we will try to escrow the generated 1.909 + * private key when building the CRMF request. If false, then 1.910 + * we will not try to escrow the private key. 1.911 + * 1.912 + * NOTES: 1.913 + * This function takes care of reading a set of 3 parameters that define 1.914 + * one key generation. The argv pointer should be one that originates 1.915 + * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest. 1.916 + * The function interprets the argument in the first index as an integer and 1.917 + * passes that as the key size for the key generation-this parameter is 1.918 + * mandatory. The second parameter is read in as a string. This value can 1.919 + * be null in JavaScript world and everything will still work. The third 1.920 + * parameter is a mandatory string that indicates what kind of key to generate. 1.921 + * There should always be 1-to-1 correspondence between the strings compared 1.922 + * in the function cryptojs_interpret_key_gen_type and the strings listed in 1.923 + * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html 1.924 + * under the definition of the method generateCRMFRequest, for the parameter 1.925 + * "keyGenAlgN". After reading the parameters, the function then 1.926 + * generates the key pairs passing the parameters parsed from the JavaScript i 1.927 + * routine. 1.928 + * 1.929 + * RETURN: 1.930 + * NS_OK if creating the Key was successful. Any other return value 1.931 + * indicates an error. 1.932 + */ 1.933 + 1.934 +static nsresult 1.935 +cryptojs_ReadArgsAndGenerateKey(JSContext *cx, 1.936 + JS::Value *argv, 1.937 + nsKeyPairInfo *keyGenType, 1.938 + nsIInterfaceRequestor *uiCxt, 1.939 + PK11SlotInfo **slot, bool willEscrow) 1.940 +{ 1.941 + JSString *jsString; 1.942 + JSAutoByteString params; 1.943 + int keySize; 1.944 + nsresult rv; 1.945 + 1.946 + if (!JSVAL_IS_INT(argv[0])) { 1.947 + JS_ReportError(cx, "%s%s", JS_ERROR, 1.948 + "passed in non-integer for key size"); 1.949 + return NS_ERROR_FAILURE; 1.950 + } 1.951 + keySize = JSVAL_TO_INT(argv[0]); 1.952 + if (!JSVAL_IS_NULL(argv[1])) { 1.953 + JS::Rooted<JS::Value> v(cx, argv[1]); 1.954 + jsString = JS::ToString(cx, v); 1.955 + NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY); 1.956 + argv[1] = STRING_TO_JSVAL(jsString); 1.957 + params.encodeLatin1(cx, jsString); 1.958 + NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY); 1.959 + } 1.960 + 1.961 + if (JSVAL_IS_NULL(argv[2])) { 1.962 + JS_ReportError(cx,"%s%s", JS_ERROR, 1.963 + "key generation type not specified"); 1.964 + return NS_ERROR_FAILURE; 1.965 + } 1.966 + JS::Rooted<JS::Value> v(cx, argv[2]); 1.967 + jsString = JS::ToString(cx, v); 1.968 + NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY); 1.969 + argv[2] = STRING_TO_JSVAL(jsString); 1.970 + nsDependentJSString dependentKeyGenAlg; 1.971 + NS_ENSURE_TRUE(dependentKeyGenAlg.init(cx, jsString), NS_ERROR_UNEXPECTED); 1.972 + nsAutoString keyGenAlg(dependentKeyGenAlg); 1.973 + keyGenAlg.Trim("\r\n\t "); 1.974 + keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg); 1.975 + if (keyGenType->keyGenType == invalidKeyGen) { 1.976 + NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg); 1.977 + JS_ReportError(cx, "%s%s%s", JS_ERROR, 1.978 + "invalid key generation argument:", 1.979 + keyGenAlgNarrow.get()); 1.980 + goto loser; 1.981 + } 1.982 + if (!*slot) { 1.983 + *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt); 1.984 + if (!*slot) 1.985 + goto loser; 1.986 + } 1.987 + 1.988 + rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt, 1.989 + *slot,willEscrow); 1.990 + 1.991 + if (rv != NS_OK) { 1.992 + NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg); 1.993 + JS_ReportError(cx,"%s%s%s", JS_ERROR, 1.994 + "could not generate the key for algorithm ", 1.995 + keyGenAlgNarrow.get()); 1.996 + goto loser; 1.997 + } 1.998 + return NS_OK; 1.999 +loser: 1.1000 + return NS_ERROR_FAILURE; 1.1001 +} 1.1002 + 1.1003 +//Utility funciton to free up the memory used by nsKeyPairInfo 1.1004 +//arrays. 1.1005 +static void 1.1006 +nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs) 1.1007 +{ 1.1008 + NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo"); 1.1009 + if (!keyids) 1.1010 + return; 1.1011 + int i; 1.1012 + for (i=0; i<numIDs; i++) { 1.1013 + if (keyids[i].pubKey) 1.1014 + SECKEY_DestroyPublicKey(keyids[i].pubKey); 1.1015 + if (keyids[i].privKey) 1.1016 + SECKEY_DestroyPrivateKey(keyids[i].privKey); 1.1017 + if (keyids[i].ecPopCert) 1.1018 + CERT_DestroyCertificate(keyids[i].ecPopCert); 1.1019 + if (keyids[i].ecPopPubKey) 1.1020 + SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey); 1.1021 + } 1.1022 + delete []keyids; 1.1023 +} 1.1024 + 1.1025 +//Utility funciton used to free the genertaed cert request messages 1.1026 +static void 1.1027 +nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, int32_t numMessages) 1.1028 +{ 1.1029 + int32_t i; 1.1030 + for (i=0; i<numMessages && certReqMsgs[i]; i++) { 1.1031 + CRMF_DestroyCertReqMsg(certReqMsgs[i]); 1.1032 + } 1.1033 + delete []certReqMsgs; 1.1034 +} 1.1035 + 1.1036 +//If the form called for escrowing the private key we just generated, 1.1037 +//this function adds all the correct elements to the request. 1.1038 +//That consists of adding CRMFEncryptedKey to the reques as part 1.1039 +//of the CRMFPKIArchiveOptions Control. 1.1040 +static nsresult 1.1041 +nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo, 1.1042 + nsNSSCertificate *wrappingCert) 1.1043 +{ 1.1044 + if (!wrappingCert || 1.1045 + CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){ 1.1046 + return NS_ERROR_FAILURE; 1.1047 + } 1.1048 + mozilla::pkix::ScopedCERTCertificate cert(wrappingCert->GetCert()); 1.1049 + if (!cert) 1.1050 + return NS_ERROR_FAILURE; 1.1051 + 1.1052 + CRMFEncryptedKey *encrKey = 1.1053 + CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert.get()); 1.1054 + if (!encrKey) 1.1055 + return NS_ERROR_FAILURE; 1.1056 + 1.1057 + CRMFPKIArchiveOptions *archOpt = 1.1058 + CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey); 1.1059 + if (!archOpt) { 1.1060 + CRMF_DestroyEncryptedKey(encrKey); 1.1061 + return NS_ERROR_FAILURE; 1.1062 + } 1.1063 + SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt); 1.1064 + CRMF_DestroyEncryptedKey(encrKey); 1.1065 + CRMF_DestroyPKIArchiveOptions(archOpt); 1.1066 + if (srv != SECSuccess) 1.1067 + return NS_ERROR_FAILURE; 1.1068 + 1.1069 + return NS_OK; 1.1070 +} 1.1071 + 1.1072 +//Set the Distinguished Name (Subject Name) for the cert 1.1073 +//being requested. 1.1074 +static nsresult 1.1075 +nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN) 1.1076 +{ 1.1077 + if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) { 1.1078 + return NS_ERROR_FAILURE; 1.1079 + } 1.1080 + ScopedCERTName subjectName(CERT_AsciiToName(reqDN)); 1.1081 + if (!subjectName) { 1.1082 + return NS_ERROR_FAILURE; 1.1083 + } 1.1084 + SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject, 1.1085 + static_cast<void*> 1.1086 + (subjectName)); 1.1087 + return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE; 1.1088 +} 1.1089 + 1.1090 +//Set Registration Token Control on the request. 1.1091 +static nsresult 1.1092 +nsSetRegToken(CRMFCertRequest *certReq, char *regToken) 1.1093 +{ 1.1094 + // this should never happen, but might as well add this. 1.1095 + NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken"); 1.1096 + if (regToken){ 1.1097 + if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl)) 1.1098 + return NS_ERROR_FAILURE; 1.1099 + 1.1100 + SECItem src; 1.1101 + src.data = (unsigned char*)regToken; 1.1102 + src.len = strlen(regToken); 1.1103 + SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src, 1.1104 + SEC_ASN1_GET(SEC_UTF8StringTemplate)); 1.1105 + 1.1106 + if (!derEncoded) 1.1107 + return NS_ERROR_FAILURE; 1.1108 + 1.1109 + SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded); 1.1110 + SECITEM_FreeItem(derEncoded,true); 1.1111 + if (srv != SECSuccess) 1.1112 + return NS_ERROR_FAILURE; 1.1113 + } 1.1114 + return NS_OK; 1.1115 +} 1.1116 + 1.1117 +//Set the Authenticator control on the cert reuest. It's just 1.1118 +//a string that gets passed along. 1.1119 +static nsresult 1.1120 +nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator) 1.1121 +{ 1.1122 + //This should never happen, but might as well check. 1.1123 + NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator"); 1.1124 + if (authenticator) { 1.1125 + if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl)) 1.1126 + return NS_ERROR_FAILURE; 1.1127 + 1.1128 + SECItem src; 1.1129 + src.data = (unsigned char*)authenticator; 1.1130 + src.len = strlen(authenticator); 1.1131 + SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src, 1.1132 + SEC_ASN1_GET(SEC_UTF8StringTemplate)); 1.1133 + if (!derEncoded) 1.1134 + return NS_ERROR_FAILURE; 1.1135 + 1.1136 + SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq, 1.1137 + derEncoded); 1.1138 + SECITEM_FreeItem(derEncoded, true); 1.1139 + if (srv != SECSuccess) 1.1140 + return NS_ERROR_FAILURE; 1.1141 + } 1.1142 + return NS_OK; 1.1143 +} 1.1144 + 1.1145 +// ASN1 DER encoding rules say that when encoding a BIT string, 1.1146 +// the length in the header for the bit string is the number 1.1147 +// of "useful" bits in the BIT STRING. So the function finds 1.1148 +// it and sets accordingly for the returned item. 1.1149 +static void 1.1150 +nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value) 1.1151 +{ 1.1152 + unsigned char onebyte; 1.1153 + unsigned int i, len = 0; 1.1154 + 1.1155 + /* to prevent warning on some platform at compile time */ 1.1156 + onebyte = '\0'; 1.1157 + /* Get the position of the right-most turn-on bit */ 1.1158 + for (i = 0; i < (value->len ) * 8; ++i) { 1.1159 + if (i % 8 == 0) 1.1160 + onebyte = value->data[i/8]; 1.1161 + if (onebyte & 0x80) 1.1162 + len = i; 1.1163 + onebyte <<= 1; 1.1164 + } 1.1165 + 1.1166 + bitsmap->data = value->data; 1.1167 + /* Add one here since we work with base 1 */ 1.1168 + bitsmap->len = len + 1; 1.1169 +} 1.1170 + 1.1171 +//This next section defines all the functions that sets the 1.1172 +//keyUsageExtension for all the different types of key gens 1.1173 +//we handle. The keyUsageExtension is just a bit flag extension 1.1174 +//that we set in wrapper functions that call straight into 1.1175 +//nsSetKeyUsageExtension. There is one wrapper funciton for each 1.1176 +//keyGenType. The correct function will eventually be called 1.1177 +//by going through a switch statement based on the nsKeyGenType 1.1178 +//in the nsKeyPairInfo struct. 1.1179 +static nsresult 1.1180 +nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, 1.1181 + unsigned char keyUsage) 1.1182 +{ 1.1183 + SECItem *encodedExt= nullptr; 1.1184 + SECItem keyUsageValue = { (SECItemType) 0, nullptr, 0 }; 1.1185 + SECItem bitsmap = { (SECItemType) 0, nullptr, 0 }; 1.1186 + SECStatus srv; 1.1187 + CRMFCertExtension *ext = nullptr; 1.1188 + CRMFCertExtCreationInfo extAddParams; 1.1189 + SEC_ASN1Template bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nullptr, 1.1190 + sizeof(SECItem)}; 1.1191 + 1.1192 + keyUsageValue.data = &keyUsage; 1.1193 + keyUsageValue.len = 1; 1.1194 + nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue); 1.1195 + 1.1196 + encodedExt = SEC_ASN1EncodeItem(nullptr, nullptr, &bitsmap,&bitStrTemplate); 1.1197 + if (!encodedExt) { 1.1198 + goto loser; 1.1199 + } 1.1200 + ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt); 1.1201 + if (!ext) { 1.1202 + goto loser; 1.1203 + } 1.1204 + extAddParams.numExtensions = 1; 1.1205 + extAddParams.extensions = &ext; 1.1206 + srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension, 1.1207 + &extAddParams); 1.1208 + if (srv != SECSuccess) { 1.1209 + goto loser; 1.1210 + } 1.1211 + CRMF_DestroyCertExtension(ext); 1.1212 + SECITEM_FreeItem(encodedExt, true); 1.1213 + return NS_OK; 1.1214 + loser: 1.1215 + if (ext) { 1.1216 + CRMF_DestroyCertExtension(ext); 1.1217 + } 1.1218 + if (encodedExt) { 1.1219 + SECITEM_FreeItem(encodedExt, true); 1.1220 + } 1.1221 + return NS_ERROR_FAILURE; 1.1222 +} 1.1223 + 1.1224 +static nsresult 1.1225 +nsSetRSADualUse(CRMFCertRequest *crmfReq) 1.1226 +{ 1.1227 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE 1.1228 + | KU_NON_REPUDIATION 1.1229 + | KU_KEY_ENCIPHERMENT; 1.1230 + 1.1231 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1232 +} 1.1233 + 1.1234 +static nsresult 1.1235 +nsSetRSAKeyEx(CRMFCertRequest *crmfReq) 1.1236 +{ 1.1237 + unsigned char keyUsage = KU_KEY_ENCIPHERMENT; 1.1238 + 1.1239 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1240 +} 1.1241 + 1.1242 +static nsresult 1.1243 +nsSetRSASign(CRMFCertRequest *crmfReq) 1.1244 +{ 1.1245 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE; 1.1246 + 1.1247 + 1.1248 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1249 +} 1.1250 + 1.1251 +static nsresult 1.1252 +nsSetRSANonRepudiation(CRMFCertRequest *crmfReq) 1.1253 +{ 1.1254 + unsigned char keyUsage = KU_NON_REPUDIATION; 1.1255 + 1.1256 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1257 +} 1.1258 + 1.1259 +static nsresult 1.1260 +nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq) 1.1261 +{ 1.1262 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE | 1.1263 + KU_NON_REPUDIATION; 1.1264 + 1.1265 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1266 +} 1.1267 + 1.1268 +static nsresult 1.1269 +nsSetECDualUse(CRMFCertRequest *crmfReq) 1.1270 +{ 1.1271 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE 1.1272 + | KU_NON_REPUDIATION 1.1273 + | KU_KEY_AGREEMENT; 1.1274 + 1.1275 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1276 +} 1.1277 + 1.1278 +static nsresult 1.1279 +nsSetECKeyEx(CRMFCertRequest *crmfReq) 1.1280 +{ 1.1281 + unsigned char keyUsage = KU_KEY_AGREEMENT; 1.1282 + 1.1283 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1284 +} 1.1285 + 1.1286 +static nsresult 1.1287 +nsSetECSign(CRMFCertRequest *crmfReq) 1.1288 +{ 1.1289 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE; 1.1290 + 1.1291 + 1.1292 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1293 +} 1.1294 + 1.1295 +static nsresult 1.1296 +nsSetECNonRepudiation(CRMFCertRequest *crmfReq) 1.1297 +{ 1.1298 + unsigned char keyUsage = KU_NON_REPUDIATION; 1.1299 + 1.1300 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1301 +} 1.1302 + 1.1303 +static nsresult 1.1304 +nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq) 1.1305 +{ 1.1306 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE | 1.1307 + KU_NON_REPUDIATION; 1.1308 + 1.1309 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1310 +} 1.1311 + 1.1312 +static nsresult 1.1313 +nsSetDH(CRMFCertRequest *crmfReq) 1.1314 +{ 1.1315 + unsigned char keyUsage = KU_KEY_AGREEMENT; 1.1316 + 1.1317 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1318 +} 1.1319 + 1.1320 +static nsresult 1.1321 +nsSetDSASign(CRMFCertRequest *crmfReq) 1.1322 +{ 1.1323 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE; 1.1324 + 1.1325 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1326 +} 1.1327 + 1.1328 +static nsresult 1.1329 +nsSetDSANonRepudiation(CRMFCertRequest *crmfReq) 1.1330 +{ 1.1331 + unsigned char keyUsage = KU_NON_REPUDIATION; 1.1332 + 1.1333 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1334 +} 1.1335 + 1.1336 +static nsresult 1.1337 +nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq) 1.1338 +{ 1.1339 + unsigned char keyUsage = KU_DIGITAL_SIGNATURE | 1.1340 + KU_NON_REPUDIATION; 1.1341 + 1.1342 + return nsSetKeyUsageExtension(crmfReq, keyUsage); 1.1343 +} 1.1344 + 1.1345 +static nsresult 1.1346 +nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType) 1.1347 +{ 1.1348 + nsresult rv; 1.1349 + 1.1350 + switch (keyGenType) { 1.1351 + case rsaDualUse: 1.1352 + rv = nsSetRSADualUse(crmfReq); 1.1353 + break; 1.1354 + case rsaEnc: 1.1355 + rv = nsSetRSAKeyEx(crmfReq); 1.1356 + break; 1.1357 + case rsaSign: 1.1358 + rv = nsSetRSASign(crmfReq); 1.1359 + break; 1.1360 + case rsaNonrepudiation: 1.1361 + rv = nsSetRSANonRepudiation(crmfReq); 1.1362 + break; 1.1363 + case rsaSignNonrepudiation: 1.1364 + rv = nsSetRSASignNonRepudiation(crmfReq); 1.1365 + break; 1.1366 + case ecDualUse: 1.1367 + rv = nsSetECDualUse(crmfReq); 1.1368 + break; 1.1369 + case ecEnc: 1.1370 + rv = nsSetECKeyEx(crmfReq); 1.1371 + break; 1.1372 + case ecSign: 1.1373 + rv = nsSetECSign(crmfReq); 1.1374 + break; 1.1375 + case ecNonrepudiation: 1.1376 + rv = nsSetECNonRepudiation(crmfReq); 1.1377 + break; 1.1378 + case ecSignNonrepudiation: 1.1379 + rv = nsSetECSignNonRepudiation(crmfReq); 1.1380 + break; 1.1381 + case dhEx: 1.1382 + rv = nsSetDH(crmfReq); 1.1383 + break; 1.1384 + case dsaSign: 1.1385 + rv = nsSetDSASign(crmfReq); 1.1386 + break; 1.1387 + case dsaNonrepudiation: 1.1388 + rv = nsSetDSANonRepudiation(crmfReq); 1.1389 + break; 1.1390 + case dsaSignNonrepudiation: 1.1391 + rv = nsSetDSASignNonRepudiation(crmfReq); 1.1392 + break; 1.1393 + default: 1.1394 + rv = NS_ERROR_FAILURE; 1.1395 + break; 1.1396 + } 1.1397 + return rv; 1.1398 +} 1.1399 + 1.1400 +//Create a single CRMFCertRequest with all of the necessary parts 1.1401 +//already installed. The request returned by this function will 1.1402 +//have all the parts necessary and can just be added to a 1.1403 +//Certificate Request Message. 1.1404 +static CRMFCertRequest* 1.1405 +nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken, 1.1406 + char *authenticator, nsNSSCertificate *wrappingCert) 1.1407 +{ 1.1408 + uint32_t reqID; 1.1409 + nsresult rv; 1.1410 + 1.1411 + //The draft says the ID of the request should be a random 1.1412 + //number. We don't have a way of tracking this number 1.1413 + //to compare when the reply actually comes back,though. 1.1414 + PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID)); 1.1415 + CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID); 1.1416 + if (!certReq) 1.1417 + return nullptr; 1.1418 + 1.1419 + long version = SEC_CERTIFICATE_VERSION_3; 1.1420 + SECStatus srv; 1.1421 + CERTSubjectPublicKeyInfo *spki = nullptr; 1.1422 + srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version); 1.1423 + if (srv != SECSuccess) 1.1424 + goto loser; 1.1425 + 1.1426 + spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey); 1.1427 + if (!spki) 1.1428 + goto loser; 1.1429 + 1.1430 + srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki); 1.1431 + SECKEY_DestroySubjectPublicKeyInfo(spki); 1.1432 + if (srv != SECSuccess) 1.1433 + goto loser; 1.1434 + 1.1435 + if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) { 1.1436 + rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert); 1.1437 + if (NS_FAILED(rv)) 1.1438 + goto loser; 1.1439 + } 1.1440 + rv = nsSetDNForRequest(certReq, reqDN); 1.1441 + if (NS_FAILED(rv)) 1.1442 + goto loser; 1.1443 + 1.1444 + rv = nsSetRegToken(certReq, regToken); 1.1445 + if (NS_FAILED(rv)) 1.1446 + goto loser; 1.1447 + 1.1448 + rv = nsSetAuthenticator(certReq, authenticator); 1.1449 + if (NS_FAILED(rv)) 1.1450 + goto loser; 1.1451 + 1.1452 + rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType); 1.1453 + if (NS_FAILED(rv)) 1.1454 + goto loser; 1.1455 + 1.1456 + return certReq; 1.1457 +loser: 1.1458 + if (certReq) { 1.1459 + CRMF_DestroyCertRequest(certReq); 1.1460 + } 1.1461 + return nullptr; 1.1462 +} 1.1463 + 1.1464 +/* 1.1465 + * This function will set the Proof Of Possession (POP) for a request 1.1466 + * associated with a key pair intended to do Key Encipherment. Currently 1.1467 + * this means encryption only keys. 1.1468 + */ 1.1469 +static nsresult 1.1470 +nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed) 1.1471 +{ 1.1472 + SECItem bitString; 1.1473 + unsigned char der[2]; 1.1474 + SECStatus srv; 1.1475 + 1.1476 + if (isEscrowed) { 1.1477 + /* For proof of possession on escrowed keys, we use the 1.1478 + * this Message option of POPOPrivKey and include a zero 1.1479 + * length bit string in the POP field. This is OK because the encrypted 1.1480 + * private key already exists as part of the PKIArchiveOptions 1.1481 + * Control and that for all intents and purposes proves that 1.1482 + * we do own the private key. 1.1483 + */ 1.1484 + der[0] = 0x03; /*We've got a bit string */ 1.1485 + der[1] = 0x00; /*We've got a 0 length bit string */ 1.1486 + bitString.data = der; 1.1487 + bitString.len = 2; 1.1488 + srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage, 1.1489 + crmfNoSubseqMess, &bitString); 1.1490 + } else { 1.1491 + /* If the encryption key is not being escrowed, then we set the 1.1492 + * Proof Of Possession to be a Challenge Response mechanism. 1.1493 + */ 1.1494 + srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, 1.1495 + crmfSubsequentMessage, 1.1496 + crmfChallengeResp, nullptr); 1.1497 + } 1.1498 + return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE; 1.1499 +} 1.1500 + 1.1501 +static void 1.1502 +nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len); 1.1503 + 1.1504 +static void 1.1505 +nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len); 1.1506 + 1.1507 +static nsresult 1.1508 +nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg, 1.1509 + nsKeyPairInfo *keyInfo, 1.1510 + CRMFCertRequest *certReq) 1.1511 +{ 1.1512 + // RFC 2511 Appendix A section 2 a) defines, 1.1513 + // the "text" input for HMAC shall be the DER encoded version of 1.1514 + // of the single cert request. 1.1515 + // We'll produce that encoding and destroy it afterwards, 1.1516 + // because when sending the complete package to the CA, 1.1517 + // we'll use a different encoding, one that includes POP and 1.1518 + // allows multiple requests to be sent in one step. 1.1519 + 1.1520 + unsigned long der_request_len = 0; 1.1521 + ScopedSECItem der_request; 1.1522 + 1.1523 + if (SECSuccess != CRMF_EncodeCertRequest(certReq, 1.1524 + nsCRMFEncoderItemCount, 1.1525 + &der_request_len)) 1.1526 + return NS_ERROR_FAILURE; 1.1527 + 1.1528 + der_request = SECITEM_AllocItem(nullptr, nullptr, der_request_len); 1.1529 + if (!der_request) 1.1530 + return NS_ERROR_FAILURE; 1.1531 + 1.1532 + // set len in returned SECItem back to zero, because it will 1.1533 + // be used as the destination offset inside the 1.1534 + // nsCRMFEncoderItemStore callback. 1.1535 + 1.1536 + der_request->len = 0; 1.1537 + 1.1538 + if (SECSuccess != CRMF_EncodeCertRequest(certReq, 1.1539 + nsCRMFEncoderItemStore, 1.1540 + der_request)) 1.1541 + return NS_ERROR_FAILURE; 1.1542 + 1.1543 + // RFC 2511 Appendix A section 2 c): 1.1544 + // "A key K is derived from the shared secret Kec and the subject and 1.1545 + // issuer names in the CA's certificate as follows: 1.1546 + // K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)" 1.1547 + 1.1548 + ScopedPK11SymKey shared_secret; 1.1549 + ScopedPK11SymKey subject_and_secret; 1.1550 + ScopedPK11SymKey subject_and_secret_and_issuer; 1.1551 + ScopedPK11SymKey sha1_of_subject_and_secret_and_issuer; 1.1552 + 1.1553 + shared_secret = 1.1554 + PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey 1.1555 + keyInfo->ecPopPubKey, // SECKEYPublicKey *pubKey 1.1556 + false, // bool isSender 1.1557 + nullptr, // SECItem *randomA 1.1558 + nullptr, // SECItem *randomB 1.1559 + CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive 1.1560 + CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target 1.1561 + CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation 1.1562 + 0, // int keySize 1.1563 + CKD_NULL, // CK_ULONG kdf 1.1564 + nullptr, // SECItem *sharedData 1.1565 + nullptr); // void *wincx 1.1566 + 1.1567 + if (!shared_secret) 1.1568 + return NS_ERROR_FAILURE; 1.1569 + 1.1570 + CK_KEY_DERIVATION_STRING_DATA concat_data_base; 1.1571 + concat_data_base.pData = keyInfo->ecPopCert->derSubject.data; 1.1572 + concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len; 1.1573 + SECItem concat_data_base_item; 1.1574 + concat_data_base_item.data = (unsigned char*)&concat_data_base; 1.1575 + concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA); 1.1576 + 1.1577 + subject_and_secret = 1.1578 + PK11_Derive(shared_secret, // PK11SymKey *baseKey 1.1579 + CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism 1.1580 + &concat_data_base_item, // SECItem *param 1.1581 + CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target 1.1582 + CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation 1.1583 + 0); // int keySize 1.1584 + 1.1585 + if (!subject_and_secret) 1.1586 + return NS_ERROR_FAILURE; 1.1587 + 1.1588 + CK_KEY_DERIVATION_STRING_DATA concat_base_data; 1.1589 + concat_base_data.pData = keyInfo->ecPopCert->derSubject.data; 1.1590 + concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len; 1.1591 + SECItem concat_base_data_item; 1.1592 + concat_base_data_item.data = (unsigned char*)&concat_base_data; 1.1593 + concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA); 1.1594 + 1.1595 + subject_and_secret_and_issuer = 1.1596 + PK11_Derive(subject_and_secret, // PK11SymKey *baseKey 1.1597 + CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism 1.1598 + &concat_base_data_item, // SECItem *param 1.1599 + CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target 1.1600 + CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation 1.1601 + 0); // int keySize 1.1602 + 1.1603 + if (!subject_and_secret_and_issuer) 1.1604 + return NS_ERROR_FAILURE; 1.1605 + 1.1606 + sha1_of_subject_and_secret_and_issuer = 1.1607 + PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey 1.1608 + CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism 1.1609 + nullptr, // SECItem *param 1.1610 + CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target 1.1611 + CKA_SIGN, // CK_ATTRIBUTE_TYPE operation 1.1612 + 0); // int keySize 1.1613 + 1.1614 + if (!sha1_of_subject_and_secret_and_issuer) 1.1615 + return NS_ERROR_FAILURE; 1.1616 + 1.1617 + PK11Context *context = nullptr; 1.1618 + PK11ContextCleanerTrueParam context_cleaner(context); 1.1619 + 1.1620 + SECItem ignore; 1.1621 + ignore.data = 0; 1.1622 + ignore.len = 0; 1.1623 + 1.1624 + context = 1.1625 + PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type 1.1626 + CKA_SIGN, // CK_ATTRIBUTE_TYPE operation 1.1627 + sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey 1.1628 + &ignore); // SECItem *param 1.1629 + 1.1630 + if (!context) 1.1631 + return NS_ERROR_FAILURE; 1.1632 + 1.1633 + if (SECSuccess != PK11_DigestBegin(context)) 1.1634 + return NS_ERROR_FAILURE; 1.1635 + 1.1636 + if (SECSuccess != 1.1637 + PK11_DigestOp(context, der_request->data, der_request->len)) 1.1638 + return NS_ERROR_FAILURE; 1.1639 + 1.1640 + ScopedAutoSECItem result_hmac_sha1_item(SHA1_LENGTH); 1.1641 + 1.1642 + if (SECSuccess != 1.1643 + PK11_DigestFinal(context, 1.1644 + result_hmac_sha1_item.data, 1.1645 + &result_hmac_sha1_item.len, 1.1646 + SHA1_LENGTH)) 1.1647 + return NS_ERROR_FAILURE; 1.1648 + 1.1649 + if (SECSuccess != 1.1650 + CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC, 1.1651 + crmfNoSubseqMess, &result_hmac_sha1_item)) 1.1652 + return NS_ERROR_FAILURE; 1.1653 + 1.1654 + return NS_OK; 1.1655 +} 1.1656 + 1.1657 +static nsresult 1.1658 +nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg, 1.1659 + nsKeyPairInfo *keyInfo, 1.1660 + CRMFCertRequest *certReq) 1.1661 +{ 1.1662 + // Depending on the type of cert request we'll try 1.1663 + // POP mechanisms in different order, 1.1664 + // and add the result to the cert request message. 1.1665 + // 1.1666 + // For any signing or dual use cert, 1.1667 + // try signing first, 1.1668 + // fall back to DHMAC if we can 1.1669 + // (EC cert requests that provide keygen param "popcert"), 1.1670 + // otherwise fail. 1.1671 + // 1.1672 + // For encryption only certs that get escrowed, this is sufficient. 1.1673 + // 1.1674 + // For encryption only certs, that are not being escrowed, 1.1675 + // try DHMAC if we can 1.1676 + // (EC cert requests that provide keygen param "popcert"), 1.1677 + // otherwise we'll indicate challenge response should be used. 1.1678 + 1.1679 + bool isEncryptionOnlyCertRequest = false; 1.1680 + bool escrowEncryptionOnlyCert = false; 1.1681 + 1.1682 + switch (keyInfo->keyGenType) 1.1683 + { 1.1684 + case rsaEnc: 1.1685 + case ecEnc: 1.1686 + isEncryptionOnlyCertRequest = true; 1.1687 + break; 1.1688 + 1.1689 + case rsaSign: 1.1690 + case rsaDualUse: 1.1691 + case rsaNonrepudiation: 1.1692 + case rsaSignNonrepudiation: 1.1693 + case ecSign: 1.1694 + case ecDualUse: 1.1695 + case ecNonrepudiation: 1.1696 + case ecSignNonrepudiation: 1.1697 + case dsaSign: 1.1698 + case dsaNonrepudiation: 1.1699 + case dsaSignNonrepudiation: 1.1700 + break; 1.1701 + 1.1702 + case dhEx: 1.1703 + /* This case may be supported in the future, but for now, we just fall 1.1704 + * though to the default case and return an error for diffie-hellman keys. 1.1705 + */ 1.1706 + default: 1.1707 + return NS_ERROR_FAILURE; 1.1708 + }; 1.1709 + 1.1710 + if (isEncryptionOnlyCertRequest) 1.1711 + { 1.1712 + escrowEncryptionOnlyCert = 1.1713 + CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl); 1.1714 + } 1.1715 + 1.1716 + bool gotDHMACParameters = false; 1.1717 + 1.1718 + if (isECKeyGenType(keyInfo->keyGenType) && 1.1719 + keyInfo->ecPopCert && 1.1720 + keyInfo->ecPopPubKey) 1.1721 + { 1.1722 + gotDHMACParameters = true; 1.1723 + } 1.1724 + 1.1725 + if (isEncryptionOnlyCertRequest) 1.1726 + { 1.1727 + if (escrowEncryptionOnlyCert) 1.1728 + return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed 1.1729 + 1.1730 + if (gotDHMACParameters) 1.1731 + return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq); 1.1732 + 1.1733 + return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed 1.1734 + } 1.1735 + 1.1736 + // !isEncryptionOnlyCertRequest 1.1737 + 1.1738 + SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg, 1.1739 + keyInfo->privKey, 1.1740 + keyInfo->pubKey, nullptr, 1.1741 + nullptr, nullptr); 1.1742 + 1.1743 + if (srv == SECSuccess) 1.1744 + return NS_OK; 1.1745 + 1.1746 + if (!gotDHMACParameters) 1.1747 + return NS_ERROR_FAILURE; 1.1748 + 1.1749 + return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq); 1.1750 +} 1.1751 + 1.1752 +static void 1.1753 +nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len) 1.1754 +{ 1.1755 + unsigned long *count = (unsigned long *)arg; 1.1756 + *count += len; 1.1757 +} 1.1758 + 1.1759 +static void 1.1760 +nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len) 1.1761 +{ 1.1762 + SECItem *dest = (SECItem *)arg; 1.1763 + memcpy(dest->data + dest->len, buf, len); 1.1764 + dest->len += len; 1.1765 +} 1.1766 + 1.1767 +static SECItem* 1.1768 +nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs) 1.1769 +{ 1.1770 + unsigned long len = 0; 1.1771 + if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len) 1.1772 + != SECSuccess) { 1.1773 + return nullptr; 1.1774 + } 1.1775 + SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem)); 1.1776 + if (!dest) { 1.1777 + return nullptr; 1.1778 + } 1.1779 + dest->type = siBuffer; 1.1780 + dest->data = (unsigned char *)PORT_Alloc(len); 1.1781 + if (!dest->data) { 1.1782 + PORT_Free(dest); 1.1783 + return nullptr; 1.1784 + } 1.1785 + dest->len = 0; 1.1786 + 1.1787 + if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest) 1.1788 + != SECSuccess) { 1.1789 + SECITEM_FreeItem(dest, true); 1.1790 + return nullptr; 1.1791 + } 1.1792 + return dest; 1.1793 +} 1.1794 + 1.1795 +//Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA 1.1796 +//requesting one or more certificates to be issued. This function 1.1797 +//creates a single cert request per key pair and then appends it to 1.1798 +//a message that is ultimately sent off to a CA. 1.1799 +static char* 1.1800 +nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, int32_t numRequests, 1.1801 + char *reqDN, char *regToken, char *authenticator, 1.1802 + nsNSSCertificate *wrappingCert) 1.1803 +{ 1.1804 + // We'use the goto notation for clean-up purposes in this function 1.1805 + // that calls the C API of NSS. 1.1806 + int32_t i; 1.1807 + // The ASN1 encoder in NSS wants the last entry in the array to be 1.1808 + // nullptr so that it knows when the last element is. 1.1809 + CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1]; 1.1810 + CRMFCertRequest *certReq; 1.1811 + if (!certReqMsgs) 1.1812 + return nullptr; 1.1813 + memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests)); 1.1814 + SECStatus srv; 1.1815 + nsresult rv; 1.1816 + SECItem *encodedReq; 1.1817 + char *retString; 1.1818 + for (i=0; i<numRequests; i++) { 1.1819 + certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator, 1.1820 + wrappingCert); 1.1821 + if (!certReq) 1.1822 + goto loser; 1.1823 + 1.1824 + certReqMsgs[i] = CRMF_CreateCertReqMsg(); 1.1825 + if (!certReqMsgs[i]) 1.1826 + goto loser; 1.1827 + srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq); 1.1828 + if (srv != SECSuccess) 1.1829 + goto loser; 1.1830 + 1.1831 + rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq); 1.1832 + if (NS_FAILED(rv)) 1.1833 + goto loser; 1.1834 + CRMF_DestroyCertRequest(certReq); 1.1835 + } 1.1836 + encodedReq = nsEncodeCertReqMessages(certReqMsgs); 1.1837 + nsFreeCertReqMessages(certReqMsgs, numRequests); 1.1838 + 1.1839 + retString = NSSBase64_EncodeItem (nullptr, nullptr, 0, encodedReq); 1.1840 + SECITEM_FreeItem(encodedReq, true); 1.1841 + return retString; 1.1842 +loser: 1.1843 + nsFreeCertReqMessages(certReqMsgs,numRequests); 1.1844 + return nullptr; 1.1845 +} 1.1846 + 1.1847 +static nsISupports * 1.1848 +GetISupportsFromContext(JSContext *cx) 1.1849 +{ 1.1850 + if (JS::ContextOptionsRef(cx).privateIsNSISupports()) 1.1851 + return static_cast<nsISupports *>(JS_GetContextPrivate(cx)); 1.1852 + 1.1853 + return nullptr; 1.1854 +} 1.1855 + 1.1856 +//The top level method which is a member of nsIDOMCrypto 1.1857 +//for generate a base64 encoded CRMF request. 1.1858 +CRMFObject* 1.1859 +nsCrypto::GenerateCRMFRequest(JSContext* aContext, 1.1860 + const nsCString& aReqDN, 1.1861 + const nsCString& aRegToken, 1.1862 + const nsCString& aAuthenticator, 1.1863 + const nsCString& aEaCert, 1.1864 + const nsCString& aJsCallback, 1.1865 + const Sequence<JS::Value>& aArgs, 1.1866 + ErrorResult& aRv) 1.1867 +{ 1.1868 + nsNSSShutDownPreventionLock locker; 1.1869 + nsresult nrv; 1.1870 + 1.1871 + uint32_t argc = aArgs.Length(); 1.1872 + 1.1873 + /* 1.1874 + * Get all of the parameters. 1.1875 + */ 1.1876 + if (argc % 3 != 0) { 1.1877 + aRv.ThrowNotEnoughArgsError(); 1.1878 + return nullptr; 1.1879 + } 1.1880 + 1.1881 + if (aReqDN.IsVoid()) { 1.1882 + NS_WARNING("no DN specified"); 1.1883 + aRv.Throw(NS_ERROR_FAILURE); 1.1884 + return nullptr; 1.1885 + } 1.1886 + 1.1887 + if (aJsCallback.IsVoid()) { 1.1888 + NS_WARNING("no completion function specified"); 1.1889 + aRv.Throw(NS_ERROR_FAILURE); 1.1890 + return nullptr; 1.1891 + } 1.1892 + 1.1893 + JS::RootedObject script_obj(aContext, GetWrapper()); 1.1894 + if (MOZ_UNLIKELY(!script_obj)) { 1.1895 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.1896 + return nullptr; 1.1897 + } 1.1898 + 1.1899 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.1900 + if (!nsContentUtils::GetContentSecurityPolicy(aContext, getter_AddRefs(csp))) { 1.1901 + NS_ERROR("Error: failed to get CSP"); 1.1902 + aRv.Throw(NS_ERROR_FAILURE); 1.1903 + return nullptr; 1.1904 + } 1.1905 + 1.1906 + bool evalAllowed = true; 1.1907 + bool reportEvalViolations = false; 1.1908 + if (csp && NS_FAILED(csp->GetAllowsEval(&reportEvalViolations, &evalAllowed))) { 1.1909 + NS_WARNING("CSP: failed to get allowsEval"); 1.1910 + aRv.Throw(NS_ERROR_FAILURE); 1.1911 + return nullptr; 1.1912 + } 1.1913 + 1.1914 + if (reportEvalViolations) { 1.1915 + NS_NAMED_LITERAL_STRING(scriptSample, "window.crypto.generateCRMFRequest: call to eval() or related function blocked by CSP"); 1.1916 + 1.1917 + const char *fileName; 1.1918 + uint32_t lineNum; 1.1919 + nsJSUtils::GetCallingLocation(aContext, &fileName, &lineNum); 1.1920 + csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, 1.1921 + NS_ConvertASCIItoUTF16(fileName), 1.1922 + scriptSample, 1.1923 + lineNum, 1.1924 + EmptyString(), 1.1925 + EmptyString()); 1.1926 + } 1.1927 + 1.1928 + if (!evalAllowed) { 1.1929 + NS_WARNING("eval() not allowed by Content Security Policy"); 1.1930 + aRv.Throw(NS_ERROR_FAILURE); 1.1931 + return nullptr; 1.1932 + } 1.1933 + 1.1934 + //Put up some UI warning that someone is trying to 1.1935 + //escrow the private key. 1.1936 + //Don't addref this copy. That way ths reference goes away 1.1937 + //at the same the nsIX09Cert ref goes away. 1.1938 + nsNSSCertificate *escrowCert = nullptr; 1.1939 + nsCOMPtr<nsIX509Cert> nssCert; 1.1940 + bool willEscrow = false; 1.1941 + if (!aEaCert.IsVoid()) { 1.1942 + SECItem certDer = {siBuffer, nullptr, 0}; 1.1943 + SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, aEaCert.get()); 1.1944 + if (srv != SECSuccess) { 1.1945 + aRv.Throw(NS_ERROR_FAILURE); 1.1946 + return nullptr; 1.1947 + } 1.1948 + mozilla::pkix::ScopedCERTCertificate cert( 1.1949 + CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 1.1950 + &certDer, nullptr, false, true)); 1.1951 + if (!cert) { 1.1952 + aRv.Throw(NS_ERROR_FAILURE); 1.1953 + return nullptr; 1.1954 + } 1.1955 + 1.1956 + escrowCert = nsNSSCertificate::Create(cert.get()); 1.1957 + nssCert = escrowCert; 1.1958 + if (!nssCert) { 1.1959 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.1960 + return nullptr; 1.1961 + } 1.1962 + 1.1963 + nsCOMPtr<nsIDOMCryptoDialogs> dialogs; 1.1964 + nsresult rv = getNSSDialogs(getter_AddRefs(dialogs), 1.1965 + NS_GET_IID(nsIDOMCryptoDialogs), 1.1966 + NS_DOMCRYPTODIALOGS_CONTRACTID); 1.1967 + if (NS_FAILED(rv)) { 1.1968 + aRv.Throw(rv); 1.1969 + return nullptr; 1.1970 + } 1.1971 + 1.1972 + bool okay=false; 1.1973 + { 1.1974 + nsPSMUITracker tracker; 1.1975 + if (tracker.isUIForbidden()) { 1.1976 + okay = false; 1.1977 + } 1.1978 + else { 1.1979 + dialogs->ConfirmKeyEscrow(nssCert, &okay); 1.1980 + } 1.1981 + } 1.1982 + if (!okay) { 1.1983 + aRv.Throw(NS_ERROR_FAILURE); 1.1984 + return nullptr; 1.1985 + } 1.1986 + willEscrow = true; 1.1987 + } 1.1988 + nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext; 1.1989 + int32_t numRequests = argc / 3; 1.1990 + nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests]; 1.1991 + memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests); 1.1992 + int keyInfoIndex; 1.1993 + uint32_t i; 1.1994 + PK11SlotInfo *slot = nullptr; 1.1995 + // Go through all of the arguments and generate the appropriate key pairs. 1.1996 + for (i=0,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) { 1.1997 + nrv = cryptojs_ReadArgsAndGenerateKey(aContext, 1.1998 + const_cast<JS::Value*>(&aArgs[i]), 1.1999 + &keyids[keyInfoIndex], 1.2000 + uiCxt, &slot, willEscrow); 1.2001 + 1.2002 + if (NS_FAILED(nrv)) { 1.2003 + if (slot) 1.2004 + PK11_FreeSlot(slot); 1.2005 + nsFreeKeyPairInfo(keyids,numRequests); 1.2006 + aRv.Throw(nrv); 1.2007 + return nullptr; 1.2008 + } 1.2009 + } 1.2010 + // By this time we'd better have a slot for the key gen. 1.2011 + NS_ASSERTION(slot, "There was no slot selected for key generation"); 1.2012 + if (slot) 1.2013 + PK11_FreeSlot(slot); 1.2014 + 1.2015 + char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests, 1.2016 + const_cast<char*>(aReqDN.get()), 1.2017 + const_cast<char*>(aRegToken.get()), 1.2018 + const_cast<char*>(aAuthenticator.get()), 1.2019 + escrowCert); 1.2020 +#ifdef DEBUG_javi 1.2021 + printf ("Created the folloing CRMF request:\n%s\n", encodedRequest); 1.2022 +#endif 1.2023 + if (!encodedRequest) { 1.2024 + nsFreeKeyPairInfo(keyids, numRequests); 1.2025 + aRv.Throw(NS_ERROR_FAILURE); 1.2026 + return nullptr; 1.2027 + } 1.2028 + CRMFObject* newObject = new CRMFObject(); 1.2029 + newObject->SetCRMFRequest(encodedRequest); 1.2030 + PORT_Free(encodedRequest); 1.2031 + nsFreeKeyPairInfo(keyids, numRequests); 1.2032 + 1.2033 + // Post an event on the UI queue so that the JS gets called after 1.2034 + // we return control to the JS layer. Why do we have to this? 1.2035 + // Because when this API was implemented for PSM 1.x w/ Communicator, 1.2036 + // the only way to make this method work was to have a callback 1.2037 + // in the JS layer that got called after key generation had happened. 1.2038 + // So for backwards compatibility, we return control and then just post 1.2039 + // an event to call the JS the script provides as the code to execute 1.2040 + // when the request has been generated. 1.2041 + // 1.2042 + 1.2043 + nsCOMPtr<nsIScriptSecurityManager> secMan = 1.2044 + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); 1.2045 + if (MOZ_UNLIKELY(!secMan)) { 1.2046 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.2047 + return nullptr; 1.2048 + } 1.2049 + 1.2050 + nsCOMPtr<nsIPrincipal> principals; 1.2051 + nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principals)); 1.2052 + if (NS_FAILED(nrv)) { 1.2053 + aRv.Throw(nrv); 1.2054 + return nullptr; 1.2055 + } 1.2056 + if (MOZ_UNLIKELY(!principals)) { 1.2057 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.2058 + return nullptr; 1.2059 + } 1.2060 + 1.2061 + nsCryptoRunArgs *args = new nsCryptoRunArgs(aContext); 1.2062 + 1.2063 + args->m_kungFuDeathGrip = GetISupportsFromContext(aContext); 1.2064 + args->m_scope = JS_GetParent(script_obj); 1.2065 + if (!aJsCallback.IsVoid()) { 1.2066 + args->m_jsCallback = aJsCallback; 1.2067 + } 1.2068 + args->m_principals = principals; 1.2069 + 1.2070 + nsCryptoRunnable *cryptoRunnable = new nsCryptoRunnable(args); 1.2071 + 1.2072 + rv = NS_DispatchToMainThread(cryptoRunnable); 1.2073 + if (NS_FAILED(rv)) { 1.2074 + aRv.Throw(rv); 1.2075 + delete cryptoRunnable; 1.2076 + } 1.2077 + 1.2078 + return newObject; 1.2079 +} 1.2080 + 1.2081 +// Reminder that we inherit the memory passed into us here. 1.2082 +// An implementation to let us back up certs as an event. 1.2083 +nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts, 1.2084 + nsIPK11Token *token) 1.2085 +{ 1.2086 + mCertArr = certArr; 1.2087 + mNumCerts = numCerts; 1.2088 + mToken = token; 1.2089 +} 1.2090 + 1.2091 +nsP12Runnable::~nsP12Runnable() 1.2092 +{ 1.2093 + int32_t i; 1.2094 + for (i=0; i<mNumCerts; i++) { 1.2095 + NS_IF_RELEASE(mCertArr[i]); 1.2096 + } 1.2097 + delete []mCertArr; 1.2098 +} 1.2099 + 1.2100 + 1.2101 +//Implementation that backs cert(s) into a PKCS12 file 1.2102 +NS_IMETHODIMP 1.2103 +nsP12Runnable::Run() 1.2104 +{ 1.2105 + NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.2106 + 1.2107 + NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread"); 1.2108 + 1.2109 + nsNSSShutDownPreventionLock locker; 1.2110 + NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up"); 1.2111 + 1.2112 + nsString final; 1.2113 + nsString temp; 1.2114 + nsresult rv; 1.2115 + 1.2116 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.2117 + if (NS_FAILED(rv)) 1.2118 + return rv; 1.2119 + 1.2120 + //Build up the message that let's the user know we're trying to 1.2121 + //make PKCS12 backups of the new certs. 1.2122 + nssComponent->GetPIPNSSBundleString("ForcedBackup1", final); 1.2123 + final.Append(MOZ_UTF16("\n\n")); 1.2124 + nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp); 1.2125 + final.Append(temp.get()); 1.2126 + final.Append(MOZ_UTF16("\n\n")); 1.2127 + 1.2128 + nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp); 1.2129 + 1.2130 + final.Append(temp.get()); 1.2131 + nsNSSComponent::ShowAlertWithConstructedString(final); 1.2132 + 1.2133 + nsCOMPtr<nsIFilePicker> filePicker = 1.2134 + do_CreateInstance("@mozilla.org/filepicker;1", &rv); 1.2135 + if (!filePicker) { 1.2136 + NS_ERROR("Could not create a file picker when backing up certs."); 1.2137 + return rv; 1.2138 + } 1.2139 + 1.2140 + nsCOMPtr<nsIWindowWatcher> wwatch = 1.2141 + (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv)); 1.2142 + NS_ENSURE_SUCCESS(rv, rv); 1.2143 + 1.2144 + nsCOMPtr<nsIDOMWindow> window; 1.2145 + wwatch->GetActiveWindow(getter_AddRefs(window)); 1.2146 + 1.2147 + nsString filePickMessage; 1.2148 + nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog", 1.2149 + filePickMessage); 1.2150 + rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave); 1.2151 + NS_ENSURE_SUCCESS(rv, rv); 1.2152 + 1.2153 + filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"), 1.2154 + NS_LITERAL_STRING("*.p12")); 1.2155 + filePicker->AppendFilters(nsIFilePicker::filterAll); 1.2156 + 1.2157 + int16_t dialogReturn; 1.2158 + filePicker->Show(&dialogReturn); 1.2159 + if (dialogReturn == nsIFilePicker::returnCancel) 1.2160 + return NS_OK; //User canceled. It'd be nice if they couldn't, 1.2161 + //but oh well. 1.2162 + 1.2163 + nsCOMPtr<nsIFile> localFile; 1.2164 + rv = filePicker->GetFile(getter_AddRefs(localFile)); 1.2165 + if (NS_FAILED(rv)) 1.2166 + return NS_ERROR_FAILURE; 1.2167 + 1.2168 + nsPKCS12Blob p12Cxt; 1.2169 + 1.2170 + p12Cxt.SetToken(mToken); 1.2171 + p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts); 1.2172 + return NS_OK; 1.2173 +} 1.2174 + 1.2175 +nsCryptoRunArgs::nsCryptoRunArgs(JSContext *cx) : m_cx(cx), m_scope(cx) {} 1.2176 + 1.2177 +nsCryptoRunArgs::~nsCryptoRunArgs() {} 1.2178 + 1.2179 +nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args) 1.2180 +{ 1.2181 + nsNSSShutDownPreventionLock locker; 1.2182 + NS_ASSERTION(args,"Passed nullptr to nsCryptoRunnable constructor."); 1.2183 + m_args = args; 1.2184 + NS_IF_ADDREF(m_args); 1.2185 +} 1.2186 + 1.2187 +nsCryptoRunnable::~nsCryptoRunnable() 1.2188 +{ 1.2189 + nsNSSShutDownPreventionLock locker; 1.2190 + NS_IF_RELEASE(m_args); 1.2191 +} 1.2192 + 1.2193 +//Implementation that runs the callback passed to 1.2194 +//crypto.generateCRMFRequest as an event. 1.2195 +NS_IMETHODIMP 1.2196 +nsCryptoRunnable::Run() 1.2197 +{ 1.2198 + nsNSSShutDownPreventionLock locker; 1.2199 + AutoPushJSContext cx(m_args->m_cx); 1.2200 + JSAutoRequest ar(cx); 1.2201 + JS::Rooted<JSObject*> scope(cx, m_args->m_scope); 1.2202 + JSAutoCompartment ac(cx, scope); 1.2203 + 1.2204 + bool ok = 1.2205 + JS_EvaluateScript(cx, scope, m_args->m_jsCallback, 1.2206 + strlen(m_args->m_jsCallback), nullptr, 0); 1.2207 + return ok ? NS_OK : NS_ERROR_FAILURE; 1.2208 +} 1.2209 + 1.2210 +//Quick helper function to check if a newly issued cert 1.2211 +//already exists in the user's database. 1.2212 +static bool 1.2213 +nsCertAlreadyExists(SECItem *derCert) 1.2214 +{ 1.2215 + CERTCertDBHandle *handle = CERT_GetDefaultCertDB(); 1.2216 + bool retVal = false; 1.2217 + 1.2218 + mozilla::pkix::ScopedCERTCertificate cert( 1.2219 + CERT_FindCertByDERCert(handle, derCert)); 1.2220 + if (cert) { 1.2221 + if (cert->isperm && !cert->nickname && !cert->emailAddr) { 1.2222 + //If the cert doesn't have a nickname or email addr, it is 1.2223 + //bogus cruft, so delete it. 1.2224 + SEC_DeletePermCertificate(cert.get()); 1.2225 + } else if (cert->isperm) { 1.2226 + retVal = true; 1.2227 + } 1.2228 + } 1.2229 + return retVal; 1.2230 +} 1.2231 + 1.2232 +static int32_t 1.2233 +nsCertListCount(CERTCertList *certList) 1.2234 +{ 1.2235 + int32_t numCerts = 0; 1.2236 + CERTCertListNode *node; 1.2237 + 1.2238 + node = CERT_LIST_HEAD(certList); 1.2239 + while (!CERT_LIST_END(node, certList)) { 1.2240 + numCerts++; 1.2241 + node = CERT_LIST_NEXT(node); 1.2242 + } 1.2243 + return numCerts; 1.2244 +} 1.2245 + 1.2246 +//Import user certificates that arrive as a CMMF base64 encoded 1.2247 +//string. 1.2248 +void 1.2249 +nsCrypto::ImportUserCertificates(const nsAString& aNickname, 1.2250 + const nsAString& aCmmfResponse, 1.2251 + bool aDoForcedBackup, 1.2252 + nsAString& aReturn, 1.2253 + ErrorResult& aRv) 1.2254 +{ 1.2255 + nsNSSShutDownPreventionLock locker; 1.2256 + char *nickname=nullptr, *cmmfResponse=nullptr; 1.2257 + CMMFCertRepContent *certRepContent = nullptr; 1.2258 + int numResponses = 0; 1.2259 + nsIX509Cert **certArr = nullptr; 1.2260 + int i; 1.2261 + CMMFCertResponse *currResponse; 1.2262 + CMMFPKIStatus reqStatus; 1.2263 + CERTCertificate *currCert; 1.2264 + PK11SlotInfo *slot; 1.2265 + nsAutoCString localNick; 1.2266 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.2267 + nsresult rv = NS_OK; 1.2268 + nsCOMPtr<nsIPK11Token> token; 1.2269 + 1.2270 + nickname = ToNewCString(aNickname); 1.2271 + cmmfResponse = ToNewCString(aCmmfResponse); 1.2272 + if (nsCRT::strcmp("null", nickname) == 0) { 1.2273 + nsMemory::Free(nickname); 1.2274 + nickname = nullptr; 1.2275 + } 1.2276 + 1.2277 + SECItem cmmfDer = {siBuffer, nullptr, 0}; 1.2278 + SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse); 1.2279 + 1.2280 + if (srv != SECSuccess) { 1.2281 + rv = NS_ERROR_FAILURE; 1.2282 + goto loser; 1.2283 + } 1.2284 + 1.2285 + certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(), 1.2286 + (const char*)cmmfDer.data, 1.2287 + cmmfDer.len); 1.2288 + if (!certRepContent) { 1.2289 + rv = NS_ERROR_FAILURE; 1.2290 + goto loser; 1.2291 + } 1.2292 + 1.2293 + numResponses = CMMF_CertRepContentGetNumResponses(certRepContent); 1.2294 + 1.2295 + if (aDoForcedBackup) { 1.2296 + //We've been asked to force the user to back up these 1.2297 + //certificates. Let's keep an array of them around which 1.2298 + //we pass along to the nsP12Runnable to use. 1.2299 + certArr = new nsIX509Cert*[numResponses]; 1.2300 + // If this is nullptr, chances are we're gonna fail really 1.2301 + // soon, but let's try to keep going just in case. 1.2302 + if (!certArr) 1.2303 + aDoForcedBackup = false; 1.2304 + 1.2305 + memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses); 1.2306 + } 1.2307 + for (i=0; i<numResponses; i++) { 1.2308 + currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i); 1.2309 + if (!currResponse) { 1.2310 + rv = NS_ERROR_FAILURE; 1.2311 + goto loser; 1.2312 + } 1.2313 + reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse); 1.2314 + if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) { 1.2315 + // The CA didn't give us the cert we requested. 1.2316 + rv = NS_ERROR_FAILURE; 1.2317 + goto loser; 1.2318 + } 1.2319 + currCert = CMMF_CertResponseGetCertificate(currResponse, 1.2320 + CERT_GetDefaultCertDB()); 1.2321 + if (!currCert) { 1.2322 + rv = NS_ERROR_FAILURE; 1.2323 + goto loser; 1.2324 + } 1.2325 + 1.2326 + if (nsCertAlreadyExists(&currCert->derCert)) { 1.2327 + if (aDoForcedBackup) { 1.2328 + certArr[i] = nsNSSCertificate::Create(currCert); 1.2329 + if (!certArr[i]) 1.2330 + goto loser; 1.2331 + NS_ADDREF(certArr[i]); 1.2332 + } 1.2333 + CERT_DestroyCertificate(currCert); 1.2334 + CMMF_DestroyCertResponse(currResponse); 1.2335 + continue; 1.2336 + } 1.2337 + // Let's figure out which nickname to give the cert. If 1.2338 + // a certificate with the same subject name already exists, 1.2339 + // then just use that one, otherwise, get the default nickname. 1.2340 + if (currCert->nickname) { 1.2341 + localNick = currCert->nickname; 1.2342 + } 1.2343 + else if (!nickname || nickname[0] == '\0') { 1.2344 + nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick, locker); 1.2345 + } else { 1.2346 + //This is the case where we're getting a brand new 1.2347 + //cert that doesn't have the same subjectName as a cert 1.2348 + //that already exists in our db and the CA page has 1.2349 + //designated a nickname to use for the newly issued cert. 1.2350 + localNick = nickname; 1.2351 + } 1.2352 + { 1.2353 + char *cast_const_away = const_cast<char*>(localNick.get()); 1.2354 + slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx); 1.2355 + } 1.2356 + if (!slot) { 1.2357 + rv = NS_ERROR_FAILURE; 1.2358 + goto loser; 1.2359 + } 1.2360 + if (aDoForcedBackup) { 1.2361 + certArr[i] = nsNSSCertificate::Create(currCert); 1.2362 + if (!certArr[i]) 1.2363 + goto loser; 1.2364 + NS_ADDREF(certArr[i]); 1.2365 + } 1.2366 + CERT_DestroyCertificate(currCert); 1.2367 + 1.2368 + if (!token) 1.2369 + token = new nsPK11Token(slot); 1.2370 + 1.2371 + PK11_FreeSlot(slot); 1.2372 + CMMF_DestroyCertResponse(currResponse); 1.2373 + } 1.2374 + //Let the loser: label take care of freeing up our reference to 1.2375 + //nickname (This way we don't free it twice and avoid crashing. 1.2376 + //That would be a good thing. 1.2377 + 1.2378 + //Import the root chain into the cert db. 1.2379 + { 1.2380 + mozilla::pkix::ScopedCERTCertList 1.2381 + caPubs(CMMF_CertRepContentGetCAPubs(certRepContent)); 1.2382 + if (caPubs) { 1.2383 + int32_t numCAs = nsCertListCount(caPubs.get()); 1.2384 + 1.2385 + NS_ASSERTION(numCAs > 0, "Invalid number of CA's"); 1.2386 + if (numCAs > 0) { 1.2387 + CERTCertListNode *node; 1.2388 + SECItem *derCerts; 1.2389 + 1.2390 + derCerts = static_cast<SECItem*> 1.2391 + (nsMemory::Alloc(sizeof(SECItem)*numCAs)); 1.2392 + if (!derCerts) { 1.2393 + rv = NS_ERROR_OUT_OF_MEMORY; 1.2394 + goto loser; 1.2395 + } 1.2396 + for (node = CERT_LIST_HEAD(caPubs), i=0; 1.2397 + !CERT_LIST_END(node, caPubs); 1.2398 + node = CERT_LIST_NEXT(node), i++) { 1.2399 + derCerts[i] = node->cert->derCert; 1.2400 + } 1.2401 + nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx, locker); 1.2402 + nsMemory::Free(derCerts); 1.2403 + } 1.2404 + } 1.2405 + } 1.2406 + 1.2407 + if (aDoForcedBackup) { 1.2408 + // I can't pop up a file picker from the depths of JavaScript, 1.2409 + // so I'll just post an event on the UI queue to do the backups 1.2410 + // later. 1.2411 + nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses, 1.2412 + token); 1.2413 + if (!p12Runnable) { 1.2414 + rv = NS_ERROR_FAILURE; 1.2415 + goto loser; 1.2416 + } 1.2417 + 1.2418 + // null out the certArr pointer which has now been inherited by 1.2419 + // the nsP12Runnable instance so that we don't free up the 1.2420 + // memory on the way out. 1.2421 + certArr = nullptr; 1.2422 + 1.2423 + rv = NS_DispatchToMainThread(p12Runnable); 1.2424 + if (NS_FAILED(rv)) 1.2425 + goto loser; 1.2426 + } 1.2427 + 1.2428 + loser: 1.2429 + if (certArr) { 1.2430 + for (i=0; i<numResponses; i++) { 1.2431 + NS_IF_RELEASE(certArr[i]); 1.2432 + } 1.2433 + delete []certArr; 1.2434 + } 1.2435 + aReturn.Assign(EmptyString()); 1.2436 + if (nickname) { 1.2437 + NS_Free(nickname); 1.2438 + } 1.2439 + if (cmmfResponse) { 1.2440 + NS_Free(cmmfResponse); 1.2441 + } 1.2442 + if (certRepContent) { 1.2443 + CMMF_DestroyCertRepContent(certRepContent); 1.2444 + } 1.2445 + 1.2446 + if (NS_FAILED(rv)) { 1.2447 + aRv.Throw(rv); 1.2448 + } 1.2449 +} 1.2450 + 1.2451 +static void 1.2452 +GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument) 1.2453 +{ 1.2454 + // Get the script context. 1.2455 + nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx); 1.2456 + if (!scriptContext) { 1.2457 + return; 1.2458 + } 1.2459 + 1.2460 + nsCOMPtr<nsIDOMWindow> domWindow = 1.2461 + do_QueryInterface(scriptContext->GetGlobalObject()); 1.2462 + if (!domWindow) { 1.2463 + return; 1.2464 + } 1.2465 + 1.2466 + nsCOMPtr<nsIDOMDocument> domDocument; 1.2467 + domWindow->GetDocument(getter_AddRefs(domDocument)); 1.2468 + if (!domDocument) { 1.2469 + return; 1.2470 + } 1.2471 + 1.2472 + CallQueryInterface(domDocument, aDocument); 1.2473 + 1.2474 + return; 1.2475 +} 1.2476 + 1.2477 +void signTextOutputCallback(void *arg, const char *buf, unsigned long len) 1.2478 +{ 1.2479 + ((nsCString*)arg)->Append(buf, len); 1.2480 +} 1.2481 + 1.2482 +void 1.2483 +nsCrypto::SignText(JSContext* aContext, 1.2484 + const nsAString& aStringToSign, 1.2485 + const nsAString& aCaOption, 1.2486 + const Sequence<nsCString>& aArgs, 1.2487 + nsAString& aReturn) 1.2488 +{ 1.2489 + // XXX This code should return error codes, but we're keeping this 1.2490 + // backwards compatible with NS4.x and so we can't throw exceptions. 1.2491 + NS_NAMED_LITERAL_STRING(internalError, "error:internalError"); 1.2492 + 1.2493 + aReturn.Truncate(); 1.2494 + 1.2495 + uint32_t argc = aArgs.Length(); 1.2496 + 1.2497 + if (!aCaOption.EqualsLiteral("auto") && 1.2498 + !aCaOption.EqualsLiteral("ask")) { 1.2499 + NS_WARNING("caOption argument must be ask or auto"); 1.2500 + aReturn.Append(internalError); 1.2501 + 1.2502 + return; 1.2503 + } 1.2504 + 1.2505 + // It was decided to always behave as if "ask" were specified. 1.2506 + // XXX Should we warn in the JS Console for auto? 1.2507 + 1.2508 + nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext; 1.2509 + if (!uiContext) { 1.2510 + aReturn.Append(internalError); 1.2511 + 1.2512 + return; 1.2513 + } 1.2514 + 1.2515 + bool bestOnly = true; 1.2516 + bool validOnly = true; 1.2517 + CERTCertList* certList = 1.2518 + CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner, 1.2519 + bestOnly, validOnly, uiContext); 1.2520 + 1.2521 + uint32_t numCAs = argc; 1.2522 + if (numCAs > 0) { 1.2523 + nsAutoArrayPtr<char*> caNames(new char*[numCAs]); 1.2524 + if (!caNames) { 1.2525 + aReturn.Append(internalError); 1.2526 + return; 1.2527 + } 1.2528 + 1.2529 + uint32_t i; 1.2530 + for (i = 0; i < numCAs; ++i) 1.2531 + caNames[i] = const_cast<char*>(aArgs[i].get()); 1.2532 + 1.2533 + if (certList && 1.2534 + CERT_FilterCertListByCANames(certList, numCAs, caNames, 1.2535 + certUsageEmailSigner) != SECSuccess) { 1.2536 + aReturn.Append(internalError); 1.2537 + 1.2538 + return; 1.2539 + } 1.2540 + } 1.2541 + 1.2542 + if (!certList || CERT_LIST_EMPTY(certList)) { 1.2543 + aReturn.AppendLiteral("error:noMatchingCert"); 1.2544 + 1.2545 + return; 1.2546 + } 1.2547 + 1.2548 + nsCOMPtr<nsIFormSigningDialog> fsd = 1.2549 + do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID); 1.2550 + if (!fsd) { 1.2551 + aReturn.Append(internalError); 1.2552 + 1.2553 + return; 1.2554 + } 1.2555 + 1.2556 + nsCOMPtr<nsIDocument> document; 1.2557 + GetDocumentFromContext(aContext, getter_AddRefs(document)); 1.2558 + if (!document) { 1.2559 + aReturn.Append(internalError); 1.2560 + 1.2561 + return; 1.2562 + } 1.2563 + 1.2564 + // Get the hostname from the URL of the document. 1.2565 + nsIURI* uri = document->GetDocumentURI(); 1.2566 + if (!uri) { 1.2567 + aReturn.Append(internalError); 1.2568 + 1.2569 + return; 1.2570 + } 1.2571 + 1.2572 + nsresult rv; 1.2573 + 1.2574 + nsCString host; 1.2575 + rv = uri->GetHost(host); 1.2576 + if (NS_FAILED(rv)) { 1.2577 + aReturn.Append(internalError); 1.2578 + 1.2579 + return; 1.2580 + } 1.2581 + 1.2582 + int32_t numberOfCerts = 0; 1.2583 + CERTCertListNode* node; 1.2584 + for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); 1.2585 + node = CERT_LIST_NEXT(node)) { 1.2586 + ++numberOfCerts; 1.2587 + } 1.2588 + 1.2589 + ScopedCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList)); 1.2590 + 1.2591 + if (!nicknames) { 1.2592 + aReturn.Append(internalError); 1.2593 + 1.2594 + return; 1.2595 + } 1.2596 + 1.2597 + NS_ASSERTION(nicknames->numnicknames == numberOfCerts, 1.2598 + "nicknames->numnicknames != numberOfCerts"); 1.2599 + 1.2600 + nsAutoArrayPtr<char16_t*> certNicknameList(new char16_t*[nicknames->numnicknames * 2]); 1.2601 + if (!certNicknameList) { 1.2602 + aReturn.Append(internalError); 1.2603 + 1.2604 + return; 1.2605 + } 1.2606 + 1.2607 + char16_t** certDetailsList = certNicknameList.get() + nicknames->numnicknames; 1.2608 + 1.2609 + int32_t certsToUse; 1.2610 + for (node = CERT_LIST_HEAD(certList), certsToUse = 0; 1.2611 + !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames; 1.2612 + node = CERT_LIST_NEXT(node)) { 1.2613 + RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert)); 1.2614 + if (tempCert) { 1.2615 + nsAutoString nickWithSerial, details; 1.2616 + rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]), 1.2617 + nickWithSerial, details); 1.2618 + if (NS_SUCCEEDED(rv)) { 1.2619 + certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial); 1.2620 + if (certNicknameList[certsToUse]) { 1.2621 + certDetailsList[certsToUse] = ToNewUnicode(details); 1.2622 + if (!certDetailsList[certsToUse]) { 1.2623 + nsMemory::Free(certNicknameList[certsToUse]); 1.2624 + continue; 1.2625 + } 1.2626 + ++certsToUse; 1.2627 + } 1.2628 + } 1.2629 + } 1.2630 + } 1.2631 + 1.2632 + if (certsToUse == 0) { 1.2633 + aReturn.Append(internalError); 1.2634 + 1.2635 + return; 1.2636 + } 1.2637 + 1.2638 + NS_ConvertUTF8toUTF16 utf16Host(host); 1.2639 + 1.2640 + CERTCertificate *signingCert = nullptr; 1.2641 + bool tryAgain, canceled; 1.2642 + nsAutoString password; 1.2643 + do { 1.2644 + // Throw up the form signing confirmation dialog and get back the index 1.2645 + // of the selected cert. 1.2646 + int32_t selectedIndex = -1; 1.2647 + rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign, 1.2648 + const_cast<const char16_t**>(certNicknameList.get()), 1.2649 + const_cast<const char16_t**>(certDetailsList), 1.2650 + certsToUse, &selectedIndex, password, 1.2651 + &canceled); 1.2652 + if (NS_FAILED(rv) || canceled) { 1.2653 + break; // out of tryAgain loop 1.2654 + } 1.2655 + 1.2656 + int32_t j = 0; 1.2657 + for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); 1.2658 + node = CERT_LIST_NEXT(node)) { 1.2659 + if (j == selectedIndex) { 1.2660 + signingCert = CERT_DupCertificate(node->cert); 1.2661 + break; // out of cert list iteration loop 1.2662 + } 1.2663 + ++j; 1.2664 + } 1.2665 + 1.2666 + if (!signingCert) { 1.2667 + rv = NS_ERROR_FAILURE; 1.2668 + break; // out of tryAgain loop 1.2669 + } 1.2670 + 1.2671 + NS_ConvertUTF16toUTF8 pwUtf8(password); 1.2672 + 1.2673 + tryAgain = 1.2674 + PK11_CheckUserPassword(signingCert->slot, 1.2675 + const_cast<char *>(pwUtf8.get())) != SECSuccess; 1.2676 + // XXX we should show an error dialog before retrying 1.2677 + } while (tryAgain); 1.2678 + 1.2679 + int32_t k; 1.2680 + for (k = 0; k < certsToUse; ++k) { 1.2681 + nsMemory::Free(certNicknameList[k]); 1.2682 + nsMemory::Free(certDetailsList[k]); 1.2683 + } 1.2684 + 1.2685 + if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop 1.2686 + aReturn.Append(internalError); 1.2687 + 1.2688 + return; 1.2689 + } 1.2690 + 1.2691 + if (canceled) { 1.2692 + aReturn.AppendLiteral("error:userCancel"); 1.2693 + 1.2694 + return; 1.2695 + } 1.2696 + 1.2697 + SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext); 1.2698 + if (!privKey) { 1.2699 + aReturn.Append(internalError); 1.2700 + 1.2701 + return; 1.2702 + } 1.2703 + 1.2704 + nsAutoCString charset(document->GetDocumentCharacterSet()); 1.2705 + 1.2706 + // XXX Doing what nsFormSubmission::GetEncoder does (see 1.2707 + // http://bugzilla.mozilla.org/show_bug.cgi?id=81203). 1.2708 + if (charset.EqualsLiteral("ISO-8859-1")) { 1.2709 + charset.AssignLiteral("windows-1252"); 1.2710 + } 1.2711 + 1.2712 + nsCOMPtr<nsISaveAsCharset> encoder = 1.2713 + do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID); 1.2714 + if (encoder) { 1.2715 + rv = encoder->Init(charset.get(), 1.2716 + (nsISaveAsCharset::attr_EntityAfterCharsetConv + 1.2717 + nsISaveAsCharset::attr_FallbackDecimalNCR), 1.2718 + 0); 1.2719 + } 1.2720 + 1.2721 + nsXPIDLCString buffer; 1.2722 + if (aStringToSign.Length() > 0) { 1.2723 + if (encoder && NS_SUCCEEDED(rv)) { 1.2724 + rv = encoder->Convert(PromiseFlatString(aStringToSign).get(), 1.2725 + getter_Copies(buffer)); 1.2726 + if (NS_FAILED(rv)) { 1.2727 + aReturn.Append(internalError); 1.2728 + 1.2729 + return; 1.2730 + } 1.2731 + } 1.2732 + else { 1.2733 + AppendUTF16toUTF8(aStringToSign, buffer); 1.2734 + } 1.2735 + } 1.2736 + 1.2737 + HASHContext *hc = HASH_Create(HASH_AlgSHA1); 1.2738 + if (!hc) { 1.2739 + aReturn.Append(internalError); 1.2740 + 1.2741 + return; 1.2742 + } 1.2743 + 1.2744 + unsigned char hash[SHA1_LENGTH]; 1.2745 + 1.2746 + SECItem digest; 1.2747 + digest.data = hash; 1.2748 + 1.2749 + HASH_Begin(hc); 1.2750 + HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()), 1.2751 + buffer.Length()); 1.2752 + HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH); 1.2753 + HASH_Destroy(hc); 1.2754 + 1.2755 + nsCString p7; 1.2756 + SECStatus srv = SECFailure; 1.2757 + 1.2758 + SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert, 1.2759 + certUsageEmailSigner, 1.2760 + nullptr, SEC_OID_SHA1, 1.2761 + &digest, nullptr, uiContext); 1.2762 + if (ci) { 1.2763 + srv = SEC_PKCS7IncludeCertChain(ci, nullptr); 1.2764 + if (srv == SECSuccess) { 1.2765 + srv = SEC_PKCS7AddSigningTime(ci); 1.2766 + if (srv == SECSuccess) { 1.2767 + srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nullptr, nullptr, 1.2768 + uiContext); 1.2769 + } 1.2770 + } 1.2771 + 1.2772 + SEC_PKCS7DestroyContentInfo(ci); 1.2773 + } 1.2774 + 1.2775 + if (srv != SECSuccess) { 1.2776 + aReturn.Append(internalError); 1.2777 + 1.2778 + return; 1.2779 + } 1.2780 + 1.2781 + SECItem binary_item; 1.2782 + binary_item.data = reinterpret_cast<unsigned char*> 1.2783 + (const_cast<char*>(p7.get())); 1.2784 + binary_item.len = p7.Length(); 1.2785 + 1.2786 + char *result = NSSBase64_EncodeItem(nullptr, nullptr, 0, &binary_item); 1.2787 + if (result) { 1.2788 + AppendASCIItoUTF16(result, aReturn); 1.2789 + } 1.2790 + else { 1.2791 + aReturn.Append(internalError); 1.2792 + } 1.2793 + 1.2794 + PORT_Free(result); 1.2795 + 1.2796 + return; 1.2797 +} 1.2798 + 1.2799 +void 1.2800 +nsCrypto::Logout(ErrorResult& aRv) 1.2801 +{ 1.2802 + NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.2803 + 1.2804 + nsresult rv; 1.2805 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.2806 + if (NS_FAILED(rv)) { 1.2807 + aRv.Throw(rv); 1.2808 + return; 1.2809 + } 1.2810 + 1.2811 + { 1.2812 + nsNSSShutDownPreventionLock locker; 1.2813 + PK11_LogoutAll(); 1.2814 + SSL_ClearSessionCache(); 1.2815 + } 1.2816 + 1.2817 + rv = nssComponent->LogoutAuthenticatedPK11(); 1.2818 + if (NS_FAILED(rv)) { 1.2819 + aRv.Throw(rv); 1.2820 + } 1.2821 +} 1.2822 + 1.2823 +CRMFObject::CRMFObject() 1.2824 +{ 1.2825 + MOZ_COUNT_CTOR(CRMFObject); 1.2826 +} 1.2827 + 1.2828 +CRMFObject::~CRMFObject() 1.2829 +{ 1.2830 + MOZ_COUNT_DTOR(CRMFObject); 1.2831 +} 1.2832 + 1.2833 +JSObject* 1.2834 +CRMFObject::WrapObject(JSContext *aCx, bool* aTookOwnership) 1.2835 +{ 1.2836 + return CRMFObjectBinding::Wrap(aCx, this, aTookOwnership); 1.2837 +} 1.2838 + 1.2839 +void 1.2840 +CRMFObject::GetRequest(nsAString& aRequest) 1.2841 +{ 1.2842 + aRequest.Assign(mBase64Request); 1.2843 +} 1.2844 + 1.2845 +nsresult 1.2846 +CRMFObject::SetCRMFRequest(char *inRequest) 1.2847 +{ 1.2848 + mBase64Request.AssignWithConversion(inRequest); 1.2849 + return NS_OK; 1.2850 +} 1.2851 + 1.2852 +#endif // MOZ_DISABLE_CRYPTOLEGACY 1.2853 + 1.2854 +nsPkcs11::nsPkcs11() 1.2855 +{ 1.2856 +} 1.2857 + 1.2858 +nsPkcs11::~nsPkcs11() 1.2859 +{ 1.2860 +} 1.2861 + 1.2862 +//Delete a PKCS11 module from the user's profile. 1.2863 +NS_IMETHODIMP 1.2864 +nsPkcs11::DeleteModule(const nsAString& aModuleName) 1.2865 +{ 1.2866 + NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.2867 + 1.2868 + nsNSSShutDownPreventionLock locker; 1.2869 + nsresult rv; 1.2870 + nsString errorMessage; 1.2871 + 1.2872 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.2873 + if (NS_FAILED(rv)) 1.2874 + return rv; 1.2875 + 1.2876 + if (aModuleName.IsEmpty()) { 1.2877 + return NS_ERROR_ILLEGAL_VALUE; 1.2878 + } 1.2879 + 1.2880 + NS_ConvertUTF16toUTF8 modName(aModuleName); 1.2881 + int32_t modType; 1.2882 + SECStatus srv = SECMOD_DeleteModule(modName.get(), &modType); 1.2883 + if (srv == SECSuccess) { 1.2884 + SECMODModule *module = SECMOD_FindModule(modName.get()); 1.2885 + if (module) { 1.2886 +#ifndef MOZ_DISABLE_CRYPTOLEGACY 1.2887 + nssComponent->ShutdownSmartCardThread(module); 1.2888 +#endif 1.2889 + SECMOD_DestroyModule(module); 1.2890 + } 1.2891 + rv = NS_OK; 1.2892 + } else { 1.2893 + rv = NS_ERROR_FAILURE; 1.2894 + } 1.2895 + return rv; 1.2896 +} 1.2897 + 1.2898 +//Add a new PKCS11 module to the user's profile. 1.2899 +NS_IMETHODIMP 1.2900 +nsPkcs11::AddModule(const nsAString& aModuleName, 1.2901 + const nsAString& aLibraryFullPath, 1.2902 + int32_t aCryptoMechanismFlags, 1.2903 + int32_t aCipherFlags) 1.2904 +{ 1.2905 + NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.2906 + 1.2907 + nsNSSShutDownPreventionLock locker; 1.2908 + nsresult rv; 1.2909 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.2910 + 1.2911 + NS_ConvertUTF16toUTF8 moduleName(aModuleName); 1.2912 + nsCString fullPath; 1.2913 + // NSS doesn't support Unicode path. Use native charset 1.2914 + NS_CopyUnicodeToNative(aLibraryFullPath, fullPath); 1.2915 + uint32_t mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags); 1.2916 + uint32_t cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags); 1.2917 + SECStatus srv = SECMOD_AddNewModule(moduleName.get(), fullPath.get(), 1.2918 + mechFlags, cipherFlags); 1.2919 + if (srv == SECSuccess) { 1.2920 + SECMODModule *module = SECMOD_FindModule(moduleName.get()); 1.2921 + if (module) { 1.2922 +#ifndef MOZ_DISABLE_CRYPTOLEGACY 1.2923 + nssComponent->LaunchSmartCardThread(module); 1.2924 +#endif 1.2925 + SECMOD_DestroyModule(module); 1.2926 + } 1.2927 + } 1.2928 + 1.2929 + // The error message we report to the user depends directly on 1.2930 + // what the return value for SEDMOD_AddNewModule is 1.2931 + switch (srv) { 1.2932 + case SECSuccess: 1.2933 + return NS_OK; 1.2934 + case SECFailure: 1.2935 + return NS_ERROR_FAILURE; 1.2936 + case -2: 1.2937 + return NS_ERROR_ILLEGAL_VALUE; 1.2938 + } 1.2939 + NS_ERROR("Bogus return value, this should never happen"); 1.2940 + return NS_ERROR_FAILURE; 1.2941 +} 1.2942 +