зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1034855 - Implement generateKey() for ECDH r=rbarnes,keeler
This commit is contained in:
Родитель
77ac66adc8
Коммит
d4733a1ad7
|
@ -49,6 +49,11 @@
|
||||||
#define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
|
#define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
|
||||||
#define WEBCRYPTO_KEY_USAGE_UNWRAPKEY "unwrapKey"
|
#define WEBCRYPTO_KEY_USAGE_UNWRAPKEY "unwrapKey"
|
||||||
|
|
||||||
|
// WebCrypto named curves
|
||||||
|
#define WEBCRYPTO_NAMED_CURVE_P256 "P-256"
|
||||||
|
#define WEBCRYPTO_NAMED_CURVE_P384 "P-384"
|
||||||
|
#define WEBCRYPTO_NAMED_CURVE_P521 "P-521"
|
||||||
|
|
||||||
// JWK key types
|
// JWK key types
|
||||||
#define JWK_TYPE_SYMMETRIC "oct"
|
#define JWK_TYPE_SYMMETRIC "oct"
|
||||||
#define JWK_TYPE_RSA "RSA"
|
#define JWK_TYPE_RSA "RSA"
|
||||||
|
@ -184,6 +189,88 @@ MapAlgorithmNameToMechanism(const nsString& aName)
|
||||||
return mechanism;
|
return mechanism;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
NormalizeNamedCurveValue(const nsString& aNamedCurve, nsString& aDest)
|
||||||
|
{
|
||||||
|
if (aNamedCurve.EqualsIgnoreCase(WEBCRYPTO_NAMED_CURVE_P256)) {
|
||||||
|
aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
|
||||||
|
} else if (aNamedCurve.EqualsIgnoreCase(WEBCRYPTO_NAMED_CURVE_P384)) {
|
||||||
|
aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
|
||||||
|
} else if (aNamedCurve.EqualsIgnoreCase(WEBCRYPTO_NAMED_CURVE_P521)) {
|
||||||
|
aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
CheckEncodedECParameters(const SECItem* aEcParams)
|
||||||
|
{
|
||||||
|
// Need at least two bytes for a valid ASN.1 encoding.
|
||||||
|
if (aEcParams->len < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the ASN.1 tag.
|
||||||
|
if (aEcParams->data[0] != SEC_ASN1_OBJECT_ID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OID tags are short, we never need more than one length byte.
|
||||||
|
if (aEcParams->data[1] >= 128) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the SECItem's length is correct.
|
||||||
|
if (aEcParams->len != (unsigned)aEcParams->data[1] + 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SECItem*
|
||||||
|
CreateECParamsForCurve(const nsString& aNamedCurve, PLArenaPool* aArena)
|
||||||
|
{
|
||||||
|
SECOidTag curveOIDTag;
|
||||||
|
|
||||||
|
if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P256)) {
|
||||||
|
curveOIDTag = SEC_OID_SECG_EC_SECP256R1;
|
||||||
|
} else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P384)) {
|
||||||
|
curveOIDTag = SEC_OID_SECG_EC_SECP384R1;
|
||||||
|
} else if (aNamedCurve.EqualsLiteral(WEBCRYPTO_NAMED_CURVE_P521)) {
|
||||||
|
curveOIDTag = SEC_OID_SECG_EC_SECP521R1;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve curve data by OID tag.
|
||||||
|
SECOidData* oidData = SECOID_FindOIDByTag(curveOIDTag);
|
||||||
|
if (!oidData) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create parameters.
|
||||||
|
SECItem* params = ::SECITEM_AllocItem(aArena, nullptr, 2 + oidData->oid.len);
|
||||||
|
if (!params) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set parameters.
|
||||||
|
params->data[0] = SEC_ASN1_OBJECT_ID;
|
||||||
|
params->data[1] = oidData->oid.len;
|
||||||
|
memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
|
||||||
|
|
||||||
|
// Sanity check the params we just created.
|
||||||
|
if (!CheckEncodedECParameters(params)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -2000,6 +2000,24 @@ public:
|
||||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||||
|
RootedDictionary<EcKeyGenParams> params(aCx);
|
||||||
|
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||||
|
if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) {
|
||||||
|
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NormalizeNamedCurveValue(params.mNamedCurve.Value(), mNamedCurve)) {
|
||||||
|
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create algorithm.
|
||||||
|
algorithm = new EcKeyAlgorithm(global, algName, mNamedCurve);
|
||||||
|
mKeyPair->PublicKey()->SetAlgorithm(algorithm);
|
||||||
|
mKeyPair->PrivateKey()->SetAlgorithm(algorithm);
|
||||||
|
mMechanism = CKM_EC_KEY_PAIR_GEN;
|
||||||
} else {
|
} else {
|
||||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||||
return;
|
return;
|
||||||
|
@ -2013,6 +2031,9 @@ public:
|
||||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||||
privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
|
privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
|
||||||
publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
|
publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
|
||||||
|
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||||
|
privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
|
||||||
|
publicAllowedUsages = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mKeyPair->PrivateKey()->SetExtractable(aExtractable);
|
mKeyPair->PrivateKey()->SetExtractable(aExtractable);
|
||||||
|
@ -2044,6 +2065,7 @@ private:
|
||||||
PK11RSAGenParams mRsaParams;
|
PK11RSAGenParams mRsaParams;
|
||||||
ScopedSECKEYPublicKey mPublicKey;
|
ScopedSECKEYPublicKey mPublicKey;
|
||||||
ScopedSECKEYPrivateKey mPrivateKey;
|
ScopedSECKEYPrivateKey mPrivateKey;
|
||||||
|
nsString mNamedCurve;
|
||||||
|
|
||||||
virtual void ReleaseNSSResources() MOZ_OVERRIDE
|
virtual void ReleaseNSSResources() MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -2057,9 +2079,26 @@ private:
|
||||||
MOZ_ASSERT(slot.get());
|
MOZ_ASSERT(slot.get());
|
||||||
|
|
||||||
void* param;
|
void* param;
|
||||||
|
ScopedPLArenaPool arena;
|
||||||
|
|
||||||
switch (mMechanism) {
|
switch (mMechanism) {
|
||||||
case CKM_RSA_PKCS_KEY_PAIR_GEN: param = &mRsaParams; break;
|
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||||
default: return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
param = &mRsaParams;
|
||||||
|
break;
|
||||||
|
case CKM_EC_KEY_PAIR_GEN: {
|
||||||
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||||
|
if (!arena) {
|
||||||
|
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
param = CreateECParamsForCurve(mNamedCurve, arena.get());
|
||||||
|
if (!param) {
|
||||||
|
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
SECKEYPublicKey* pubKey = nullptr;
|
SECKEYPublicKey* pubKey = nullptr;
|
||||||
|
@ -2477,7 +2516,8 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
|
||||||
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||||
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSAES_PKCS1) ||
|
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSAES_PKCS1) ||
|
||||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP)) {
|
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
|
||||||
|
algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
|
||||||
return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||||
} else {
|
} else {
|
||||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
|
|
|
@ -1867,3 +1867,31 @@ TestArray.addTest(
|
||||||
.then(complete(that), error(that));
|
.then(complete(that), error(that));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
TestArray.addTest(
|
||||||
|
"Generate an ECDH key for named curve P-256",
|
||||||
|
function() {
|
||||||
|
var that = this;
|
||||||
|
var alg = { name: "ECDH", namedCurve: "P-256" };
|
||||||
|
crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"]).then(
|
||||||
|
complete(that, function(x) {
|
||||||
|
return exists(x.publicKey) &&
|
||||||
|
(x.publicKey.algorithm.name == alg.name) &&
|
||||||
|
(x.publicKey.algorithm.namedCurve == alg.namedCurve) &&
|
||||||
|
(x.publicKey.type == "public") &&
|
||||||
|
x.publicKey.extractable &&
|
||||||
|
(x.publicKey.usages.length == 0) &&
|
||||||
|
exists(x.privateKey) &&
|
||||||
|
(x.privateKey.algorithm.name == alg.name) &&
|
||||||
|
(x.privateKey.algorithm.namedCurve == alg.namedCurve) &&
|
||||||
|
(x.privateKey.type == "private") &&
|
||||||
|
!x.privateKey.extractable &&
|
||||||
|
(x.privateKey.usages.length == 2) &&
|
||||||
|
(x.privateKey.usages[0] == "deriveKey") &&
|
||||||
|
(x.privateKey.usages[1] == "deriveBits");
|
||||||
|
}),
|
||||||
|
error(that)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче