mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1034855 - Implement generateKey() for ECDH r=rbarnes,keeler
This commit is contained in:
parent
d2132b58df
commit
48844df532
@ -49,6 +49,11 @@
|
||||
#define WEBCRYPTO_KEY_USAGE_WRAPKEY "wrapKey"
|
||||
#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
|
||||
#define JWK_TYPE_SYMMETRIC "oct"
|
||||
#define JWK_TYPE_RSA "RSA"
|
||||
@ -184,6 +189,88 @@ MapAlgorithmNameToMechanism(const nsString& aName)
|
||||
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 mozilla
|
||||
|
||||
|
@ -2000,6 +2000,24 @@ public:
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
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 {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
@ -2013,6 +2031,9 @@ public:
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
|
||||
publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||
privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
|
||||
publicAllowedUsages = 0;
|
||||
}
|
||||
|
||||
mKeyPair->PrivateKey()->SetExtractable(aExtractable);
|
||||
@ -2044,6 +2065,7 @@ private:
|
||||
PK11RSAGenParams mRsaParams;
|
||||
ScopedSECKEYPublicKey mPublicKey;
|
||||
ScopedSECKEYPrivateKey mPrivateKey;
|
||||
nsString mNamedCurve;
|
||||
|
||||
virtual void ReleaseNSSResources() MOZ_OVERRIDE
|
||||
{
|
||||
@ -2057,9 +2079,26 @@ private:
|
||||
MOZ_ASSERT(slot.get());
|
||||
|
||||
void* param;
|
||||
ScopedPLArenaPool arena;
|
||||
|
||||
switch (mMechanism) {
|
||||
case CKM_RSA_PKCS_KEY_PAIR_GEN: param = &mRsaParams; break;
|
||||
default: return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||
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;
|
||||
@ -2477,7 +2516,8 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
|
||||
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSAES_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);
|
||||
} else {
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
@ -1867,3 +1867,31 @@ TestArray.addTest(
|
||||
.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)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user