/security/manager/ssl/src/nsCrypto.cpp
http://github.com/zpao/v8monkey · C++ · 3003 lines · 2170 code · 434 blank · 399 comment · 400 complexity · fd2d54d9f08a9afeb413eb9d2ac6fc86 MD5 · raw file
Large files are truncated click here to view the full file
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Javier Delgadillo <javi@netscape.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- #include "nsNSSComponent.h"
- #include "nsCrypto.h"
- #include "nsKeygenHandler.h"
- #include "nsKeygenThread.h"
- #include "nsNSSCertificate.h"
- #include "nsNSSCertificateDB.h"
- #include "nsPKCS12Blob.h"
- #include "nsPK11TokenDB.h"
- #include "nsThreadUtils.h"
- #include "nsIServiceManager.h"
- #include "nsIMemory.h"
- #include "nsAutoPtr.h"
- #include "nsAlgorithm.h"
- #include "nsCRT.h"
- #include "prprf.h"
- #include "prmem.h"
- #include "nsDOMCID.h"
- #include "nsIDOMWindow.h"
- #include "nsIDOMClassInfo.h"
- #include "nsIDOMDocument.h"
- #include "nsIDocument.h"
- #include "nsIScriptObjectPrincipal.h"
- #include "nsIScriptContext.h"
- #include "nsIScriptGlobalObject.h"
- #include "nsDOMJSUtils.h"
- #include "nsIXPConnect.h"
- #include "nsIRunnable.h"
- #include "nsIWindowWatcher.h"
- #include "nsIPrompt.h"
- #include "nsIFilePicker.h"
- #include "nsJSPrincipals.h"
- #include "nsIPrincipal.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsXPIDLString.h"
- #include "nsIGenKeypairInfoDlg.h"
- #include "nsIDOMCryptoDialogs.h"
- #include "nsIFormSigningDialog.h"
- #include "nsIJSContextStack.h"
- #include "jsapi.h"
- #include "jsdbgapi.h"
- #include <ctype.h>
- #include "nsReadableUtils.h"
- #include "pk11func.h"
- #include "keyhi.h"
- #include "cryptohi.h"
- #include "seccomon.h"
- #include "secerr.h"
- #include "sechash.h"
- extern "C" {
- #include "crmf.h"
- #include "pk11pqg.h"
- }
- #include "cmmf.h"
- #include "nssb64.h"
- #include "base64.h"
- #include "cert.h"
- #include "certdb.h"
- #include "secmod.h"
- #include "nsISaveAsCharset.h"
- #include "ssl.h" // For SSL_ClearSessionCache
- #include "nsNSSCleaner.h"
- NSSCleanupAutoPtrClass(SECKEYPrivateKey, SECKEY_DestroyPrivateKey)
- NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
- NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
- NSSCleanupAutoPtrClass(PK11SymKey, PK11_FreeSymKey)
- NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, true)
- NSSCleanupAutoPtrClass_WithParam(SECItem, SECITEM_FreeItem, TrueParam, true)
- #include "nsNSSShutDown.h"
- #include "nsNSSCertHelper.h"
- /*
- * These are the most common error strings that are returned
- * by the JavaScript methods in case of error.
- */
- #define JS_ERROR "error:"
- #define JS_ERROR_INTERNAL JS_ERROR"internalError"
- #undef REPORT_INCORRECT_NUM_ARGS
- #define JS_OK_ADD_MOD 3
- #define JS_OK_DEL_EXTERNAL_MOD 2
- #define JS_OK_DEL_INTERNAL_MOD 1
- #define JS_ERR_INTERNAL -1
- #define JS_ERR_USER_CANCEL_ACTION -2
- #define JS_ERR_INCORRECT_NUM_OF_ARGUMENTS -3
- #define JS_ERR_DEL_MOD -4
- #define JS_ERR_ADD_MOD -5
- #define JS_ERR_BAD_MODULE_NAME -6
- #define JS_ERR_BAD_DLL_NAME -7
- #define JS_ERR_BAD_MECHANISM_FLAGS -8
- #define JS_ERR_BAD_CIPHER_ENABLE_FLAGS -9
- #define JS_ERR_ADD_DUPLICATE_MOD -10
- /*
- * This structure is used to store information for one key generation.
- * The nsCrypto::GenerateCRMFRequest method parses the inputs and then
- * stores one of these structures for every key generation that happens.
- * The information stored in this structure is then used to set some
- * values in the CRMF request.
- */
- typedef enum {
- rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
- ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
- dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
- } nsKeyGenType;
- bool isECKeyGenType(nsKeyGenType kgt)
- {
- switch (kgt)
- {
- case ecEnc:
- case ecDualUse:
- case ecSign:
- case ecNonrepudiation:
- case ecSignNonrepudiation:
- return true;
-
- default:
- break;
- }
- return false;
- }
- typedef struct nsKeyPairInfoStr {
- SECKEYPublicKey *pubKey; /* The putlic key associated with gen'd
- priv key. */
- SECKEYPrivateKey *privKey; /* The private key we generated */
- nsKeyGenType keyGenType; /* What type of key gen are we doing.*/
- CERTCertificate *ecPopCert;
- /* null: use signing for pop
- other than null: a cert that defines EC keygen params
- and will be used for dhMac PoP. */
- SECKEYPublicKey *ecPopPubKey;
- /* extracted public key from ecPopCert */
- } nsKeyPairInfo;
- //This class is just used to pass arguments
- //to the nsCryptoRunnable event.
- class nsCryptoRunArgs : public nsISupports {
- public:
- nsCryptoRunArgs();
- virtual ~nsCryptoRunArgs();
- nsCOMPtr<nsISupports> m_kungFuDeathGrip;
- JSContext *m_cx;
- JSObject *m_scope;
- nsCOMPtr<nsIPrincipal> m_principals;
- nsXPIDLCString m_jsCallback;
- NS_DECL_ISUPPORTS
- };
- //This class is used to run the callback code
- //passed to crypto.generateCRMFRequest
- //We have to do that for backwards compatibility
- //reasons w/ PSM 1.x and Communciator 4.x
- class nsCryptoRunnable : public nsIRunnable {
- public:
- nsCryptoRunnable(nsCryptoRunArgs *args);
- virtual ~nsCryptoRunnable();
- NS_IMETHOD Run ();
- NS_DECL_ISUPPORTS
- private:
- nsCryptoRunArgs *m_args;
- };
- //We're going to inherit the memory passed
- //into us.
- //This class backs up an array of certificates
- //as an event.
- class nsP12Runnable : public nsIRunnable {
- public:
- nsP12Runnable(nsIX509Cert **certArr, PRInt32 numCerts, nsIPK11Token *token);
- virtual ~nsP12Runnable();
- NS_IMETHOD Run();
- NS_DECL_ISUPPORTS
- private:
- nsCOMPtr<nsIPK11Token> mToken;
- nsIX509Cert **mCertArr;
- PRInt32 mNumCerts;
- };
- // QueryInterface implementation for nsCrypto
- NS_INTERFACE_MAP_BEGIN(nsCrypto)
- NS_INTERFACE_MAP_ENTRY(nsIDOMCrypto)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Crypto)
- NS_INTERFACE_MAP_END
- NS_IMPL_ADDREF(nsCrypto)
- NS_IMPL_RELEASE(nsCrypto)
- // QueryInterface implementation for nsCRMFObject
- NS_INTERFACE_MAP_BEGIN(nsCRMFObject)
- NS_INTERFACE_MAP_ENTRY(nsIDOMCRMFObject)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CRMFObject)
- NS_INTERFACE_MAP_END
- NS_IMPL_ADDREF(nsCRMFObject)
- NS_IMPL_RELEASE(nsCRMFObject)
- // QueryInterface implementation for nsPkcs11
- NS_INTERFACE_MAP_BEGIN(nsPkcs11)
- NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- NS_IMPL_ADDREF(nsPkcs11)
- NS_IMPL_RELEASE(nsPkcs11)
- // ISupports implementation for nsCryptoRunnable
- NS_IMPL_ISUPPORTS1(nsCryptoRunnable, nsIRunnable)
- // ISupports implementation for nsP12Runnable
- NS_IMPL_ISUPPORTS1(nsP12Runnable, nsIRunnable)
- // ISupports implementation for nsCryptoRunArgs
- NS_IMPL_ISUPPORTS0(nsCryptoRunArgs)
- static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
- nsCrypto::nsCrypto() :
- mEnableSmartCardEvents(false)
- {
- }
- nsCrypto::~nsCrypto()
- {
- }
- NS_IMETHODIMP
- nsCrypto::SetEnableSmartCardEvents(bool aEnable)
- {
- nsresult rv = NS_OK;
- // this has the side effect of starting the nssComponent (and initializing
- // NSS) even if it isn't already going. Starting the nssComponent is a
- // prerequisite for getting smartCard events.
- if (aEnable) {
- nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
- mEnableSmartCardEvents = aEnable;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsCrypto::GetEnableSmartCardEvents(bool *aEnable)
- {
- *aEnable = mEnableSmartCardEvents;
- return NS_OK;
- }
- //A quick function to let us know if the key we're trying to generate
- //can be escrowed.
- static bool
- ns_can_escrow(nsKeyGenType keyGenType)
- {
- /* For now, we only escrow rsa-encryption and ec-encryption keys. */
- return (bool)(keyGenType == rsaEnc || keyGenType == ecEnc);
- }
- //Retrieve crypto.version so that callers know what
- //version of PSM this is.
- NS_IMETHODIMP
- nsCrypto::GetVersion(nsAString& aVersion)
- {
- aVersion.Assign(NS_LITERAL_STRING(PSM_VERSION_STRING).get());
- return NS_OK;
- }
- /*
- * Given an nsKeyGenType, return the PKCS11 mechanism that will
- * perform the correct key generation.
- */
- static PRUint32
- cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
- {
- PRUint32 retMech;
- switch (keyGenType) {
- case rsaEnc:
- case rsaDualUse:
- case rsaSign:
- case rsaNonrepudiation:
- case rsaSignNonrepudiation:
- retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
- break;
- case ecEnc:
- case ecDualUse:
- case ecSign:
- case ecNonrepudiation:
- case ecSignNonrepudiation:
- retMech = CKM_EC_KEY_PAIR_GEN;
- break;
- case dhEx:
- retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
- break;
- case dsaSign:
- case dsaSignNonrepudiation:
- case dsaNonrepudiation:
- retMech = CKM_DSA_KEY_PAIR_GEN;
- break;
- default:
- retMech = CKM_INVALID_MECHANISM;
- }
- return retMech;
- }
- /*
- * This function converts a string read through JavaScript parameters
- * and translates it to the internal enumeration representing the
- * key gen type.
- */
- static nsKeyGenType
- cryptojs_interpret_key_gen_type(char *keyAlg)
- {
- char *end;
- if (keyAlg == nsnull) {
- return invalidKeyGen;
- }
- /* First let's remove all leading and trailing white space */
- while (isspace(keyAlg[0])) keyAlg++;
- end = strchr(keyAlg, '\0');
- if (end == nsnull) {
- return invalidKeyGen;
- }
- end--;
- while (isspace(*end)) end--;
- end[1] = '\0';
- if (strcmp(keyAlg, "rsa-ex") == 0) {
- return rsaEnc;
- } else if (strcmp(keyAlg, "rsa-dual-use") == 0) {
- return rsaDualUse;
- } else if (strcmp(keyAlg, "rsa-sign") == 0) {
- return rsaSign;
- } else if (strcmp(keyAlg, "rsa-sign-nonrepudiation") == 0) {
- return rsaSignNonrepudiation;
- } else if (strcmp(keyAlg, "rsa-nonrepudiation") == 0) {
- return rsaNonrepudiation;
- } else if (strcmp(keyAlg, "ec-ex") == 0) {
- return ecEnc;
- } else if (strcmp(keyAlg, "ec-dual-use") == 0) {
- return ecDualUse;
- } else if (strcmp(keyAlg, "ec-sign") == 0) {
- return ecSign;
- } else if (strcmp(keyAlg, "ec-sign-nonrepudiation") == 0) {
- return ecSignNonrepudiation;
- } else if (strcmp(keyAlg, "ec-nonrepudiation") == 0) {
- return ecNonrepudiation;
- } else if (strcmp(keyAlg, "dsa-sign-nonrepudiation") == 0) {
- return dsaSignNonrepudiation;
- } else if (strcmp(keyAlg, "dsa-sign") ==0 ){
- return dsaSign;
- } else if (strcmp(keyAlg, "dsa-nonrepudiation") == 0) {
- return dsaNonrepudiation;
- } else if (strcmp(keyAlg, "dh-ex") == 0) {
- return dhEx;
- }
- return invalidKeyGen;
- }
- /*
- * input: null terminated char* pointing to (the remainder of) an
- * EC key param string.
- *
- * bool return value, false means "no more name=value pair found",
- * true means "found, see out params"
- *
- * out param name: char * pointing to name (not zero terminated)
- * out param name_len: length of found name
- * out param value: char * pointing to value (not zero terminated)
- * out param value_len: length of found value
- * out param next_pair: to be used for a follow up call to this function
- */
- bool getNextNameValueFromECKeygenParamString(char *input,
- char *&name,
- int &name_len,
- char *&value,
- int &value_len,
- char *&next_call)
- {
- if (!input || !*input)
- return false;
- // we allow leading ; and leading space in front of each name value pair
- while (*input && *input == ';')
- ++input;
- while (*input && *input == ' ')
- ++input;
- name = input;
- while (*input && *input != '=')
- ++input;
- if (*input != '=')
- return false;
- name_len = input - name;
- ++input;
- value = input;
- while (*input && *input != ';')
- ++input;
- value_len = input - value;
- next_call = input;
- return true;
- }
- //Take the string passed into us via crypto.generateCRMFRequest
- //as the keygen type parameter and convert it to parameters
- //we can actually pass to the PKCS#11 layer.
- static void*
- nsConvertToActualKeyGenParams(PRUint32 keyGenMech, char *params,
- PRUint32 paramLen, PRInt32 keySize,
- nsKeyPairInfo *keyPairInfo)
- {
- void *returnParams = nsnull;
- switch (keyGenMech) {
- case CKM_RSA_PKCS_KEY_PAIR_GEN:
- {
- // For RSA, we don't support passing in key generation arguments from
- // the JS code just yet.
- if (params)
- return nsnull;
- PK11RSAGenParams *rsaParams;
- rsaParams = static_cast<PK11RSAGenParams*>
- (nsMemory::Alloc(sizeof(PK11RSAGenParams)));
-
- if (rsaParams == nsnull) {
- return nsnull;
- }
- /* I'm just taking the same parameters used in
- * certdlgs.c:GenKey
- */
- if (keySize > 0) {
- rsaParams->keySizeInBits = keySize;
- } else {
- rsaParams->keySizeInBits = 1024;
- }
- rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
- returnParams = rsaParams;
- break;
- }
- case CKM_EC_KEY_PAIR_GEN:
- {
- /*
- * keygen params for generating EC keys must be composed of name=value pairs,
- * multiple pairs allowed, separated using semicolon ;
- *
- * Either param "curve" or param "popcert" must be specified.
- * curve=name-of-curve
- * popcert=base64-encoded-cert
- *
- * When both params are specified, popcert will be used.
- * If no popcert param is given, or if popcert can not be decoded,
- * we will fall back to the curve param.
- *
- * Additional name=value pairs may be defined in the future.
- *
- * If param popcert is present and valid, the given certificate will be used
- * to determine the key generation params. In addition the certificate
- * will be used to produce a dhMac based Proof of Posession,
- * using the cert's public key, subject and issuer names,
- * as specified in RFC 2511 section 4.3 paragraph 2 and Appendix A.
- *
- * If neither param popcert nor param curve could be used,
- * tse a curve based on the keysize param.
- * NOTE: Here keysize is used only as an indication of
- * High/Medium/Low strength; elliptic curve
- * cryptography uses smaller keys than RSA to provide
- * equivalent security.
- */
- char *curve = nsnull;
- {
- // extract components of name=value list
- char *next_input = params;
- char *name = nsnull;
- char *value = nsnull;
- int name_len = 0;
- int value_len = 0;
-
- while (getNextNameValueFromECKeygenParamString(
- next_input, name, name_len, value, value_len,
- next_input))
- {
- if (PL_strncmp(name, "curve", NS_MIN(name_len, 5)) == 0)
- {
- curve = PL_strndup(value, value_len);
- }
- else if (PL_strncmp(name, "popcert", NS_MIN(name_len, 7)) == 0)
- {
- char *certstr = PL_strndup(value, value_len);
- if (certstr) {
- keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
- PL_strfree(certstr);
- if (keyPairInfo->ecPopCert)
- {
- keyPairInfo->ecPopPubKey = CERT_ExtractPublicKey(keyPairInfo->ecPopCert);
- }
- }
- }
- }
- }
- // first try to use the params of the provided CA cert
- if (keyPairInfo->ecPopPubKey)
- {
- returnParams = SECITEM_DupItem(&keyPairInfo->ecPopPubKey->u.ec.DEREncodedParams);
- }
- // if we did not yet find good params, do we have a curve name?
- if (!returnParams && curve)
- {
- returnParams = decode_ec_params(curve);
- }
- // if we did not yet find good params, do something based on keysize
- if (!returnParams)
- {
- switch (keySize) {
- case 512:
- case 1024:
- returnParams = decode_ec_params("secp256r1");
- break;
- case 2048:
- default:
- returnParams = decode_ec_params("secp384r1");
- break;
- }
- }
- if (curve)
- PL_strfree(curve);
- break;
- }
- case CKM_DSA_KEY_PAIR_GEN:
- {
- // For DSA, we don't support passing in key generation arguments from
- // the JS code just yet.
- if (params)
- return nsnull;
- PQGParams *pqgParams = nsnull;
- PQGVerify *vfy = nsnull;
- SECStatus rv;
- int index;
-
- index = PQG_PBITS_TO_INDEX(keySize);
- if (index == -1) {
- returnParams = nsnull;
- break;
- }
- rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
- if (vfy) {
- PK11_PQG_DestroyVerify(vfy);
- }
- if (rv != SECSuccess) {
- if (pqgParams) {
- PK11_PQG_DestroyParams(pqgParams);
- }
- return nsnull;
- }
- returnParams = pqgParams;
- break;
- }
- default:
- returnParams = nsnull;
- }
- return returnParams;
- }
- //We need to choose which PKCS11 slot we're going to generate
- //the key on. Calls the default implementation provided by
- //nsKeygenHandler.cpp
- static PK11SlotInfo*
- nsGetSlotForKeyGen(nsKeyGenType keyGenType, nsIInterfaceRequestor *ctx)
- {
- nsNSSShutDownPreventionLock locker;
- PRUint32 mechanism = cryptojs_convert_to_mechanism(keyGenType);
- PK11SlotInfo *slot = nsnull;
- nsresult rv = GetSlotWithMechanism(mechanism,ctx, &slot);
- if (NS_FAILED(rv)) {
- if (slot)
- PK11_FreeSlot(slot);
- slot = nsnull;
- }
- return slot;
- }
- //Free the parameters that were passed into PK11_GenerateKeyPair
- //depending on the mechanism type used.
- static void
- nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
- {
- switch (keyGenMechanism) {
- case CKM_RSA_PKCS_KEY_PAIR_GEN:
- nsMemory::Free(params);
- break;
- case CKM_EC_KEY_PAIR_GEN:
- SECITEM_FreeItem(reinterpret_cast<SECItem*>(params), true);
- break;
- case CKM_DSA_KEY_PAIR_GEN:
- PK11_PQG_DestroyParams(static_cast<PQGParams*>(params));
- break;
- }
- }
- //Function that is used to generate a single key pair.
- //Once all the arguments have been parsed and processed, this
- //function gets called and takes care of actually generating
- //the key pair passing the appopriate parameters to the NSS
- //functions.
- static nsresult
- cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo,
- PRInt32 keySize, char *params,
- nsIInterfaceRequestor *uiCxt,
- PK11SlotInfo *slot, bool willEscrow)
-
- {
- nsIGeneratingKeypairInfoDialogs * dialogs;
- nsKeygenThread *KeygenRunnable = 0;
- nsCOMPtr<nsIKeygenThread> runnable;
- PRUint32 mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
- void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params,
- (params) ? strlen(params):0,
- keySize, keyPairInfo);
- if (!keyGenParams) {
- return NS_ERROR_INVALID_ARG;
- }
- // Make sure the token has password already set on it before trying
- // to generate the key.
- nsresult rv = setPassword(slot, uiCxt);
- if (NS_FAILED(rv))
- return rv;
- if (PK11_Authenticate(slot, true, uiCxt) != SECSuccess)
- return NS_ERROR_FAILURE;
-
- // Smart cards will not let you extract a private key once
- // it is on the smart card. If we've been told to escrow
- // a private key that will ultimately wind up on a smart card,
- // then we'll generate the private key on the internal slot
- // as a temporary key, then move it to the destination slot.
- // NOTE: We call PK11_GetInternalSlot instead of PK11_GetInternalKeySlot
- // so that the key has zero chance of being store in the
- // user's key3.db file. Which the slot returned by
- // PK11_GetInternalKeySlot has access to and PK11_GetInternalSlot
- // does not.
- PK11SlotInfo *intSlot = nsnull;
- PK11SlotInfoCleaner siCleaner(intSlot);
-
- PK11SlotInfo *origSlot = nsnull;
- bool isPerm;
- if (willEscrow && !PK11_IsInternal(slot)) {
- intSlot = PK11_GetInternalSlot();
- NS_ASSERTION(intSlot,"Couldn't get the internal slot");
- isPerm = false;
- origSlot = slot;
- slot = intSlot;
- } else {
- isPerm = true;
- }
- rv = getNSSDialogs((void**)&dialogs,
- NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
- NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
- if (NS_SUCCEEDED(rv)) {
- KeygenRunnable = new nsKeygenThread();
- if (KeygenRunnable) {
- NS_ADDREF(KeygenRunnable);
- }
- }
- if (NS_FAILED(rv) || !KeygenRunnable) {
- rv = NS_OK;
- keyPairInfo->privKey = PK11_GenerateKeyPair(slot, mechanism, keyGenParams,
- &keyPairInfo->pubKey, isPerm,
- isPerm, uiCxt);
- } else {
- KeygenRunnable->SetParams( slot, mechanism, keyGenParams, isPerm, isPerm, uiCxt );
- runnable = do_QueryInterface(KeygenRunnable);
- if (runnable) {
- {
- nsPSMUITracker tracker;
- if (tracker.isUIForbidden()) {
- rv = NS_ERROR_NOT_AVAILABLE;
- }
- else {
- rv = dialogs->DisplayGeneratingKeypairInfo(uiCxt, runnable);
- // We call join on the thread,
- // so we can be sure that no simultaneous access to the passed parameters will happen.
- KeygenRunnable->Join();
- }
- }
- NS_RELEASE(dialogs);
- if (NS_SUCCEEDED(rv)) {
- rv = KeygenRunnable->GetParams(&keyPairInfo->privKey, &keyPairInfo->pubKey);
- }
- }
- }
- nsFreeKeyGenParams(mechanism, keyGenParams);
- if (KeygenRunnable) {
- NS_RELEASE(KeygenRunnable);
- }
- if (!keyPairInfo->privKey || !keyPairInfo->pubKey) {
- return NS_ERROR_FAILURE;
- }
-
- //If we generated the key pair on the internal slot because the
- // keys were going to be escrowed, move the keys over right now.
- if (willEscrow && intSlot) {
- SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(origSlot,
- keyPairInfo->privKey,
- keyPairInfo->pubKey,
- true, true);
- SECKEYPrivateKeyCleaner pkCleaner(newPrivKey);
- if (!newPrivKey)
- return NS_ERROR_FAILURE;
- // The private key is stored on the selected slot now, and the copy we
- // ultimately use for escrowing when the time comes lives
- // in the internal slot. We will delete it from that slot
- // after the requests are made. This call only gives up
- // our reference to the key object and does not actually
- // physically remove it from the card itself.
- // The actual delete calls are being made in the destructors
- // of the cleaner helper instances.
- }
- return NS_OK;
- }
- /*
- * FUNCTION: cryptojs_ReadArgsAndGenerateKey
- * -------------------------------------
- * INPUTS:
- * cx
- * The JSContext associated with the execution of the corresponging
- * crypto.generateCRMFRequest call
- * argv
- * A pointer to an array of JavaScript parameters passed to the
- * method crypto.generateCRMFRequest. The array should have the
- * 3 arguments keySize, "keyParams", and "keyGenAlg" mentioned in
- * the definition of crypto.generateCRMFRequest at the following
- * document http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html
- * keyGenType
- * A structure used to store the information about the newly created
- * key pair.
- * uiCxt
- * An interface requestor that would be used to get an nsIPrompt
- * if we need to ask the user for a password.
- * slotToUse
- * The PKCS11 slot to use for generating the key pair. If nsnull, then
- * this function should select a slot that can do the key generation
- * from the keytype associted with the keyPairInfo, and pass it back to
- * the caller so that subsequence key generations can use the same slot.
- * willEscrow
- * If true, then that means we will try to escrow the generated
- * private key when building the CRMF request. If false, then
- * we will not try to escrow the private key.
- *
- * NOTES:
- * This function takes care of reading a set of 3 parameters that define
- * one key generation. The argv pointer should be one that originates
- * from the argv parameter passed in to the method nsCrypto::GenerateCRMFRequest.
- * The function interprets the argument in the first index as an integer and
- * passes that as the key size for the key generation-this parameter is
- * mandatory. The second parameter is read in as a string. This value can
- * be null in JavaScript world and everything will still work. The third
- * parameter is a mandatory string that indicates what kind of key to generate.
- * There should always be 1-to-1 correspondence between the strings compared
- * in the function cryptojs_interpret_key_gen_type and the strings listed in
- * document at http://docs.iplanet.com/docs/manuals/psm/11/cmcjavascriptapi.html
- * under the definition of the method generateCRMFRequest, for the parameter
- * "keyGenAlgN". After reading the parameters, the function then
- * generates the key pairs passing the parameters parsed from the JavaScript i
- * routine.
- *
- * RETURN:
- * NS_OK if creating the Key was successful. Any other return value
- * indicates an error.
- */
- static nsresult
- cryptojs_ReadArgsAndGenerateKey(JSContext *cx,
- jsval *argv,
- nsKeyPairInfo *keyGenType,
- nsIInterfaceRequestor *uiCxt,
- PK11SlotInfo **slot, bool willEscrow)
- {
- JSString *jsString;
- JSAutoByteString params, keyGenAlg;
- int keySize;
- nsresult rv;
- if (!JSVAL_IS_INT(argv[0])) {
- JS_ReportError(cx, "%s%s\n", JS_ERROR,
- "passed in non-integer for key size");
- return NS_ERROR_FAILURE;
- }
- keySize = JSVAL_TO_INT(argv[0]);
- if (!JSVAL_IS_NULL(argv[1])) {
- jsString = JS_ValueToString(cx,argv[1]);
- NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
- argv[1] = STRING_TO_JSVAL(jsString);
- params.encode(cx, jsString);
- NS_ENSURE_TRUE(!!params, NS_ERROR_OUT_OF_MEMORY);
- }
- if (JSVAL_IS_NULL(argv[2])) {
- JS_ReportError(cx,"%s%s\n", JS_ERROR,
- "key generation type not specified");
- return NS_ERROR_FAILURE;
- }
- jsString = JS_ValueToString(cx, argv[2]);
- NS_ENSURE_TRUE(jsString, NS_ERROR_OUT_OF_MEMORY);
- argv[2] = STRING_TO_JSVAL(jsString);
- keyGenAlg.encode(cx, jsString);
- NS_ENSURE_TRUE(!!keyGenAlg, NS_ERROR_OUT_OF_MEMORY);
- keyGenType->keyGenType = cryptojs_interpret_key_gen_type(keyGenAlg.ptr());
- if (keyGenType->keyGenType == invalidKeyGen) {
- JS_ReportError(cx, "%s%s%s", JS_ERROR,
- "invalid key generation argument:",
- keyGenAlg.ptr());
- goto loser;
- }
- if (*slot == nsnull) {
- *slot = nsGetSlotForKeyGen(keyGenType->keyGenType, uiCxt);
- if (*slot == nsnull)
- goto loser;
- }
- rv = cryptojs_generateOneKeyPair(cx,keyGenType,keySize,params.ptr(),uiCxt,
- *slot,willEscrow);
- if (rv != NS_OK) {
- JS_ReportError(cx,"%s%s%s", JS_ERROR,
- "could not generate the key for algorithm ",
- keyGenAlg.ptr());
- goto loser;
- }
- return NS_OK;
- loser:
- return NS_ERROR_FAILURE;
- }
- //Utility funciton to free up the memory used by nsKeyPairInfo
- //arrays.
- static void
- nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
- {
- NS_ASSERTION(keyids, "NULL pointer passed to nsFreeKeyPairInfo");
- if (!keyids)
- return;
- int i;
- for (i=0; i<numIDs; i++) {
- if (keyids[i].pubKey)
- SECKEY_DestroyPublicKey(keyids[i].pubKey);
- if (keyids[i].privKey)
- SECKEY_DestroyPrivateKey(keyids[i].privKey);
- if (keyids[i].ecPopCert)
- CERT_DestroyCertificate(keyids[i].ecPopCert);
- if (keyids[i].ecPopPubKey)
- SECKEY_DestroyPublicKey(keyids[i].ecPopPubKey);
- }
- delete []keyids;
- }
- //Utility funciton used to free the genertaed cert request messages
- static void
- nsFreeCertReqMessages(CRMFCertReqMsg **certReqMsgs, PRInt32 numMessages)
- {
- PRInt32 i;
- for (i=0; i<numMessages && certReqMsgs[i]; i++) {
- CRMF_DestroyCertReqMsg(certReqMsgs[i]);
- }
- delete []certReqMsgs;
- }
- //If the form called for escrowing the private key we just generated,
- //this function adds all the correct elements to the request.
- //That consists of adding CRMFEncryptedKey to the reques as part
- //of the CRMFPKIArchiveOptions Control.
- static nsresult
- nsSetEscrowAuthority(CRMFCertRequest *certReq, nsKeyPairInfo *keyInfo,
- nsNSSCertificate *wrappingCert)
- {
- if (!wrappingCert ||
- CRMF_CertRequestIsControlPresent(certReq, crmfPKIArchiveOptionsControl)){
- return NS_ERROR_FAILURE;
- }
- CERTCertificate *cert = wrappingCert->GetCert();
- if (!cert)
- return NS_ERROR_FAILURE;
- CRMFEncryptedKey *encrKey =
- CRMF_CreateEncryptedKeyWithEncryptedValue(keyInfo->privKey, cert);
- CERT_DestroyCertificate(cert);
- if (!encrKey)
- return NS_ERROR_FAILURE;
- CRMFPKIArchiveOptions *archOpt =
- CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encrKey);
- if (!archOpt) {
- CRMF_DestroyEncryptedKey(encrKey);
- return NS_ERROR_FAILURE;
- }
- SECStatus srv = CRMF_CertRequestSetPKIArchiveOptions(certReq, archOpt);
- CRMF_DestroyEncryptedKey(encrKey);
- CRMF_DestroyPKIArchiveOptions(archOpt);
- if (srv != SECSuccess)
- return NS_ERROR_FAILURE;
- return NS_OK;
- }
- //Set the Distinguished Name (Subject Name) for the cert
- //being requested.
- static nsresult
- nsSetDNForRequest(CRMFCertRequest *certReq, char *reqDN)
- {
- if (!reqDN || CRMF_CertRequestIsFieldPresent(certReq, crmfSubject)) {
- return NS_ERROR_FAILURE;
- }
- CERTName *subjectName = CERT_AsciiToName(reqDN);
- if (!subjectName) {
- return NS_ERROR_FAILURE;
- }
- SECStatus srv = CRMF_CertRequestSetTemplateField(certReq, crmfSubject,
- static_cast<void*>
- (subjectName));
- CERT_DestroyName(subjectName);
- return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
- }
- //Set Registration Token Control on the request.
- static nsresult
- nsSetRegToken(CRMFCertRequest *certReq, char *regToken)
- {
- // this should never happen, but might as well add this.
- NS_ASSERTION(certReq, "A bogus certReq passed to nsSetRegToken");
- if (regToken){
- if (CRMF_CertRequestIsControlPresent(certReq, crmfRegTokenControl))
- return NS_ERROR_FAILURE;
-
- SECItem src;
- src.data = (unsigned char*)regToken;
- src.len = strlen(regToken);
- SECItem *derEncoded = SEC_ASN1EncodeItem(nsnull, nsnull, &src,
- SEC_ASN1_GET(SEC_UTF8StringTemplate));
- if (!derEncoded)
- return NS_ERROR_FAILURE;
- SECStatus srv = CRMF_CertRequestSetRegTokenControl(certReq, derEncoded);
- SECITEM_FreeItem(derEncoded,true);
- if (srv != SECSuccess)
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- //Set the Authenticator control on the cert reuest. It's just
- //a string that gets passed along.
- static nsresult
- nsSetAuthenticator(CRMFCertRequest *certReq, char *authenticator)
- {
- //This should never happen, but might as well check.
- NS_ASSERTION(certReq, "Bogus certReq passed to nsSetAuthenticator");
- if (authenticator) {
- if (CRMF_CertRequestIsControlPresent(certReq, crmfAuthenticatorControl))
- return NS_ERROR_FAILURE;
-
- SECItem src;
- src.data = (unsigned char*)authenticator;
- src.len = strlen(authenticator);
- SECItem *derEncoded = SEC_ASN1EncodeItem(nsnull, nsnull, &src,
- SEC_ASN1_GET(SEC_UTF8StringTemplate));
- if (!derEncoded)
- return NS_ERROR_FAILURE;
- SECStatus srv = CRMF_CertRequestSetAuthenticatorControl(certReq,
- derEncoded);
- SECITEM_FreeItem(derEncoded, true);
- if (srv != SECSuccess)
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- // ASN1 DER encoding rules say that when encoding a BIT string,
- // the length in the header for the bit string is the number
- // of "useful" bits in the BIT STRING. So the function finds
- // it and sets accordingly for the returned item.
- static void
- nsPrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
- {
- unsigned char onebyte;
- unsigned int i, len = 0;
- /* to prevent warning on some platform at compile time */
- onebyte = '\0';
- /* Get the position of the right-most turn-on bit */
- for (i = 0; i < (value->len ) * 8; ++i) {
- if (i % 8 == 0)
- onebyte = value->data[i/8];
- if (onebyte & 0x80)
- len = i;
- onebyte <<= 1;
- }
- bitsmap->data = value->data;
- /* Add one here since we work with base 1 */
- bitsmap->len = len + 1;
- }
- //This next section defines all the functions that sets the
- //keyUsageExtension for all the different types of key gens
- //we handle. The keyUsageExtension is just a bit flag extension
- //that we set in wrapper functions that call straight into
- //nsSetKeyUsageExtension. There is one wrapper funciton for each
- //keyGenType. The correct function will eventually be called
- //by going through a switch statement based on the nsKeyGenType
- //in the nsKeyPairInfo struct.
- static nsresult
- nsSetKeyUsageExtension(CRMFCertRequest *crmfReq,
- unsigned char keyUsage)
- {
- SECItem *encodedExt= nsnull;
- SECItem keyUsageValue = { (SECItemType) 0, nsnull, 0 };
- SECItem bitsmap = { (SECItemType) 0, nsnull, 0 };
- SECStatus srv;
- CRMFCertExtension *ext = nsnull;
- CRMFCertExtCreationInfo extAddParams;
- SEC_ASN1Template bitStrTemplate = {SEC_ASN1_BIT_STRING, 0, nsnull,
- sizeof(SECItem)};
- keyUsageValue.data = &keyUsage;
- keyUsageValue.len = 1;
- nsPrepareBitStringForEncoding(&bitsmap, &keyUsageValue);
- encodedExt = SEC_ASN1EncodeItem(nsnull, nsnull, &bitsmap,&bitStrTemplate);
- if (encodedExt == nsnull) {
- goto loser;
- }
- ext = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE, true, encodedExt);
- if (ext == nsnull) {
- goto loser;
- }
- extAddParams.numExtensions = 1;
- extAddParams.extensions = &ext;
- srv = CRMF_CertRequestSetTemplateField(crmfReq, crmfExtension,
- &extAddParams);
- if (srv != SECSuccess) {
- goto loser;
- }
- CRMF_DestroyCertExtension(ext);
- SECITEM_FreeItem(encodedExt, true);
- return NS_OK;
- loser:
- if (ext) {
- CRMF_DestroyCertExtension(ext);
- }
- if (encodedExt) {
- SECITEM_FreeItem(encodedExt, true);
- }
- return NS_ERROR_FAILURE;
- }
- static nsresult
- nsSetRSADualUse(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE
- | KU_NON_REPUDIATION
- | KU_KEY_ENCIPHERMENT;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetRSAKeyEx(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_KEY_ENCIPHERMENT;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetRSASign(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetRSANonRepudiation(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_NON_REPUDIATION;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
- KU_NON_REPUDIATION;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetECDualUse(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE
- | KU_NON_REPUDIATION
- | KU_KEY_AGREEMENT;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetECKeyEx(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_KEY_AGREEMENT;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetECSign(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetECNonRepudiation(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_NON_REPUDIATION;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetECSignNonRepudiation(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
- KU_NON_REPUDIATION;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetDH(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_KEY_AGREEMENT;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetDSASign(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetDSANonRepudiation(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_NON_REPUDIATION;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetDSASignNonRepudiation(CRMFCertRequest *crmfReq)
- {
- unsigned char keyUsage = KU_DIGITAL_SIGNATURE |
- KU_NON_REPUDIATION;
- return nsSetKeyUsageExtension(crmfReq, keyUsage);
- }
- static nsresult
- nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
- {
- nsresult rv;
- switch (keyGenType) {
- case rsaDualUse:
- rv = nsSetRSADualUse(crmfReq);
- break;
- case rsaEnc:
- rv = nsSetRSAKeyEx(crmfReq);
- break;
- case rsaSign:
- rv = nsSetRSASign(crmfReq);
- break;
- case rsaNonrepudiation:
- rv = nsSetRSANonRepudiation(crmfReq);
- break;
- case rsaSignNonrepudiation:
- rv = nsSetRSASignNonRepudiation(crmfReq);
- break;
- case ecDualUse:
- rv = nsSetECDualUse(crmfReq);
- break;
- case ecEnc:
- rv = nsSetECKeyEx(crmfReq);
- break;
- case ecSign:
- rv = nsSetECSign(crmfReq);
- break;
- case ecNonrepudiation:
- rv = nsSetECNonRepudiation(crmfReq);
- break;
- case ecSignNonrepudiation:
- rv = nsSetECSignNonRepudiation(crmfReq);
- break;
- case dhEx:
- rv = nsSetDH(crmfReq);
- break;
- case dsaSign:
- rv = nsSetDSASign(crmfReq);
- break;
- case dsaNonrepudiation:
- rv = nsSetDSANonRepudiation(crmfReq);
- break;
- case dsaSignNonrepudiation:
- rv = nsSetDSASignNonRepudiation(crmfReq);
- break;
- default:
- rv = NS_ERROR_FAILURE;
- break;
- }
- return rv;
- }
- //Create a single CRMFCertRequest with all of the necessary parts
- //already installed. The request returned by this function will
- //have all the parts necessary and can just be added to a
- //Certificate Request Message.
- static CRMFCertRequest*
- nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken,
- char *authenticator, nsNSSCertificate *wrappingCert)
- {
- PRUint32 reqID;
- nsresult rv;
- //The draft says the ID of the request should be a random
- //number. We don't have a way of tracking this number
- //to compare when the reply actually comes back,though.
- PK11_GenerateRandom((unsigned char*)&reqID, sizeof(reqID));
- CRMFCertRequest *certReq = CRMF_CreateCertRequest(reqID);
- if (!certReq)
- return nsnull;
- long version = SEC_CERTIFICATE_VERSION_3;
- SECStatus srv;
- CERTSubjectPublicKeyInfo *spki = nsnull;
- srv = CRMF_CertRequestSetTemplateField(certReq, crmfVersion, &version);
- if (srv != SECSuccess)
- goto loser;
-
- spki = SECKEY_CreateSubjectPublicKeyInfo(keyInfo->pubKey);
- if (!spki)
- goto loser;
- srv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, spki);
- SECKEY_DestroySubjectPublicKeyInfo(spki);
- if (srv != SECSuccess)
- goto loser;
- if (wrappingCert && ns_can_escrow(keyInfo->keyGenType)) {
- rv = nsSetEscrowAuthority(certReq, keyInfo, wrappingCert);
- if (NS_FAILED(rv))
- goto loser;
- }
- rv = nsSetDNForRequest(certReq, reqDN);
- if (NS_FAILED(rv))
- goto loser;
- rv = nsSetRegToken(certReq, regToken);
- if (NS_FAILED(rv))
- goto loser;
- rv = nsSetAuthenticator(certReq, authenticator);
- if (NS_FAILED(rv))
- goto loser;
- rv = nsSetKeyUsageExtension(certReq, keyInfo->keyGenType);
- if (NS_FAILED(rv))
- goto loser;
- return certReq;
- loser:
- if (certReq) {
- CRMF_DestroyCertRequest(certReq);
- }
- return nsnull;
- }
- /*
- * This function will set the Proof Of Possession (POP) for a request
- * associated with a key pair intended to do Key Encipherment. Currently
- * this means encryption only keys.
- */
- static nsresult
- nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, bool isEscrowed)
- {
- SECItem bitString;
- unsigned char der[2];
- SECStatus srv;
- if (isEscrowed) {
- /* For proof of possession on escrowed keys, we use the
- * this Message option of POPOPrivKey and include a zero
- * length bit string in the POP field. This is OK because the encrypted
- * private key already exists as part of the PKIArchiveOptions
- * Control and that for all intents and purposes proves that
- * we do own the private key.
- */
- der[0] = 0x03; /*We've got a bit string */
- der[1] = 0x00; /*We've got a 0 length bit string */
- bitString.data = der;
- bitString.len = 2;
- srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, crmfThisMessage,
- crmfNoSubseqMess, &bitString);
- } else {
- /* If the encryption key is not being escrowed, then we set the
- * Proof Of Possession to be a Challenge Response mechanism.
- */
- srv = CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg,
- crmfSubsequentMessage,
- crmfChallengeResp, nsnull);
- }
- return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
- }
- static void PR_CALLBACK
- nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
- static void PR_CALLBACK
- nsCRMFEncoderItemStore(void *arg, const char *buf, unsigned long len);
- static nsresult
- nsSet_EC_DHMAC_ProofOfPossession(CRMFCertReqMsg *certReqMsg,
- nsKeyPairInfo *keyInfo,
- CRMFCertRequest *certReq)
- {
- // RFC 2511 Appendix A section 2 a) defines,
- // the "text" input for HMAC shall be the DER encoded version of
- // of the single cert request.
- // We'll produce that encoding and destroy it afterwards,
- // because when sending the complete package to the CA,
- // we'll use a different encoding, one that includes POP and
- // allows multiple requests to be sent in one step.
- unsigned long der_request_len = 0;
- SECItem *der_request = NULL;
- SECItemCleanerTrueParam der_request_cleaner(der_request);
- if (SECSuccess != CRMF_EncodeCertRequest(certReq,
- nsCRMFEncoderItemCount,
- &der_request_len))
- return NS_ERROR_FAILURE;
- der_request = SECITEM_AllocItem(nsnull, nsnull, der_request_len);
- if (!der_request)
- return NS_ERROR_FAILURE;
- // set len in returned SECItem back to zero, because it will
- // be used as the destination offset inside the
- // nsCRMFEncoderItemStore callback.
- der_request->len = 0;
- if (SECSuccess != CRMF_EncodeCertRequest(certReq,
- nsCRMFEncoderItemStore,
- der_request))
- return NS_ERROR_FAILURE;
- // RFC 2511 Appendix A section 2 c):
- // "A key K is derived from the shared secret Kec and the subject and
- // issuer names in the CA's certificate as follows:
- // K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)"
- PK11SymKey *shared_secret = NULL;
- PK11SymKeyCleaner shared_secret_cleaner(shared_secret);
- PK11SymKey *subject_and_secret = NULL;
- PK11SymKeyCleaner subject_and_secret_cleaner(subject_and_secret);
- PK11SymKey *subject_and_secret_and_issuer = NULL;
- PK11SymKeyCleaner subject_and_secret_and_issuer_cleaner(subject_and_secret_and_issuer);
- PK11SymKey *sha1_of_subject_and_secret_and_issuer = NULL;
- PK11SymKeyCleaner sha1_of_subject_and_secret_and_issuer_cleaner(sha1_of_subject_and_secret_and_issuer);
- shared_secret =
- PK11_PubDeriveWithKDF(keyInfo->privKey, // SECKEYPrivateKey *privKey
- keyInfo->ecPopPubKey, // SECKEYPublicKey *pubKey
- false, // bool isSender
- NULL, // SECItem *randomA
- NULL, // SECItem *randomB
- CKM_ECDH1_DERIVE, // CK_MECHANISM_TYPE derive
- CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE target
- CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
- 0, // int keySize
- CKD_NULL, // CK_ULONG kdf
- NULL, // SECItem *sharedData
- NULL); // void *wincx
- if (!shared_secret)
- return NS_ERROR_FAILURE;
- CK_KEY_DERIVATION_STRING_DATA concat_data_base;
- concat_data_base.pData = keyInfo->ecPopCert->derSubject.data;
- concat_data_base.ulLen = keyInfo->ecPopCert->derSubject.len;
- SECItem concat_data_base_item;
- concat_data_base_item.data = (unsigned char*)&concat_data_base;
- concat_data_base_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
- subject_and_secret =
- PK11_Derive(shared_secret, // PK11SymKey *baseKey
- CKM_CONCATENATE_DATA_AND_BASE, // CK_MECHANISM_TYPE mechanism
- &concat_data_base_item, // SECItem *param
- CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE target
- CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
- 0); // int keySize
- if (!subject_and_secret)
- return NS_ERROR_FAILURE;
- CK_KEY_DERIVATION_STRING_DATA concat_base_data;
- concat_base_data.pData = keyInfo->ecPopCert->derSubject.data;
- concat_base_data.ulLen = keyInfo->ecPopCert->derSubject.len;
- SECItem concat_base_data_item;
- concat_base_data_item.data = (unsigned char*)&concat_base_data;
- concat_base_data_item.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
- subject_and_secret_and_issuer =
- PK11_Derive(subject_and_secret, // PK11SymKey *baseKey
- CKM_CONCATENATE_BASE_AND_DATA, // CK_MECHANISM_TYPE mechanism
- &concat_base_data_item, // SECItem *param
- CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE target
- CKA_DERIVE, // CK_ATTRIBUTE_TYPE operation
- 0); // int keySize
- if (!subject_and_secret_and_issuer)
- return NS_ERROR_FAILURE;
- sha1_of_subject_and_secret_and_issuer =
- PK11_Derive(subject_and_secret_and_issuer, // PK11SymKey *baseKey
- CKM_SHA1_KEY_DERIVATION, // CK_MECHANISM_TYPE mechanism
- NULL, // SECItem *param
- CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE target
- CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
- 0); // int keySize
- if (!sha1_of_subject_and_secret_and_issuer)
- return NS_ERROR_FAILURE;
- PK11Context *context = NULL;
- PK11ContextCleanerTrueParam context_cleaner(context);
- SECItem ignore;
- ignore.data = 0;
- ignore.len = 0;
- context =
- PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, // CK_MECHANISM_TYPE type
- CKA_SIGN, // CK_ATTRIBUTE_TYPE operation
- sha1_of_subject_and_secret_and_issuer, // PK11SymKey *symKey
- &ignore); // SECItem *param
- if (!context)
- return NS_ERROR_FAILURE;
- if (SECSuccess != PK11_DigestBegin(context))
- return NS_ERROR_FAILURE;
- if (SECSuccess !=
- PK11_DigestOp(context, der_request->data, der_request->len))
- return NS_ERROR_FAILURE;
- SECItem *result_hmac_sha1_item = NULL;
- SECItemCleanerTrueParam result_hmac_sha1_item_cleaner(result_hmac_sha1_item);
- result_hmac_sha1_item = SECITEM_AllocItem(nsnull, nsnull, SHA1_LENGTH);
- if (!result_hmac_sha1_item)
- return NS_ERROR_FAILURE;
- if (SECSuccess !=
- PK11_DigestFinal(context,
- result_hmac_sha1_item->data,
- &result_hmac_sha1_item->len,
- SHA1_LENGTH))
- return NS_ERROR_FAILURE;
- if (SECSuccess !=
- CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfDHMAC,
- crmfNoSubseqMess, result_hmac_sha1_item))
- return NS_ERROR_FAILURE;
- return NS_OK;
- }
- static nsresult
- nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg,
- nsKeyPairInfo *keyInfo,
- CRMFCertR…