security/manager/ssl/src/nsCrypto.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6 #include "nsCrypto.h"
michael@0 7 #include "nsNSSComponent.h"
michael@0 8 #include "secmod.h"
michael@0 9
michael@0 10 #include "nsReadableUtils.h"
michael@0 11 #include "nsCRT.h"
michael@0 12 #include "nsXPIDLString.h"
michael@0 13 #include "nsISaveAsCharset.h"
michael@0 14 #include "nsNativeCharsetUtils.h"
michael@0 15 #include "nsServiceManagerUtils.h"
michael@0 16
michael@0 17 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 18 #include "nsKeygenHandler.h"
michael@0 19 #include "nsKeygenThread.h"
michael@0 20 #include "nsNSSCertificate.h"
michael@0 21 #include "nsNSSCertificateDB.h"
michael@0 22 #include "nsPKCS12Blob.h"
michael@0 23 #include "nsPK11TokenDB.h"
michael@0 24 #include "nsThreadUtils.h"
michael@0 25 #include "nsIServiceManager.h"
michael@0 26 #include "nsIMemory.h"
michael@0 27 #include "nsAlgorithm.h"
michael@0 28 #include "prprf.h"
michael@0 29 #include "nsDOMCID.h"
michael@0 30 #include "nsIDOMWindow.h"
michael@0 31 #include "nsIDOMClassInfo.h"
michael@0 32 #include "nsIDOMDocument.h"
michael@0 33 #include "nsIDocument.h"
michael@0 34 #include "nsIScriptObjectPrincipal.h"
michael@0 35 #include "nsIScriptContext.h"
michael@0 36 #include "nsIScriptGlobalObject.h"
michael@0 37 #include "nsContentUtils.h"
michael@0 38 #include "nsCxPusher.h"
michael@0 39 #include "nsDOMJSUtils.h"
michael@0 40 #include "nsJSUtils.h"
michael@0 41 #include "nsIXPConnect.h"
michael@0 42 #include "nsIRunnable.h"
michael@0 43 #include "nsIWindowWatcher.h"
michael@0 44 #include "nsIPrompt.h"
michael@0 45 #include "nsIFilePicker.h"
michael@0 46 #include "nsJSPrincipals.h"
michael@0 47 #include "nsJSUtils.h"
michael@0 48 #include "nsIPrincipal.h"
michael@0 49 #include "nsIScriptSecurityManager.h"
michael@0 50 #include "nsIGenKeypairInfoDlg.h"
michael@0 51 #include "nsIDOMCryptoDialogs.h"
michael@0 52 #include "nsIFormSigningDialog.h"
michael@0 53 #include "nsIContentSecurityPolicy.h"
michael@0 54 #include "nsIURI.h"
michael@0 55 #include "jsapi.h"
michael@0 56 #include "js/OldDebugAPI.h"
michael@0 57 #include <ctype.h>
michael@0 58 #include "pk11func.h"
michael@0 59 #include "keyhi.h"
michael@0 60 #include "cryptohi.h"
michael@0 61 #include "seccomon.h"
michael@0 62 #include "secerr.h"
michael@0 63 #include "sechash.h"
michael@0 64 #include "crmf.h"
michael@0 65 #include "pk11pqg.h"
michael@0 66 #include "cmmf.h"
michael@0 67 #include "nssb64.h"
michael@0 68 #include "base64.h"
michael@0 69 #include "cert.h"
michael@0 70 #include "certdb.h"
michael@0 71 #include "secmod.h"
michael@0 72 #include "ScopedNSSTypes.h"
michael@0 73 #include "pkix/pkixtypes.h"
michael@0 74
michael@0 75 #include "ssl.h" // For SSL_ClearSessionCache
michael@0 76
michael@0 77 #include "nsNSSCleaner.h"
michael@0 78
michael@0 79 #include "nsNSSCertHelper.h"
michael@0 80 #include <algorithm>
michael@0 81 #include "nsWrapperCacheInlines.h"
michael@0 82 #endif
michael@0 83 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 84 #include "mozilla/dom/CRMFObjectBinding.h"
michael@0 85 #endif
michael@0 86
michael@0 87 using namespace mozilla;
michael@0 88 using namespace mozilla::dom;
michael@0 89
michael@0 90 /*
michael@0 91 * These are the most common error strings that are returned
michael@0 92 * by the JavaScript methods in case of error.
michael@0 93 */
michael@0 94
michael@0 95 #define JS_ERROR "error:"
michael@0 96 #define JS_ERROR_INTERNAL JS_ERROR"internalError"
michael@0 97
michael@0 98 #undef REPORT_INCORRECT_NUM_ARGS
michael@0 99
michael@0 100 #define JS_OK_ADD_MOD 3
michael@0 101 #define JS_OK_DEL_EXTERNAL_MOD 2
michael@0 102 #define JS_OK_DEL_INTERNAL_MOD 1
michael@0 103
michael@0 104 #define JS_ERR_INTERNAL -1
michael@0 105 #define JS_ERR_USER_CANCEL_ACTION -2
michael@0 106 #define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
michael@0 107 #define JS_ERR_DEL_MOD -4
michael@0 108 #define JS_ERR_ADD_MOD -5
michael@0 109 #define JS_ERR_BAD_MODULE_NAME -6
michael@0 110 #define JS_ERR_BAD_DLL_NAME -7
michael@0 111 #define JS_ERR_BAD_MECHANISM_FLAGS -8
michael@0 112 #define JS_ERR_BAD_CIPHER_ENABLE_FLAGS -9
michael@0 113 #define JS_ERR_ADD_DUPLICATE_MOD -10
michael@0 114
michael@0 115 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 116
michael@0 117 NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
michael@0 118
michael@0 119 /*
michael@0 120 * This structure is used to store information for one key generation.
michael@0 121 * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
michael@0 122 * stores one of these structures for every key generation that happens.
michael@0 123 * The information stored in this structure is then used to set some
michael@0 124 * values in the CRMF request.
michael@0 125 */
michael@0 126 typedef enum {
michael@0 127 rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
michael@0 128 ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
michael@0 129 dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
michael@0 130 } nsKeyGenType;
michael@0 131
michael@0 132 bool isECKeyGenType(nsKeyGenType kgt)
michael@0 133 {
michael@0 134 switch (kgt)
michael@0 135 {
michael@0 136 case ecEnc:
michael@0 137 case ecDualUse:
michael@0 138 case ecSign:
michael@0 139 case ecNonrepudiation:
michael@0 140 case ecSignNonrepudiation:
michael@0 141 return true;
michael@0 142
michael@0 143 default:
michael@0 144 break;
michael@0 145 }
michael@0 146
michael@0 147 return false;
michael@0 148 }
michael@0 149
michael@0 150 typedef struct nsKeyPairInfoStr {
michael@0 151 SECKEYPublicKey *pubKey; /* The putlic key associated with gen'd
michael@0 152 priv key. */
michael@0 153 SECKEYPrivateKey *privKey; /* The private key we generated */
michael@0 154 nsKeyGenType keyGenType; /* What type of key gen are we doing.*/
michael@0 155
michael@0 156 CERTCertificate *ecPopCert;
michael@0 157 /* null: use signing for pop
michael@0 158 other than null: a cert that defines EC keygen params
michael@0 159 and will be used for dhMac PoP. */
michael@0 160
michael@0 161 SECKEYPublicKey *ecPopPubKey;
michael@0 162 /* extracted public key from ecPopCert */
michael@0 163 } nsKeyPairInfo;
michael@0 164
michael@0 165
michael@0 166 //This class is just used to pass arguments
michael@0 167 //to the nsCryptoRunnable event.
michael@0 168 class nsCryptoRunArgs : public nsISupports {
michael@0 169 public:
michael@0 170 nsCryptoRunArgs(JSContext *aCx);
michael@0 171 virtual ~nsCryptoRunArgs();
michael@0 172 nsCOMPtr<nsISupports> m_kungFuDeathGrip;
michael@0 173 JSContext *m_cx;
michael@0 174 JS::PersistentRooted<JSObject*> m_scope;
michael@0 175 nsCOMPtr<nsIPrincipal> m_principals;
michael@0 176 nsXPIDLCString m_jsCallback;
michael@0 177 NS_DECL_ISUPPORTS
michael@0 178 };
michael@0 179
michael@0 180 //This class is used to run the callback code
michael@0 181 //passed to crypto.generateCRMFRequest
michael@0 182 //We have to do that for backwards compatibility
michael@0 183 //reasons w/ PSM 1.x and Communciator 4.x
michael@0 184 class nsCryptoRunnable : public nsIRunnable {
michael@0 185 public:
michael@0 186 nsCryptoRunnable(nsCryptoRunArgs *args);
michael@0 187 virtual ~nsCryptoRunnable();
michael@0 188
michael@0 189 NS_IMETHOD Run ();
michael@0 190 NS_DECL_ISUPPORTS
michael@0 191 private:
michael@0 192 nsCryptoRunArgs *m_args;
michael@0 193 };
michael@0 194
michael@0 195
michael@0 196 //We're going to inherit the memory passed
michael@0 197 //into us.
michael@0 198 //This class backs up an array of certificates
michael@0 199 //as an event.
michael@0 200 class nsP12Runnable : public nsIRunnable {
michael@0 201 public:
michael@0 202 nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts, nsIPK11Token *token);
michael@0 203 virtual ~nsP12Runnable();
michael@0 204
michael@0 205 NS_IMETHOD Run();
michael@0 206 NS_DECL_ISUPPORTS
michael@0 207 private:
michael@0 208 nsCOMPtr<nsIPK11Token> mToken;
michael@0 209 nsIX509Cert **mCertArr;
michael@0 210 int32_t mNumCerts;
michael@0 211 };
michael@0 212
michael@0 213 // QueryInterface implementation for nsCrypto
michael@0 214 NS_INTERFACE_MAP_BEGIN(nsCrypto)
michael@0 215 NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
michael@0 216 NS_INTERFACE_MAP_END_INHERITING(mozilla::dom::Crypto)
michael@0 217
michael@0 218 NS_IMPL_ADDREF_INHERITED(nsCrypto, mozilla::dom::Crypto)
michael@0 219 NS_IMPL_RELEASE_INHERITED(nsCrypto, mozilla::dom::Crypto)
michael@0 220
michael@0 221 // QueryInterface implementation for nsPkcs11
michael@0 222 #endif // MOZ_DISABLE_CRYPTOLEGACY
michael@0 223
michael@0 224 NS_INTERFACE_MAP_BEGIN(nsPkcs11)
michael@0 225 NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
michael@0 226 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 227 NS_INTERFACE_MAP_END
michael@0 228
michael@0 229 NS_IMPL_ADDREF(nsPkcs11)
michael@0 230 NS_IMPL_RELEASE(nsPkcs11)
michael@0 231
michael@0 232 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 233
michael@0 234 // ISupports implementation for nsCryptoRunnable
michael@0 235 NS_IMPL_ISUPPORTS(nsCryptoRunnable, nsIRunnable)
michael@0 236
michael@0 237 // ISupports implementation for nsP12Runnable
michael@0 238 NS_IMPL_ISUPPORTS(nsP12Runnable, nsIRunnable)
michael@0 239
michael@0 240 // ISupports implementation for nsCryptoRunArgs
michael@0 241 NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
michael@0 242
michael@0 243 nsCrypto::nsCrypto() :
michael@0 244 mEnableSmartCardEvents(false)
michael@0 245 {
michael@0 246 }
michael@0 247
michael@0 248 nsCrypto::~nsCrypto()
michael@0 249 {
michael@0 250 }
michael@0 251
michael@0 252 void
michael@0 253 nsCrypto::Init(nsIDOMWindow* aWindow)
michael@0 254 {
michael@0 255 mozilla::dom::Crypto::Init(aWindow);
michael@0 256 }
michael@0 257
michael@0 258 void
michael@0 259 nsCrypto::SetEnableSmartCardEvents(bool aEnable, ErrorResult& aRv)
michael@0 260 {
michael@0 261 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
michael@0 262
michael@0 263 nsresult rv = NS_OK;
michael@0 264
michael@0 265 // this has the side effect of starting the nssComponent (and initializing
michael@0 266 // NSS) even if it isn't already going. Starting the nssComponent is a
michael@0 267 // prerequisite for getting smartCard events.
michael@0 268 if (aEnable) {
michael@0 269 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
michael@0 270 }
michael@0 271
michael@0 272 if (NS_FAILED(rv)) {
michael@0 273 aRv.Throw(rv);
michael@0 274 return;
michael@0 275 }
michael@0 276
michael@0 277 mEnableSmartCardEvents = aEnable;
michael@0 278 }
michael@0 279
michael@0 280 NS_IMETHODIMP
michael@0 281 nsCrypto::SetEnableSmartCardEvents(bool aEnable)
michael@0 282 {
michael@0 283 ErrorResult rv;
michael@0 284 SetEnableSmartCardEvents(aEnable, rv);
michael@0 285 return rv.ErrorCode();
michael@0 286 }
michael@0 287
michael@0 288 bool
michael@0 289 nsCrypto::EnableSmartCardEvents()
michael@0 290 {
michael@0 291 return mEnableSmartCardEvents;
michael@0 292 }
michael@0 293
michael@0 294 NS_IMETHODIMP
michael@0 295 nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
michael@0 296 {
michael@0 297 *aEnable = EnableSmartCardEvents();
michael@0 298 return NS_OK;
michael@0 299 }
michael@0 300
michael@0 301 //A quick function to let us know if the key we're trying to generate
michael@0 302 //can be escrowed.
michael@0 303 static bool
michael@0 304 ns_can_escrow(nsKeyGenType keyGenType)
michael@0 305 {
michael@0 306 /* For now, we only escrow rsa-encryption and ec-encryption keys. */
michael@0 307 return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
michael@0 308 }
michael@0 309
michael@0 310 //Retrieve crypto.version so that callers know what
michael@0 311 //version of PSM this is.
michael@0 312 void
michael@0 313 nsCrypto::GetVersion(nsString& aVersion)
michael@0 314 {
michael@0 315 aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING));
michael@0 316 }
michael@0 317
michael@0 318 /*
michael@0 319 * Given an nsKeyGenType, return the PKCS11 mechanism that will
michael@0 320 * perform the correct key generation.
michael@0 321 */
michael@0 322 static uint32_t
michael@0 323 cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
michael@0 324 {
michael@0 325 uint32_t retMech;
michael@0 326
michael@0 327 switch (keyGenType) {
michael@0 328 case rsaEnc:
michael@0 329 case rsaDualUse:
michael@0 330 case rsaSign:
michael@0 331 case rsaNonrepudiation:
michael@0 332 case rsaSignNonrepudiation:
michael@0 333 retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
michael@0 334 break;
michael@0 335 case ecEnc:
michael@0 336 case ecDualUse:
michael@0 337 case ecSign:
michael@0 338 case ecNonrepudiation:
michael@0 339 case ecSignNonrepudiation:
michael@0 340 retMech = CKM_EC_KEY_PAIR_GEN;
michael@0 341 break;
michael@0 342 case dhEx:
michael@0 343 retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
michael@0 344 break;
michael@0 345 case dsaSign:
michael@0 346 case dsaSignNonrepudiation:
michael@0 347 case dsaNonrepudiation:
michael@0 348 retMech = CKM_DSA_KEY_PAIR_GEN;
michael@0 349 break;
michael@0 350 default:
michael@0 351 retMech = CKM_INVALID_MECHANISM;
michael@0 352 }
michael@0 353 return retMech;
michael@0 354 }
michael@0 355
michael@0 356 /*
michael@0 357 * This function takes a string read through JavaScript parameters
michael@0 358 * and translates it to the internal enumeration representing the
michael@0 359 * key gen type. Leading and trailing whitespace must be already removed.
michael@0 360 */
michael@0 361 static nsKeyGenType
michael@0 362 cryptojs_interpret_key_gen_type(const nsAString& keyAlg)
michael@0 363 {
michael@0 364 if (keyAlg.EqualsLiteral("rsa-ex")) {
michael@0 365 return rsaEnc;
michael@0 366 }
michael@0 367 if (keyAlg.EqualsLiteral("rsa-dual-use")) {
michael@0 368 return rsaDualUse;
michael@0 369 }
michael@0 370 if (keyAlg.EqualsLiteral("rsa-sign")) {
michael@0 371 return rsaSign;
michael@0 372 }
michael@0 373 if (keyAlg.EqualsLiteral("rsa-sign-nonrepudiation")) {
michael@0 374 return rsaSignNonrepudiation;
michael@0 375 }
michael@0 376 if (keyAlg.EqualsLiteral("rsa-nonrepudiation")) {
michael@0 377 return rsaNonrepudiation;
michael@0 378 }
michael@0 379 if (keyAlg.EqualsLiteral("ec-ex")) {
michael@0 380 return ecEnc;
michael@0 381 }
michael@0 382 if (keyAlg.EqualsLiteral("ec-dual-use")) {
michael@0 383 return ecDualUse;
michael@0 384 }
michael@0 385 if (keyAlg.EqualsLiteral("ec-sign")) {
michael@0 386 return ecSign;
michael@0 387 }
michael@0 388 if (keyAlg.EqualsLiteral("ec-sign-nonrepudiation")) {
michael@0 389 return ecSignNonrepudiation;
michael@0 390 }
michael@0 391 if (keyAlg.EqualsLiteral("ec-nonrepudiation")) {
michael@0 392 return ecNonrepudiation;
michael@0 393 }
michael@0 394 if (keyAlg.EqualsLiteral("dsa-sign-nonrepudiation")) {
michael@0 395 return dsaSignNonrepudiation;
michael@0 396 }
michael@0 397 if (keyAlg.EqualsLiteral("dsa-sign")) {
michael@0 398 return dsaSign;
michael@0 399 }
michael@0 400 if (keyAlg.EqualsLiteral("dsa-nonrepudiation")) {
michael@0 401 return dsaNonrepudiation;
michael@0 402 }
michael@0 403 if (keyAlg.EqualsLiteral("dh-ex")) {
michael@0 404 return dhEx;
michael@0 405 }
michael@0 406 return invalidKeyGen;
michael@0 407 }
michael@0 408
michael@0 409 /*
michael@0 410 * input: null terminated char* pointing to (the remainder of) an
michael@0 411 * EC key param string.
michael@0 412 *
michael@0 413 * bool return value, false means "no more name=value pair found",
michael@0 414 * true means "found, see out params"
michael@0 415 *
michael@0 416 * out param name: char * pointing to name (not zero terminated)
michael@0 417 * out param name_len: length of found name
michael@0 418 * out param value: char * pointing to value (not zero terminated)
michael@0 419 * out param value_len: length of found value
michael@0 420 * out param next_pair: to be used for a follow up call to this function
michael@0 421 */
michael@0 422
michael@0 423 bool getNextNameValueFromECKeygenParamString(char *input,
michael@0 424 char *&name,
michael@0 425 int &name_len,
michael@0 426 char *&value,
michael@0 427 int &value_len,
michael@0 428 char *&next_call)
michael@0 429 {
michael@0 430 if (!input || !*input)
michael@0 431 return false;
michael@0 432
michael@0 433 // we allow leading ; and leading space in front of each name value pair
michael@0 434
michael@0 435 while (*input && *input == ';')
michael@0 436 ++input;
michael@0 437
michael@0 438 while (*input && *input == ' ')
michael@0 439 ++input;
michael@0 440
michael@0 441 name = input;
michael@0 442
michael@0 443 while (*input && *input != '=')
michael@0 444 ++input;
michael@0 445
michael@0 446 if (*input != '=')
michael@0 447 return false;
michael@0 448
michael@0 449 name_len = input - name;
michael@0 450 ++input;
michael@0 451
michael@0 452 value = input;
michael@0 453
michael@0 454 while (*input && *input != ';')
michael@0 455 ++input;
michael@0 456
michael@0 457 value_len = input - value;
michael@0 458 next_call = input;
michael@0 459
michael@0 460 return true;
michael@0 461 }
michael@0 462
michael@0 463 //Take the string passed into us via crypto.generateCRMFRequest
michael@0 464 //as the keygen type parameter and convert it to parameters
michael@0 465 //we can actually pass to the PKCS#11 layer.
michael@0 466 static void*
michael@0 467 nsConvertToActualKeyGenParams(uint32_t keyGenMech, char *params,
michael@0 468 uint32_t paramLen, int32_t keySize,
michael@0 469 nsKeyPairInfo *keyPairInfo)
michael@0 470 {
michael@0 471 void *returnParams = nullptr;
michael@0 472
michael@0 473
michael@0 474 switch (keyGenMech) {
michael@0 475 case CKM_RSA_PKCS_KEY_PAIR_GEN:
michael@0 476 {
michael@0 477 // For RSA, we don't support passing in key generation arguments from
michael@0 478 // the JS code just yet.
michael@0 479 if (params)
michael@0 480 return nullptr;
michael@0 481
michael@0 482 PK11RSAGenParams *rsaParams;
michael@0 483 rsaParams = static_cast<PK11RSAGenParams*>
michael@0 484 (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
michael@0 485
michael@0 486 if (!rsaParams) {
michael@0 487 return nullptr;
michael@0 488 }
michael@0 489 /* I'm just taking the same parameters used in
michael@0 490 * certdlgs.c:GenKey
michael@0 491 */
michael@0 492 if (keySize > 0) {
michael@0 493 rsaParams->keySizeInBits = keySize;
michael@0 494 } else {
michael@0 495 rsaParams->keySizeInBits = 1024;
michael@0 496 }
michael@0 497 rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
michael@0 498 returnParams = rsaParams;
michael@0 499 break;
michael@0 500 }
michael@0 501 case CKM_EC_KEY_PAIR_GEN:
michael@0 502 {
michael@0 503 /*
michael@0 504 * keygen params for generating EC keys must be composed of name=value pairs,
michael@0 505 * multiple pairs allowed, separated using semicolon ;
michael@0 506 *
michael@0 507 * Either param "curve" or param "popcert" must be specified.
michael@0 508 * curve=name-of-curve
michael@0 509 * popcert=base64-encoded-cert
michael@0 510 *
michael@0 511 * When both params are specified, popcert will be used.
michael@0 512 * If no popcert param is given, or if popcert can not be decoded,
michael@0 513 * we will fall back to the curve param.
michael@0 514 *
michael@0 515 * Additional name=value pairs may be defined in the future.
michael@0 516 *
michael@0 517 * If param popcert is present and valid, the given certificate will be used
michael@0 518 * to determine the key generation params. In addition the certificate
michael@0 519 * will be used to produce a dhMac based Proof of Posession,
michael@0 520 * using the cert's public key, subject and issuer names,
michael@0 521 * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
michael@0 522 *
michael@0 523 * If neither param popcert nor param curve could be used,
michael@0 524 * tse a curve based on the keysize param.
michael@0 525 * NOTE: Here keysize is used only as an indication of
michael@0 526 * High/Medium/Low strength; elliptic curve
michael@0 527 * cryptography uses smaller keys than RSA to provide
michael@0 528 * equivalent security.
michael@0 529 */
michael@0 530
michael@0 531 char *curve = nullptr;
michael@0 532
michael@0 533 {
michael@0 534 // extract components of name=value list
michael@0 535
michael@0 536 char *next_input = params;
michael@0 537 char *name = nullptr;
michael@0 538 char *value = nullptr;
michael@0 539 int name_len = 0;
michael@0 540 int value_len = 0;
michael@0 541
michael@0 542 while (getNextNameValueFromECKeygenParamString(
michael@0 543 next_input, name, name_len, value, value_len,
michael@0 544 next_input))
michael@0 545 {
michael@0 546 // use only the first specified curve
michael@0 547 if (!curve && PL_strncmp(name, "curve", std::min(name_len, 5)) == 0)
michael@0 548 {
michael@0 549 curve = PL_strndup(value, value_len);
michael@0 550 }
michael@0 551 // use only the first specified popcert
michael@0 552 else if (!keyPairInfo->ecPopCert &&
michael@0 553 PL_strncmp(name, "popcert", std::min(name_len, 7)) == 0)
michael@0 554 {
michael@0 555 char *certstr = PL_strndup(value, value_len);
michael@0 556 if (certstr) {
michael@0 557 keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
michael@0 558 PL_strfree(certstr);
michael@0 559
michael@0 560 if (keyPairInfo->ecPopCert)
michael@0 561 {
michael@0 562 keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
michael@0 563 }
michael@0 564 }
michael@0 565 }
michael@0 566 }
michael@0 567 }
michael@0 568
michael@0 569 // first try to use the params of the provided CA cert
michael@0 570 if (keyPairInfo->ecPopPubKey && keyPairInfo->ecPopPubKey->keyType == ecKey)
michael@0 571 {
michael@0 572 returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
michael@0 573 }
michael@0 574
michael@0 575 // if we did not yet find good params, do we have a curve name?
michael@0 576 if (!returnParams && curve)
michael@0 577 {
michael@0 578 returnParams = decode_ec_params(curve);
michael@0 579 }
michael@0 580
michael@0 581 // if we did not yet find good params, do something based on keysize
michael@0 582 if (!returnParams)
michael@0 583 {
michael@0 584 switch (keySize) {
michael@0 585 case 512:
michael@0 586 case 1024:
michael@0 587 returnParams = decode_ec_params("secp256r1");
michael@0 588 break;
michael@0 589 case 2048:
michael@0 590 default:
michael@0 591 returnParams = decode_ec_params("secp384r1");
michael@0 592 break;
michael@0 593 }
michael@0 594 }
michael@0 595
michael@0 596 if (curve)
michael@0 597 PL_strfree(curve);
michael@0 598
michael@0 599 break;
michael@0 600 }
michael@0 601 case CKM_DSA_KEY_PAIR_GEN:
michael@0 602 {
michael@0 603 // For DSA, we don't support passing in key generation arguments from
michael@0 604 // the JS code just yet.
michael@0 605 if (params)
michael@0 606 return nullptr;
michael@0 607
michael@0 608 PQGParams *pqgParams = nullptr;
michael@0 609 PQGVerify *vfy = nullptr;
michael@0 610 SECStatus rv;
michael@0 611 int index;
michael@0 612
michael@0 613 index = PQG_PBITS_TO_INDEX(keySize);
michael@0 614 if (index == -1) {
michael@0 615 returnParams = nullptr;
michael@0 616 break;
michael@0 617 }
michael@0 618 rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
michael@0 619 if (vfy) {
michael@0 620 PK11_PQG_DestroyVerify(vfy);
michael@0 621 }
michael@0 622 if (rv != SECSuccess) {
michael@0 623 if (pqgParams) {
michael@0 624 PK11_PQG_DestroyParams(pqgParams);
michael@0 625 }
michael@0 626 return nullptr;
michael@0 627 }
michael@0 628 returnParams = pqgParams;
michael@0 629 break;
michael@0 630 }
michael@0 631 default:
michael@0 632 returnParams = nullptr;
michael@0 633 }
michael@0 634 return returnParams;
michael@0 635 }
michael@0 636
michael@0 637 //We need to choose which PKCS11 slot we're going to generate
michael@0 638 //the key on. Calls the default implementation provided by
michael@0 639 //nsKeygenHandler.cpp
michael@0 640 static PK11SlotInfo*
michael@0 641 nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
michael@0 642 {
michael@0 643 nsNSSShutDownPreventionLock locker;
michael@0 644 uint32_t mechanism = cryptojs_convert_to_mechanism(keyGenType);
michael@0 645 PK11SlotInfo *slot = nullptr;
michael@0 646 nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
michael@0 647 if (NS_FAILED(rv)) {
michael@0 648 if (slot)
michael@0 649 PK11_FreeSlot(slot);
michael@0 650 slot = nullptr;
michael@0 651 }
michael@0 652 return slot;
michael@0 653 }
michael@0 654
michael@0 655 //Free the parameters that were passed into PK11_GenerateKeyPair
michael@0 656 //depending on the mechanism type used.
michael@0 657 static void
michael@0 658 nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
michael@0 659 {
michael@0 660 switch (keyGenMechanism) {
michael@0 661 case CKM_RSA_PKCS_KEY_PAIR_GEN:
michael@0 662 nsMemory::Free(params);
michael@0 663 break;
michael@0 664 case CKM_EC_KEY_PAIR_GEN:
michael@0 665 SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
michael@0 666 break;
michael@0 667 case CKM_DSA_KEY_PAIR_GEN:
michael@0 668 PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
michael@0 669 break;
michael@0 670 }
michael@0 671 }
michael@0 672
michael@0 673 //Function that is used to generate a single key pair.
michael@0 674 //Once all the arguments have been parsed and processed, this
michael@0 675 //function gets called and takes care of actually generating
michael@0 676 //the key pair passing the appopriate parameters to the NSS
michael@0 677 //functions.
michael@0 678 static nsresult
michael@0 679 cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo,
michael@0 680 int32_t keySize, char *params,
michael@0 681 nsIInterfaceRequestor *uiCxt,
michael@0 682 PK11SlotInfo *slot, bool willEscrow)
michael@0 683
michael@0 684 {
michael@0 685 const PK11AttrFlags sensitiveFlags = (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE);
michael@0 686 const PK11AttrFlags temporarySessionFlags = PK11_ATTR_SESSION;
michael@0 687 const PK11AttrFlags permanentTokenFlags = PK11_ATTR_TOKEN;
michael@0 688 const PK11AttrFlags extractableFlags = PK11_ATTR_EXTRACTABLE;
michael@0 689
michael@0 690 nsIGeneratingKeypairInfoDialogs * dialogs;
michael@0 691 nsKeygenThread *KeygenRunnable = 0;
michael@0 692 nsCOMPtr<nsIKeygenThread> runnable;
michael@0 693
michael@0 694 uint32_t mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
michael@0 695 void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params,
michael@0 696 (params) ? strlen(params):0,
michael@0 697 keySize, keyPairInfo);
michael@0 698
michael@0 699 if (!keyGenParams || !slot) {
michael@0 700 return NS_ERROR_INVALID_ARG;
michael@0 701 }
michael@0 702
michael@0 703 // Make sure the token has password already set on it before trying
michael@0 704 // to generate the key.
michael@0 705
michael@0 706 nsresult rv = setPassword(slot, uiCxt);
michael@0 707 if (NS_FAILED(rv))
michael@0 708 return rv;
michael@0 709
michael@0 710 if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
michael@0 711 return NS_ERROR_FAILURE;
michael@0 712
michael@0 713 // Smart cards will not let you extract a private key once
michael@0 714 // it is on the smart card. If we've been told to escrow
michael@0 715 // a private key that will be stored on a smart card,
michael@0 716 // then we'll use the following strategy to ensure we can escrow it.
michael@0 717 // We'll attempt to generate the key on our internal token,
michael@0 718 // because this is expected to avoid some problems.
michael@0 719 // If it works, we'll escrow, move the key to the smartcard, done.
michael@0 720 // If it didn't work (or the internal key doesn't support the desired
michael@0 721 // mechanism), then we'll attempt to generate the key on
michael@0 722 // the destination token, with the EXTRACTABLE flag set.
michael@0 723 // If it works, we'll extract, escrow, done.
michael@0 724 // If it failed, then we're unable to escrow and return failure.
michael@0 725 // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
michael@0 726 // so that the key has zero chance of being store in the
michael@0 727 // user's key3.db file. Which the slot returned by
michael@0 728 // PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
michael@0 729 // does not.
michael@0 730 ScopedPK11SlotInfo intSlot;
michael@0 731
michael@0 732 if (willEscrow && !PK11_IsInternal(slot)) {
michael@0 733 intSlot = PK11_GetInternalSlot();
michael@0 734 NS_ASSERTION(intSlot,"Couldn't get the internal slot");
michael@0 735
michael@0 736 if (!PK11_DoesMechanism(intSlot, mechanism)) {
michael@0 737 // Set to null, and the subsequent code will not attempt to use it.
michael@0 738 intSlot = nullptr;
michael@0 739 }
michael@0 740 }
michael@0 741
michael@0 742 rv = getNSSDialogs((void**)&dialogs,
michael@0 743 NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
michael@0 744 NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
michael@0 745
michael@0 746 if (NS_SUCCEEDED(rv)) {
michael@0 747 KeygenRunnable = new nsKeygenThread();
michael@0 748 if (KeygenRunnable) {
michael@0 749 NS_ADDREF(KeygenRunnable);
michael@0 750 }
michael@0 751 }
michael@0 752
michael@0 753 // "firstAttemptSlot" and "secondAttemptSlot" are alternative names
michael@0 754 // for better code readability, we don't increase the reference counts.
michael@0 755
michael@0 756 PK11SlotInfo *firstAttemptSlot = nullptr;
michael@0 757 PK11AttrFlags firstAttemptFlags = 0;
michael@0 758
michael@0 759 PK11SlotInfo *secondAttemptSlot = slot;
michael@0 760 PK11AttrFlags secondAttemptFlags = sensitiveFlags | permanentTokenFlags;
michael@0 761
michael@0 762 if (willEscrow) {
michael@0 763 secondAttemptFlags |= extractableFlags;
michael@0 764 }
michael@0 765
michael@0 766 if (!intSlot || PK11_IsInternal(slot)) {
michael@0 767 // if we cannot use the internal slot, then there is only one attempt
michael@0 768 // if the destination slot is the internal slot, then there is only one attempt
michael@0 769 firstAttemptSlot = secondAttemptSlot;
michael@0 770 firstAttemptFlags = secondAttemptFlags;
michael@0 771 secondAttemptSlot = nullptr;
michael@0 772 secondAttemptFlags = 0;
michael@0 773 }
michael@0 774 else {
michael@0 775 firstAttemptSlot = intSlot;
michael@0 776 firstAttemptFlags = sensitiveFlags | temporarySessionFlags;
michael@0 777
michael@0 778 // We always need the extractable flag on the first attempt,
michael@0 779 // because we want to move the key to another slot - ### is this correct?
michael@0 780 firstAttemptFlags |= extractableFlags;
michael@0 781 }
michael@0 782
michael@0 783 bool mustMoveKey = false;
michael@0 784
michael@0 785 if (NS_FAILED(rv) || !KeygenRunnable) {
michael@0 786 /* execute key generation on this thread */
michael@0 787 rv = NS_OK;
michael@0 788
michael@0 789 keyPairInfo->privKey =
michael@0 790 PK11_GenerateKeyPairWithFlags(firstAttemptSlot, mechanism,
michael@0 791 keyGenParams, &keyPairInfo->pubKey,
michael@0 792 firstAttemptFlags, uiCxt);
michael@0 793
michael@0 794 if (keyPairInfo->privKey) {
michael@0 795 // success on first attempt
michael@0 796 if (secondAttemptSlot) {
michael@0 797 mustMoveKey = true;
michael@0 798 }
michael@0 799 }
michael@0 800 else {
michael@0 801 keyPairInfo->privKey =
michael@0 802 PK11_GenerateKeyPairWithFlags(secondAttemptSlot, mechanism,
michael@0 803 keyGenParams, &keyPairInfo->pubKey,
michael@0 804 secondAttemptFlags, uiCxt);
michael@0 805 }
michael@0 806
michael@0 807 } else {
michael@0 808 /* execute key generation on separate thread */
michael@0 809 KeygenRunnable->SetParams( firstAttemptSlot, firstAttemptFlags,
michael@0 810 secondAttemptSlot, secondAttemptFlags,
michael@0 811 mechanism, keyGenParams, uiCxt );
michael@0 812
michael@0 813 runnable = do_QueryInterface(KeygenRunnable);
michael@0 814
michael@0 815 if (runnable) {
michael@0 816 {
michael@0 817 nsPSMUITracker tracker;
michael@0 818 if (tracker.isUIForbidden()) {
michael@0 819 rv = NS_ERROR_NOT_AVAILABLE;
michael@0 820 }
michael@0 821 else {
michael@0 822 rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
michael@0 823 // We call join on the thread,
michael@0 824 // so we can be sure that no simultaneous access to the passed parameters will happen.
michael@0 825 KeygenRunnable->Join();
michael@0 826 }
michael@0 827 }
michael@0 828
michael@0 829 NS_RELEASE(dialogs);
michael@0 830 if (NS_SUCCEEDED(rv)) {
michael@0 831 PK11SlotInfo *used_slot = nullptr;
michael@0 832 rv = KeygenRunnable->ConsumeResult(&used_slot,
michael@0 833 &keyPairInfo->privKey, &keyPairInfo->pubKey);
michael@0 834
michael@0 835 if (NS_SUCCEEDED(rv)) {
michael@0 836 if ((used_slot == firstAttemptSlot) && secondAttemptSlot) {
michael@0 837 mustMoveKey = true;
michael@0 838 }
michael@0 839
michael@0 840 if (used_slot) {
michael@0 841 PK11_FreeSlot(used_slot);
michael@0 842 }
michael@0 843 }
michael@0 844 }
michael@0 845 }
michael@0 846 }
michael@0 847
michael@0 848 firstAttemptSlot = nullptr;
michael@0 849 secondAttemptSlot = nullptr;
michael@0 850
michael@0 851 nsFreeKeyGenParams(mechanism, keyGenParams);
michael@0 852
michael@0 853 if (KeygenRunnable) {
michael@0 854 NS_RELEASE(KeygenRunnable);
michael@0 855 }
michael@0 856
michael@0 857 if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
michael@0 858 return NS_ERROR_FAILURE;
michael@0 859 }
michael@0 860
michael@0 861 //If we generated the key pair on the internal slot because the
michael@0 862 // keys were going to be escrowed, move the keys over right now.
michael@0 863 if (mustMoveKey) {
michael@0 864 ScopedSECKEYPrivateKey newPrivKey(PK11_LoadPrivKey(slot,
michael@0 865 keyPairInfo->privKey,
michael@0 866 keyPairInfo->pubKey,
michael@0 867 true, true));
michael@0 868 if (!newPrivKey)
michael@0 869 return NS_ERROR_FAILURE;
michael@0 870
michael@0 871 // The private key is stored on the selected slot now, and the copy we
michael@0 872 // ultimately use for escrowing when the time comes lives
michael@0 873 // in the internal slot. We will delete it from that slot
michael@0 874 // after the requests are made.
michael@0 875 }
michael@0 876
michael@0 877 return NS_OK;
michael@0 878 }
michael@0 879
michael@0 880 /*
michael@0 881 * FUNCTION: cryptojs_ReadArgsAndGenerateKey
michael@0 882 * -------------------------------------
michael@0 883 * INPUTS:
michael@0 884 * cx
michael@0 885 * The JSContext associated with the execution of the corresponging
michael@0 886 * crypto.generateCRMFRequest call
michael@0 887 * argv
michael@0 888 * A pointer to an array of JavaScript parameters passed to the
michael@0 889 * method crypto.generateCRMFRequest. The array should have the
michael@0 890 * 3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
michael@0 891 * the definition of crypto.generateCRMFRequest at the following
michael@0 892 * document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html
michael@0 893 * keyGenType
michael@0 894 * A structure used to store the information about the newly created
michael@0 895 * key pair.
michael@0 896 * uiCxt
michael@0 897 * An interface requestor that would be used to get an nsIPrompt
michael@0 898 * if we need to ask the user for a password.
michael@0 899 * slotToUse
michael@0 900 * The PKCS11 slot to use for generating the key pair. If nullptr, then
michael@0 901 * this function should select a slot that can do the key generation
michael@0 902 * from the keytype associted with the keyPairInfo, and pass it back to
michael@0 903 * the caller so that subsequence key generations can use the same slot.
michael@0 904 * willEscrow
michael@0 905 * If true, then that means we will try to escrow the generated
michael@0 906 * private key when building the CRMF request. If false, then
michael@0 907 * we will not try to escrow the private key.
michael@0 908 *
michael@0 909 * NOTES:
michael@0 910 * This function takes care of reading a set of 3 parameters that define
michael@0 911 * one key generation. The argv pointer should be one that originates
michael@0 912 * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
michael@0 913 * The function interprets the argument in the first index as an integer and
michael@0 914 * passes that as the key size for the key generation-this parameter is
michael@0 915 * mandatory. The second parameter is read in as a string. This value can
michael@0 916 * be null in JavaScript world and everything will still work. The third
michael@0 917 * parameter is a mandatory string that indicates what kind of key to generate.
michael@0 918 * There should always be 1-to-1 correspondence between the strings compared
michael@0 919 * in the function cryptojs_interpret_key_gen_type and the strings listed in
michael@0 920 * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html
michael@0 921 * under the definition of the method generateCRMFRequest, for the parameter
michael@0 922 * "keyGenAlgN". After reading the parameters, the function then
michael@0 923 * generates the key pairs passing the parameters parsed from the JavaScript i
michael@0 924 * routine.
michael@0 925 *
michael@0 926 * RETURN:
michael@0 927 * NS_OK if creating the Key was successful. Any other return value
michael@0 928 * indicates an error.
michael@0 929 */
michael@0 930
michael@0 931 static nsresult
michael@0 932 cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
michael@0 933 JS::Value *argv,
michael@0 934 nsKeyPairInfo *keyGenType,
michael@0 935 nsIInterfaceRequestor *uiCxt,
michael@0 936 PK11SlotInfo **slot, bool willEscrow)
michael@0 937 {
michael@0 938 JSString *jsString;
michael@0 939 JSAutoByteString params;
michael@0 940 int keySize;
michael@0 941 nsresult rv;
michael@0 942
michael@0 943 if (!JSVAL_IS_INT(argv[0])) {
michael@0 944 JS_ReportError(cx, "%s%s", JS_ERROR,
michael@0 945 "passed in non-integer for key size");
michael@0 946 return NS_ERROR_FAILURE;
michael@0 947 }
michael@0 948 keySize = JSVAL_TO_INT(argv[0]);
michael@0 949 if (!JSVAL_IS_NULL(argv[1])) {
michael@0 950 JS::Rooted<JS::Value> v(cx, argv[1]);
michael@0 951 jsString = JS::ToString(cx, v);
michael@0 952 NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
michael@0 953 argv[1] = STRING_TO_JSVAL(jsString);
michael@0 954 params.encodeLatin1(cx, jsString);
michael@0 955 NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
michael@0 956 }
michael@0 957
michael@0 958 if (JSVAL_IS_NULL(argv[2])) {
michael@0 959 JS_ReportError(cx,"%s%s", JS_ERROR,
michael@0 960 "key generation type not specified");
michael@0 961 return NS_ERROR_FAILURE;
michael@0 962 }
michael@0 963 JS::Rooted<JS::Value> v(cx, argv[2]);
michael@0 964 jsString = JS::ToString(cx, v);
michael@0 965 NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
michael@0 966 argv[2] = STRING_TO_JSVAL(jsString);
michael@0 967 nsDependentJSString dependentKeyGenAlg;
michael@0 968 NS_ENSURE_TRUE(dependentKeyGenAlg.init(cx, jsString), NS_ERROR_UNEXPECTED);
michael@0 969 nsAutoString keyGenAlg(dependentKeyGenAlg);
michael@0 970 keyGenAlg.Trim("\r\n\t ");
michael@0 971 keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg);
michael@0 972 if (keyGenType->keyGenType == invalidKeyGen) {
michael@0 973 NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg);
michael@0 974 JS_ReportError(cx, "%s%s%s", JS_ERROR,
michael@0 975 "invalid key generation argument:",
michael@0 976 keyGenAlgNarrow.get());
michael@0 977 goto loser;
michael@0 978 }
michael@0 979 if (!*slot) {
michael@0 980 *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
michael@0 981 if (!*slot)
michael@0 982 goto loser;
michael@0 983 }
michael@0 984
michael@0 985 rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
michael@0 986 *slot,willEscrow);
michael@0 987
michael@0 988 if (rv != NS_OK) {
michael@0 989 NS_LossyConvertUTF16toASCII keyGenAlgNarrow(dependentKeyGenAlg);
michael@0 990 JS_ReportError(cx,"%s%s%s", JS_ERROR,
michael@0 991 "could not generate the key for algorithm ",
michael@0 992 keyGenAlgNarrow.get());
michael@0 993 goto loser;
michael@0 994 }
michael@0 995 return NS_OK;
michael@0 996 loser:
michael@0 997 return NS_ERROR_FAILURE;
michael@0 998 }
michael@0 999
michael@0 1000 //Utility funciton to free up the memory used by nsKeyPairInfo
michael@0 1001 //arrays.
michael@0 1002 static void
michael@0 1003 nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
michael@0 1004 {
michael@0 1005 NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
michael@0 1006 if (!keyids)
michael@0 1007 return;
michael@0 1008 int i;
michael@0 1009 for (i=0; i<numIDs; i++) {
michael@0 1010 if (keyids[i].pubKey)
michael@0 1011 SECKEY_DestroyPublicKey(keyids[i].pubKey);
michael@0 1012 if (keyids[i].privKey)
michael@0 1013 SECKEY_DestroyPrivateKey(keyids[i].privKey);
michael@0 1014 if (keyids[i].ecPopCert)
michael@0 1015 CERT_DestroyCertificate(keyids[i].ecPopCert);
michael@0 1016 if (keyids[i].ecPopPubKey)
michael@0 1017 SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
michael@0 1018 }
michael@0 1019 delete []keyids;
michael@0 1020 }
michael@0 1021
michael@0 1022 //Utility funciton used to free the genertaed cert request messages
michael@0 1023 static void
michael@0 1024 nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, int32_t numMessages)
michael@0 1025 {
michael@0 1026 int32_t i;
michael@0 1027 for (i=0; i<numMessages && certReqMsgs[i]; i++) {
michael@0 1028 CRMF_DestroyCertReqMsg(certReqMsgs[i]);
michael@0 1029 }
michael@0 1030 delete []certReqMsgs;
michael@0 1031 }
michael@0 1032
michael@0 1033 //If the form called for escrowing the private key we just generated,
michael@0 1034 //this function adds all the correct elements to the request.
michael@0 1035 //That consists of adding CRMFEncryptedKey to the reques as part
michael@0 1036 //of the CRMFPKIArchiveOptions Control.
michael@0 1037 static nsresult
michael@0 1038 nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
michael@0 1039 nsNSSCertificate *wrappingCert)
michael@0 1040 {
michael@0 1041 if (!wrappingCert ||
michael@0 1042 CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
michael@0 1043 return NS_ERROR_FAILURE;
michael@0 1044 }
michael@0 1045 mozilla::pkix::ScopedCERTCertificate cert(wrappingCert->GetCert());
michael@0 1046 if (!cert)
michael@0 1047 return NS_ERROR_FAILURE;
michael@0 1048
michael@0 1049 CRMFEncryptedKey *encrKey =
michael@0 1050 CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert.get());
michael@0 1051 if (!encrKey)
michael@0 1052 return NS_ERROR_FAILURE;
michael@0 1053
michael@0 1054 CRMFPKIArchiveOptions *archOpt =
michael@0 1055 CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
michael@0 1056 if (!archOpt) {
michael@0 1057 CRMF_DestroyEncryptedKey(encrKey);
michael@0 1058 return NS_ERROR_FAILURE;
michael@0 1059 }
michael@0 1060 SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
michael@0 1061 CRMF_DestroyEncryptedKey(encrKey);
michael@0 1062 CRMF_DestroyPKIArchiveOptions(archOpt);
michael@0 1063 if (srv != SECSuccess)
michael@0 1064 return NS_ERROR_FAILURE;
michael@0 1065
michael@0 1066 return NS_OK;
michael@0 1067 }
michael@0 1068
michael@0 1069 //Set the Distinguished Name (Subject Name) for the cert
michael@0 1070 //being requested.
michael@0 1071 static nsresult
michael@0 1072 nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
michael@0 1073 {
michael@0 1074 if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
michael@0 1075 return NS_ERROR_FAILURE;
michael@0 1076 }
michael@0 1077 ScopedCERTName subjectName(CERT_AsciiToName(reqDN));
michael@0 1078 if (!subjectName) {
michael@0 1079 return NS_ERROR_FAILURE;
michael@0 1080 }
michael@0 1081 SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
michael@0 1082 static_cast<void*>
michael@0 1083 (subjectName));
michael@0 1084 return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
michael@0 1085 }
michael@0 1086
michael@0 1087 //Set Registration Token Control on the request.
michael@0 1088 static nsresult
michael@0 1089 nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
michael@0 1090 {
michael@0 1091 // this should never happen, but might as well add this.
michael@0 1092 NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
michael@0 1093 if (regToken){
michael@0 1094 if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
michael@0 1095 return NS_ERROR_FAILURE;
michael@0 1096
michael@0 1097 SECItem src;
michael@0 1098 src.data = (unsigned char*)regToken;
michael@0 1099 src.len = strlen(regToken);
michael@0 1100 SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src,
michael@0 1101 SEC_ASN1_GET(SEC_UTF8StringTemplate));
michael@0 1102
michael@0 1103 if (!derEncoded)
michael@0 1104 return NS_ERROR_FAILURE;
michael@0 1105
michael@0 1106 SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
michael@0 1107 SECITEM_FreeItem(derEncoded,true);
michael@0 1108 if (srv != SECSuccess)
michael@0 1109 return NS_ERROR_FAILURE;
michael@0 1110 }
michael@0 1111 return NS_OK;
michael@0 1112 }
michael@0 1113
michael@0 1114 //Set the Authenticator control on the cert reuest. It's just
michael@0 1115 //a string that gets passed along.
michael@0 1116 static nsresult
michael@0 1117 nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
michael@0 1118 {
michael@0 1119 //This should never happen, but might as well check.
michael@0 1120 NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
michael@0 1121 if (authenticator) {
michael@0 1122 if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
michael@0 1123 return NS_ERROR_FAILURE;
michael@0 1124
michael@0 1125 SECItem src;
michael@0 1126 src.data = (unsigned char*)authenticator;
michael@0 1127 src.len = strlen(authenticator);
michael@0 1128 SECItem *derEncoded = SEC_ASN1EncodeItem(nullptr, nullptr, &src,
michael@0 1129 SEC_ASN1_GET(SEC_UTF8StringTemplate));
michael@0 1130 if (!derEncoded)
michael@0 1131 return NS_ERROR_FAILURE;
michael@0 1132
michael@0 1133 SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq,
michael@0 1134 derEncoded);
michael@0 1135 SECITEM_FreeItem(derEncoded, true);
michael@0 1136 if (srv != SECSuccess)
michael@0 1137 return NS_ERROR_FAILURE;
michael@0 1138 }
michael@0 1139 return NS_OK;
michael@0 1140 }
michael@0 1141
michael@0 1142 // ASN1 DER encoding rules say that when encoding a BIT string,
michael@0 1143 // the length in the header for the bit string is the number
michael@0 1144 // of "useful" bits in the BIT STRING. So the function finds
michael@0 1145 // it and sets accordingly for the returned item.
michael@0 1146 static void
michael@0 1147 nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
michael@0 1148 {
michael@0 1149 unsigned char onebyte;
michael@0 1150 unsigned int i, len = 0;
michael@0 1151
michael@0 1152 /* to prevent warning on some platform at compile time */
michael@0 1153 onebyte = '\0';
michael@0 1154 /* Get the position of the right-most turn-on bit */
michael@0 1155 for (i = 0; i < (value->len ) * 8; ++i) {
michael@0 1156 if (i % 8 == 0)
michael@0 1157 onebyte = value->data[i/8];
michael@0 1158 if (onebyte & 0x80)
michael@0 1159 len = i;
michael@0 1160 onebyte <<= 1;
michael@0 1161 }
michael@0 1162
michael@0 1163 bitsmap->data = value->data;
michael@0 1164 /* Add one here since we work with base 1 */
michael@0 1165 bitsmap->len = len + 1;
michael@0 1166 }
michael@0 1167
michael@0 1168 //This next section defines all the functions that sets the
michael@0 1169 //keyUsageExtension for all the different types of key gens
michael@0 1170 //we handle. The keyUsageExtension is just a bit flag extension
michael@0 1171 //that we set in wrapper functions that call straight into
michael@0 1172 //nsSetKeyUsageExtension. There is one wrapper funciton for each
michael@0 1173 //keyGenType. The correct function will eventually be called
michael@0 1174 //by going through a switch statement based on the nsKeyGenType
michael@0 1175 //in the nsKeyPairInfo struct.
michael@0 1176 static nsresult
michael@0 1177 nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
michael@0 1178 unsigned char keyUsage)
michael@0 1179 {
michael@0 1180 SECItem *encodedExt= nullptr;
michael@0 1181 SECItem keyUsageValue = { (SECItemType) 0, nullptr, 0 };
michael@0 1182 SECItem bitsmap = { (SECItemType) 0, nullptr, 0 };
michael@0 1183 SECStatus srv;
michael@0 1184 CRMFCertExtension *ext = nullptr;
michael@0 1185 CRMFCertExtCreationInfo extAddParams;
michael@0 1186 SEC_ASN1Template bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nullptr,
michael@0 1187 sizeof(SECItem)};
michael@0 1188
michael@0 1189 keyUsageValue.data = &keyUsage;
michael@0 1190 keyUsageValue.len = 1;
michael@0 1191 nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
michael@0 1192
michael@0 1193 encodedExt = SEC_ASN1EncodeItem(nullptr, nullptr, &bitsmap,&bitStrTemplate);
michael@0 1194 if (!encodedExt) {
michael@0 1195 goto loser;
michael@0 1196 }
michael@0 1197 ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
michael@0 1198 if (!ext) {
michael@0 1199 goto loser;
michael@0 1200 }
michael@0 1201 extAddParams.numExtensions = 1;
michael@0 1202 extAddParams.extensions = &ext;
michael@0 1203 srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
michael@0 1204 &extAddParams);
michael@0 1205 if (srv != SECSuccess) {
michael@0 1206 goto loser;
michael@0 1207 }
michael@0 1208 CRMF_DestroyCertExtension(ext);
michael@0 1209 SECITEM_FreeItem(encodedExt, true);
michael@0 1210 return NS_OK;
michael@0 1211 loser:
michael@0 1212 if (ext) {
michael@0 1213 CRMF_DestroyCertExtension(ext);
michael@0 1214 }
michael@0 1215 if (encodedExt) {
michael@0 1216 SECITEM_FreeItem(encodedExt, true);
michael@0 1217 }
michael@0 1218 return NS_ERROR_FAILURE;
michael@0 1219 }
michael@0 1220
michael@0 1221 static nsresult
michael@0 1222 nsSetRSADualUse(CRMFCertRequest *crmfReq)
michael@0 1223 {
michael@0 1224 unsigned char keyUsage = KU_DIGITAL_SIGNATURE
michael@0 1225 | KU_NON_REPUDIATION
michael@0 1226 | KU_KEY_ENCIPHERMENT;
michael@0 1227
michael@0 1228 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1229 }
michael@0 1230
michael@0 1231 static nsresult
michael@0 1232 nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
michael@0 1233 {
michael@0 1234 unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
michael@0 1235
michael@0 1236 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1237 }
michael@0 1238
michael@0 1239 static nsresult
michael@0 1240 nsSetRSASign(CRMFCertRequest *crmfReq)
michael@0 1241 {
michael@0 1242 unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
michael@0 1243
michael@0 1244
michael@0 1245 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1246 }
michael@0 1247
michael@0 1248 static nsresult
michael@0 1249 nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
michael@0 1250 {
michael@0 1251 unsigned char keyUsage = KU_NON_REPUDIATION;
michael@0 1252
michael@0 1253 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1254 }
michael@0 1255
michael@0 1256 static nsresult
michael@0 1257 nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
michael@0 1258 {
michael@0 1259 unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
michael@0 1260 KU_NON_REPUDIATION;
michael@0 1261
michael@0 1262 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1263 }
michael@0 1264
michael@0 1265 static nsresult
michael@0 1266 nsSetECDualUse(CRMFCertRequest *crmfReq)
michael@0 1267 {
michael@0 1268 unsigned char keyUsage = KU_DIGITAL_SIGNATURE
michael@0 1269 | KU_NON_REPUDIATION
michael@0 1270 | KU_KEY_AGREEMENT;
michael@0 1271
michael@0 1272 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1273 }
michael@0 1274
michael@0 1275 static nsresult
michael@0 1276 nsSetECKeyEx(CRMFCertRequest *crmfReq)
michael@0 1277 {
michael@0 1278 unsigned char keyUsage = KU_KEY_AGREEMENT;
michael@0 1279
michael@0 1280 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1281 }
michael@0 1282
michael@0 1283 static nsresult
michael@0 1284 nsSetECSign(CRMFCertRequest *crmfReq)
michael@0 1285 {
michael@0 1286 unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
michael@0 1287
michael@0 1288
michael@0 1289 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1290 }
michael@0 1291
michael@0 1292 static nsresult
michael@0 1293 nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
michael@0 1294 {
michael@0 1295 unsigned char keyUsage = KU_NON_REPUDIATION;
michael@0 1296
michael@0 1297 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1298 }
michael@0 1299
michael@0 1300 static nsresult
michael@0 1301 nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
michael@0 1302 {
michael@0 1303 unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
michael@0 1304 KU_NON_REPUDIATION;
michael@0 1305
michael@0 1306 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1307 }
michael@0 1308
michael@0 1309 static nsresult
michael@0 1310 nsSetDH(CRMFCertRequest *crmfReq)
michael@0 1311 {
michael@0 1312 unsigned char keyUsage = KU_KEY_AGREEMENT;
michael@0 1313
michael@0 1314 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1315 }
michael@0 1316
michael@0 1317 static nsresult
michael@0 1318 nsSetDSASign(CRMFCertRequest *crmfReq)
michael@0 1319 {
michael@0 1320 unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
michael@0 1321
michael@0 1322 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1323 }
michael@0 1324
michael@0 1325 static nsresult
michael@0 1326 nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
michael@0 1327 {
michael@0 1328 unsigned char keyUsage = KU_NON_REPUDIATION;
michael@0 1329
michael@0 1330 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1331 }
michael@0 1332
michael@0 1333 static nsresult
michael@0 1334 nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
michael@0 1335 {
michael@0 1336 unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
michael@0 1337 KU_NON_REPUDIATION;
michael@0 1338
michael@0 1339 return nsSetKeyUsageExtension(crmfReq, keyUsage);
michael@0 1340 }
michael@0 1341
michael@0 1342 static nsresult
michael@0 1343 nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
michael@0 1344 {
michael@0 1345 nsresult rv;
michael@0 1346
michael@0 1347 switch (keyGenType) {
michael@0 1348 case rsaDualUse:
michael@0 1349 rv = nsSetRSADualUse(crmfReq);
michael@0 1350 break;
michael@0 1351 case rsaEnc:
michael@0 1352 rv = nsSetRSAKeyEx(crmfReq);
michael@0 1353 break;
michael@0 1354 case rsaSign:
michael@0 1355 rv = nsSetRSASign(crmfReq);
michael@0 1356 break;
michael@0 1357 case rsaNonrepudiation:
michael@0 1358 rv = nsSetRSANonRepudiation(crmfReq);
michael@0 1359 break;
michael@0 1360 case rsaSignNonrepudiation:
michael@0 1361 rv = nsSetRSASignNonRepudiation(crmfReq);
michael@0 1362 break;
michael@0 1363 case ecDualUse:
michael@0 1364 rv = nsSetECDualUse(crmfReq);
michael@0 1365 break;
michael@0 1366 case ecEnc:
michael@0 1367 rv = nsSetECKeyEx(crmfReq);
michael@0 1368 break;
michael@0 1369 case ecSign:
michael@0 1370 rv = nsSetECSign(crmfReq);
michael@0 1371 break;
michael@0 1372 case ecNonrepudiation:
michael@0 1373 rv = nsSetECNonRepudiation(crmfReq);
michael@0 1374 break;
michael@0 1375 case ecSignNonrepudiation:
michael@0 1376 rv = nsSetECSignNonRepudiation(crmfReq);
michael@0 1377 break;
michael@0 1378 case dhEx:
michael@0 1379 rv = nsSetDH(crmfReq);
michael@0 1380 break;
michael@0 1381 case dsaSign:
michael@0 1382 rv = nsSetDSASign(crmfReq);
michael@0 1383 break;
michael@0 1384 case dsaNonrepudiation:
michael@0 1385 rv = nsSetDSANonRepudiation(crmfReq);
michael@0 1386 break;
michael@0 1387 case dsaSignNonrepudiation:
michael@0 1388 rv = nsSetDSASignNonRepudiation(crmfReq);
michael@0 1389 break;
michael@0 1390 default:
michael@0 1391 rv = NS_ERROR_FAILURE;
michael@0 1392 break;
michael@0 1393 }
michael@0 1394 return rv;
michael@0 1395 }
michael@0 1396
michael@0 1397 //Create a single CRMFCertRequest with all of the necessary parts
michael@0 1398 //already installed. The request returned by this function will
michael@0 1399 //have all the parts necessary and can just be added to a
michael@0 1400 //Certificate Request Message.
michael@0 1401 static CRMFCertRequest*
michael@0 1402 nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken,
michael@0 1403 char *authenticator, nsNSSCertificate *wrappingCert)
michael@0 1404 {
michael@0 1405 uint32_t reqID;
michael@0 1406 nsresult rv;
michael@0 1407
michael@0 1408 //The draft says the ID of the request should be a random
michael@0 1409 //number. We don't have a way of tracking this number
michael@0 1410 //to compare when the reply actually comes back,though.
michael@0 1411 PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
michael@0 1412 CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
michael@0 1413 if (!certReq)
michael@0 1414 return nullptr;
michael@0 1415
michael@0 1416 long version = SEC_CERTIFICATE_VERSION_3;
michael@0 1417 SECStatus srv;
michael@0 1418 CERTSubjectPublicKeyInfo *spki = nullptr;
michael@0 1419 srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
michael@0 1420 if (srv != SECSuccess)
michael@0 1421 goto loser;
michael@0 1422
michael@0 1423 spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
michael@0 1424 if (!spki)
michael@0 1425 goto loser;
michael@0 1426
michael@0 1427 srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
michael@0 1428 SECKEY_DestroySubjectPublicKeyInfo(spki);
michael@0 1429 if (srv != SECSuccess)
michael@0 1430 goto loser;
michael@0 1431
michael@0 1432 if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
michael@0 1433 rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
michael@0 1434 if (NS_FAILED(rv))
michael@0 1435 goto loser;
michael@0 1436 }
michael@0 1437 rv = nsSetDNForRequest(certReq, reqDN);
michael@0 1438 if (NS_FAILED(rv))
michael@0 1439 goto loser;
michael@0 1440
michael@0 1441 rv = nsSetRegToken(certReq, regToken);
michael@0 1442 if (NS_FAILED(rv))
michael@0 1443 goto loser;
michael@0 1444
michael@0 1445 rv = nsSetAuthenticator(certReq, authenticator);
michael@0 1446 if (NS_FAILED(rv))
michael@0 1447 goto loser;
michael@0 1448
michael@0 1449 rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType);
michael@0 1450 if (NS_FAILED(rv))
michael@0 1451 goto loser;
michael@0 1452
michael@0 1453 return certReq;
michael@0 1454 loser:
michael@0 1455 if (certReq) {
michael@0 1456 CRMF_DestroyCertRequest(certReq);
michael@0 1457 }
michael@0 1458 return nullptr;
michael@0 1459 }
michael@0 1460
michael@0 1461 /*
michael@0 1462 * This function will set the Proof Of Possession (POP) for a request
michael@0 1463 * associated with a key pair intended to do Key Encipherment. Currently
michael@0 1464 * this means encryption only keys.
michael@0 1465 */
michael@0 1466 static nsresult
michael@0 1467 nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
michael@0 1468 {
michael@0 1469 SECItem bitString;
michael@0 1470 unsigned char der[2];
michael@0 1471 SECStatus srv;
michael@0 1472
michael@0 1473 if (isEscrowed) {
michael@0 1474 /* For proof of possession on escrowed keys, we use the
michael@0 1475 * this Message option of POPOPrivKey and include a zero
michael@0 1476 * length bit string in the POP field. This is OK because the encrypted
michael@0 1477 * private key already exists as part of the PKIArchiveOptions
michael@0 1478 * Control and that for all intents and purposes proves that
michael@0 1479 * we do own the private key.
michael@0 1480 */
michael@0 1481 der[0] = 0x03; /*We've got a bit string */
michael@0 1482 der[1] = 0x00; /*We've got a 0 length bit string */
michael@0 1483 bitString.data = der;
michael@0 1484 bitString.len = 2;
michael@0 1485 srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
michael@0 1486 crmfNoSubseqMess, &bitString);
michael@0 1487 } else {
michael@0 1488 /* If the encryption key is not being escrowed, then we set the
michael@0 1489 * Proof Of Possession to be a Challenge Response mechanism.
michael@0 1490 */
michael@0 1491 srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
michael@0 1492 crmfSubsequentMessage,
michael@0 1493 crmfChallengeResp, nullptr);
michael@0 1494 }
michael@0 1495 return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
michael@0 1496 }
michael@0 1497
michael@0 1498 static void
michael@0 1499 nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
michael@0 1500
michael@0 1501 static void
michael@0 1502 nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
michael@0 1503
michael@0 1504 static nsresult
michael@0 1505 nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg,
michael@0 1506 nsKeyPairInfo *keyInfo,
michael@0 1507 CRMFCertRequest *certReq)
michael@0 1508 {
michael@0 1509 // RFC 2511 Appendix A section 2 a) defines,
michael@0 1510 // the "text" input for HMAC shall be the DER encoded version of
michael@0 1511 // of the single cert request.
michael@0 1512 // We'll produce that encoding and destroy it afterwards,
michael@0 1513 // because when sending the complete package to the CA,
michael@0 1514 // we'll use a different encoding, one that includes POP and
michael@0 1515 // allows multiple requests to be sent in one step.
michael@0 1516
michael@0 1517 unsigned long der_request_len = 0;
michael@0 1518 ScopedSECItem der_request;
michael@0 1519
michael@0 1520 if (SECSuccess != CRMF_EncodeCertRequest(certReq,
michael@0 1521 nsCRMFEncoderItemCount,
michael@0 1522 &der_request_len))
michael@0 1523 return NS_ERROR_FAILURE;
michael@0 1524
michael@0 1525 der_request = SECITEM_AllocItem(nullptr, nullptr, der_request_len);
michael@0 1526 if (!der_request)
michael@0 1527 return NS_ERROR_FAILURE;
michael@0 1528
michael@0 1529 // set len in returned SECItem back to zero, because it will
michael@0 1530 // be used as the destination offset inside the
michael@0 1531 // nsCRMFEncoderItemStore callback.
michael@0 1532
michael@0 1533 der_request->len = 0;
michael@0 1534
michael@0 1535 if (SECSuccess != CRMF_EncodeCertRequest(certReq,
michael@0 1536 nsCRMFEncoderItemStore,
michael@0 1537 der_request))
michael@0 1538 return NS_ERROR_FAILURE;
michael@0 1539
michael@0 1540 // RFC 2511 Appendix A section 2 c):
michael@0 1541 // "A key K is derived from the shared secret Kec and the subject and
michael@0 1542 // issuer names in the CA's certificate as follows:
michael@0 1543 // K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
michael@0 1544
michael@0 1545 ScopedPK11SymKey shared_secret;
michael@0 1546 ScopedPK11SymKey subject_and_secret;
michael@0 1547 ScopedPK11SymKey subject_and_secret_and_issuer;
michael@0 1548 ScopedPK11SymKey sha1_of_subject_and_secret_and_issuer;
michael@0 1549
michael@0 1550 shared_secret =
michael@0 1551 PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
michael@0 1552 keyInfo->ecPopPubKey, // SECKEYPublicKey *pubKey
michael@0 1553 false, // bool isSender
michael@0 1554 nullptr, // SECItem *randomA
michael@0 1555 nullptr, // SECItem *randomB
michael@0 1556 CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
michael@0 1557 CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
michael@0 1558 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
michael@0 1559 0, // int keySize
michael@0 1560 CKD_NULL, // CK_ULONG kdf
michael@0 1561 nullptr, // SECItem *sharedData
michael@0 1562 nullptr); // void *wincx
michael@0 1563
michael@0 1564 if (!shared_secret)
michael@0 1565 return NS_ERROR_FAILURE;
michael@0 1566
michael@0 1567 CK_KEY_DERIVATION_STRING_DATA concat_data_base;
michael@0 1568 concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
michael@0 1569 concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
michael@0 1570 SECItem concat_data_base_item;
michael@0 1571 concat_data_base_item.data = (unsigned char*)&concat_data_base;
michael@0 1572 concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
michael@0 1573
michael@0 1574 subject_and_secret =
michael@0 1575 PK11_Derive(shared_secret, // PK11SymKey *baseKey
michael@0 1576 CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
michael@0 1577 &concat_data_base_item, // SECItem *param
michael@0 1578 CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
michael@0 1579 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
michael@0 1580 0); // int keySize
michael@0 1581
michael@0 1582 if (!subject_and_secret)
michael@0 1583 return NS_ERROR_FAILURE;
michael@0 1584
michael@0 1585 CK_KEY_DERIVATION_STRING_DATA concat_base_data;
michael@0 1586 concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
michael@0 1587 concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
michael@0 1588 SECItem concat_base_data_item;
michael@0 1589 concat_base_data_item.data = (unsigned char*)&concat_base_data;
michael@0 1590 concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
michael@0 1591
michael@0 1592 subject_and_secret_and_issuer =
michael@0 1593 PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
michael@0 1594 CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
michael@0 1595 &concat_base_data_item, // SECItem *param
michael@0 1596 CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
michael@0 1597 CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
michael@0 1598 0); // int keySize
michael@0 1599
michael@0 1600 if (!subject_and_secret_and_issuer)
michael@0 1601 return NS_ERROR_FAILURE;
michael@0 1602
michael@0 1603 sha1_of_subject_and_secret_and_issuer =
michael@0 1604 PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
michael@0 1605 CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
michael@0 1606 nullptr, // SECItem *param
michael@0 1607 CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
michael@0 1608 CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
michael@0 1609 0); // int keySize
michael@0 1610
michael@0 1611 if (!sha1_of_subject_and_secret_and_issuer)
michael@0 1612 return NS_ERROR_FAILURE;
michael@0 1613
michael@0 1614 PK11Context *context = nullptr;
michael@0 1615 PK11ContextCleanerTrueParam context_cleaner(context);
michael@0 1616
michael@0 1617 SECItem ignore;
michael@0 1618 ignore.data = 0;
michael@0 1619 ignore.len = 0;
michael@0 1620
michael@0 1621 context =
michael@0 1622 PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
michael@0 1623 CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
michael@0 1624 sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
michael@0 1625 &ignore); // SECItem *param
michael@0 1626
michael@0 1627 if (!context)
michael@0 1628 return NS_ERROR_FAILURE;
michael@0 1629
michael@0 1630 if (SECSuccess != PK11_DigestBegin(context))
michael@0 1631 return NS_ERROR_FAILURE;
michael@0 1632
michael@0 1633 if (SECSuccess !=
michael@0 1634 PK11_DigestOp(context, der_request->data, der_request->len))
michael@0 1635 return NS_ERROR_FAILURE;
michael@0 1636
michael@0 1637 ScopedAutoSECItem result_hmac_sha1_item(SHA1_LENGTH);
michael@0 1638
michael@0 1639 if (SECSuccess !=
michael@0 1640 PK11_DigestFinal(context,
michael@0 1641 result_hmac_sha1_item.data,
michael@0 1642 &result_hmac_sha1_item.len,
michael@0 1643 SHA1_LENGTH))
michael@0 1644 return NS_ERROR_FAILURE;
michael@0 1645
michael@0 1646 if (SECSuccess !=
michael@0 1647 CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
michael@0 1648 crmfNoSubseqMess, &result_hmac_sha1_item))
michael@0 1649 return NS_ERROR_FAILURE;
michael@0 1650
michael@0 1651 return NS_OK;
michael@0 1652 }
michael@0 1653
michael@0 1654 static nsresult
michael@0 1655 nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg,
michael@0 1656 nsKeyPairInfo *keyInfo,
michael@0 1657 CRMFCertRequest *certReq)
michael@0 1658 {
michael@0 1659 // Depending on the type of cert request we'll try
michael@0 1660 // POP mechanisms in different order,
michael@0 1661 // and add the result to the cert request message.
michael@0 1662 //
michael@0 1663 // For any signing or dual use cert,
michael@0 1664 // try signing first,
michael@0 1665 // fall back to DHMAC if we can
michael@0 1666 // (EC cert requests that provide keygen param "popcert"),
michael@0 1667 // otherwise fail.
michael@0 1668 //
michael@0 1669 // For encryption only certs that get escrowed, this is sufficient.
michael@0 1670 //
michael@0 1671 // For encryption only certs, that are not being escrowed,
michael@0 1672 // try DHMAC if we can
michael@0 1673 // (EC cert requests that provide keygen param "popcert"),
michael@0 1674 // otherwise we'll indicate challenge response should be used.
michael@0 1675
michael@0 1676 bool isEncryptionOnlyCertRequest = false;
michael@0 1677 bool escrowEncryptionOnlyCert = false;
michael@0 1678
michael@0 1679 switch (keyInfo->keyGenType)
michael@0 1680 {
michael@0 1681 case rsaEnc:
michael@0 1682 case ecEnc:
michael@0 1683 isEncryptionOnlyCertRequest = true;
michael@0 1684 break;
michael@0 1685
michael@0 1686 case rsaSign:
michael@0 1687 case rsaDualUse:
michael@0 1688 case rsaNonrepudiation:
michael@0 1689 case rsaSignNonrepudiation:
michael@0 1690 case ecSign:
michael@0 1691 case ecDualUse:
michael@0 1692 case ecNonrepudiation:
michael@0 1693 case ecSignNonrepudiation:
michael@0 1694 case dsaSign:
michael@0 1695 case dsaNonrepudiation:
michael@0 1696 case dsaSignNonrepudiation:
michael@0 1697 break;
michael@0 1698
michael@0 1699 case dhEx:
michael@0 1700 /* This case may be supported in the future, but for now, we just fall
michael@0 1701 * though to the default case and return an error for diffie-hellman keys.
michael@0 1702 */
michael@0 1703 default:
michael@0 1704 return NS_ERROR_FAILURE;
michael@0 1705 };
michael@0 1706
michael@0 1707 if (isEncryptionOnlyCertRequest)
michael@0 1708 {
michael@0 1709 escrowEncryptionOnlyCert =
michael@0 1710 CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
michael@0 1711 }
michael@0 1712
michael@0 1713 bool gotDHMACParameters = false;
michael@0 1714
michael@0 1715 if (isECKeyGenType(keyInfo->keyGenType) &&
michael@0 1716 keyInfo->ecPopCert &&
michael@0 1717 keyInfo->ecPopPubKey)
michael@0 1718 {
michael@0 1719 gotDHMACParameters = true;
michael@0 1720 }
michael@0 1721
michael@0 1722 if (isEncryptionOnlyCertRequest)
michael@0 1723 {
michael@0 1724 if (escrowEncryptionOnlyCert)
michael@0 1725 return nsSetKeyEnciphermentPOP(certReqMsg, true); // escrowed
michael@0 1726
michael@0 1727 if (gotDHMACParameters)
michael@0 1728 return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
michael@0 1729
michael@0 1730 return nsSetKeyEnciphermentPOP(certReqMsg, false); // not escrowed
michael@0 1731 }
michael@0 1732
michael@0 1733 // !isEncryptionOnlyCertRequest
michael@0 1734
michael@0 1735 SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
michael@0 1736 keyInfo->privKey,
michael@0 1737 keyInfo->pubKey, nullptr,
michael@0 1738 nullptr, nullptr);
michael@0 1739
michael@0 1740 if (srv == SECSuccess)
michael@0 1741 return NS_OK;
michael@0 1742
michael@0 1743 if (!gotDHMACParameters)
michael@0 1744 return NS_ERROR_FAILURE;
michael@0 1745
michael@0 1746 return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
michael@0 1747 }
michael@0 1748
michael@0 1749 static void
michael@0 1750 nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len)
michael@0 1751 {
michael@0 1752 unsigned long *count = (unsigned long *)arg;
michael@0 1753 *count += len;
michael@0 1754 }
michael@0 1755
michael@0 1756 static void
michael@0 1757 nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len)
michael@0 1758 {
michael@0 1759 SECItem *dest = (SECItem *)arg;
michael@0 1760 memcpy(dest->data + dest->len, buf, len);
michael@0 1761 dest->len += len;
michael@0 1762 }
michael@0 1763
michael@0 1764 static SECItem*
michael@0 1765 nsEncodeCertReqMessages(CRMFCertReqMsg **certReqMsgs)
michael@0 1766 {
michael@0 1767 unsigned long len = 0;
michael@0 1768 if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemCount, &len)
michael@0 1769 != SECSuccess) {
michael@0 1770 return nullptr;
michael@0 1771 }
michael@0 1772 SECItem *dest = (SECItem *)PORT_Alloc(sizeof(SECItem));
michael@0 1773 if (!dest) {
michael@0 1774 return nullptr;
michael@0 1775 }
michael@0 1776 dest->type = siBuffer;
michael@0 1777 dest->data = (unsigned char *)PORT_Alloc(len);
michael@0 1778 if (!dest->data) {
michael@0 1779 PORT_Free(dest);
michael@0 1780 return nullptr;
michael@0 1781 }
michael@0 1782 dest->len = 0;
michael@0 1783
michael@0 1784 if (CRMF_EncodeCertReqMessages(certReqMsgs, nsCRMFEncoderItemStore, dest)
michael@0 1785 != SECSuccess) {
michael@0 1786 SECITEM_FreeItem(dest, true);
michael@0 1787 return nullptr;
michael@0 1788 }
michael@0 1789 return dest;
michael@0 1790 }
michael@0 1791
michael@0 1792 //Create a Base64 encoded CRMFCertReqMsg that can be sent to a CA
michael@0 1793 //requesting one or more certificates to be issued. This function
michael@0 1794 //creates a single cert request per key pair and then appends it to
michael@0 1795 //a message that is ultimately sent off to a CA.
michael@0 1796 static char*
michael@0 1797 nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, int32_t numRequests,
michael@0 1798 char *reqDN, char *regToken, char *authenticator,
michael@0 1799 nsNSSCertificate *wrappingCert)
michael@0 1800 {
michael@0 1801 // We'use the goto notation for clean-up purposes in this function
michael@0 1802 // that calls the C API of NSS.
michael@0 1803 int32_t i;
michael@0 1804 // The ASN1 encoder in NSS wants the last entry in the array to be
michael@0 1805 // nullptr so that it knows when the last element is.
michael@0 1806 CRMFCertReqMsg **certReqMsgs = new CRMFCertReqMsg*[numRequests+1];
michael@0 1807 CRMFCertRequest *certReq;
michael@0 1808 if (!certReqMsgs)
michael@0 1809 return nullptr;
michael@0 1810 memset(certReqMsgs, 0, sizeof(CRMFCertReqMsg*)*(1+numRequests));
michael@0 1811 SECStatus srv;
michael@0 1812 nsresult rv;
michael@0 1813 SECItem *encodedReq;
michael@0 1814 char *retString;
michael@0 1815 for (i=0; i<numRequests; i++) {
michael@0 1816 certReq = nsCreateSingleCertReq(&keyids[i], reqDN, regToken, authenticator,
michael@0 1817 wrappingCert);
michael@0 1818 if (!certReq)
michael@0 1819 goto loser;
michael@0 1820
michael@0 1821 certReqMsgs[i] = CRMF_CreateCertReqMsg();
michael@0 1822 if (!certReqMsgs[i])
michael@0 1823 goto loser;
michael@0 1824 srv = CRMF_CertReqMsgSetCertRequest(certReqMsgs[i], certReq);
michael@0 1825 if (srv != SECSuccess)
michael@0 1826 goto loser;
michael@0 1827
michael@0 1828 rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
michael@0 1829 if (NS_FAILED(rv))
michael@0 1830 goto loser;
michael@0 1831 CRMF_DestroyCertRequest(certReq);
michael@0 1832 }
michael@0 1833 encodedReq = nsEncodeCertReqMessages(certReqMsgs);
michael@0 1834 nsFreeCertReqMessages(certReqMsgs, numRequests);
michael@0 1835
michael@0 1836 retString = NSSBase64_EncodeItem (nullptr, nullptr, 0, encodedReq);
michael@0 1837 SECITEM_FreeItem(encodedReq, true);
michael@0 1838 return retString;
michael@0 1839 loser:
michael@0 1840 nsFreeCertReqMessages(certReqMsgs,numRequests);
michael@0 1841 return nullptr;
michael@0 1842 }
michael@0 1843
michael@0 1844 static nsISupports *
michael@0 1845 GetISupportsFromContext(JSContext *cx)
michael@0 1846 {
michael@0 1847 if (JS::ContextOptionsRef(cx).privateIsNSISupports())
michael@0 1848 return static_cast<nsISupports *>(JS_GetContextPrivate(cx));
michael@0 1849
michael@0 1850 return nullptr;
michael@0 1851 }
michael@0 1852
michael@0 1853 //The top level method which is a member of nsIDOMCrypto
michael@0 1854 //for generate a base64 encoded CRMF request.
michael@0 1855 CRMFObject*
michael@0 1856 nsCrypto::GenerateCRMFRequest(JSContext* aContext,
michael@0 1857 const nsCString& aReqDN,
michael@0 1858 const nsCString& aRegToken,
michael@0 1859 const nsCString& aAuthenticator,
michael@0 1860 const nsCString& aEaCert,
michael@0 1861 const nsCString& aJsCallback,
michael@0 1862 const Sequence<JS::Value>& aArgs,
michael@0 1863 ErrorResult& aRv)
michael@0 1864 {
michael@0 1865 nsNSSShutDownPreventionLock locker;
michael@0 1866 nsresult nrv;
michael@0 1867
michael@0 1868 uint32_t argc = aArgs.Length();
michael@0 1869
michael@0 1870 /*
michael@0 1871 * Get all of the parameters.
michael@0 1872 */
michael@0 1873 if (argc % 3 != 0) {
michael@0 1874 aRv.ThrowNotEnoughArgsError();
michael@0 1875 return nullptr;
michael@0 1876 }
michael@0 1877
michael@0 1878 if (aReqDN.IsVoid()) {
michael@0 1879 NS_WARNING("no DN specified");
michael@0 1880 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1881 return nullptr;
michael@0 1882 }
michael@0 1883
michael@0 1884 if (aJsCallback.IsVoid()) {
michael@0 1885 NS_WARNING("no completion function specified");
michael@0 1886 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1887 return nullptr;
michael@0 1888 }
michael@0 1889
michael@0 1890 JS::RootedObject script_obj(aContext, GetWrapper());
michael@0 1891 if (MOZ_UNLIKELY(!script_obj)) {
michael@0 1892 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 1893 return nullptr;
michael@0 1894 }
michael@0 1895
michael@0 1896 nsCOMPtr<nsIContentSecurityPolicy> csp;
michael@0 1897 if (!nsContentUtils::GetContentSecurityPolicy(aContext, getter_AddRefs(csp))) {
michael@0 1898 NS_ERROR("Error: failed to get CSP");
michael@0 1899 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1900 return nullptr;
michael@0 1901 }
michael@0 1902
michael@0 1903 bool evalAllowed = true;
michael@0 1904 bool reportEvalViolations = false;
michael@0 1905 if (csp && NS_FAILED(csp->GetAllowsEval(&reportEvalViolations, &evalAllowed))) {
michael@0 1906 NS_WARNING("CSP: failed to get allowsEval");
michael@0 1907 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1908 return nullptr;
michael@0 1909 }
michael@0 1910
michael@0 1911 if (reportEvalViolations) {
michael@0 1912 NS_NAMED_LITERAL_STRING(scriptSample, "window.crypto.generateCRMFRequest: call to eval() or related function blocked by CSP");
michael@0 1913
michael@0 1914 const char *fileName;
michael@0 1915 uint32_t lineNum;
michael@0 1916 nsJSUtils::GetCallingLocation(aContext, &fileName, &lineNum);
michael@0 1917 csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
michael@0 1918 NS_ConvertASCIItoUTF16(fileName),
michael@0 1919 scriptSample,
michael@0 1920 lineNum,
michael@0 1921 EmptyString(),
michael@0 1922 EmptyString());
michael@0 1923 }
michael@0 1924
michael@0 1925 if (!evalAllowed) {
michael@0 1926 NS_WARNING("eval() not allowed by Content Security Policy");
michael@0 1927 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1928 return nullptr;
michael@0 1929 }
michael@0 1930
michael@0 1931 //Put up some UI warning that someone is trying to
michael@0 1932 //escrow the private key.
michael@0 1933 //Don't addref this copy. That way ths reference goes away
michael@0 1934 //at the same the nsIX09Cert ref goes away.
michael@0 1935 nsNSSCertificate *escrowCert = nullptr;
michael@0 1936 nsCOMPtr<nsIX509Cert> nssCert;
michael@0 1937 bool willEscrow = false;
michael@0 1938 if (!aEaCert.IsVoid()) {
michael@0 1939 SECItem certDer = {siBuffer, nullptr, 0};
michael@0 1940 SECStatus srv = ATOB_ConvertAsciiToItem(&certDer, aEaCert.get());
michael@0 1941 if (srv != SECSuccess) {
michael@0 1942 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1943 return nullptr;
michael@0 1944 }
michael@0 1945 mozilla::pkix::ScopedCERTCertificate cert(
michael@0 1946 CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
michael@0 1947 &certDer, nullptr, false, true));
michael@0 1948 if (!cert) {
michael@0 1949 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1950 return nullptr;
michael@0 1951 }
michael@0 1952
michael@0 1953 escrowCert = nsNSSCertificate::Create(cert.get());
michael@0 1954 nssCert = escrowCert;
michael@0 1955 if (!nssCert) {
michael@0 1956 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
michael@0 1957 return nullptr;
michael@0 1958 }
michael@0 1959
michael@0 1960 nsCOMPtr<nsIDOMCryptoDialogs> dialogs;
michael@0 1961 nsresult rv = getNSSDialogs(getter_AddRefs(dialogs),
michael@0 1962 NS_GET_IID(nsIDOMCryptoDialogs),
michael@0 1963 NS_DOMCRYPTODIALOGS_CONTRACTID);
michael@0 1964 if (NS_FAILED(rv)) {
michael@0 1965 aRv.Throw(rv);
michael@0 1966 return nullptr;
michael@0 1967 }
michael@0 1968
michael@0 1969 bool okay=false;
michael@0 1970 {
michael@0 1971 nsPSMUITracker tracker;
michael@0 1972 if (tracker.isUIForbidden()) {
michael@0 1973 okay = false;
michael@0 1974 }
michael@0 1975 else {
michael@0 1976 dialogs->ConfirmKeyEscrow(nssCert, &okay);
michael@0 1977 }
michael@0 1978 }
michael@0 1979 if (!okay) {
michael@0 1980 aRv.Throw(NS_ERROR_FAILURE);
michael@0 1981 return nullptr;
michael@0 1982 }
michael@0 1983 willEscrow = true;
michael@0 1984 }
michael@0 1985 nsCOMPtr<nsIInterfaceRequestor> uiCxt = new PipUIContext;
michael@0 1986 int32_t numRequests = argc / 3;
michael@0 1987 nsKeyPairInfo *keyids = new nsKeyPairInfo[numRequests];
michael@0 1988 memset(keyids, 0, sizeof(nsKeyPairInfo)*numRequests);
michael@0 1989 int keyInfoIndex;
michael@0 1990 uint32_t i;
michael@0 1991 PK11SlotInfo *slot = nullptr;
michael@0 1992 // Go through all of the arguments and generate the appropriate key pairs.
michael@0 1993 for (i=0,keyInfoIndex=0; i<argc; i+=3,keyInfoIndex++) {
michael@0 1994 nrv = cryptojs_ReadArgsAndGenerateKey(aContext,
michael@0 1995 const_cast<JS::Value*>(&aArgs[i]),
michael@0 1996 &keyids[keyInfoIndex],
michael@0 1997 uiCxt, &slot, willEscrow);
michael@0 1998
michael@0 1999 if (NS_FAILED(nrv)) {
michael@0 2000 if (slot)
michael@0 2001 PK11_FreeSlot(slot);
michael@0 2002 nsFreeKeyPairInfo(keyids,numRequests);
michael@0 2003 aRv.Throw(nrv);
michael@0 2004 return nullptr;
michael@0 2005 }
michael@0 2006 }
michael@0 2007 // By this time we'd better have a slot for the key gen.
michael@0 2008 NS_ASSERTION(slot, "There was no slot selected for key generation");
michael@0 2009 if (slot)
michael@0 2010 PK11_FreeSlot(slot);
michael@0 2011
michael@0 2012 char *encodedRequest = nsCreateReqFromKeyPairs(keyids,numRequests,
michael@0 2013 const_cast<char*>(aReqDN.get()),
michael@0 2014 const_cast<char*>(aRegToken.get()),
michael@0 2015 const_cast<char*>(aAuthenticator.get()),
michael@0 2016 escrowCert);
michael@0 2017 #ifdef DEBUG_javi
michael@0 2018 printf ("Created the folloing CRMF request:\n%s\n", encodedRequest);
michael@0 2019 #endif
michael@0 2020 if (!encodedRequest) {
michael@0 2021 nsFreeKeyPairInfo(keyids, numRequests);
michael@0 2022 aRv.Throw(NS_ERROR_FAILURE);
michael@0 2023 return nullptr;
michael@0 2024 }
michael@0 2025 CRMFObject* newObject = new CRMFObject();
michael@0 2026 newObject->SetCRMFRequest(encodedRequest);
michael@0 2027 PORT_Free(encodedRequest);
michael@0 2028 nsFreeKeyPairInfo(keyids, numRequests);
michael@0 2029
michael@0 2030 // Post an event on the UI queue so that the JS gets called after
michael@0 2031 // we return control to the JS layer. Why do we have to this?
michael@0 2032 // Because when this API was implemented for PSM 1.x w/ Communicator,
michael@0 2033 // the only way to make this method work was to have a callback
michael@0 2034 // in the JS layer that got called after key generation had happened.
michael@0 2035 // So for backwards compatibility, we return control and then just post
michael@0 2036 // an event to call the JS the script provides as the code to execute
michael@0 2037 // when the request has been generated.
michael@0 2038 //
michael@0 2039
michael@0 2040 nsCOMPtr<nsIScriptSecurityManager> secMan =
michael@0 2041 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
michael@0 2042 if (MOZ_UNLIKELY(!secMan)) {
michael@0 2043 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 2044 return nullptr;
michael@0 2045 }
michael@0 2046
michael@0 2047 nsCOMPtr<nsIPrincipal> principals;
michael@0 2048 nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(principals));
michael@0 2049 if (NS_FAILED(nrv)) {
michael@0 2050 aRv.Throw(nrv);
michael@0 2051 return nullptr;
michael@0 2052 }
michael@0 2053 if (MOZ_UNLIKELY(!principals)) {
michael@0 2054 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 2055 return nullptr;
michael@0 2056 }
michael@0 2057
michael@0 2058 nsCryptoRunArgs *args = new nsCryptoRunArgs(aContext);
michael@0 2059
michael@0 2060 args->m_kungFuDeathGrip = GetISupportsFromContext(aContext);
michael@0 2061 args->m_scope = JS_GetParent(script_obj);
michael@0 2062 if (!aJsCallback.IsVoid()) {
michael@0 2063 args->m_jsCallback = aJsCallback;
michael@0 2064 }
michael@0 2065 args->m_principals = principals;
michael@0 2066
michael@0 2067 nsCryptoRunnable *cryptoRunnable = new nsCryptoRunnable(args);
michael@0 2068
michael@0 2069 rv = NS_DispatchToMainThread(cryptoRunnable);
michael@0 2070 if (NS_FAILED(rv)) {
michael@0 2071 aRv.Throw(rv);
michael@0 2072 delete cryptoRunnable;
michael@0 2073 }
michael@0 2074
michael@0 2075 return newObject;
michael@0 2076 }
michael@0 2077
michael@0 2078 // Reminder that we inherit the memory passed into us here.
michael@0 2079 // An implementation to let us back up certs as an event.
michael@0 2080 nsP12Runnable::nsP12Runnable(nsIX509Cert **certArr, int32_t numCerts,
michael@0 2081 nsIPK11Token *token)
michael@0 2082 {
michael@0 2083 mCertArr = certArr;
michael@0 2084 mNumCerts = numCerts;
michael@0 2085 mToken = token;
michael@0 2086 }
michael@0 2087
michael@0 2088 nsP12Runnable::~nsP12Runnable()
michael@0 2089 {
michael@0 2090 int32_t i;
michael@0 2091 for (i=0; i<mNumCerts; i++) {
michael@0 2092 NS_IF_RELEASE(mCertArr[i]);
michael@0 2093 }
michael@0 2094 delete []mCertArr;
michael@0 2095 }
michael@0 2096
michael@0 2097
michael@0 2098 //Implementation that backs cert(s) into a PKCS12 file
michael@0 2099 NS_IMETHODIMP
michael@0 2100 nsP12Runnable::Run()
michael@0 2101 {
michael@0 2102 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
michael@0 2103
michael@0 2104 NS_ASSERTION(NS_IsMainThread(), "nsP12Runnable dispatched to the wrong thread");
michael@0 2105
michael@0 2106 nsNSSShutDownPreventionLock locker;
michael@0 2107 NS_ASSERTION(mCertArr, "certArr is NULL while trying to back up");
michael@0 2108
michael@0 2109 nsString final;
michael@0 2110 nsString temp;
michael@0 2111 nsresult rv;
michael@0 2112
michael@0 2113 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
michael@0 2114 if (NS_FAILED(rv))
michael@0 2115 return rv;
michael@0 2116
michael@0 2117 //Build up the message that let's the user know we're trying to
michael@0 2118 //make PKCS12 backups of the new certs.
michael@0 2119 nssComponent->GetPIPNSSBundleString("ForcedBackup1", final);
michael@0 2120 final.Append(MOZ_UTF16("\n\n"));
michael@0 2121 nssComponent->GetPIPNSSBundleString("ForcedBackup2", temp);
michael@0 2122 final.Append(temp.get());
michael@0 2123 final.Append(MOZ_UTF16("\n\n"));
michael@0 2124
michael@0 2125 nssComponent->GetPIPNSSBundleString("ForcedBackup3", temp);
michael@0 2126
michael@0 2127 final.Append(temp.get());
michael@0 2128 nsNSSComponent::ShowAlertWithConstructedString(final);
michael@0 2129
michael@0 2130 nsCOMPtr<nsIFilePicker> filePicker =
michael@0 2131 do_CreateInstance("@mozilla.org/filepicker;1", &rv);
michael@0 2132 if (!filePicker) {
michael@0 2133 NS_ERROR("Could not create a file picker when backing up certs.");
michael@0 2134 return rv;
michael@0 2135 }
michael@0 2136
michael@0 2137 nsCOMPtr<nsIWindowWatcher> wwatch =
michael@0 2138 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
michael@0 2139 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2140
michael@0 2141 nsCOMPtr<nsIDOMWindow> window;
michael@0 2142 wwatch->GetActiveWindow(getter_AddRefs(window));
michael@0 2143
michael@0 2144 nsString filePickMessage;
michael@0 2145 nssComponent->GetPIPNSSBundleString("chooseP12BackupFileDialog",
michael@0 2146 filePickMessage);
michael@0 2147 rv = filePicker->Init(window, filePickMessage, nsIFilePicker::modeSave);
michael@0 2148 NS_ENSURE_SUCCESS(rv, rv);
michael@0 2149
michael@0 2150 filePicker->AppendFilter(NS_LITERAL_STRING("PKCS12"),
michael@0 2151 NS_LITERAL_STRING("*.p12"));
michael@0 2152 filePicker->AppendFilters(nsIFilePicker::filterAll);
michael@0 2153
michael@0 2154 int16_t dialogReturn;
michael@0 2155 filePicker->Show(&dialogReturn);
michael@0 2156 if (dialogReturn == nsIFilePicker::returnCancel)
michael@0 2157 return NS_OK; //User canceled. It'd be nice if they couldn't,
michael@0 2158 //but oh well.
michael@0 2159
michael@0 2160 nsCOMPtr<nsIFile> localFile;
michael@0 2161 rv = filePicker->GetFile(getter_AddRefs(localFile));
michael@0 2162 if (NS_FAILED(rv))
michael@0 2163 return NS_ERROR_FAILURE;
michael@0 2164
michael@0 2165 nsPKCS12Blob p12Cxt;
michael@0 2166
michael@0 2167 p12Cxt.SetToken(mToken);
michael@0 2168 p12Cxt.ExportToFile(localFile, mCertArr, mNumCerts);
michael@0 2169 return NS_OK;
michael@0 2170 }
michael@0 2171
michael@0 2172 nsCryptoRunArgs::nsCryptoRunArgs(JSContext *cx) : m_cx(cx), m_scope(cx) {}
michael@0 2173
michael@0 2174 nsCryptoRunArgs::~nsCryptoRunArgs() {}
michael@0 2175
michael@0 2176 nsCryptoRunnable::nsCryptoRunnable(nsCryptoRunArgs *args)
michael@0 2177 {
michael@0 2178 nsNSSShutDownPreventionLock locker;
michael@0 2179 NS_ASSERTION(args,"Passed nullptr to nsCryptoRunnable constructor.");
michael@0 2180 m_args = args;
michael@0 2181 NS_IF_ADDREF(m_args);
michael@0 2182 }
michael@0 2183
michael@0 2184 nsCryptoRunnable::~nsCryptoRunnable()
michael@0 2185 {
michael@0 2186 nsNSSShutDownPreventionLock locker;
michael@0 2187 NS_IF_RELEASE(m_args);
michael@0 2188 }
michael@0 2189
michael@0 2190 //Implementation that runs the callback passed to
michael@0 2191 //crypto.generateCRMFRequest as an event.
michael@0 2192 NS_IMETHODIMP
michael@0 2193 nsCryptoRunnable::Run()
michael@0 2194 {
michael@0 2195 nsNSSShutDownPreventionLock locker;
michael@0 2196 AutoPushJSContext cx(m_args->m_cx);
michael@0 2197 JSAutoRequest ar(cx);
michael@0 2198 JS::Rooted<JSObject*> scope(cx, m_args->m_scope);
michael@0 2199 JSAutoCompartment ac(cx, scope);
michael@0 2200
michael@0 2201 bool ok =
michael@0 2202 JS_EvaluateScript(cx, scope, m_args->m_jsCallback,
michael@0 2203 strlen(m_args->m_jsCallback), nullptr, 0);
michael@0 2204 return ok ? NS_OK : NS_ERROR_FAILURE;
michael@0 2205 }
michael@0 2206
michael@0 2207 //Quick helper function to check if a newly issued cert
michael@0 2208 //already exists in the user's database.
michael@0 2209 static bool
michael@0 2210 nsCertAlreadyExists(SECItem *derCert)
michael@0 2211 {
michael@0 2212 CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
michael@0 2213 bool retVal = false;
michael@0 2214
michael@0 2215 mozilla::pkix::ScopedCERTCertificate cert(
michael@0 2216 CERT_FindCertByDERCert(handle, derCert));
michael@0 2217 if (cert) {
michael@0 2218 if (cert->isperm && !cert->nickname && !cert->emailAddr) {
michael@0 2219 //If the cert doesn't have a nickname or email addr, it is
michael@0 2220 //bogus cruft, so delete it.
michael@0 2221 SEC_DeletePermCertificate(cert.get());
michael@0 2222 } else if (cert->isperm) {
michael@0 2223 retVal = true;
michael@0 2224 }
michael@0 2225 }
michael@0 2226 return retVal;
michael@0 2227 }
michael@0 2228
michael@0 2229 static int32_t
michael@0 2230 nsCertListCount(CERTCertList *certList)
michael@0 2231 {
michael@0 2232 int32_t numCerts = 0;
michael@0 2233 CERTCertListNode *node;
michael@0 2234
michael@0 2235 node = CERT_LIST_HEAD(certList);
michael@0 2236 while (!CERT_LIST_END(node, certList)) {
michael@0 2237 numCerts++;
michael@0 2238 node = CERT_LIST_NEXT(node);
michael@0 2239 }
michael@0 2240 return numCerts;
michael@0 2241 }
michael@0 2242
michael@0 2243 //Import user certificates that arrive as a CMMF base64 encoded
michael@0 2244 //string.
michael@0 2245 void
michael@0 2246 nsCrypto::ImportUserCertificates(const nsAString& aNickname,
michael@0 2247 const nsAString& aCmmfResponse,
michael@0 2248 bool aDoForcedBackup,
michael@0 2249 nsAString& aReturn,
michael@0 2250 ErrorResult& aRv)
michael@0 2251 {
michael@0 2252 nsNSSShutDownPreventionLock locker;
michael@0 2253 char *nickname=nullptr, *cmmfResponse=nullptr;
michael@0 2254 CMMFCertRepContent *certRepContent = nullptr;
michael@0 2255 int numResponses = 0;
michael@0 2256 nsIX509Cert **certArr = nullptr;
michael@0 2257 int i;
michael@0 2258 CMMFCertResponse *currResponse;
michael@0 2259 CMMFPKIStatus reqStatus;
michael@0 2260 CERTCertificate *currCert;
michael@0 2261 PK11SlotInfo *slot;
michael@0 2262 nsAutoCString localNick;
michael@0 2263 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
michael@0 2264 nsresult rv = NS_OK;
michael@0 2265 nsCOMPtr<nsIPK11Token> token;
michael@0 2266
michael@0 2267 nickname = ToNewCString(aNickname);
michael@0 2268 cmmfResponse = ToNewCString(aCmmfResponse);
michael@0 2269 if (nsCRT::strcmp("null", nickname) == 0) {
michael@0 2270 nsMemory::Free(nickname);
michael@0 2271 nickname = nullptr;
michael@0 2272 }
michael@0 2273
michael@0 2274 SECItem cmmfDer = {siBuffer, nullptr, 0};
michael@0 2275 SECStatus srv = ATOB_ConvertAsciiToItem(&cmmfDer, cmmfResponse);
michael@0 2276
michael@0 2277 if (srv != SECSuccess) {
michael@0 2278 rv = NS_ERROR_FAILURE;
michael@0 2279 goto loser;
michael@0 2280 }
michael@0 2281
michael@0 2282 certRepContent = CMMF_CreateCertRepContentFromDER(CERT_GetDefaultCertDB(),
michael@0 2283 (const char*)cmmfDer.data,
michael@0 2284 cmmfDer.len);
michael@0 2285 if (!certRepContent) {
michael@0 2286 rv = NS_ERROR_FAILURE;
michael@0 2287 goto loser;
michael@0 2288 }
michael@0 2289
michael@0 2290 numResponses = CMMF_CertRepContentGetNumResponses(certRepContent);
michael@0 2291
michael@0 2292 if (aDoForcedBackup) {
michael@0 2293 //We've been asked to force the user to back up these
michael@0 2294 //certificates. Let's keep an array of them around which
michael@0 2295 //we pass along to the nsP12Runnable to use.
michael@0 2296 certArr = new nsIX509Cert*[numResponses];
michael@0 2297 // If this is nullptr, chances are we're gonna fail really
michael@0 2298 // soon, but let's try to keep going just in case.
michael@0 2299 if (!certArr)
michael@0 2300 aDoForcedBackup = false;
michael@0 2301
michael@0 2302 memset(certArr, 0, sizeof(nsIX509Cert*)*numResponses);
michael@0 2303 }
michael@0 2304 for (i=0; i<numResponses; i++) {
michael@0 2305 currResponse = CMMF_CertRepContentGetResponseAtIndex(certRepContent,i);
michael@0 2306 if (!currResponse) {
michael@0 2307 rv = NS_ERROR_FAILURE;
michael@0 2308 goto loser;
michael@0 2309 }
michael@0 2310 reqStatus = CMMF_CertResponseGetPKIStatusInfoStatus(currResponse);
michael@0 2311 if (!(reqStatus == cmmfGranted || reqStatus == cmmfGrantedWithMods)) {
michael@0 2312 // The CA didn't give us the cert we requested.
michael@0 2313 rv = NS_ERROR_FAILURE;
michael@0 2314 goto loser;
michael@0 2315 }
michael@0 2316 currCert = CMMF_CertResponseGetCertificate(currResponse,
michael@0 2317 CERT_GetDefaultCertDB());
michael@0 2318 if (!currCert) {
michael@0 2319 rv = NS_ERROR_FAILURE;
michael@0 2320 goto loser;
michael@0 2321 }
michael@0 2322
michael@0 2323 if (nsCertAlreadyExists(&currCert->derCert)) {
michael@0 2324 if (aDoForcedBackup) {
michael@0 2325 certArr[i] = nsNSSCertificate::Create(currCert);
michael@0 2326 if (!certArr[i])
michael@0 2327 goto loser;
michael@0 2328 NS_ADDREF(certArr[i]);
michael@0 2329 }
michael@0 2330 CERT_DestroyCertificate(currCert);
michael@0 2331 CMMF_DestroyCertResponse(currResponse);
michael@0 2332 continue;
michael@0 2333 }
michael@0 2334 // Let's figure out which nickname to give the cert. If
michael@0 2335 // a certificate with the same subject name already exists,
michael@0 2336 // then just use that one, otherwise, get the default nickname.
michael@0 2337 if (currCert->nickname) {
michael@0 2338 localNick = currCert->nickname;
michael@0 2339 }
michael@0 2340 else if (!nickname || nickname[0] == '\0') {
michael@0 2341 nsNSSCertificateDB::get_default_nickname(currCert, ctx, localNick, locker);
michael@0 2342 } else {
michael@0 2343 //This is the case where we're getting a brand new
michael@0 2344 //cert that doesn't have the same subjectName as a cert
michael@0 2345 //that already exists in our db and the CA page has
michael@0 2346 //designated a nickname to use for the newly issued cert.
michael@0 2347 localNick = nickname;
michael@0 2348 }
michael@0 2349 {
michael@0 2350 char *cast_const_away = const_cast<char*>(localNick.get());
michael@0 2351 slot = PK11_ImportCertForKey(currCert, cast_const_away, ctx);
michael@0 2352 }
michael@0 2353 if (!slot) {
michael@0 2354 rv = NS_ERROR_FAILURE;
michael@0 2355 goto loser;
michael@0 2356 }
michael@0 2357 if (aDoForcedBackup) {
michael@0 2358 certArr[i] = nsNSSCertificate::Create(currCert);
michael@0 2359 if (!certArr[i])
michael@0 2360 goto loser;
michael@0 2361 NS_ADDREF(certArr[i]);
michael@0 2362 }
michael@0 2363 CERT_DestroyCertificate(currCert);
michael@0 2364
michael@0 2365 if (!token)
michael@0 2366 token = new nsPK11Token(slot);
michael@0 2367
michael@0 2368 PK11_FreeSlot(slot);
michael@0 2369 CMMF_DestroyCertResponse(currResponse);
michael@0 2370 }
michael@0 2371 //Let the loser: label take care of freeing up our reference to
michael@0 2372 //nickname (This way we don't free it twice and avoid crashing.
michael@0 2373 //That would be a good thing.
michael@0 2374
michael@0 2375 //Import the root chain into the cert db.
michael@0 2376 {
michael@0 2377 mozilla::pkix::ScopedCERTCertList
michael@0 2378 caPubs(CMMF_CertRepContentGetCAPubs(certRepContent));
michael@0 2379 if (caPubs) {
michael@0 2380 int32_t numCAs = nsCertListCount(caPubs.get());
michael@0 2381
michael@0 2382 NS_ASSERTION(numCAs > 0, "Invalid number of CA's");
michael@0 2383 if (numCAs > 0) {
michael@0 2384 CERTCertListNode *node;
michael@0 2385 SECItem *derCerts;
michael@0 2386
michael@0 2387 derCerts = static_cast<SECItem*>
michael@0 2388 (nsMemory::Alloc(sizeof(SECItem)*numCAs));
michael@0 2389 if (!derCerts) {
michael@0 2390 rv = NS_ERROR_OUT_OF_MEMORY;
michael@0 2391 goto loser;
michael@0 2392 }
michael@0 2393 for (node = CERT_LIST_HEAD(caPubs), i=0;
michael@0 2394 !CERT_LIST_END(node, caPubs);
michael@0 2395 node = CERT_LIST_NEXT(node), i++) {
michael@0 2396 derCerts[i] = node->cert->derCert;
michael@0 2397 }
michael@0 2398 nsNSSCertificateDB::ImportValidCACerts(numCAs, derCerts, ctx, locker);
michael@0 2399 nsMemory::Free(derCerts);
michael@0 2400 }
michael@0 2401 }
michael@0 2402 }
michael@0 2403
michael@0 2404 if (aDoForcedBackup) {
michael@0 2405 // I can't pop up a file picker from the depths of JavaScript,
michael@0 2406 // so I'll just post an event on the UI queue to do the backups
michael@0 2407 // later.
michael@0 2408 nsCOMPtr<nsIRunnable> p12Runnable = new nsP12Runnable(certArr, numResponses,
michael@0 2409 token);
michael@0 2410 if (!p12Runnable) {
michael@0 2411 rv = NS_ERROR_FAILURE;
michael@0 2412 goto loser;
michael@0 2413 }
michael@0 2414
michael@0 2415 // null out the certArr pointer which has now been inherited by
michael@0 2416 // the nsP12Runnable instance so that we don't free up the
michael@0 2417 // memory on the way out.
michael@0 2418 certArr = nullptr;
michael@0 2419
michael@0 2420 rv = NS_DispatchToMainThread(p12Runnable);
michael@0 2421 if (NS_FAILED(rv))
michael@0 2422 goto loser;
michael@0 2423 }
michael@0 2424
michael@0 2425 loser:
michael@0 2426 if (certArr) {
michael@0 2427 for (i=0; i<numResponses; i++) {
michael@0 2428 NS_IF_RELEASE(certArr[i]);
michael@0 2429 }
michael@0 2430 delete []certArr;
michael@0 2431 }
michael@0 2432 aReturn.Assign(EmptyString());
michael@0 2433 if (nickname) {
michael@0 2434 NS_Free(nickname);
michael@0 2435 }
michael@0 2436 if (cmmfResponse) {
michael@0 2437 NS_Free(cmmfResponse);
michael@0 2438 }
michael@0 2439 if (certRepContent) {
michael@0 2440 CMMF_DestroyCertRepContent(certRepContent);
michael@0 2441 }
michael@0 2442
michael@0 2443 if (NS_FAILED(rv)) {
michael@0 2444 aRv.Throw(rv);
michael@0 2445 }
michael@0 2446 }
michael@0 2447
michael@0 2448 static void
michael@0 2449 GetDocumentFromContext(JSContext *cx, nsIDocument **aDocument)
michael@0 2450 {
michael@0 2451 // Get the script context.
michael@0 2452 nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
michael@0 2453 if (!scriptContext) {
michael@0 2454 return;
michael@0 2455 }
michael@0 2456
michael@0 2457 nsCOMPtr<nsIDOMWindow> domWindow =
michael@0 2458 do_QueryInterface(scriptContext->GetGlobalObject());
michael@0 2459 if (!domWindow) {
michael@0 2460 return;
michael@0 2461 }
michael@0 2462
michael@0 2463 nsCOMPtr<nsIDOMDocument> domDocument;
michael@0 2464 domWindow->GetDocument(getter_AddRefs(domDocument));
michael@0 2465 if (!domDocument) {
michael@0 2466 return;
michael@0 2467 }
michael@0 2468
michael@0 2469 CallQueryInterface(domDocument, aDocument);
michael@0 2470
michael@0 2471 return;
michael@0 2472 }
michael@0 2473
michael@0 2474 void signTextOutputCallback(void *arg, const char *buf, unsigned long len)
michael@0 2475 {
michael@0 2476 ((nsCString*)arg)->Append(buf, len);
michael@0 2477 }
michael@0 2478
michael@0 2479 void
michael@0 2480 nsCrypto::SignText(JSContext* aContext,
michael@0 2481 const nsAString& aStringToSign,
michael@0 2482 const nsAString& aCaOption,
michael@0 2483 const Sequence<nsCString>& aArgs,
michael@0 2484 nsAString& aReturn)
michael@0 2485 {
michael@0 2486 // XXX This code should return error codes, but we're keeping this
michael@0 2487 // backwards compatible with NS4.x and so we can't throw exceptions.
michael@0 2488 NS_NAMED_LITERAL_STRING(internalError, "error:internalError");
michael@0 2489
michael@0 2490 aReturn.Truncate();
michael@0 2491
michael@0 2492 uint32_t argc = aArgs.Length();
michael@0 2493
michael@0 2494 if (!aCaOption.EqualsLiteral("auto") &&
michael@0 2495 !aCaOption.EqualsLiteral("ask")) {
michael@0 2496 NS_WARNING("caOption argument must be ask or auto");
michael@0 2497 aReturn.Append(internalError);
michael@0 2498
michael@0 2499 return;
michael@0 2500 }
michael@0 2501
michael@0 2502 // It was decided to always behave as if "ask" were specified.
michael@0 2503 // XXX Should we warn in the JS Console for auto?
michael@0 2504
michael@0 2505 nsCOMPtr<nsIInterfaceRequestor> uiContext = new PipUIContext;
michael@0 2506 if (!uiContext) {
michael@0 2507 aReturn.Append(internalError);
michael@0 2508
michael@0 2509 return;
michael@0 2510 }
michael@0 2511
michael@0 2512 bool bestOnly = true;
michael@0 2513 bool validOnly = true;
michael@0 2514 CERTCertList* certList =
michael@0 2515 CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), certUsageEmailSigner,
michael@0 2516 bestOnly, validOnly, uiContext);
michael@0 2517
michael@0 2518 uint32_t numCAs = argc;
michael@0 2519 if (numCAs > 0) {
michael@0 2520 nsAutoArrayPtr<char*> caNames(new char*[numCAs]);
michael@0 2521 if (!caNames) {
michael@0 2522 aReturn.Append(internalError);
michael@0 2523 return;
michael@0 2524 }
michael@0 2525
michael@0 2526 uint32_t i;
michael@0 2527 for (i = 0; i < numCAs; ++i)
michael@0 2528 caNames[i] = const_cast<char*>(aArgs[i].get());
michael@0 2529
michael@0 2530 if (certList &&
michael@0 2531 CERT_FilterCertListByCANames(certList, numCAs, caNames,
michael@0 2532 certUsageEmailSigner) != SECSuccess) {
michael@0 2533 aReturn.Append(internalError);
michael@0 2534
michael@0 2535 return;
michael@0 2536 }
michael@0 2537 }
michael@0 2538
michael@0 2539 if (!certList || CERT_LIST_EMPTY(certList)) {
michael@0 2540 aReturn.AppendLiteral("error:noMatchingCert");
michael@0 2541
michael@0 2542 return;
michael@0 2543 }
michael@0 2544
michael@0 2545 nsCOMPtr<nsIFormSigningDialog> fsd =
michael@0 2546 do_CreateInstance(NS_FORMSIGNINGDIALOG_CONTRACTID);
michael@0 2547 if (!fsd) {
michael@0 2548 aReturn.Append(internalError);
michael@0 2549
michael@0 2550 return;
michael@0 2551 }
michael@0 2552
michael@0 2553 nsCOMPtr<nsIDocument> document;
michael@0 2554 GetDocumentFromContext(aContext, getter_AddRefs(document));
michael@0 2555 if (!document) {
michael@0 2556 aReturn.Append(internalError);
michael@0 2557
michael@0 2558 return;
michael@0 2559 }
michael@0 2560
michael@0 2561 // Get the hostname from the URL of the document.
michael@0 2562 nsIURI* uri = document->GetDocumentURI();
michael@0 2563 if (!uri) {
michael@0 2564 aReturn.Append(internalError);
michael@0 2565
michael@0 2566 return;
michael@0 2567 }
michael@0 2568
michael@0 2569 nsresult rv;
michael@0 2570
michael@0 2571 nsCString host;
michael@0 2572 rv = uri->GetHost(host);
michael@0 2573 if (NS_FAILED(rv)) {
michael@0 2574 aReturn.Append(internalError);
michael@0 2575
michael@0 2576 return;
michael@0 2577 }
michael@0 2578
michael@0 2579 int32_t numberOfCerts = 0;
michael@0 2580 CERTCertListNode* node;
michael@0 2581 for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
michael@0 2582 node = CERT_LIST_NEXT(node)) {
michael@0 2583 ++numberOfCerts;
michael@0 2584 }
michael@0 2585
michael@0 2586 ScopedCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList));
michael@0 2587
michael@0 2588 if (!nicknames) {
michael@0 2589 aReturn.Append(internalError);
michael@0 2590
michael@0 2591 return;
michael@0 2592 }
michael@0 2593
michael@0 2594 NS_ASSERTION(nicknames->numnicknames == numberOfCerts,
michael@0 2595 "nicknames->numnicknames != numberOfCerts");
michael@0 2596
michael@0 2597 nsAutoArrayPtr<char16_t*> certNicknameList(new char16_t*[nicknames->numnicknames * 2]);
michael@0 2598 if (!certNicknameList) {
michael@0 2599 aReturn.Append(internalError);
michael@0 2600
michael@0 2601 return;
michael@0 2602 }
michael@0 2603
michael@0 2604 char16_t** certDetailsList = certNicknameList.get() + nicknames->numnicknames;
michael@0 2605
michael@0 2606 int32_t certsToUse;
michael@0 2607 for (node = CERT_LIST_HEAD(certList), certsToUse = 0;
michael@0 2608 !CERT_LIST_END(node, certList) && certsToUse < nicknames->numnicknames;
michael@0 2609 node = CERT_LIST_NEXT(node)) {
michael@0 2610 RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
michael@0 2611 if (tempCert) {
michael@0 2612 nsAutoString nickWithSerial, details;
michael@0 2613 rv = tempCert->FormatUIStrings(NS_ConvertUTF8toUTF16(nicknames->nicknames[certsToUse]),
michael@0 2614 nickWithSerial, details);
michael@0 2615 if (NS_SUCCEEDED(rv)) {
michael@0 2616 certNicknameList[certsToUse] = ToNewUnicode(nickWithSerial);
michael@0 2617 if (certNicknameList[certsToUse]) {
michael@0 2618 certDetailsList[certsToUse] = ToNewUnicode(details);
michael@0 2619 if (!certDetailsList[certsToUse]) {
michael@0 2620 nsMemory::Free(certNicknameList[certsToUse]);
michael@0 2621 continue;
michael@0 2622 }
michael@0 2623 ++certsToUse;
michael@0 2624 }
michael@0 2625 }
michael@0 2626 }
michael@0 2627 }
michael@0 2628
michael@0 2629 if (certsToUse == 0) {
michael@0 2630 aReturn.Append(internalError);
michael@0 2631
michael@0 2632 return;
michael@0 2633 }
michael@0 2634
michael@0 2635 NS_ConvertUTF8toUTF16 utf16Host(host);
michael@0 2636
michael@0 2637 CERTCertificate *signingCert = nullptr;
michael@0 2638 bool tryAgain, canceled;
michael@0 2639 nsAutoString password;
michael@0 2640 do {
michael@0 2641 // Throw up the form signing confirmation dialog and get back the index
michael@0 2642 // of the selected cert.
michael@0 2643 int32_t selectedIndex = -1;
michael@0 2644 rv = fsd->ConfirmSignText(uiContext, utf16Host, aStringToSign,
michael@0 2645 const_cast<const char16_t**>(certNicknameList.get()),
michael@0 2646 const_cast<const char16_t**>(certDetailsList),
michael@0 2647 certsToUse, &selectedIndex, password,
michael@0 2648 &canceled);
michael@0 2649 if (NS_FAILED(rv) || canceled) {
michael@0 2650 break; // out of tryAgain loop
michael@0 2651 }
michael@0 2652
michael@0 2653 int32_t j = 0;
michael@0 2654 for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
michael@0 2655 node = CERT_LIST_NEXT(node)) {
michael@0 2656 if (j == selectedIndex) {
michael@0 2657 signingCert = CERT_DupCertificate(node->cert);
michael@0 2658 break; // out of cert list iteration loop
michael@0 2659 }
michael@0 2660 ++j;
michael@0 2661 }
michael@0 2662
michael@0 2663 if (!signingCert) {
michael@0 2664 rv = NS_ERROR_FAILURE;
michael@0 2665 break; // out of tryAgain loop
michael@0 2666 }
michael@0 2667
michael@0 2668 NS_ConvertUTF16toUTF8 pwUtf8(password);
michael@0 2669
michael@0 2670 tryAgain =
michael@0 2671 PK11_CheckUserPassword(signingCert->slot,
michael@0 2672 const_cast<char *>(pwUtf8.get())) != SECSuccess;
michael@0 2673 // XXX we should show an error dialog before retrying
michael@0 2674 } while (tryAgain);
michael@0 2675
michael@0 2676 int32_t k;
michael@0 2677 for (k = 0; k < certsToUse; ++k) {
michael@0 2678 nsMemory::Free(certNicknameList[k]);
michael@0 2679 nsMemory::Free(certDetailsList[k]);
michael@0 2680 }
michael@0 2681
michael@0 2682 if (NS_FAILED(rv)) { // something went wrong inside the tryAgain loop
michael@0 2683 aReturn.Append(internalError);
michael@0 2684
michael@0 2685 return;
michael@0 2686 }
michael@0 2687
michael@0 2688 if (canceled) {
michael@0 2689 aReturn.AppendLiteral("error:userCancel");
michael@0 2690
michael@0 2691 return;
michael@0 2692 }
michael@0 2693
michael@0 2694 SECKEYPrivateKey* privKey = PK11_FindKeyByAnyCert(signingCert, uiContext);
michael@0 2695 if (!privKey) {
michael@0 2696 aReturn.Append(internalError);
michael@0 2697
michael@0 2698 return;
michael@0 2699 }
michael@0 2700
michael@0 2701 nsAutoCString charset(document->GetDocumentCharacterSet());
michael@0 2702
michael@0 2703 // XXX Doing what nsFormSubmission::GetEncoder does (see
michael@0 2704 // http://bugzilla.mozilla.org/show_bug.cgi?id=81203).
michael@0 2705 if (charset.EqualsLiteral("ISO-8859-1")) {
michael@0 2706 charset.AssignLiteral("windows-1252");
michael@0 2707 }
michael@0 2708
michael@0 2709 nsCOMPtr<nsISaveAsCharset> encoder =
michael@0 2710 do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
michael@0 2711 if (encoder) {
michael@0 2712 rv = encoder->Init(charset.get(),
michael@0 2713 (nsISaveAsCharset::attr_EntityAfterCharsetConv +
michael@0 2714 nsISaveAsCharset::attr_FallbackDecimalNCR),
michael@0 2715 0);
michael@0 2716 }
michael@0 2717
michael@0 2718 nsXPIDLCString buffer;
michael@0 2719 if (aStringToSign.Length() > 0) {
michael@0 2720 if (encoder && NS_SUCCEEDED(rv)) {
michael@0 2721 rv = encoder->Convert(PromiseFlatString(aStringToSign).get(),
michael@0 2722 getter_Copies(buffer));
michael@0 2723 if (NS_FAILED(rv)) {
michael@0 2724 aReturn.Append(internalError);
michael@0 2725
michael@0 2726 return;
michael@0 2727 }
michael@0 2728 }
michael@0 2729 else {
michael@0 2730 AppendUTF16toUTF8(aStringToSign, buffer);
michael@0 2731 }
michael@0 2732 }
michael@0 2733
michael@0 2734 HASHContext *hc = HASH_Create(HASH_AlgSHA1);
michael@0 2735 if (!hc) {
michael@0 2736 aReturn.Append(internalError);
michael@0 2737
michael@0 2738 return;
michael@0 2739 }
michael@0 2740
michael@0 2741 unsigned char hash[SHA1_LENGTH];
michael@0 2742
michael@0 2743 SECItem digest;
michael@0 2744 digest.data = hash;
michael@0 2745
michael@0 2746 HASH_Begin(hc);
michael@0 2747 HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer.get()),
michael@0 2748 buffer.Length());
michael@0 2749 HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
michael@0 2750 HASH_Destroy(hc);
michael@0 2751
michael@0 2752 nsCString p7;
michael@0 2753 SECStatus srv = SECFailure;
michael@0 2754
michael@0 2755 SEC_PKCS7ContentInfo *ci = SEC_PKCS7CreateSignedData(signingCert,
michael@0 2756 certUsageEmailSigner,
michael@0 2757 nullptr, SEC_OID_SHA1,
michael@0 2758 &digest, nullptr, uiContext);
michael@0 2759 if (ci) {
michael@0 2760 srv = SEC_PKCS7IncludeCertChain(ci, nullptr);
michael@0 2761 if (srv == SECSuccess) {
michael@0 2762 srv = SEC_PKCS7AddSigningTime(ci);
michael@0 2763 if (srv == SECSuccess) {
michael@0 2764 srv = SEC_PKCS7Encode(ci, signTextOutputCallback, &p7, nullptr, nullptr,
michael@0 2765 uiContext);
michael@0 2766 }
michael@0 2767 }
michael@0 2768
michael@0 2769 SEC_PKCS7DestroyContentInfo(ci);
michael@0 2770 }
michael@0 2771
michael@0 2772 if (srv != SECSuccess) {
michael@0 2773 aReturn.Append(internalError);
michael@0 2774
michael@0 2775 return;
michael@0 2776 }
michael@0 2777
michael@0 2778 SECItem binary_item;
michael@0 2779 binary_item.data = reinterpret_cast<unsigned char*>
michael@0 2780 (const_cast<char*>(p7.get()));
michael@0 2781 binary_item.len = p7.Length();
michael@0 2782
michael@0 2783 char *result = NSSBase64_EncodeItem(nullptr, nullptr, 0, &binary_item);
michael@0 2784 if (result) {
michael@0 2785 AppendASCIItoUTF16(result, aReturn);
michael@0 2786 }
michael@0 2787 else {
michael@0 2788 aReturn.Append(internalError);
michael@0 2789 }
michael@0 2790
michael@0 2791 PORT_Free(result);
michael@0 2792
michael@0 2793 return;
michael@0 2794 }
michael@0 2795
michael@0 2796 void
michael@0 2797 nsCrypto::Logout(ErrorResult& aRv)
michael@0 2798 {
michael@0 2799 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
michael@0 2800
michael@0 2801 nsresult rv;
michael@0 2802 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
michael@0 2803 if (NS_FAILED(rv)) {
michael@0 2804 aRv.Throw(rv);
michael@0 2805 return;
michael@0 2806 }
michael@0 2807
michael@0 2808 {
michael@0 2809 nsNSSShutDownPreventionLock locker;
michael@0 2810 PK11_LogoutAll();
michael@0 2811 SSL_ClearSessionCache();
michael@0 2812 }
michael@0 2813
michael@0 2814 rv = nssComponent->LogoutAuthenticatedPK11();
michael@0 2815 if (NS_FAILED(rv)) {
michael@0 2816 aRv.Throw(rv);
michael@0 2817 }
michael@0 2818 }
michael@0 2819
michael@0 2820 CRMFObject::CRMFObject()
michael@0 2821 {
michael@0 2822 MOZ_COUNT_CTOR(CRMFObject);
michael@0 2823 }
michael@0 2824
michael@0 2825 CRMFObject::~CRMFObject()
michael@0 2826 {
michael@0 2827 MOZ_COUNT_DTOR(CRMFObject);
michael@0 2828 }
michael@0 2829
michael@0 2830 JSObject*
michael@0 2831 CRMFObject::WrapObject(JSContext *aCx, bool* aTookOwnership)
michael@0 2832 {
michael@0 2833 return CRMFObjectBinding::Wrap(aCx, this, aTookOwnership);
michael@0 2834 }
michael@0 2835
michael@0 2836 void
michael@0 2837 CRMFObject::GetRequest(nsAString& aRequest)
michael@0 2838 {
michael@0 2839 aRequest.Assign(mBase64Request);
michael@0 2840 }
michael@0 2841
michael@0 2842 nsresult
michael@0 2843 CRMFObject::SetCRMFRequest(char *inRequest)
michael@0 2844 {
michael@0 2845 mBase64Request.AssignWithConversion(inRequest);
michael@0 2846 return NS_OK;
michael@0 2847 }
michael@0 2848
michael@0 2849 #endif // MOZ_DISABLE_CRYPTOLEGACY
michael@0 2850
michael@0 2851 nsPkcs11::nsPkcs11()
michael@0 2852 {
michael@0 2853 }
michael@0 2854
michael@0 2855 nsPkcs11::~nsPkcs11()
michael@0 2856 {
michael@0 2857 }
michael@0 2858
michael@0 2859 //Delete a PKCS11 module from the user's profile.
michael@0 2860 NS_IMETHODIMP
michael@0 2861 nsPkcs11::DeleteModule(const nsAString& aModuleName)
michael@0 2862 {
michael@0 2863 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
michael@0 2864
michael@0 2865 nsNSSShutDownPreventionLock locker;
michael@0 2866 nsresult rv;
michael@0 2867 nsString errorMessage;
michael@0 2868
michael@0 2869 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
michael@0 2870 if (NS_FAILED(rv))
michael@0 2871 return rv;
michael@0 2872
michael@0 2873 if (aModuleName.IsEmpty()) {
michael@0 2874 return NS_ERROR_ILLEGAL_VALUE;
michael@0 2875 }
michael@0 2876
michael@0 2877 NS_ConvertUTF16toUTF8 modName(aModuleName);
michael@0 2878 int32_t modType;
michael@0 2879 SECStatus srv = SECMOD_DeleteModule(modName.get(), &modType);
michael@0 2880 if (srv == SECSuccess) {
michael@0 2881 SECMODModule *module = SECMOD_FindModule(modName.get());
michael@0 2882 if (module) {
michael@0 2883 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 2884 nssComponent->ShutdownSmartCardThread(module);
michael@0 2885 #endif
michael@0 2886 SECMOD_DestroyModule(module);
michael@0 2887 }
michael@0 2888 rv = NS_OK;
michael@0 2889 } else {
michael@0 2890 rv = NS_ERROR_FAILURE;
michael@0 2891 }
michael@0 2892 return rv;
michael@0 2893 }
michael@0 2894
michael@0 2895 //Add a new PKCS11 module to the user's profile.
michael@0 2896 NS_IMETHODIMP
michael@0 2897 nsPkcs11::AddModule(const nsAString& aModuleName,
michael@0 2898 const nsAString& aLibraryFullPath,
michael@0 2899 int32_t aCryptoMechanismFlags,
michael@0 2900 int32_t aCipherFlags)
michael@0 2901 {
michael@0 2902 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
michael@0 2903
michael@0 2904 nsNSSShutDownPreventionLock locker;
michael@0 2905 nsresult rv;
michael@0 2906 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
michael@0 2907
michael@0 2908 NS_ConvertUTF16toUTF8 moduleName(aModuleName);
michael@0 2909 nsCString fullPath;
michael@0 2910 // NSS doesn't support Unicode path. Use native charset
michael@0 2911 NS_CopyUnicodeToNative(aLibraryFullPath, fullPath);
michael@0 2912 uint32_t mechFlags = SECMOD_PubMechFlagstoInternal(aCryptoMechanismFlags);
michael@0 2913 uint32_t cipherFlags = SECMOD_PubCipherFlagstoInternal(aCipherFlags);
michael@0 2914 SECStatus srv = SECMOD_AddNewModule(moduleName.get(), fullPath.get(),
michael@0 2915 mechFlags, cipherFlags);
michael@0 2916 if (srv == SECSuccess) {
michael@0 2917 SECMODModule *module = SECMOD_FindModule(moduleName.get());
michael@0 2918 if (module) {
michael@0 2919 #ifndef MOZ_DISABLE_CRYPTOLEGACY
michael@0 2920 nssComponent->LaunchSmartCardThread(module);
michael@0 2921 #endif
michael@0 2922 SECMOD_DestroyModule(module);
michael@0 2923 }
michael@0 2924 }
michael@0 2925
michael@0 2926 // The error message we report to the user depends directly on
michael@0 2927 // what the return value for SEDMOD_AddNewModule is
michael@0 2928 switch (srv) {
michael@0 2929 case SECSuccess:
michael@0 2930 return NS_OK;
michael@0 2931 case SECFailure:
michael@0 2932 return NS_ERROR_FAILURE;
michael@0 2933 case -2:
michael@0 2934 return NS_ERROR_ILLEGAL_VALUE;
michael@0 2935 }
michael@0 2936 NS_ERROR("Bogus return value, this should never happen");
michael@0 2937 return NS_ERROR_FAILURE;
michael@0 2938 }
michael@0 2939

mercurial