diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index ea729ad4daba..e4991aa048cb 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -2327,17 +2327,18 @@ private: } }; -class DerivePbkdfKeyTask : public DerivePbkdfBitsTask +template +class DeriveKeyTask : public DeriveBitsTask { public: - DerivePbkdfKeyTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, CryptoKey& aBaseKey, - const ObjectOrString& aDerivedKeyType, bool aExtractable, - const Sequence& aKeyUsages) - : DerivePbkdfBitsTask(aCx, aAlgorithm, aBaseKey, aDerivedKeyType) + DeriveKeyTask(JSContext* aCx, + const ObjectOrString& aAlgorithm, CryptoKey& aBaseKey, + const ObjectOrString& aDerivedKeyType, bool aExtractable, + const Sequence& aKeyUsages) + : DeriveBitsTask(aCx, aAlgorithm, aBaseKey, aDerivedKeyType) , mResolved(false) { - if (NS_FAILED(mEarlyRv)) { + if (NS_FAILED(this->mEarlyRv)) { return; } @@ -2352,8 +2353,8 @@ protected: private: virtual void Resolve() MOZ_OVERRIDE { - mTask->SetKeyData(mResult); - mTask->DispatchWithPromise(mResultPromise); + mTask->SetKeyData(this->mResult); + mTask->DispatchWithPromise(this->mResultPromise); mResolved = true; } @@ -2737,8 +2738,15 @@ WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx, } if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) { - return new DerivePbkdfKeyTask(aCx, aAlgorithm, aBaseKey, aDerivedKeyType, - aExtractable, aKeyUsages); + return new DeriveKeyTask(aCx, aAlgorithm, aBaseKey, + aDerivedKeyType, aExtractable, + aKeyUsages); + } + + if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) { + return new DeriveKeyTask(aCx, aAlgorithm, aBaseKey, + aDerivedKeyType, aExtractable, + aKeyUsages); } return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); diff --git a/dom/crypto/test/tests.js b/dom/crypto/test/tests.js index 7b4f10ec283d..20f85ba11a3f 100644 --- a/dom/crypto/test/tests.js +++ b/dom/crypto/test/tests.js @@ -2143,3 +2143,51 @@ TestArray.addTest( .then(error(that), complete(that)); } ); + +// ----------------------------------------------------------------------------- +TestArray.addTest( + "Derive an HMAC key from two ECDH keys and test sign/verify", + function() { + var that = this; + var alg = { name: "ECDH" }; + var algDerived = { name: "HMAC", hash: {name: "SHA-1"} }; + + var pubKey, privKey; + function setPub(x) { pubKey = x; } + function setPriv(x) { privKey = x; } + + function doDerive() { + var alg = { name: "ECDH", public: pubKey }; + return crypto.subtle.deriveKey(alg, privKey, algDerived, false, ["sign", "verify"]) + .then(function (x) { + if (!hasKeyFields(x)) { + throw "Invalid key; missing field(s)"; + } + + // 512 bit is the default for HMAC-SHA1. + if (x.algorithm.length != 512) { + throw "Invalid key; incorrect length"; + } + + return x; + }); + } + + function doSignAndVerify(x) { + var data = crypto.getRandomValues(new Uint8Array(1024)); + return crypto.subtle.sign("HMAC", x, data) + .then(function (sig) { + return crypto.subtle.verify("HMAC", x, sig, data); + }); + } + + Promise.all([ + crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_priv, alg, false, ["deriveBits"]) + .then(setPriv, error(that)), + crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_pub, alg, false, ["deriveBits"]) + .then(setPub, error(that)) + ]).then(doDerive, error(that)) + .then(doSignAndVerify, error(that)) + .then(complete(that), error(that)); + } +);