зеркало из https://github.com/mozilla/pjs.git
Bug 326159, enhance cert request generation using KEYGEN tag and JS function crypto.generateCRMFRequest
r=rrelyea Portions of this patch originally appeared in bug 235773 and were contributed by Sheueling Chang / Vipul Gupta / Douglas Stebila
This commit is contained in:
Родитель
f7f4a3f024
Коммит
3b856d07c0
|
@ -87,8 +87,8 @@ VerifyUserImport=User Import Cert
|
|||
VerifyCAVerifier=CA Verifier
|
||||
VerifyStatusResponder=Status Responder Certificate
|
||||
VerifyAnyCA=Any Certificate Authority
|
||||
HighGrade=2048 (High Grade)
|
||||
MediumGrade=1024 (Medium Grade)
|
||||
HighGrade=High Grade
|
||||
MediumGrade=Medium Grade
|
||||
nick_template=%1$s's %2$s ID
|
||||
nick_template_with_num=%1$s's %2$s ID #%3$d
|
||||
#These are the strings set for the ASN1 objects in a certificate.
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsIServiceManager.h"
|
||||
#include "nsIMemory.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsCRT.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
|
@ -90,6 +91,7 @@ extern "C" {
|
|||
#include "cmmf.h"
|
||||
#include "nssb64.h"
|
||||
#include "base64.h"
|
||||
#include "cert.h"
|
||||
#include "certdb.h"
|
||||
#include "secmod.h"
|
||||
#include "nsISaveAsCharset.h"
|
||||
|
@ -100,6 +102,9 @@ extern "C" {
|
|||
NSSCleanupAutoPtrClass(SECKEYPrivateKey, SECKEY_DestroyPrivateKey)
|
||||
NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
|
||||
NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
|
||||
NSSCleanupAutoPtrClass(PK11SymKey, PK11_FreeSymKey)
|
||||
NSSCleanupAutoPtrClass_WithParam(PK11Context, PK11_DestroyContext, TrueParam, PR_TRUE)
|
||||
NSSCleanupAutoPtrClass_WithParam(SECItem, SECITEM_FreeItem, TrueParam, PR_TRUE)
|
||||
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsNSSCertHelper.h"
|
||||
|
@ -138,14 +143,41 @@ NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
|
|||
*/
|
||||
typedef enum {
|
||||
rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
|
||||
ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
|
||||
dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
|
||||
} nsKeyGenType;
|
||||
|
||||
PRBool isECKeyGenType(nsKeyGenType kgt)
|
||||
{
|
||||
switch (kgt)
|
||||
{
|
||||
case ecEnc:
|
||||
case ecDualUse:
|
||||
case ecSign:
|
||||
case ecNonrepudiation:
|
||||
case ecSignNonrepudiation:
|
||||
return PR_TRUE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PR_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;
|
||||
|
||||
|
||||
|
@ -404,8 +436,8 @@ nsCrypto::GetScriptPrincipal(JSContext *cx)
|
|||
static PRBool
|
||||
ns_can_escrow(nsKeyGenType keyGenType)
|
||||
{
|
||||
/* For now, we only escrow rsa-encryption keys. */
|
||||
return (PRBool)(keyGenType == rsaEnc);
|
||||
/* For now, we only escrow rsa-encryption and ec-encryption keys. */
|
||||
return (PRBool)(keyGenType == rsaEnc || keyGenType == ecEnc);
|
||||
}
|
||||
|
||||
//Retrieve crypto.version so that callers know what
|
||||
|
@ -434,6 +466,13 @@ cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
|
|||
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;
|
||||
|
@ -479,6 +518,16 @@ cryptojs_interpret_key_gen_type(char *keyAlg)
|
|||
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 ){
|
||||
|
@ -491,69 +540,227 @@ cryptojs_interpret_key_gen_type(char *keyAlg)
|
|||
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
|
||||
*/
|
||||
|
||||
PRBool getNextNameValueFromECKeygenParamString(char *input,
|
||||
char *&name,
|
||||
int &name_len,
|
||||
char *&value,
|
||||
int &value_len,
|
||||
char *&next_call)
|
||||
{
|
||||
if (!input || !*input)
|
||||
return PR_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 PR_FALSE;
|
||||
|
||||
name_len = input - name;
|
||||
++input;
|
||||
|
||||
value = input;
|
||||
|
||||
while (*input && *input != ';')
|
||||
++input;
|
||||
|
||||
value_len = input - value;
|
||||
next_call = input;
|
||||
|
||||
return PR_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)
|
||||
PRUint32 paramLen, PRInt32 keySize,
|
||||
nsKeyPairInfo *keyPairInfo)
|
||||
{
|
||||
void *returnParams = nsnull;
|
||||
|
||||
// We don't support passing in key generation arguments from
|
||||
// the JS code just yet.
|
||||
if (!params) {
|
||||
/* In this case we provide the parameters ourselves. */
|
||||
switch (keyGenMech) {
|
||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||
{
|
||||
PK11RSAGenParams *rsaParams;
|
||||
rsaParams = NS_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;
|
||||
|
||||
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 = NS_STATIC_CAST(PK11RSAGenParams*,
|
||||
nsMemory::Alloc(sizeof(PK11RSAGenParams)));
|
||||
|
||||
if (rsaParams == nsnull) {
|
||||
return nsnull;
|
||||
}
|
||||
case CKM_DSA_KEY_PAIR_GEN:
|
||||
/* 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;
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
// 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 (strncmp(name, "curve", NS_MIN(name_len, 5)) == 0)
|
||||
{
|
||||
curve = strndup(value, value_len);
|
||||
}
|
||||
else if (strncmp(name, "popcert", NS_MIN(name_len, 7)) == 0)
|
||||
{
|
||||
char *certstr = strndup(value, value_len);
|
||||
if (certstr) {
|
||||
keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
|
||||
free(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)
|
||||
free(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;
|
||||
}
|
||||
|
@ -585,6 +792,9 @@ nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
|
|||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||
nsMemory::Free(params);
|
||||
break;
|
||||
case CKM_EC_KEY_PAIR_GEN:
|
||||
SECITEM_FreeItem(NS_REINTERPRET_CAST(SECItem*, params), PR_TRUE);
|
||||
break;
|
||||
case CKM_DSA_KEY_PAIR_GEN:
|
||||
PK11_PQG_DestroyParams(NS_STATIC_CAST(PQGParams*,params));
|
||||
break;
|
||||
|
@ -610,7 +820,7 @@ cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo,
|
|||
PRUint32 mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
|
||||
void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params,
|
||||
(params) ? strlen(params):0,
|
||||
keySize);
|
||||
keySize, keyPairInfo);
|
||||
|
||||
// Make sure the token has password already set on it before trying
|
||||
// to generate the key.
|
||||
|
@ -852,6 +1062,10 @@ nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
|
|||
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;
|
||||
}
|
||||
|
@ -1101,6 +1315,50 @@ nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
|
|||
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)
|
||||
{
|
||||
|
@ -1155,6 +1413,21 @@ nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
|
|||
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;
|
||||
|
@ -1182,7 +1455,7 @@ static CRMFCertRequest*
|
|||
nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken,
|
||||
char *authenticator, nsNSSCertificate *wrappingCert)
|
||||
{
|
||||
PRInt32 reqID;
|
||||
PRUint32 reqID;
|
||||
nsresult rv;
|
||||
|
||||
//The draft says the ID of the request should be a random
|
||||
|
@ -1244,17 +1517,13 @@ loser:
|
|||
* this means encryption only keys.
|
||||
*/
|
||||
static nsresult
|
||||
nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg)
|
||||
nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, PRBool isEscrowed)
|
||||
{
|
||||
SECItem bitString;
|
||||
unsigned char der[2];
|
||||
SECStatus srv;
|
||||
CRMFCertRequest *certReq = CRMF_CertReqMsgGetCertRequest(certReqMsg);
|
||||
NS_ASSERTION(certReq,"Error getting the certRequest from the message");
|
||||
if (!certReq)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl)) {
|
||||
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
|
||||
|
@ -1276,47 +1545,271 @@ nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg)
|
|||
crmfSubsequentMessage,
|
||||
crmfChallengeResp, nsnull);
|
||||
}
|
||||
CRMF_DestroyCertRequest(certReq);
|
||||
return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//CRMF require ProofOfPossession to be set on a Certificate
|
||||
//Request message. Switch on the keyGenType here and add
|
||||
//the appropriate POP.
|
||||
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
|
||||
PR_FALSE, // PRBool 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)
|
||||
nsKeyPairInfo *keyInfo,
|
||||
CRMFCertRequest *certReq)
|
||||
{
|
||||
nsresult rv;
|
||||
switch (keyInfo->keyGenType) {
|
||||
case rsaSign:
|
||||
case rsaDualUse:
|
||||
case rsaNonrepudiation:
|
||||
case rsaSignNonrepudiation:
|
||||
case dsaSign:
|
||||
case dsaNonrepudiation:
|
||||
case dsaSignNonrepudiation:
|
||||
{
|
||||
SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
|
||||
keyInfo->privKey,
|
||||
keyInfo->pubKey, nsnull,
|
||||
nsnull, nsnull);
|
||||
rv = (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
break;
|
||||
case rsaEnc:
|
||||
rv = nsSetKeyEnciphermentPOP(certReqMsg);
|
||||
break;
|
||||
case dhEx:
|
||||
// Depending on the type of cert request we'll try
|
||||
// POP mechanisms in different order,
|
||||
// and add the result to the cert request message.
|
||||
//
|
||||
// For any signing or dual use cert,
|
||||
// try signing first,
|
||||
// fall back to DHMAC if we can
|
||||
// (EC cert requests that provide keygen param "popcert"),
|
||||
// otherwise fail.
|
||||
//
|
||||
// For encryption only certs that get escrowed, this is sufficient.
|
||||
//
|
||||
// For encryption only certs, that are not being escrowed,
|
||||
// try DHMAC if we can
|
||||
// (EC cert requests that provide keygen param "popcert"),
|
||||
// otherwise we'll indicate challenge response should be used.
|
||||
|
||||
PRBool isEncryptionOnlyCertRequest = PR_FALSE;
|
||||
PRBool escrowEncryptionOnlyCert = PR_FALSE;
|
||||
|
||||
switch (keyInfo->keyGenType)
|
||||
{
|
||||
case rsaEnc:
|
||||
case ecEnc:
|
||||
isEncryptionOnlyCertRequest = PR_TRUE;
|
||||
break;
|
||||
|
||||
case rsaSign:
|
||||
case rsaDualUse:
|
||||
case rsaNonrepudiation:
|
||||
case rsaSignNonrepudiation:
|
||||
case ecSign:
|
||||
case ecDualUse:
|
||||
case ecNonrepudiation:
|
||||
case ecSignNonrepudiation:
|
||||
case dsaSign:
|
||||
case dsaNonrepudiation:
|
||||
case dsaSignNonrepudiation:
|
||||
break;
|
||||
|
||||
case dhEx:
|
||||
/* This case may be supported in the future, but for now, we just fall
|
||||
* though to the default case and return an error for diffie-hellman keys.
|
||||
*/
|
||||
default:
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
* though to the default case and return an error for diffie-hellman keys.
|
||||
*/
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
};
|
||||
|
||||
if (isEncryptionOnlyCertRequest)
|
||||
{
|
||||
escrowEncryptionOnlyCert =
|
||||
CRMF_CertRequestIsControlPresent(certReq,crmfPKIArchiveOptionsControl);
|
||||
}
|
||||
return rv;
|
||||
|
||||
PRBool gotDHMACParameters = PR_FALSE;
|
||||
|
||||
if (isECKeyGenType(keyInfo->keyGenType) &&
|
||||
keyInfo->ecPopCert &&
|
||||
keyInfo->ecPopPubKey)
|
||||
{
|
||||
gotDHMACParameters = PR_TRUE;
|
||||
}
|
||||
|
||||
if (isEncryptionOnlyCertRequest)
|
||||
{
|
||||
if (escrowEncryptionOnlyCert)
|
||||
return nsSetKeyEnciphermentPOP(certReqMsg, PR_TRUE); // escrowed
|
||||
|
||||
if (gotDHMACParameters)
|
||||
return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
|
||||
|
||||
return nsSetKeyEnciphermentPOP(certReqMsg, PR_FALSE); // not escrowed
|
||||
}
|
||||
|
||||
// !isEncryptionOnlyCertRequest
|
||||
|
||||
SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
|
||||
keyInfo->privKey,
|
||||
keyInfo->pubKey, nsnull,
|
||||
nsnull, nsnull);
|
||||
|
||||
if (srv == SECSuccess)
|
||||
return NS_OK;
|
||||
|
||||
if (!gotDHMACParameters)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return nsSet_EC_DHMAC_ProofOfPossession(certReqMsg, keyInfo, certReq);
|
||||
}
|
||||
|
||||
static void PR_CALLBACK
|
||||
|
@ -1398,7 +1891,7 @@ nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, PRInt32 numRequests,
|
|||
if (srv != SECSuccess)
|
||||
goto loser;
|
||||
|
||||
rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i]);
|
||||
rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
|
||||
if (NS_FAILED(rv))
|
||||
goto loser;
|
||||
CRMF_DestroyCertRequest(certReq);
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vipul Gupta <vipul.gupta@sun.com>
|
||||
* Douglas Stebila <douglas@stebila.ca>
|
||||
*
|
||||
* 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
|
||||
|
@ -175,6 +177,134 @@ done:
|
|||
return primeBits;
|
||||
}
|
||||
|
||||
typedef struct curveNameTagPairStr {
|
||||
char *curveName;
|
||||
SECOidTag curveOidTag;
|
||||
} CurveNameTagPair;
|
||||
|
||||
static CurveNameTagPair nameTagPair[] =
|
||||
{
|
||||
{ "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
|
||||
{ "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
|
||||
{ "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
|
||||
{ "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
|
||||
{ "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
|
||||
{ "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
|
||||
{ "prime256v1", SEC_OID_ANSIX962_EC_PRIME256V1 },
|
||||
|
||||
{ "secp112r1", SEC_OID_SECG_EC_SECP112R1},
|
||||
{ "secp112r2", SEC_OID_SECG_EC_SECP112R2},
|
||||
{ "secp128r1", SEC_OID_SECG_EC_SECP128R1},
|
||||
{ "secp128r2", SEC_OID_SECG_EC_SECP128R2},
|
||||
{ "secp160k1", SEC_OID_SECG_EC_SECP160K1},
|
||||
{ "secp160r1", SEC_OID_SECG_EC_SECP160R1},
|
||||
{ "secp160r2", SEC_OID_SECG_EC_SECP160R2},
|
||||
{ "secp192k1", SEC_OID_SECG_EC_SECP192K1},
|
||||
{ "secp192r1", SEC_OID_ANSIX962_EC_PRIME192V1 },
|
||||
{ "nistp192", SEC_OID_ANSIX962_EC_PRIME192V1 },
|
||||
{ "secp224k1", SEC_OID_SECG_EC_SECP224K1},
|
||||
{ "secp224r1", SEC_OID_SECG_EC_SECP224R1},
|
||||
{ "nistp224", SEC_OID_SECG_EC_SECP224R1},
|
||||
{ "secp256k1", SEC_OID_SECG_EC_SECP256K1},
|
||||
{ "secp256r1", SEC_OID_ANSIX962_EC_PRIME256V1 },
|
||||
{ "nistp256", SEC_OID_ANSIX962_EC_PRIME256V1 },
|
||||
{ "secp384r1", SEC_OID_SECG_EC_SECP384R1},
|
||||
{ "nistp384", SEC_OID_SECG_EC_SECP384R1},
|
||||
{ "secp521r1", SEC_OID_SECG_EC_SECP521R1},
|
||||
{ "nistp521", SEC_OID_SECG_EC_SECP521R1},
|
||||
|
||||
{ "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
|
||||
{ "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
|
||||
{ "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
|
||||
{ "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
|
||||
{ "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
|
||||
{ "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
|
||||
{ "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
|
||||
{ "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
|
||||
{ "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
|
||||
{ "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
|
||||
{ "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
|
||||
{ "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
|
||||
{ "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
|
||||
{ "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
|
||||
{ "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
|
||||
{ "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
|
||||
{ "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
|
||||
{ "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
|
||||
{ "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
|
||||
{ "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
|
||||
|
||||
{ "sect113r1", SEC_OID_SECG_EC_SECT113R1},
|
||||
{ "sect113r2", SEC_OID_SECG_EC_SECT113R2},
|
||||
{ "sect131r1", SEC_OID_SECG_EC_SECT131R1},
|
||||
{ "sect131r2", SEC_OID_SECG_EC_SECT131R2},
|
||||
{ "sect163k1", SEC_OID_SECG_EC_SECT163K1},
|
||||
{ "nistk163", SEC_OID_SECG_EC_SECT163K1},
|
||||
{ "sect163r1", SEC_OID_SECG_EC_SECT163R1},
|
||||
{ "sect163r2", SEC_OID_SECG_EC_SECT163R2},
|
||||
{ "nistb163", SEC_OID_SECG_EC_SECT163R2},
|
||||
{ "sect193r1", SEC_OID_SECG_EC_SECT193R1},
|
||||
{ "sect193r2", SEC_OID_SECG_EC_SECT193R2},
|
||||
{ "sect233k1", SEC_OID_SECG_EC_SECT233K1},
|
||||
{ "nistk233", SEC_OID_SECG_EC_SECT233K1},
|
||||
{ "sect233r1", SEC_OID_SECG_EC_SECT233R1},
|
||||
{ "nistb233", SEC_OID_SECG_EC_SECT233R1},
|
||||
{ "sect239k1", SEC_OID_SECG_EC_SECT239K1},
|
||||
{ "sect283k1", SEC_OID_SECG_EC_SECT283K1},
|
||||
{ "nistk283", SEC_OID_SECG_EC_SECT283K1},
|
||||
{ "sect283r1", SEC_OID_SECG_EC_SECT283R1},
|
||||
{ "nistb283", SEC_OID_SECG_EC_SECT283R1},
|
||||
{ "sect409k1", SEC_OID_SECG_EC_SECT409K1},
|
||||
{ "nistk409", SEC_OID_SECG_EC_SECT409K1},
|
||||
{ "sect409r1", SEC_OID_SECG_EC_SECT409R1},
|
||||
{ "nistb409", SEC_OID_SECG_EC_SECT409R1},
|
||||
{ "sect571k1", SEC_OID_SECG_EC_SECT571K1},
|
||||
{ "nistk571", SEC_OID_SECG_EC_SECT571K1},
|
||||
{ "sect571r1", SEC_OID_SECG_EC_SECT571R1},
|
||||
{ "nistb571", SEC_OID_SECG_EC_SECT571R1},
|
||||
|
||||
};
|
||||
|
||||
SECKEYECParams *
|
||||
decode_ec_params(char *curve)
|
||||
{
|
||||
SECKEYECParams *ecparams;
|
||||
SECOidData *oidData = NULL;
|
||||
SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
|
||||
int i, numCurves;
|
||||
|
||||
if (curve && *curve) {
|
||||
numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
|
||||
for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
|
||||
i++) {
|
||||
if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
|
||||
curveOidTag = nameTagPair[i].curveOidTag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return NULL if curve name is not recognized */
|
||||
if ((curveOidTag == SEC_OID_UNKNOWN) ||
|
||||
(oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
|
||||
|
||||
if (!ecparams)
|
||||
return nsnull;
|
||||
|
||||
/*
|
||||
* ecparams->data needs to contain the ASN encoding of an object ID (OID)
|
||||
* representing the named curve. The actual OID is in
|
||||
* oidData->oid.data so we simply prepend 0x06 and OID length
|
||||
*/
|
||||
ecparams->data[0] = SEC_ASN1_OBJECT_ID;
|
||||
ecparams->data[1] = oidData->oid.len;
|
||||
memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
|
||||
|
||||
return ecparams;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenFormProcessor, nsIFormProcessor)
|
||||
|
||||
nsKeygenFormProcessor::nsKeygenFormProcessor()
|
||||
|
@ -261,6 +391,8 @@ PRUint32 MapGenMechToAlgoMech(PRUint32 mechanism)
|
|||
/* What do we do about DES keygen? Right now, we're just using
|
||||
DES_KEY_GEN to look for tokens, because otherwise we'll have
|
||||
to search the token list three times. */
|
||||
case CKM_EC_KEY_PAIR_GEN:
|
||||
/* The default should also work for EC key pair generation. */
|
||||
default:
|
||||
searchMech = mechanism;
|
||||
break;
|
||||
|
@ -382,12 +514,12 @@ loser:
|
|||
nsresult
|
||||
nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
||||
nsAFlatString& aKeyType,
|
||||
nsAString& aOutPublicKey, nsAString& aPqg)
|
||||
nsAString& aOutPublicKey, nsAString& aKeyParams)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
char *keystring = nsnull;
|
||||
char *pqgString = nsnull, *str = nsnull;
|
||||
char *keyparamsString = nsnull, *str = nsnull;
|
||||
KeyType type;
|
||||
PRUint32 keyGenMechanism;
|
||||
PRInt32 primeBits;
|
||||
|
@ -435,17 +567,17 @@ nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
|||
keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
||||
} else if (aKeyType.LowerCaseEqualsLiteral("dsa")) {
|
||||
char * end;
|
||||
pqgString = ToNewCString(aPqg);
|
||||
if (!pqgString) {
|
||||
keyparamsString = ToNewCString(aKeyParams);
|
||||
if (!keyparamsString) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto loser;
|
||||
}
|
||||
|
||||
type = dsaKey;
|
||||
keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
|
||||
if (strcmp(pqgString, "null") == 0)
|
||||
if (strcmp(keyparamsString, "null") == 0)
|
||||
goto loser;
|
||||
str = pqgString;
|
||||
str = keyparamsString;
|
||||
do {
|
||||
end = strchr(str, ',');
|
||||
if (end != nsnull)
|
||||
|
@ -458,6 +590,16 @@ nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
|||
goto loser;
|
||||
found_match:
|
||||
pqgParams = decode_pqg_params(str);
|
||||
} else if (aKeyType.LowerCaseEqualsLiteral("ec")) {
|
||||
keyparamsString = ToNewCString(aKeyParams);
|
||||
if (!keyparamsString) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto loser;
|
||||
}
|
||||
|
||||
type = ecKey;
|
||||
keyGenMechanism = CKM_EC_KEY_PAIR_GEN;
|
||||
/* ecParams are initialized later */
|
||||
} else {
|
||||
goto loser;
|
||||
}
|
||||
|
@ -477,6 +619,48 @@ found_match:
|
|||
case CKM_DSA_KEY_PAIR_GEN:
|
||||
// XXX Fix this! XXX //
|
||||
goto loser;
|
||||
case CKM_EC_KEY_PAIR_GEN:
|
||||
/* XXX We ought to rethink how the KEYGEN tag is
|
||||
* displayed. The pulldown selections presented
|
||||
* to the user must depend on the keytype.
|
||||
* The displayed selection could be picked
|
||||
* from the keyparams attribute (this is currently called
|
||||
* the pqg attribute).
|
||||
* For now, we pick ecparams from the keyparams field
|
||||
* if it specifies a valid supported curve, or else
|
||||
* we pick one of secp384r1, secp256r1 or secp192r1
|
||||
* respectively depending on the user's selection
|
||||
* (High, Medium, Low).
|
||||
* (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical
|
||||
* reasons, while ECC choices represent a stronger mapping)
|
||||
* NOTE: The user's selection
|
||||
* is silently ignored when a valid curve is presented
|
||||
* in keyparams.
|
||||
*/
|
||||
if ((params = decode_ec_params(keyparamsString)) == nsnull) {
|
||||
/* The keyparams attribute did not specify a valid
|
||||
* curve name so use a curve based on the keysize.
|
||||
* 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.
|
||||
*/
|
||||
switch (keysize) {
|
||||
case 2048:
|
||||
params = decode_ec_params("secp384r1");
|
||||
break;
|
||||
case 1024:
|
||||
case 512:
|
||||
params = decode_ec_params("secp256r1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* XXX The signature algorithm ought to choose the hashing
|
||||
* algorithm based on key size once ECDSA variations based
|
||||
* on SHA256 SHA384 and SHA512 are standardized.
|
||||
*/
|
||||
algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
|
||||
break;
|
||||
default:
|
||||
goto loser;
|
||||
}
|
||||
|
@ -619,8 +803,8 @@ loser:
|
|||
if (KeygenRunnable) {
|
||||
NS_RELEASE(KeygenRunnable);
|
||||
}
|
||||
if (pqgString) {
|
||||
nsMemory::Free(pqgString);
|
||||
if (keyparamsString) {
|
||||
nsMemory::Free(keyparamsString);
|
||||
}
|
||||
if (pkac.challenge.data) {
|
||||
nsMemory::Free(pkac.challenge.data);
|
||||
|
@ -641,20 +825,31 @@ nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement,
|
|||
nsAutoString keygenvalue;
|
||||
nsAutoString challengeValue;
|
||||
nsAutoString keyTypeValue;
|
||||
nsAutoString pqgValue;
|
||||
nsAutoString keyParamsValue;
|
||||
|
||||
selectElement->GetAttribute(NS_LITERAL_STRING("_moz-type"), keygenvalue);
|
||||
if (keygenvalue.EqualsLiteral("-mozilla-keygen")) {
|
||||
|
||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("pqg"), pqgValue);
|
||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
|
||||
if (NS_FAILED(res) || keyTypeValue.IsEmpty()) {
|
||||
// If this field is not present, we default to rsa.
|
||||
keyTypeValue.AssignLiteral("rsa");
|
||||
}
|
||||
|
||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("pqg"),
|
||||
keyParamsValue);
|
||||
/* XXX We can still support the pqg attribute in the keygen
|
||||
* tag for backward compatibility while introducing a more
|
||||
* general attribute named keyparams.
|
||||
*/
|
||||
if (NS_FAILED(res) || keyParamsValue.IsEmpty()) {
|
||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("keyparams"),
|
||||
keyParamsValue);
|
||||
}
|
||||
|
||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
|
||||
rv = GetPublicKey(aValue, challengeValue, keyTypeValue,
|
||||
aValue, pqgValue);
|
||||
aValue, keyParamsValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ nsresult GetSlotWithMechanism(PRUint32 mechanism,
|
|||
#define DEFAULT_RSA_KEYGEN_PE 65537L
|
||||
#define DEFAULT_RSA_KEYGEN_ALG SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
|
||||
|
||||
SECKEYECParams *decode_ec_params(char *curve);
|
||||
|
||||
class nsKeygenFormProcessor : public nsIFormProcessor {
|
||||
public:
|
||||
|
|
|
@ -103,4 +103,23 @@ public: \
|
|||
} \
|
||||
};
|
||||
|
||||
#define NSSCleanupAutoPtrClass_WithParam(nsstype, cleanfunc, namesuffix, paramvalue) \
|
||||
class nsstype##Cleaner##namesuffix \
|
||||
{ \
|
||||
private: \
|
||||
nsstype##Cleaner##namesuffix(const nsstype##Cleaner##namesuffix &); \
|
||||
nsstype##Cleaner##namesuffix(); \
|
||||
void operator=(const nsstype##Cleaner##namesuffix &); \
|
||||
nsstype *&object; \
|
||||
public: \
|
||||
nsstype##Cleaner##namesuffix(nsstype *&a_object) \
|
||||
:object(a_object) {} \
|
||||
~nsstype##Cleaner##namesuffix() { \
|
||||
if (object) { \
|
||||
cleanfunc(object, paramvalue); \
|
||||
object = nsnull; \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче