зеркало из 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
|
VerifyCAVerifier=CA Verifier
|
||||||
VerifyStatusResponder=Status Responder Certificate
|
VerifyStatusResponder=Status Responder Certificate
|
||||||
VerifyAnyCA=Any Certificate Authority
|
VerifyAnyCA=Any Certificate Authority
|
||||||
HighGrade=2048 (High Grade)
|
HighGrade=High Grade
|
||||||
MediumGrade=1024 (Medium Grade)
|
MediumGrade=Medium Grade
|
||||||
nick_template=%1$s's %2$s ID
|
nick_template=%1$s's %2$s ID
|
||||||
nick_template_with_num=%1$s's %2$s ID #%3$d
|
nick_template_with_num=%1$s's %2$s ID #%3$d
|
||||||
#These are the strings set for the ASN1 objects in a certificate.
|
#These are the strings set for the ASN1 objects in a certificate.
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsIMemory.h"
|
#include "nsIMemory.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
|
#include "nsAlgorithm.h"
|
||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "prmem.h"
|
#include "prmem.h"
|
||||||
|
@ -90,6 +91,7 @@ extern "C" {
|
||||||
#include "cmmf.h"
|
#include "cmmf.h"
|
||||||
#include "nssb64.h"
|
#include "nssb64.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
#include "cert.h"
|
||||||
#include "certdb.h"
|
#include "certdb.h"
|
||||||
#include "secmod.h"
|
#include "secmod.h"
|
||||||
#include "nsISaveAsCharset.h"
|
#include "nsISaveAsCharset.h"
|
||||||
|
@ -100,6 +102,9 @@ extern "C" {
|
||||||
NSSCleanupAutoPtrClass(SECKEYPrivateKey, SECKEY_DestroyPrivateKey)
|
NSSCleanupAutoPtrClass(SECKEYPrivateKey, SECKEY_DestroyPrivateKey)
|
||||||
NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
|
NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
|
||||||
NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
|
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 "nsNSSShutDown.h"
|
||||||
#include "nsNSSCertHelper.h"
|
#include "nsNSSCertHelper.h"
|
||||||
|
@ -138,14 +143,41 @@ NSSCleanupAutoPtrClass(CERTCertNicknames, CERT_FreeNicknames)
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
|
rsaEnc, rsaDualUse, rsaSign, rsaNonrepudiation, rsaSignNonrepudiation,
|
||||||
|
ecEnc, ecDualUse, ecSign, ecNonrepudiation, ecSignNonrepudiation,
|
||||||
dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
|
dhEx, dsaSignNonrepudiation, dsaSign, dsaNonrepudiation, invalidKeyGen
|
||||||
} nsKeyGenType;
|
} 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 {
|
typedef struct nsKeyPairInfoStr {
|
||||||
SECKEYPublicKey *pubKey; /* The putlic key associated with gen'd
|
SECKEYPublicKey *pubKey; /* The putlic key associated with gen'd
|
||||||
priv key. */
|
priv key. */
|
||||||
SECKEYPrivateKey *privKey; /* The private key we generated */
|
SECKEYPrivateKey *privKey; /* The private key we generated */
|
||||||
nsKeyGenType keyGenType; /* What type of key gen are we doing.*/
|
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;
|
} nsKeyPairInfo;
|
||||||
|
|
||||||
|
|
||||||
|
@ -404,8 +436,8 @@ nsCrypto::GetScriptPrincipal(JSContext *cx)
|
||||||
static PRBool
|
static PRBool
|
||||||
ns_can_escrow(nsKeyGenType keyGenType)
|
ns_can_escrow(nsKeyGenType keyGenType)
|
||||||
{
|
{
|
||||||
/* For now, we only escrow rsa-encryption keys. */
|
/* For now, we only escrow rsa-encryption and ec-encryption keys. */
|
||||||
return (PRBool)(keyGenType == rsaEnc);
|
return (PRBool)(keyGenType == rsaEnc || keyGenType == ecEnc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Retrieve crypto.version so that callers know what
|
//Retrieve crypto.version so that callers know what
|
||||||
|
@ -434,6 +466,13 @@ cryptojs_convert_to_mechanism(nsKeyGenType keyGenType)
|
||||||
case rsaSignNonrepudiation:
|
case rsaSignNonrepudiation:
|
||||||
retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
retMech = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
||||||
break;
|
break;
|
||||||
|
case ecEnc:
|
||||||
|
case ecDualUse:
|
||||||
|
case ecSign:
|
||||||
|
case ecNonrepudiation:
|
||||||
|
case ecSignNonrepudiation:
|
||||||
|
retMech = CKM_EC_KEY_PAIR_GEN;
|
||||||
|
break;
|
||||||
case dhEx:
|
case dhEx:
|
||||||
retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
|
retMech = CKM_DH_PKCS_KEY_PAIR_GEN;
|
||||||
break;
|
break;
|
||||||
|
@ -479,6 +518,16 @@ cryptojs_interpret_key_gen_type(char *keyAlg)
|
||||||
return rsaSignNonrepudiation;
|
return rsaSignNonrepudiation;
|
||||||
} else if (strcmp(keyAlg, "rsa-nonrepudiation") == 0) {
|
} else if (strcmp(keyAlg, "rsa-nonrepudiation") == 0) {
|
||||||
return rsaNonrepudiation;
|
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) {
|
} else if (strcmp(keyAlg, "dsa-sign-nonrepudiation") == 0) {
|
||||||
return dsaSignNonrepudiation;
|
return dsaSignNonrepudiation;
|
||||||
} else if (strcmp(keyAlg, "dsa-sign") ==0 ){
|
} else if (strcmp(keyAlg, "dsa-sign") ==0 ){
|
||||||
|
@ -491,69 +540,227 @@ cryptojs_interpret_key_gen_type(char *keyAlg)
|
||||||
return invalidKeyGen;
|
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
|
//Take the string passed into us via crypto.generateCRMFRequest
|
||||||
//as the keygen type parameter and convert it to parameters
|
//as the keygen type parameter and convert it to parameters
|
||||||
//we can actually pass to the PKCS#11 layer.
|
//we can actually pass to the PKCS#11 layer.
|
||||||
static void*
|
static void*
|
||||||
nsConvertToActualKeyGenParams(PRUint32 keyGenMech, char *params,
|
nsConvertToActualKeyGenParams(PRUint32 keyGenMech, char *params,
|
||||||
PRUint32 paramLen, PRInt32 keySize)
|
PRUint32 paramLen, PRInt32 keySize,
|
||||||
|
nsKeyPairInfo *keyPairInfo)
|
||||||
{
|
{
|
||||||
void *returnParams = nsnull;
|
void *returnParams = nsnull;
|
||||||
|
|
||||||
// We don't support passing in key generation arguments from
|
|
||||||
// the JS code just yet.
|
switch (keyGenMech) {
|
||||||
if (!params) {
|
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||||
/* In this case we provide the parameters ourselves. */
|
{
|
||||||
switch (keyGenMech) {
|
// For RSA, we don't support passing in key generation arguments from
|
||||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
// the JS code just yet.
|
||||||
{
|
if (params)
|
||||||
PK11RSAGenParams *rsaParams;
|
return nsnull;
|
||||||
rsaParams = NS_STATIC_CAST(PK11RSAGenParams*,
|
|
||||||
nsMemory::Alloc(sizeof(PK11RSAGenParams)));
|
PK11RSAGenParams *rsaParams;
|
||||||
|
rsaParams = NS_STATIC_CAST(PK11RSAGenParams*,
|
||||||
if (rsaParams == nsnull) {
|
nsMemory::Alloc(sizeof(PK11RSAGenParams)));
|
||||||
return nsnull;
|
|
||||||
}
|
if (rsaParams == nsnull) {
|
||||||
/* I'm just taking the same parameters used in
|
return nsnull;
|
||||||
* certdlgs.c:GenKey
|
|
||||||
*/
|
|
||||||
if (keySize > 0) {
|
|
||||||
rsaParams->keySizeInBits = keySize;
|
|
||||||
} else {
|
|
||||||
rsaParams->keySizeInBits = 1024;
|
|
||||||
}
|
|
||||||
rsaParams->pe = DEFAULT_RSA_KEYGEN_PE;
|
|
||||||
returnParams = rsaParams;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
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;
|
// extract components of name=value list
|
||||||
PQGVerify *vfy = nsnull;
|
|
||||||
SECStatus rv;
|
char *next_input = params;
|
||||||
int index;
|
char *name = nsnull;
|
||||||
|
char *value = nsnull;
|
||||||
index = PQG_PBITS_TO_INDEX(keySize);
|
int name_len = 0;
|
||||||
if (index == -1) {
|
int value_len = 0;
|
||||||
returnParams = nsnull;
|
|
||||||
break;
|
while (getNextNameValueFromECKeygenParamString(
|
||||||
}
|
next_input, name, name_len, value, value_len,
|
||||||
rv = PK11_PQG_ParamGen(0, &pqgParams, &vfy);
|
next_input))
|
||||||
if (vfy) {
|
{
|
||||||
PK11_PQG_DestroyVerify(vfy);
|
if (strncmp(name, "curve", NS_MIN(name_len, 5)) == 0)
|
||||||
}
|
{
|
||||||
if (rv != SECSuccess) {
|
curve = strndup(value, value_len);
|
||||||
if (pqgParams) {
|
}
|
||||||
PK11_PQG_DestroyParams(pqgParams);
|
else if (strncmp(name, "popcert", NS_MIN(name_len, 7)) == 0)
|
||||||
}
|
{
|
||||||
return nsnull;
|
char *certstr = strndup(value, value_len);
|
||||||
}
|
if (certstr) {
|
||||||
returnParams = pqgParams;
|
keyPairInfo->ecPopCert = CERT_ConvertAndDecodeCertificate(certstr);
|
||||||
break;
|
free(certstr);
|
||||||
}
|
|
||||||
default:
|
if (keyPairInfo->ecPopCert)
|
||||||
returnParams = nsnull;
|
{
|
||||||
}
|
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;
|
return returnParams;
|
||||||
}
|
}
|
||||||
|
@ -585,6 +792,9 @@ nsFreeKeyGenParams(CK_MECHANISM_TYPE keyGenMechanism, void *params)
|
||||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||||
nsMemory::Free(params);
|
nsMemory::Free(params);
|
||||||
break;
|
break;
|
||||||
|
case CKM_EC_KEY_PAIR_GEN:
|
||||||
|
SECITEM_FreeItem(NS_REINTERPRET_CAST(SECItem*, params), PR_TRUE);
|
||||||
|
break;
|
||||||
case CKM_DSA_KEY_PAIR_GEN:
|
case CKM_DSA_KEY_PAIR_GEN:
|
||||||
PK11_PQG_DestroyParams(NS_STATIC_CAST(PQGParams*,params));
|
PK11_PQG_DestroyParams(NS_STATIC_CAST(PQGParams*,params));
|
||||||
break;
|
break;
|
||||||
|
@ -610,7 +820,7 @@ cryptojs_generateOneKeyPair(JSContext *cx, nsKeyPairInfo *keyPairInfo,
|
||||||
PRUint32 mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
|
PRUint32 mechanism = cryptojs_convert_to_mechanism(keyPairInfo->keyGenType);
|
||||||
void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params,
|
void *keyGenParams = nsConvertToActualKeyGenParams(mechanism, params,
|
||||||
(params) ? strlen(params):0,
|
(params) ? strlen(params):0,
|
||||||
keySize);
|
keySize, keyPairInfo);
|
||||||
|
|
||||||
// Make sure the token has password already set on it before trying
|
// Make sure the token has password already set on it before trying
|
||||||
// to generate the key.
|
// to generate the key.
|
||||||
|
@ -852,6 +1062,10 @@ nsFreeKeyPairInfo(nsKeyPairInfo *keyids, int numIDs)
|
||||||
SECKEY_DestroyPublicKey(keyids[i].pubKey);
|
SECKEY_DestroyPublicKey(keyids[i].pubKey);
|
||||||
if (keyids[i].privKey)
|
if (keyids[i].privKey)
|
||||||
SECKEY_DestroyPrivateKey(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;
|
delete []keyids;
|
||||||
}
|
}
|
||||||
|
@ -1101,6 +1315,50 @@ nsSetRSASignNonRepudiation(CRMFCertRequest *crmfReq)
|
||||||
return nsSetKeyUsageExtension(crmfReq, keyUsage);
|
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
|
static nsresult
|
||||||
nsSetDH(CRMFCertRequest *crmfReq)
|
nsSetDH(CRMFCertRequest *crmfReq)
|
||||||
{
|
{
|
||||||
|
@ -1155,6 +1413,21 @@ nsSetKeyUsageExtension(CRMFCertRequest *crmfReq, nsKeyGenType keyGenType)
|
||||||
case rsaSignNonrepudiation:
|
case rsaSignNonrepudiation:
|
||||||
rv = nsSetRSASignNonRepudiation(crmfReq);
|
rv = nsSetRSASignNonRepudiation(crmfReq);
|
||||||
break;
|
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:
|
case dhEx:
|
||||||
rv = nsSetDH(crmfReq);
|
rv = nsSetDH(crmfReq);
|
||||||
break;
|
break;
|
||||||
|
@ -1182,7 +1455,7 @@ static CRMFCertRequest*
|
||||||
nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken,
|
nsCreateSingleCertReq(nsKeyPairInfo *keyInfo, char *reqDN, char *regToken,
|
||||||
char *authenticator, nsNSSCertificate *wrappingCert)
|
char *authenticator, nsNSSCertificate *wrappingCert)
|
||||||
{
|
{
|
||||||
PRInt32 reqID;
|
PRUint32 reqID;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
//The draft says the ID of the request should be a random
|
//The draft says the ID of the request should be a random
|
||||||
|
@ -1244,17 +1517,13 @@ loser:
|
||||||
* this means encryption only keys.
|
* this means encryption only keys.
|
||||||
*/
|
*/
|
||||||
static nsresult
|
static nsresult
|
||||||
nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg)
|
nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg, PRBool isEscrowed)
|
||||||
{
|
{
|
||||||
SECItem bitString;
|
SECItem bitString;
|
||||||
unsigned char der[2];
|
unsigned char der[2];
|
||||||
SECStatus srv;
|
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
|
/* For proof of possession on escrowed keys, we use the
|
||||||
* this Message option of POPOPrivKey and include a zero
|
* this Message option of POPOPrivKey and include a zero
|
||||||
* length bit string in the POP field. This is OK because the encrypted
|
* length bit string in the POP field. This is OK because the encrypted
|
||||||
|
@ -1276,47 +1545,271 @@ nsSetKeyEnciphermentPOP(CRMFCertReqMsg *certReqMsg)
|
||||||
crmfSubsequentMessage,
|
crmfSubsequentMessage,
|
||||||
crmfChallengeResp, nsnull);
|
crmfChallengeResp, nsnull);
|
||||||
}
|
}
|
||||||
CRMF_DestroyCertRequest(certReq);
|
|
||||||
return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
|
return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CRMF require ProofOfPossession to be set on a Certificate
|
static void PR_CALLBACK
|
||||||
//Request message. Switch on the keyGenType here and add
|
nsCRMFEncoderItemCount(void *arg, const char *buf, unsigned long len);
|
||||||
//the appropriate POP.
|
|
||||||
|
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
|
static nsresult
|
||||||
nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg,
|
nsSetProofOfPossession(CRMFCertReqMsg *certReqMsg,
|
||||||
nsKeyPairInfo *keyInfo)
|
nsKeyPairInfo *keyInfo,
|
||||||
|
CRMFCertRequest *certReq)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
// Depending on the type of cert request we'll try
|
||||||
switch (keyInfo->keyGenType) {
|
// POP mechanisms in different order,
|
||||||
case rsaSign:
|
// and add the result to the cert request message.
|
||||||
case rsaDualUse:
|
//
|
||||||
case rsaNonrepudiation:
|
// For any signing or dual use cert,
|
||||||
case rsaSignNonrepudiation:
|
// try signing first,
|
||||||
case dsaSign:
|
// fall back to DHMAC if we can
|
||||||
case dsaNonrepudiation:
|
// (EC cert requests that provide keygen param "popcert"),
|
||||||
case dsaSignNonrepudiation:
|
// otherwise fail.
|
||||||
{
|
//
|
||||||
SECStatus srv = CRMF_CertReqMsgSetSignaturePOP(certReqMsg,
|
// For encryption only certs that get escrowed, this is sufficient.
|
||||||
keyInfo->privKey,
|
//
|
||||||
keyInfo->pubKey, nsnull,
|
// For encryption only certs, that are not being escrowed,
|
||||||
nsnull, nsnull);
|
// try DHMAC if we can
|
||||||
rv = (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
|
// (EC cert requests that provide keygen param "popcert"),
|
||||||
}
|
// otherwise we'll indicate challenge response should be used.
|
||||||
break;
|
|
||||||
case rsaEnc:
|
PRBool isEncryptionOnlyCertRequest = PR_FALSE;
|
||||||
rv = nsSetKeyEnciphermentPOP(certReqMsg);
|
PRBool escrowEncryptionOnlyCert = PR_FALSE;
|
||||||
break;
|
|
||||||
case dhEx:
|
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
|
/* 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.
|
* though to the default case and return an error for diffie-hellman keys.
|
||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
rv = NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
break;
|
};
|
||||||
|
|
||||||
|
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
|
static void PR_CALLBACK
|
||||||
|
@ -1398,7 +1891,7 @@ nsCreateReqFromKeyPairs(nsKeyPairInfo *keyids, PRInt32 numRequests,
|
||||||
if (srv != SECSuccess)
|
if (srv != SECSuccess)
|
||||||
goto loser;
|
goto loser;
|
||||||
|
|
||||||
rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i]);
|
rv = nsSetProofOfPossession(certReqMsgs[i], &keyids[i], certReq);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
goto loser;
|
goto loser;
|
||||||
CRMF_DestroyCertRequest(certReq);
|
CRMF_DestroyCertRequest(certReq);
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
* the Initial Developer. All Rights Reserved.
|
* the Initial Developer. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* 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
|
* 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
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -175,6 +177,134 @@ done:
|
||||||
return primeBits;
|
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)
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeygenFormProcessor, nsIFormProcessor)
|
||||||
|
|
||||||
nsKeygenFormProcessor::nsKeygenFormProcessor()
|
nsKeygenFormProcessor::nsKeygenFormProcessor()
|
||||||
|
@ -261,6 +391,8 @@ PRUint32 MapGenMechToAlgoMech(PRUint32 mechanism)
|
||||||
/* What do we do about DES keygen? Right now, we're just using
|
/* 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
|
DES_KEY_GEN to look for tokens, because otherwise we'll have
|
||||||
to search the token list three times. */
|
to search the token list three times. */
|
||||||
|
case CKM_EC_KEY_PAIR_GEN:
|
||||||
|
/* The default should also work for EC key pair generation. */
|
||||||
default:
|
default:
|
||||||
searchMech = mechanism;
|
searchMech = mechanism;
|
||||||
break;
|
break;
|
||||||
|
@ -382,12 +514,12 @@ loser:
|
||||||
nsresult
|
nsresult
|
||||||
nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
||||||
nsAFlatString& aKeyType,
|
nsAFlatString& aKeyType,
|
||||||
nsAString& aOutPublicKey, nsAString& aPqg)
|
nsAString& aOutPublicKey, nsAString& aKeyParams)
|
||||||
{
|
{
|
||||||
nsNSSShutDownPreventionLock locker;
|
nsNSSShutDownPreventionLock locker;
|
||||||
nsresult rv = NS_ERROR_FAILURE;
|
nsresult rv = NS_ERROR_FAILURE;
|
||||||
char *keystring = nsnull;
|
char *keystring = nsnull;
|
||||||
char *pqgString = nsnull, *str = nsnull;
|
char *keyparamsString = nsnull, *str = nsnull;
|
||||||
KeyType type;
|
KeyType type;
|
||||||
PRUint32 keyGenMechanism;
|
PRUint32 keyGenMechanism;
|
||||||
PRInt32 primeBits;
|
PRInt32 primeBits;
|
||||||
|
@ -435,17 +567,17 @@ nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
||||||
keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
||||||
} else if (aKeyType.LowerCaseEqualsLiteral("dsa")) {
|
} else if (aKeyType.LowerCaseEqualsLiteral("dsa")) {
|
||||||
char * end;
|
char * end;
|
||||||
pqgString = ToNewCString(aPqg);
|
keyparamsString = ToNewCString(aKeyParams);
|
||||||
if (!pqgString) {
|
if (!keyparamsString) {
|
||||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||||
goto loser;
|
goto loser;
|
||||||
}
|
}
|
||||||
|
|
||||||
type = dsaKey;
|
type = dsaKey;
|
||||||
keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
|
keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
|
||||||
if (strcmp(pqgString, "null") == 0)
|
if (strcmp(keyparamsString, "null") == 0)
|
||||||
goto loser;
|
goto loser;
|
||||||
str = pqgString;
|
str = keyparamsString;
|
||||||
do {
|
do {
|
||||||
end = strchr(str, ',');
|
end = strchr(str, ',');
|
||||||
if (end != nsnull)
|
if (end != nsnull)
|
||||||
|
@ -458,6 +590,16 @@ nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge,
|
||||||
goto loser;
|
goto loser;
|
||||||
found_match:
|
found_match:
|
||||||
pqgParams = decode_pqg_params(str);
|
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 {
|
} else {
|
||||||
goto loser;
|
goto loser;
|
||||||
}
|
}
|
||||||
|
@ -477,6 +619,48 @@ found_match:
|
||||||
case CKM_DSA_KEY_PAIR_GEN:
|
case CKM_DSA_KEY_PAIR_GEN:
|
||||||
// XXX Fix this! XXX //
|
// XXX Fix this! XXX //
|
||||||
goto loser;
|
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:
|
default:
|
||||||
goto loser;
|
goto loser;
|
||||||
}
|
}
|
||||||
|
@ -619,8 +803,8 @@ loser:
|
||||||
if (KeygenRunnable) {
|
if (KeygenRunnable) {
|
||||||
NS_RELEASE(KeygenRunnable);
|
NS_RELEASE(KeygenRunnable);
|
||||||
}
|
}
|
||||||
if (pqgString) {
|
if (keyparamsString) {
|
||||||
nsMemory::Free(pqgString);
|
nsMemory::Free(keyparamsString);
|
||||||
}
|
}
|
||||||
if (pkac.challenge.data) {
|
if (pkac.challenge.data) {
|
||||||
nsMemory::Free(pkac.challenge.data);
|
nsMemory::Free(pkac.challenge.data);
|
||||||
|
@ -641,20 +825,31 @@ nsKeygenFormProcessor::ProcessValue(nsIDOMHTMLElement *aElement,
|
||||||
nsAutoString keygenvalue;
|
nsAutoString keygenvalue;
|
||||||
nsAutoString challengeValue;
|
nsAutoString challengeValue;
|
||||||
nsAutoString keyTypeValue;
|
nsAutoString keyTypeValue;
|
||||||
nsAutoString pqgValue;
|
nsAutoString keyParamsValue;
|
||||||
|
|
||||||
selectElement->GetAttribute(NS_LITERAL_STRING("_moz-type"), keygenvalue);
|
selectElement->GetAttribute(NS_LITERAL_STRING("_moz-type"), keygenvalue);
|
||||||
if (keygenvalue.EqualsLiteral("-mozilla-keygen")) {
|
if (keygenvalue.EqualsLiteral("-mozilla-keygen")) {
|
||||||
|
|
||||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("pqg"), pqgValue);
|
|
||||||
res = selectElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
|
res = selectElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
|
||||||
if (NS_FAILED(res) || keyTypeValue.IsEmpty()) {
|
if (NS_FAILED(res) || keyTypeValue.IsEmpty()) {
|
||||||
// If this field is not present, we default to rsa.
|
// If this field is not present, we default to rsa.
|
||||||
keyTypeValue.AssignLiteral("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);
|
res = selectElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
|
||||||
rv = GetPublicKey(aValue, challengeValue, keyTypeValue,
|
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_PE 65537L
|
||||||
#define DEFAULT_RSA_KEYGEN_ALG SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
|
#define DEFAULT_RSA_KEYGEN_ALG SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION
|
||||||
|
|
||||||
|
SECKEYECParams *decode_ec_params(char *curve);
|
||||||
|
|
||||||
class nsKeygenFormProcessor : public nsIFormProcessor {
|
class nsKeygenFormProcessor : public nsIFormProcessor {
|
||||||
public:
|
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
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче