Bug 1034856 - Implement deriveBits() for DH r=rbarnes,smaug

This commit is contained in:
Tim Taubert 2014-08-21 17:51:51 +02:00
parent 5fc05b064c
commit 1d4ba08090
4 changed files with 239 additions and 1 deletions

View File

@ -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);
}

View File

@ -665,6 +665,13 @@ tv = {
"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
"020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
"4fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"
),
prime2: util.hex2abv(
"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
"020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
"4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" +
"ee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"
)
},
}

View File

@ -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>

View File

@ -87,6 +87,10 @@ dictionary EcdhKeyDeriveParams : Algorithm {
required CryptoKey public;
};
dictionary DhKeyDeriveParams : Algorithm {
required CryptoKey public;
};
dictionary EcdsaParams : Algorithm {
required AlgorithmIdentifier hash;
};