mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
Bug 1034856 - Implement deriveBits() for DH r=rbarnes,smaug
This commit is contained in:
parent
5fc05b064c
commit
1d4ba08090
@ -2451,9 +2451,110 @@ private:
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
// CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
|
||||
// derived symmetric key and don't matter because we ignore them anyway.
|
||||
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));
|
||||
CKM_SHA512_HMAC, CKA_SIGN, 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;
|
||||
}
|
||||
};
|
||||
|
||||
class DeriveDhBitsTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
DeriveDhBitsTask(JSContext* aCx,
|
||||
const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
|
||||
: mLength(aLength),
|
||||
mPrivKey(aKey.GetPrivateKey())
|
||||
{
|
||||
Init(aCx, aAlgorithm, aKey);
|
||||
}
|
||||
|
||||
DeriveDhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
|
||||
: mPrivKey(aKey.GetPrivateKey())
|
||||
{
|
||||
mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength);
|
||||
if (NS_SUCCEEDED(mEarlyRv)) {
|
||||
Init(aCx, aAlgorithm, aKey);
|
||||
}
|
||||
}
|
||||
|
||||
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey)
|
||||
{
|
||||
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_DH);
|
||||
|
||||
// Check that we have a private key.
|
||||
if (!mPrivKey) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mLength = mLength >> 3; // bits to bytes
|
||||
|
||||
// Retrieve the peer's public key.
|
||||
RootedDictionary<DhKeyDeriveParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
CryptoKey* publicKey = params.mPublic;
|
||||
mPubKey = publicKey->GetPublicKey();
|
||||
if (!mPubKey) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
KeyAlgorithmProxy alg1 = publicKey->Algorithm();
|
||||
CHECK_KEY_ALGORITHM(alg1, WEBCRYPTO_ALG_DH);
|
||||
|
||||
// Both keys must use the same prime and generator.
|
||||
KeyAlgorithmProxy alg2 = aKey.Algorithm();
|
||||
if (alg1.mDh.mPrime != alg2.mDh.mPrime ||
|
||||
alg1.mDh.mGenerator != alg2.mDh.mGenerator) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t mLength;
|
||||
ScopedSECKEYPrivateKey mPrivKey;
|
||||
ScopedSECKEYPublicKey mPubKey;
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
// CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
|
||||
// derived symmetric key and don't matter because we ignore them anyway.
|
||||
ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
|
||||
mPrivKey, mPubKey, PR_FALSE, nullptr, nullptr, CKM_DH_PKCS_DERIVE,
|
||||
CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr, nullptr));
|
||||
|
||||
if (!symKey.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
@ -2874,6 +2975,10 @@ WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx,
|
||||
return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
if (algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
|
||||
return new DeriveDhBitsTask(aCx, aAlgorithm, aKey, aLength);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
|
||||
|
@ -665,6 +665,13 @@ tv = {
|
||||
"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
|
||||
"020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
|
||||
"4fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"
|
||||
),
|
||||
|
||||
prime2: util.hex2abv(
|
||||
"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
|
||||
"020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
|
||||
"4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" +
|
||||
"ee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"
|
||||
)
|
||||
},
|
||||
}
|
||||
|
@ -55,6 +55,128 @@ TestArray.addTest(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Derive bits from a DH key",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "DH",
|
||||
prime: tv.dh.prime,
|
||||
generator: new Uint8Array([0x02])
|
||||
};
|
||||
|
||||
function doDerive(x) {
|
||||
var alg = {
|
||||
name: "DH",
|
||||
public: x.publicKey
|
||||
};
|
||||
return crypto.subtle.deriveBits(alg, x.privateKey, 128);
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ["deriveBits"])
|
||||
.then(doDerive, error(that))
|
||||
.then(complete(that, function (x) {
|
||||
return x.byteLength == 16;
|
||||
}), error(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Test that DH deriveBits() fails when the public key is not a DH key",
|
||||
function() {
|
||||
var that = this;
|
||||
var pubKey, privKey;
|
||||
function setPub(x) { pubKey = x.publicKey; }
|
||||
function setPriv(x) { privKey = x.privateKey; }
|
||||
|
||||
function doGenerateDH() {
|
||||
var alg = {
|
||||
name: "DH",
|
||||
prime: tv.dh.prime,
|
||||
generator: new Uint8Array([0x02])
|
||||
};
|
||||
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: "DH", public: pubKey};
|
||||
return crypto.subtle.deriveBits(alg, privKey, 128);
|
||||
}
|
||||
|
||||
doGenerateDH()
|
||||
.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 DH deriveBits() fails when the given keys' primes or bases don't match",
|
||||
function() {
|
||||
var that = this;
|
||||
var pubKey, privKey;
|
||||
function setPub(x) { pubKey = x.publicKey; }
|
||||
function setPriv(x) { privKey = x.privateKey; }
|
||||
|
||||
function doGenerateDH() {
|
||||
var alg = {
|
||||
name: "DH",
|
||||
prime: tv.dh.prime,
|
||||
generator: new Uint8Array([0x02])
|
||||
};
|
||||
return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
function doGenerateDH2() {
|
||||
var alg = {
|
||||
name: "DH",
|
||||
prime: tv.dh.prime2,
|
||||
generator: new Uint8Array([0x02])
|
||||
};
|
||||
return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
function doGenerateDH3() {
|
||||
var alg = {
|
||||
name: "DH",
|
||||
prime: tv.dh.prime,
|
||||
generator: new Uint8Array([0x03])
|
||||
};
|
||||
return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
|
||||
}
|
||||
|
||||
function doDerive() {
|
||||
var alg = {name: "DH", public: pubKey};
|
||||
return crypto.subtle.deriveBits(alg, privKey, 128);
|
||||
}
|
||||
|
||||
doGenerateDH()
|
||||
.then(setPriv, error(that))
|
||||
.then(doGenerateDH2, error(that))
|
||||
.then(setPub, error(that))
|
||||
.then(doDerive, error(that))
|
||||
.then(error(that), doGenerateDH3)
|
||||
.then(setPub, error(that))
|
||||
.then(doDerive, error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
/*]]>*/</script>
|
||||
</head>
|
||||
|
||||
|
@ -87,6 +87,10 @@ dictionary EcdhKeyDeriveParams : Algorithm {
|
||||
required CryptoKey public;
|
||||
};
|
||||
|
||||
dictionary DhKeyDeriveParams : Algorithm {
|
||||
required CryptoKey public;
|
||||
};
|
||||
|
||||
dictionary EcdsaParams : Algorithm {
|
||||
required AlgorithmIdentifier hash;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user