зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1034855 - Implement deriveBits() for ECDH r=rbarnes,smaug
This commit is contained in:
Родитель
d4733a1ad7
Коммит
40e956b12c
|
@ -2283,6 +2283,116 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class DeriveEcdhBitsTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
DeriveEcdhBitsTask(JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
|
||||
: mLength(aLength),
|
||||
mPrivKey(aKey.GetPrivateKey())
|
||||
{
|
||||
Init(aCx, aAlgorithm, aKey);
|
||||
}
|
||||
|
||||
DeriveEcdhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
|
||||
: mPrivKey(aKey.GetPrivateKey())
|
||||
{
|
||||
mEarlyRv = GetKeySizeForAlgorithm(aCx, aTargetAlgorithm, mLength);
|
||||
if (NS_SUCCEEDED(mEarlyRv)) {
|
||||
Init(aCx, aAlgorithm, aKey);
|
||||
}
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey)
|
||||
{
|
||||
// Check that we have a private key.
|
||||
if (!mPrivKey) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Length must be a multiple of 8 bigger than zero.
|
||||
if (mLength == 0 || mLength % 8) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mLength = mLength >> 3; // bits to bytes
|
||||
|
||||
// Retrieve the peer's public key.
|
||||
RootedDictionary<EcdhKeyDeriveParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv) || !params.mPublic.WasPassed()) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
CryptoKey* publicKey = params.mPublic.Value();
|
||||
mPubKey = publicKey->GetPublicKey();
|
||||
if (!mPubKey) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<KeyAlgorithm> publicAlgorithm = publicKey->Algorithm();
|
||||
|
||||
// Given public key must be an ECDH key.
|
||||
nsString algName;
|
||||
publicAlgorithm->GetName(algName);
|
||||
if (!algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Both keys must use the same named curve.
|
||||
nsString curve1, curve2;
|
||||
static_cast<EcKeyAlgorithm*>(aKey.Algorithm())->GetNamedCurve(curve1);
|
||||
static_cast<EcKeyAlgorithm*>(publicAlgorithm.get())->GetNamedCurve(curve2);
|
||||
|
||||
if (!curve1.Equals(curve2)) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t mLength;
|
||||
ScopedSECKEYPrivateKey mPrivKey;
|
||||
ScopedSECKEYPublicKey mPubKey;
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
|
||||
mPrivKey, mPubKey, PR_FALSE, nullptr, nullptr, CKM_ECDH1_DERIVE,
|
||||
CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr));
|
||||
|
||||
if (!symKey.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey));
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// This doesn't leak, because the SECItem* returned by PK11_GetKeyData
|
||||
// just refers to a buffer managed by symKey. The assignment copies the
|
||||
// data, so mResult manages one copy, while symKey manages another.
|
||||
ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey));
|
||||
|
||||
if (mLength > mResult.Length()) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
|
||||
if (!mResult.SetLength(mLength)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
template<class KeyEncryptTask>
|
||||
class WrapKeyTask : public ExportKeyTask
|
||||
{
|
||||
|
@ -2566,6 +2676,10 @@ WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx,
|
|||
return new DerivePbkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
|
||||
return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
|
||||
|
|
|
@ -1895,3 +1895,106 @@ TestArray.addTest(
|
|||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Generate an ECDH key and derive some bits",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "ECDH", namedCurve: "P-256" };
|
||||
|
||||
var pair;
|
||||
function setKeyPair(x) { pair = x; }
|
||||
|
||||
function doDerive(n) {
|
||||
return function (x) {
|
||||
var alg = { name: "ECDH", public: pair.publicKey };
|
||||
return crypto.subtle.deriveBits(alg, pair.privateKey, n * 8);
|
||||
}
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["deriveBits"])
|
||||
.then(setKeyPair, error(that))
|
||||
.then(doDerive(2), error(that))
|
||||
.then(function (x) {
|
||||
// Deriving less bytes works.
|
||||
if (x.byteLength != 2) {
|
||||
throw "should have derived two bytes";
|
||||
}
|
||||
})
|
||||
// Deriving more than the curve yields doesn't.
|
||||
.then(doDerive(33), error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test that ECDH deriveBits() fails when the public key is not an ECDH key",
|
||||
function() {
|
||||
var that = this;
|
||||
var pubKey, privKey;
|
||||
function setPub(x) { pubKey = x.publicKey; }
|
||||
function setPriv(x) { privKey = x.privateKey; }
|
||||
|
||||
function doGenerateP256() {
|
||||
var alg = { name: "ECDH", namedCurve: "P-256" };
|
||||
return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
function doGenerateRSA() {
|
||||
var alg = {
|
||||
name: "RSA-OAEP",
|
||||
hash: "SHA-256",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
return crypto.subtle.generateKey(alg, false, ["encrypt"])
|
||||
}
|
||||
|
||||
function doDerive() {
|
||||
var alg = { name: "ECDH", public: pubKey };
|
||||
return crypto.subtle.deriveBits(alg, privKey, 16);
|
||||
}
|
||||
|
||||
doGenerateP256()
|
||||
.then(setPriv, error(that))
|
||||
.then(doGenerateRSA, error(that))
|
||||
.then(setPub, error(that))
|
||||
.then(doDerive, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test that ECDH deriveBits() fails when the given keys' curves don't match",
|
||||
function() {
|
||||
var that = this;
|
||||
var pubKey, privKey;
|
||||
function setPub(x) { pubKey = x.publicKey; }
|
||||
function setPriv(x) { privKey = x.privateKey; }
|
||||
|
||||
function doGenerateP256() {
|
||||
var alg = { name: "ECDH", namedCurve: "P-256" };
|
||||
return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
function doGenerateP384() {
|
||||
var alg = { name: "ECDH", namedCurve: "P-384" };
|
||||
return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
function doDerive() {
|
||||
var alg = { name: "ECDH", public: pubKey };
|
||||
return crypto.subtle.deriveBits(alg, privKey, 16);
|
||||
}
|
||||
|
||||
doGenerateP256()
|
||||
.then(setPriv, error(that))
|
||||
.then(doGenerateP384, error(that))
|
||||
.then(setPub, error(that))
|
||||
.then(doDerive, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
|
|
@ -114,6 +114,10 @@ dictionary EcKeyGenParams : Algorithm {
|
|||
NamedCurve namedCurve;
|
||||
};
|
||||
|
||||
dictionary EcdhKeyDeriveParams : Algorithm {
|
||||
CryptoKey public;
|
||||
};
|
||||
|
||||
|
||||
/***** JWK *****/
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче