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