Bug 480280 - The CKA_EC_POINT PKCS#11 attribute is encoded in the wrong way: missing encapsulating octet string
Add code to 1) accept either type of encoding on input (both NSS and softoken). 2) output the correct encoding unless the environment variable NSS_USE_DECODED_CKA_EC_POINT is set. r= nelson git-svn-id: svn://10.0.0.236/trunk@256778 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
802675b336
commit
a177763a33
@ -107,6 +107,7 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
|
||||
CK_ATTRIBUTE *signedattr = NULL;
|
||||
CK_ATTRIBUTE *attrs = theTemplate;
|
||||
SECItem *ckaId = NULL;
|
||||
SECItem *pubValue = NULL;
|
||||
int signedcount = 0;
|
||||
int templateCount = 0;
|
||||
SECStatus rv;
|
||||
@ -203,8 +204,22 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
|
||||
PK11_SETATTRS(attrs, CKA_EC_PARAMS,
|
||||
pubKey->u.ec.DEREncodedParams.data,
|
||||
pubKey->u.ec.DEREncodedParams.len); attrs++;
|
||||
PK11_SETATTRS(attrs, CKA_EC_POINT, pubKey->u.ec.publicValue.data,
|
||||
if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) {
|
||||
PK11_SETATTRS(attrs, CKA_EC_POINT,
|
||||
pubKey->u.ec.publicValue.data,
|
||||
pubKey->u.ec.publicValue.len); attrs++;
|
||||
} else {
|
||||
pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
||||
&pubKey->u.ec.publicValue, SEC_OctetStringTemplate);
|
||||
if (pubValue == NULL) {
|
||||
if (ckaId) {
|
||||
SECITEM_FreeItem(ckaId,PR_TRUE);
|
||||
}
|
||||
return CK_INVALID_HANDLE;
|
||||
}
|
||||
PK11_SETATTRS(attrs, CKA_EC_POINT,
|
||||
pubValue->data, pubValue->len); attrs++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PORT_SetError( SEC_ERROR_BAD_KEY );
|
||||
@ -222,6 +237,9 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
|
||||
if (ckaId) {
|
||||
SECITEM_FreeItem(ckaId,PR_TRUE);
|
||||
}
|
||||
if (pubValue) {
|
||||
SECITEM_FreeItem(pubValue,PR_TRUE);
|
||||
}
|
||||
if ( rv != SECSuccess) {
|
||||
return CK_INVALID_HANDLE;
|
||||
}
|
||||
@ -237,7 +255,7 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
|
||||
* take an attribute and copy it into a secitem
|
||||
*/
|
||||
static CK_RV
|
||||
pk11_Attr2SecItem(PRArenaPool *arena, CK_ATTRIBUTE *attr, SECItem *item)
|
||||
pk11_Attr2SecItem(PRArenaPool *arena, const CK_ATTRIBUTE *attr, SECItem *item)
|
||||
{
|
||||
item->data = NULL;
|
||||
|
||||
@ -249,6 +267,309 @@ pk11_Attr2SecItem(PRArenaPool *arena, CK_ATTRIBUTE *attr, SECItem *item)
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get a curve length from a set of ecParams.
|
||||
*
|
||||
* We need this so we can reliably determine if a the ecPoint passed to us
|
||||
* was encoded or not. With out this, for many curves, we would incorrectly
|
||||
* identify an unencoded curve as an encoded curve 1 in 65536 times, and for
|
||||
* a few we would make that same mistake 1 in 32768 times. These are bad
|
||||
* numbers since they are rare enough to pass tests, but common enough to
|
||||
* be tripped over in the field.
|
||||
*
|
||||
* This function will only work for curves we recognized as of March 2009.
|
||||
* The assumption is curves in use after March of 2009 would be supplied by
|
||||
* PKCS #11 modules that already pass the correct encoding to us.
|
||||
*
|
||||
* Point length = (Roundup(curveLenInBits/8)*2+1)
|
||||
*/
|
||||
static int
|
||||
pk11_get_EC_PointLenInBytes(PRArenaPool *arena, const SECItem *ecParams)
|
||||
{
|
||||
SECItem oid;
|
||||
SECOidTag tag;
|
||||
SECStatus rv;
|
||||
|
||||
/* decode the OID tag */
|
||||
rv = SEC_QuickDERDecodeItem(arena, &oid,
|
||||
SEC_ObjectIDTemplate, ecParams);
|
||||
if (rv != SECSuccess) {
|
||||
/* could be explict curves, allow them to work if the
|
||||
* PKCS #11 module support them. If we try to parse the
|
||||
* explicit curve value in the future, we may return -1 here
|
||||
* to indicate an invalid parameter if the explicit curve
|
||||
* decode fails. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
tag = SECOID_FindOIDTag(&oid);
|
||||
switch (tag) {
|
||||
case SEC_OID_SECG_EC_SECP112R1:
|
||||
case SEC_OID_SECG_EC_SECP112R2:
|
||||
return 29; /* curve len in bytes = 14 bytes */
|
||||
case SEC_OID_SECG_EC_SECT113R1:
|
||||
case SEC_OID_SECG_EC_SECT113R2:
|
||||
return 31; /* curve len in bytes = 15 bytes */
|
||||
case SEC_OID_SECG_EC_SECP128R1:
|
||||
case SEC_OID_SECG_EC_SECP128R2:
|
||||
return 33; /* curve len in bytes = 16 bytes */
|
||||
case SEC_OID_SECG_EC_SECT131R1:
|
||||
case SEC_OID_SECG_EC_SECT131R2:
|
||||
return 35; /* curve len in bytes = 17 bytes */
|
||||
case SEC_OID_SECG_EC_SECP160K1:
|
||||
case SEC_OID_SECG_EC_SECP160R1:
|
||||
case SEC_OID_SECG_EC_SECP160R2:
|
||||
return 41; /* curve len in bytes = 20 bytes */
|
||||
case SEC_OID_SECG_EC_SECT163K1:
|
||||
case SEC_OID_SECG_EC_SECT163R1:
|
||||
case SEC_OID_SECG_EC_SECT163R2:
|
||||
case SEC_OID_ANSIX962_EC_C2PNB163V1:
|
||||
case SEC_OID_ANSIX962_EC_C2PNB163V2:
|
||||
case SEC_OID_ANSIX962_EC_C2PNB163V3:
|
||||
return 43; /* curve len in bytes = 21 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2PNB176V1:
|
||||
return 45; /* curve len in bytes = 22 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2TNB191V1:
|
||||
case SEC_OID_ANSIX962_EC_C2TNB191V2:
|
||||
case SEC_OID_ANSIX962_EC_C2TNB191V3:
|
||||
case SEC_OID_SECG_EC_SECP192K1:
|
||||
case SEC_OID_ANSIX962_EC_PRIME192V1:
|
||||
case SEC_OID_ANSIX962_EC_PRIME192V2:
|
||||
case SEC_OID_ANSIX962_EC_PRIME192V3:
|
||||
return 49; /*curve len in bytes = 24 bytes */
|
||||
case SEC_OID_SECG_EC_SECT193R1:
|
||||
case SEC_OID_SECG_EC_SECT193R2:
|
||||
return 51; /*curve len in bytes = 25 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2PNB208W1:
|
||||
return 53; /*curve len in bytes = 26 bytes */
|
||||
case SEC_OID_SECG_EC_SECP224K1:
|
||||
case SEC_OID_SECG_EC_SECP224R1:
|
||||
return 57; /*curve len in bytes = 28 bytes */
|
||||
case SEC_OID_SECG_EC_SECT233K1:
|
||||
case SEC_OID_SECG_EC_SECT233R1:
|
||||
case SEC_OID_SECG_EC_SECT239K1:
|
||||
case SEC_OID_ANSIX962_EC_PRIME239V1:
|
||||
case SEC_OID_ANSIX962_EC_PRIME239V2:
|
||||
case SEC_OID_ANSIX962_EC_PRIME239V3:
|
||||
case SEC_OID_ANSIX962_EC_C2TNB239V1:
|
||||
case SEC_OID_ANSIX962_EC_C2TNB239V2:
|
||||
case SEC_OID_ANSIX962_EC_C2TNB239V3:
|
||||
return 61; /*curve len in bytes = 30 bytes */
|
||||
case SEC_OID_ANSIX962_EC_PRIME256V1:
|
||||
case SEC_OID_SECG_EC_SECP256K1:
|
||||
return 65; /*curve len in bytes = 32 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2PNB272W1:
|
||||
return 69; /*curve len in bytes = 34 bytes */
|
||||
case SEC_OID_SECG_EC_SECT283K1:
|
||||
case SEC_OID_SECG_EC_SECT283R1:
|
||||
return 73; /*curve len in bytes = 36 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2PNB304W1:
|
||||
return 77; /*curve len in bytes = 38 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2TNB359V1:
|
||||
return 91; /*curve len in bytes = 45 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2PNB368W1:
|
||||
return 93; /*curve len in bytes = 46 bytes */
|
||||
case SEC_OID_SECG_EC_SECP384R1:
|
||||
return 97; /*curve len in bytes = 48 bytes */
|
||||
case SEC_OID_SECG_EC_SECT409K1:
|
||||
case SEC_OID_SECG_EC_SECT409R1:
|
||||
return 105; /*curve len in bytes = 52 bytes */
|
||||
case SEC_OID_ANSIX962_EC_C2TNB431R1:
|
||||
return 109; /*curve len in bytes = 54 bytes */
|
||||
case SEC_OID_SECG_EC_SECP521R1:
|
||||
return 133; /*curve len in bytes = 66 bytes */
|
||||
case SEC_OID_SECG_EC_SECT571K1:
|
||||
case SEC_OID_SECG_EC_SECT571R1:
|
||||
return 145; /*curve len in bytes = 72 bytes */
|
||||
/* unknown or unrecognized OIDs. return unknown length */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the decoded point. In some cases the point may already be decoded.
|
||||
* this function tries to detect those cases and return the point in
|
||||
* publicKeyValue. In other cases it's DER encoded. In those cases the point
|
||||
* is first decoded and returned. Space for the point is allocated out of
|
||||
* the passed in arena.
|
||||
*/
|
||||
static CK_RV
|
||||
pk11_get_Decoded_ECPoint(PRArenaPool *arena, const SECItem *ecParams,
|
||||
const CK_ATTRIBUTE *ecPoint, SECItem *publicKeyValue)
|
||||
{
|
||||
SECItem encodedPublicValue;
|
||||
SECStatus rv;
|
||||
int keyLen;
|
||||
|
||||
if (ecPoint->ulValueLen == 0) {
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PKCS #11 spec requires ecPoints to be encoded as a DER OCTET String.
|
||||
* NSS has mistakenly passed unencoded values, and some PKCS #11 vendors
|
||||
* followed that mistake. Now we need to detect which encoding we were
|
||||
* passed in. The task is made more complicated by the fact the the
|
||||
* DER encoding byte (SEC_ASN_OCTET_STRING) is the same as the
|
||||
* EC_POINT_FORM_UNCOMPRESSED byte (0x04), so we can't use that to
|
||||
* determine which curve we are using.
|
||||
*/
|
||||
|
||||
/* get the expected key length for the passed in curve.
|
||||
* pk11_get_EC_PointLenInBytes only returns valid values for curves
|
||||
* NSS has traditionally recognized. If the curve is not recognized,
|
||||
* it will return '0', and we have to figure out if the key was
|
||||
* encoded or not heuristically. If the ecParams are invalid, it
|
||||
* will return -1 for the keyLen.
|
||||
*/
|
||||
keyLen = pk11_get_EC_PointLenInBytes(arena, ecParams);
|
||||
if (keyLen < 0) {
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/* If the point is uncompressed and the lengths match, it
|
||||
* must be an unencoded point */
|
||||
if ((*((char *)ecPoint->pValue) == EC_POINT_FORM_UNCOMPRESSED)
|
||||
&& (ecPoint->ulValueLen == keyLen)) {
|
||||
return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
|
||||
}
|
||||
|
||||
/* now assume the key passed to us was encoded and decode it */
|
||||
if (*((char *)ecPoint->pValue) == SEC_ASN1_OCTET_STRING) {
|
||||
/* OK, now let's try to decode it and see if it's valid */
|
||||
encodedPublicValue.data = ecPoint->pValue;
|
||||
encodedPublicValue.len = ecPoint->ulValueLen;
|
||||
rv = SEC_QuickDERDecodeItem(arena, publicKeyValue,
|
||||
SEC_OctetStringTemplate, &encodedPublicValue);
|
||||
|
||||
/* it coded correctly & we know the key length (and they match)
|
||||
* then we are done, return the results. */
|
||||
if (keyLen && rv == SECSuccess && publicKeyValue->len == keyLen) {
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
/* if we know the key length, one of the above tests should have
|
||||
* succeded. If it doesn't the module gave us bad data */
|
||||
if (keyLen) {
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/* We don't know the key length, so we don't know deterministically
|
||||
* which encoding was used. We now will try to pick the most likely
|
||||
* form that's correct, with a preference for the encoded form if we
|
||||
* can't determine for sure. We do this by checking the key we got
|
||||
* back from SEC_QuickDERDecodeItem for defects. If no defects are
|
||||
* found, we assume the encoded paramter was was passed to us.
|
||||
* our defect tests include:
|
||||
* 1) it didn't decode.
|
||||
* 2) The decode key had an invalid length (must be odd).
|
||||
* 3) The decoded key wasn't an UNCOMPRESSED key.
|
||||
* 4) The decoded key didn't include the entire encoded block
|
||||
* except the DER encoding values. (fixing DER length to one
|
||||
* particular value).
|
||||
*/
|
||||
if ((rv != SECSuccess)
|
||||
|| ((publicKeyValue->len & 1) != 1)
|
||||
|| (publicKeyValue->data[0] != EC_POINT_FORM_UNCOMPRESSED)
|
||||
|| (PORT_Memcmp(&encodedPublicValue.data[encodedPublicValue.len -
|
||||
publicKeyValue->len], publicKeyValue->data,
|
||||
publicKeyValue->len) != 0)) {
|
||||
/* The decoded public key was flawed, the original key must have
|
||||
* already been in decoded form. Do a quick sanity check then
|
||||
* return the original key value.
|
||||
*/
|
||||
if ((encodedPublicValue.len & 1) == 0) {
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
|
||||
}
|
||||
|
||||
/* as best we can figure, the passed in key was encoded, and we've
|
||||
* now decoded it. Note: there is a chance this could be wrong if the
|
||||
* following conditions hold:
|
||||
* 1) The first byte or bytes of the X point looks like a valid length
|
||||
* of precisely the right size (2*curveSize -1). this means for curves
|
||||
* less than 512 bits (64 bytes), this will happen 1 in 256 times*.
|
||||
* for curves between 512 and 1024, this will happen 1 in 65,536 times*
|
||||
* for curves between 1024 and 256K this will happen 1 in 16 million*
|
||||
* 2) The length of the 'DER length field' is odd
|
||||
* (making both the encoded and decode
|
||||
* values an odd length. this is true of all curves less than 512,
|
||||
* as well as curves between 1024 and 256K).
|
||||
* 3) The X[length of the 'DER length field'] == 0x04, 1 in 256.
|
||||
*
|
||||
* (* assuming all values are equally likely in the first byte,
|
||||
* This isn't true if the curve length is not a multiple of 8. In these
|
||||
* cases, if the DER length is possible, it's more likely,
|
||||
* if it's not possible, then we have no false decodes).
|
||||
*
|
||||
* For reference here are the odds for the various curves we currently
|
||||
* have support for (and the only curves SSL will negotiate at this
|
||||
* time). NOTE: None of the supported curves will show up here
|
||||
* because we return a valid length for all of these curves.
|
||||
* The only way to get here is to have some application (not SSL)
|
||||
* which supports some unknown curve and have some vendor supplied
|
||||
* PKCS #11 module support that curve. NOTE: in this case, one
|
||||
* presumes that that pkcs #11 module is likely to be using the
|
||||
* correct encodings.
|
||||
*
|
||||
* Prime Curves (GFp):
|
||||
* Bit False Odds of
|
||||
* Size DER Len False Decode Positive
|
||||
* 112 27 1 in 65536
|
||||
* 128 31 1 in 65536
|
||||
* 160 39 1 in 65536
|
||||
* 192 47 1 in 65536
|
||||
* 224 55 1 in 65536
|
||||
* 239 59 1 in 32768 (top byte can only be 0-127)
|
||||
* 256 63 1 in 65536
|
||||
* 521 129,131 0 (decoded value would be even)
|
||||
*
|
||||
* Binary curves (GF2m).
|
||||
* Bit False Odds of
|
||||
* Size DER Len False Decode Positive
|
||||
* 131 33 0 (top byte can only be 0-7)
|
||||
* 163 41 0 (top byte can only be 0-7)
|
||||
* 176 43 1 in 65536
|
||||
* 191 47 1 in 32768 (top byte can only be 0-127)
|
||||
* 193 49 0 (top byte can only be 0-1)
|
||||
* 208 51 1 in 65536
|
||||
* 233 59 0 (top byte can only be 0-1)
|
||||
* 239 59 1 in 32768 (top byte can only be 0-127)
|
||||
* 272 67 1 in 65536
|
||||
* 283 71 0 (top byte can only be 0-7)
|
||||
* 304 75 1 in 65536
|
||||
* 359 89 1 in 32768 (top byte can only be 0-127)
|
||||
* 368 91 1 in 65536
|
||||
* 409 103 0 (top byte can only be 0-1)
|
||||
* 431 107 1 in 32768 (top byte can only be 0-127)
|
||||
* 571 129,143 0 (decoded value would be even)
|
||||
*
|
||||
*/
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
/* In theory, we should handle the case where the curve == 0 and
|
||||
* the first byte is EC_POINT_FORM_UNCOMPRESSED, (which would be
|
||||
* handled by doing a santity check on the key length and returning
|
||||
* pk11_Attr2SecItem() to copy the ecPoint to the publicKeyValue).
|
||||
*
|
||||
* This test is unnecessary, however, due to the fact that
|
||||
* EC_POINT_FORM_UNCOMPRESSED == SEC_ASIN1_OCTET_STRING, that case is
|
||||
* handled in the above if. That means if we get here, the initial
|
||||
* byte of our ecPoint value was invalid, so we can safely return.
|
||||
* invalid attribute.
|
||||
*/
|
||||
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* extract a public key from a slot and id
|
||||
*/
|
||||
@ -399,7 +720,7 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id)
|
||||
PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++;
|
||||
templateCount = attrs - template;
|
||||
PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE));
|
||||
crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount);
|
||||
crv = PK11_GetAttributes(arena,slot,id,template,templateCount);
|
||||
if (crv != CKR_OK) break;
|
||||
|
||||
if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) {
|
||||
@ -410,8 +731,9 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id)
|
||||
crv = pk11_Attr2SecItem(arena,ecparams,
|
||||
&pubKey->u.ec.DEREncodedParams);
|
||||
if (crv != CKR_OK) break;
|
||||
crv = pk11_Attr2SecItem(arena,value,&pubKey->u.ec.publicValue);
|
||||
if (crv != CKR_OK) break;
|
||||
crv = pk11_get_Decoded_ECPoint(arena,
|
||||
&pubKey->u.ec.DEREncodedParams, value,
|
||||
&pubKey->u.ec.publicValue);
|
||||
break;
|
||||
case fortezzaKey:
|
||||
case nullKey:
|
||||
|
||||
@ -1614,6 +1614,7 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
||||
mechanism.mechanism = derive;
|
||||
|
||||
/* we can undefine these when we define diffie-helman keys */
|
||||
|
||||
mechanism.pParameter = pubKey->u.dh.publicValue.data;
|
||||
mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
|
||||
|
||||
@ -1635,6 +1636,7 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
||||
int templateCount;
|
||||
CK_ATTRIBUTE *attrs = keyTemplate;
|
||||
CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
|
||||
SECItem *pubValue = NULL;
|
||||
|
||||
if (pubKey->keyType != ecKey) {
|
||||
PORT_SetError(SEC_ERROR_BAD_KEY);
|
||||
@ -1660,8 +1662,20 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
||||
mechParams->kdf = CKD_SHA1_KDF;
|
||||
mechParams->ulSharedDataLen = 0;
|
||||
mechParams->pSharedData = NULL;
|
||||
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
||||
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
||||
|
||||
if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) {
|
||||
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
||||
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
||||
} else {
|
||||
pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
||||
&pubKey->u.ec.publicValue, SEC_OctetStringTemplate);
|
||||
if (pubValue == NULL) {
|
||||
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
||||
break;
|
||||
}
|
||||
mechParams->ulPublicDataLen = pubValue->len;
|
||||
mechParams->pPublicData = pubValue->data;
|
||||
}
|
||||
|
||||
mechanism.mechanism = derive;
|
||||
mechanism.pParameter = mechParams;
|
||||
@ -1673,6 +1687,9 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
|
||||
templateCount, &symKey->objectID);
|
||||
pk11_ExitKeyMonitor(symKey);
|
||||
|
||||
if (pubValue) {
|
||||
SECITEM_FreeItem(pubValue,PR_TRUE);
|
||||
}
|
||||
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
||||
|
||||
if (crv == CKR_OK) return symKey;
|
||||
@ -1704,6 +1721,7 @@ pk11_PubDeriveECKeyWithKDF(
|
||||
int templateCount;
|
||||
CK_ATTRIBUTE *attrs = keyTemplate;
|
||||
CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
|
||||
SECItem *pubValue = NULL;
|
||||
|
||||
if (pubKey->keyType != ecKey) {
|
||||
PORT_SetError(SEC_ERROR_BAD_KEY);
|
||||
@ -1748,8 +1766,20 @@ pk11_PubDeriveECKeyWithKDF(
|
||||
mechParams->ulSharedDataLen = sharedData->len;
|
||||
mechParams->pSharedData = sharedData->data;
|
||||
}
|
||||
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
||||
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
||||
if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) {
|
||||
mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
|
||||
mechParams->pPublicData = pubKey->u.ec.publicValue.data;
|
||||
} else {
|
||||
pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
||||
&pubKey->u.ec.publicValue, SEC_OctetStringTemplate);
|
||||
if (pubValue == NULL) {
|
||||
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
||||
PK11_FreeSymKey(symKey);
|
||||
return NULL;
|
||||
}
|
||||
mechParams->ulPublicDataLen = pubValue->len;
|
||||
mechParams->pPublicData = pubValue->data;
|
||||
}
|
||||
|
||||
mechanism.mechanism = derive;
|
||||
mechanism.pParameter = mechParams;
|
||||
@ -1761,6 +1791,9 @@ pk11_PubDeriveECKeyWithKDF(
|
||||
pk11_ExitKeyMonitor(symKey);
|
||||
|
||||
PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
|
||||
if (pubValue) {
|
||||
SECITEM_FreeItem(pubValue,PR_TRUE);
|
||||
}
|
||||
|
||||
if (crv != CKR_OK) {
|
||||
PK11_FreeSymKey(symKey);
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
#include "pcert.h"
|
||||
#include "blapi.h"
|
||||
#include "secerr.h"
|
||||
#include "secasn1.h"
|
||||
|
||||
/*
|
||||
* Cache the object we are working on during Set's and Get's
|
||||
@ -610,9 +611,23 @@ lg_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type,
|
||||
key->u.ec.ecParams.DEREncoding.data,
|
||||
key->u.ec.ecParams.DEREncoding.len);
|
||||
case CKA_EC_POINT:
|
||||
return lg_CopyAttributeSigned(attribute, type,
|
||||
if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) {
|
||||
return lg_CopyAttributeSigned(attribute, type,
|
||||
key->u.ec.publicValue.data,
|
||||
key->u.ec.publicValue.len);
|
||||
} else {
|
||||
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
||||
&(key->u.ec.publicValue), SEC_OctetStringTemplate);
|
||||
CK_RV crv;
|
||||
if (!pubValue) {
|
||||
return CKR_HOST_MEMORY;
|
||||
}
|
||||
crv = lg_CopyAttributeSigned(attribute, type,
|
||||
pubValue->data,
|
||||
pubValue->len);
|
||||
SECITEM_FreeItem(pubValue, PR_TRUE);
|
||||
return crv;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "lowkeyi.h"
|
||||
#include "blapi.h"
|
||||
#include "secder.h"
|
||||
#include "secasn1.h"
|
||||
|
||||
#include "keydbi.h"
|
||||
|
||||
@ -429,10 +430,16 @@ lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type,
|
||||
CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count)
|
||||
{
|
||||
CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE;
|
||||
CK_RV crv;
|
||||
CK_RV crv = CKR_OK;
|
||||
NSSLOWKEYPrivateKey *priv;
|
||||
SECItem pubKey;
|
||||
SECItem pubKeySpace = {siBuffer, NULL, 0};
|
||||
SECItem *pubKey;
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
SECItem pubKey2Space = {siBuffer, NULL, 0};
|
||||
PRArenaPool *arena = NULL;
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
NSSLOWKEYDBHandle *keyHandle = NULL;
|
||||
|
||||
|
||||
switch (key_type) {
|
||||
case CKK_RSA:
|
||||
@ -451,34 +458,80 @@ lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type,
|
||||
}
|
||||
|
||||
|
||||
crv = lg_Attribute2SSecItem(NULL,pubKeyAttr,templ,count,&pubKey);
|
||||
pubKey = &pubKeySpace;
|
||||
crv = lg_Attribute2SSecItem(NULL,pubKeyAttr,templ,count,pubKey);
|
||||
if (crv != CKR_OK) return crv;
|
||||
|
||||
PORT_Assert(pubKey.data);
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
if (key_type == CKK_EC) {
|
||||
SECStatus rv;
|
||||
/*
|
||||
* for ECC, use the decoded key first.
|
||||
*/
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (arena == NULL) {
|
||||
crv = CKR_HOST_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
rv= SEC_QuickDERDecodeItem(arena, &pubKey2Space,
|
||||
SEC_OctetStringTemplate, pubKey);
|
||||
if (rv != SECSuccess) {
|
||||
/* decode didn't work, just try the pubKey */
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
arena = NULL;
|
||||
} else {
|
||||
/* try the decoded pub key first */
|
||||
pubKey = &pubKey2Space;
|
||||
}
|
||||
}
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
PORT_Assert(pubKey->data);
|
||||
if (pubKey->data == NULL) {
|
||||
crv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
goto done;
|
||||
}
|
||||
keyHandle = lg_getKeyDB(sdb);
|
||||
if (keyHandle == NULL) {
|
||||
PORT_Free(pubKey.data);
|
||||
return CKR_TOKEN_WRITE_PROTECTED;
|
||||
crv = CKR_TOKEN_WRITE_PROTECTED;
|
||||
goto done;
|
||||
}
|
||||
if (keyHandle->version != 3) {
|
||||
unsigned char buf[SHA1_LENGTH];
|
||||
SHA1_HashBuf(buf,pubKey.data,pubKey.len);
|
||||
PORT_Memcpy(pubKey.data,buf,sizeof(buf));
|
||||
pubKey.len = sizeof(buf);
|
||||
SHA1_HashBuf(buf,pubKey->data,pubKey->len);
|
||||
PORT_Memcpy(pubKey->data,buf,sizeof(buf));
|
||||
pubKey->len = sizeof(buf);
|
||||
}
|
||||
/* make sure the associated private key already exists */
|
||||
/* only works if we are logged in */
|
||||
priv = nsslowkey_FindKeyByPublicKey(keyHandle, &pubKey, sdb /*password*/);
|
||||
priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, sdb /*password*/);
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
if (priv == NULL && pubKey == &pubKey2Space) {
|
||||
/* no match on the decoded key, match the original pubkey */
|
||||
pubKey = &pubKeySpace;
|
||||
priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey,
|
||||
sdb /*password*/);
|
||||
}
|
||||
#endif
|
||||
if (priv == NULL) {
|
||||
PORT_Free(pubKey.data);
|
||||
return crv;
|
||||
/* the legacy database can only 'store' public keys which already
|
||||
* have their corresponding private keys in the database */
|
||||
crv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
goto done;
|
||||
}
|
||||
nsslowkey_DestroyPrivateKey(priv);
|
||||
crv = CKR_OK;
|
||||
|
||||
*handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_PUB);
|
||||
PORT_Free(pubKey.data);
|
||||
*handle = lg_mkHandle(sdb, pubKey, LG_TOKEN_TYPE_PUB);
|
||||
|
||||
return CKR_OK;
|
||||
done:
|
||||
PORT_Free(pubKeySpace.data);
|
||||
#ifdef NSS_ENABLE_ECC
|
||||
if (arena)
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
#endif
|
||||
|
||||
return crv;
|
||||
}
|
||||
|
||||
/* make a private key from a verified object */
|
||||
|
||||
@ -67,6 +67,8 @@
|
||||
#include "secoid.h"
|
||||
#include "sftkdb.h"
|
||||
#include "sftkpars.h"
|
||||
#include "ec.h"
|
||||
#include "secasn1.h"
|
||||
|
||||
PRBool parentForkedAfterC_Initialize;
|
||||
|
||||
@ -851,7 +853,6 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
|
||||
CK_BBOOL wrap = CK_TRUE;
|
||||
CK_BBOOL derive = CK_FALSE;
|
||||
CK_BBOOL verify = CK_TRUE;
|
||||
CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE;
|
||||
CK_RV crv;
|
||||
|
||||
switch (key_type) {
|
||||
@ -865,7 +866,6 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
|
||||
if (crv != CKR_OK) {
|
||||
return crv;
|
||||
}
|
||||
pubKeyAttr = CKA_MODULUS;
|
||||
break;
|
||||
case CKK_DSA:
|
||||
crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME,
|
||||
@ -918,7 +918,6 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
|
||||
if ( !sftk_hasAttribute(object, CKA_EC_POINT)) {
|
||||
return CKR_TEMPLATE_INCOMPLETE;
|
||||
}
|
||||
pubKeyAttr = CKA_EC_POINT;
|
||||
derive = CK_TRUE; /* for ECDH */
|
||||
verify = CK_TRUE; /* for ECDSA */
|
||||
encrypt = CK_FALSE;
|
||||
@ -1258,7 +1257,6 @@ sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
|
||||
{
|
||||
SFTKAttribute *attribute;
|
||||
CK_KEY_TYPE key_type;
|
||||
CK_BBOOL cktrue = CK_TRUE;
|
||||
CK_BBOOL ckfalse = CK_FALSE;
|
||||
CK_RV crv;
|
||||
|
||||
@ -1636,6 +1634,45 @@ NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,CK_KEY_TYPE key_type,
|
||||
|
||||
crv = sftk_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue,
|
||||
object,CKA_EC_POINT);
|
||||
if (crv == CKR_OK) {
|
||||
int keyLen,curveLen;
|
||||
|
||||
curveLen = (pubKey->u.ec.ecParams.fieldID.size +7)/8;
|
||||
keyLen = (2*curveLen)+1;
|
||||
|
||||
/* special note: We can't just use the first byte to determine
|
||||
* between these 2 cases because both EC_POINT_FORM_UNCOMPRESSED
|
||||
* and SEC_ASN1_OCTET_STRING are 0x04 */
|
||||
|
||||
/* handle the non-DER encoded case (UNCOMPRESSED only) */
|
||||
if (pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED
|
||||
&& pubKey->u.ec.publicValue.len == keyLen) {
|
||||
break; /* key was not DER encoded, no need to unwrap */
|
||||
}
|
||||
|
||||
/* if we ever support compressed, handle it here */
|
||||
|
||||
/* handle the encoded case */
|
||||
if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING)
|
||||
&& pubKey->u.ec.publicValue.len > keyLen) {
|
||||
SECItem publicValue;
|
||||
SECStatus rv;
|
||||
|
||||
rv = SEC_QuickDERDecodeItem(arena, &publicValue,
|
||||
SEC_OctetStringTemplate, &pubKey->u.ec.publicValue);
|
||||
/* nope, didn't decode correctly */
|
||||
if ((rv != SECSuccess)
|
||||
|| (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)
|
||||
|| (publicValue.len != keyLen)) {
|
||||
crv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
break;
|
||||
}
|
||||
/* replace our previous with the decoded key */
|
||||
pubKey->u.ec.publicValue = publicValue;
|
||||
break;
|
||||
}
|
||||
crv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
break;
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
default:
|
||||
|
||||
@ -4017,8 +4017,20 @@ dhgn_done:
|
||||
break;
|
||||
}
|
||||
|
||||
crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT,
|
||||
if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) {
|
||||
crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT,
|
||||
sftk_item_expand(&ecPriv->publicValue));
|
||||
} else {
|
||||
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
|
||||
&ecPriv->publicValue, SEC_OctetStringTemplate);
|
||||
if (!pubValue) {
|
||||
crv = CKR_ARGUMENTS_BAD;
|
||||
goto ecgn_done;
|
||||
}
|
||||
crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT,
|
||||
sftk_item_expand(pubValue));
|
||||
SECITEM_FreeItem(pubValue, PR_TRUE);
|
||||
}
|
||||
if (crv != CKR_OK) goto ecgn_done;
|
||||
|
||||
crv = sftk_AddAttributeType(privateKey, CKA_VALUE,
|
||||
@ -5843,9 +5855,10 @@ key_and_mac_derive_fail:
|
||||
unsigned char secret_hash[20];
|
||||
unsigned char *secret;
|
||||
unsigned char *keyData = NULL;
|
||||
int secretlen;
|
||||
int secretlen, curveLen, pubKeyLen;
|
||||
CK_ECDH1_DERIVE_PARAMS *mechParams;
|
||||
NSSLOWKEYPrivateKey *privKey;
|
||||
PLArenaPool *arena = NULL;
|
||||
|
||||
/* Check mechanism parameters */
|
||||
mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter;
|
||||
@ -5868,6 +5881,31 @@ key_and_mac_derive_fail:
|
||||
ecPoint.data = mechParams->pPublicData;
|
||||
ecPoint.len = mechParams->ulPublicDataLen;
|
||||
|
||||
curveLen = (privKey->u.ec.ecParams.fieldID.size +7)/8;
|
||||
pubKeyLen = (2*curveLen) + 1;
|
||||
|
||||
/* if the len is too small, can't be a valid point */
|
||||
if (ecPoint.len < pubKeyLen) {
|
||||
goto ec_loser;
|
||||
}
|
||||
/* if the len is too large, must be an encoded point (length is
|
||||
* equal case just falls through */
|
||||
if (ecPoint.len > pubKeyLen) {
|
||||
SECItem newPoint;
|
||||
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
if (arena == NULL) {
|
||||
goto ec_loser;
|
||||
}
|
||||
|
||||
rv = SEC_QuickDERDecodeItem(arena, &newPoint,
|
||||
SEC_OctetStringTemplate, &ecPoint);
|
||||
if (rv != SECSuccess) {
|
||||
goto ec_loser;
|
||||
}
|
||||
ecPoint = newPoint;
|
||||
}
|
||||
|
||||
if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
|
||||
withCofactor = PR_TRUE;
|
||||
} else {
|
||||
@ -5877,19 +5915,22 @@ key_and_mac_derive_fail:
|
||||
*/
|
||||
if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint)
|
||||
!= SECSuccess) {
|
||||
crv = CKR_ARGUMENTS_BAD;
|
||||
PORT_Free(ecScalar.data);
|
||||
if (privKey != sourceKey->objectInfo)
|
||||
nsslowkey_DestroyPrivateKey(privKey);
|
||||
break;
|
||||
goto ec_loser;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar,
|
||||
withCofactor, &tmp);
|
||||
PORT_Free(ecScalar.data);
|
||||
if (privKey != sourceKey->objectInfo)
|
||||
ecScalar.data = NULL;
|
||||
if (privKey != sourceKey->objectInfo) {
|
||||
nsslowkey_DestroyPrivateKey(privKey);
|
||||
privKey=NULL;
|
||||
}
|
||||
if (arena) {
|
||||
PORT_FreeArena(arena,PR_FALSE);
|
||||
arena=NULL;
|
||||
}
|
||||
|
||||
if (rv != SECSuccess) {
|
||||
crv = sftk_MapCryptError(PORT_GetError());
|
||||
@ -5951,6 +5992,17 @@ key_and_mac_derive_fail:
|
||||
PORT_Memset(secret_hash, 0, 20);
|
||||
|
||||
break;
|
||||
|
||||
ec_loser:
|
||||
crv = CKR_ARGUMENTS_BAD;
|
||||
PORT_Free(ecScalar.data);
|
||||
if (privKey != sourceKey->objectInfo)
|
||||
nsslowkey_DestroyPrivateKey(privKey);
|
||||
if (arena) {
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
#endif /* NSS_ENABLE_ECC */
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user