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