Commit 523dbeff authored by eroman's avatar eroman Committed by Commit bot

Copy data bytes in Web Crypto's importKey() and verify() operations

BEFORE normalizing the algorithm.

This matches the change in the spec:
https://github.com/w3c/webcrypto/commit/ccd586cc2cf0c7fe8db524622dd35b1fa39fe7c4

The motivation is consistency with other functions. Algorithm
normalization might modify the data buffer.

BUG=641494

Review-Url: https://codereview.chromium.org/2316633003
Cr-Commit-Position: refs/heads/master@{#417010}
parent ba4daaff
Tests crypto.subtle.importKey() using a BufferSource that is modified during algorithm normalization
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Importing key...
Accessed name property
Corrupting keyData...
Exporting key...
PASS: Exported data should be [30112233445566778899aabbccddeeff] and was
Importing key (again)...
Importing second key...
PASS: Exported data should be [00002233445566778899aabbccddeeff] and was
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Tests crypto.subtle.importKey() using a BufferSource that is modified during algorithm normalization");
jsTestIsAsync = true;
var kKeyDataHex = "30112233445566778899aabbccddeeff";
keyData = hexStringToUint8Array(kKeyDataHex);
function corruptKeyData()
{
debug("Corrupting keyData...");
keyData[0] = 0;
keyData[1] = 0;
}
// This algorithm has a custom getter that modifies the key data.
var importAlgorithm = {
get name() {
debug("Accessed name property");
corruptKeyData();
return 'aes-cbc';
}
};
var extractable = true;
var usages = ['encrypt', 'decrypt'];
debug("Importing key...");
crypto.subtle.importKey('raw', keyData, importAlgorithm, extractable, usages).then(function(result) {
debug("Exporting key...");
return crypto.subtle.exportKey('raw', result);
}).then(function(result) {
bytesShouldMatchHexString("Exported data", kKeyDataHex, result);
debug("Importing key (again)...");
return crypto.subtle.importKey('raw', keyData, "AES-CBC", extractable, usages);
}).then(function(result) {
debug("Importing second key...");
return crypto.subtle.exportKey('raw', result);
}).then(function(result) {
// This time the imported key should reflect the modified version.
bytesShouldMatchHexString("Exported data", "00002233445566778899aabbccddeeff", result);
}).then(finishJSTest, failAndFinishJSTest);
</script>
</body>
</html>
Tests crypto.subtle.verify() using a BufferSource that is modified during algorithm normalization
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Importing RSA public key...
Verifying the signature...
Accessed name property
Corrupting data...
PASS verificationResult is true
Verifying the signature (again)...
PASS verificationResult is false
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Tests crypto.subtle.verify() using a BufferSource that is modified during algorithm normalization");
jsTestIsAsync = true;
var publicKeyJSON = {
kty: "RSA",
alg: "RS256",
n: Base64URL.stringify(hexStringToUint8Array("ADC0940AFECE7351D56A6D432210B3AA49D38566B03A9F102E4F198B2DA9D740728D01426A3A058B2B805A5F91D565D969FE318AD2D1ADA713F5A829CC8CDCF8C6CB4872068164063B6D651A2226CB97ED67E0FC6C702A473DB2D79A730F8738084A2EED74922C3A119D1D101B932C0E10FAB36815F66C0792BB640B1B4C59D062FBBEDAB3CC069A535195D70E4A06432CAF149C24A00353A0B99F7CF5B17273CB4E38421BD315127CF4B3DCB3D20A7C98CFAF1A0E398A55E347FA283CE7B39273259B1B2132DC18B0EB8AAE9F78EE525356B09DF39E090E76D7985B2B71E50AF85CA36CE91F8CCB2ABBD8A529D369890D98A2CA2825C4C2FF8B7FBF09E79C0B")),
e: Base64URL.stringify(hexStringToUint8Array("010001")),
};
var data = asciiToUint8Array("Hello, world!");
var signature = hexStringToUint8Array("0fd9a8aef4cc1876c0b762545336c6d1fb315ae16ae4b5e4bf34d384d8585ea7a01e76ea09ee7f7ee8d1c122e7dd15b7c94a573b2aa07203e8d13bc6fd16156cd8e5f0c15a15dccb62d152127fca09882fb53bc3e60ab586d15b95cf411e3aab4a1c231a7e91aab09ee3d4b13d11e97505ddff77683470da510ee76e8bd530c56a85f901626a5a710f716f113dfe9cf6c473ee16fa248aea3480a1033abe30f4c1243289a661e64d7818b55698280688097135968c6d4b029496d85cab2a67e4696737781f70e4392c7df71bbd6c92465947f029a1de48160aced11b5721b1cd25039fe2c16c2b38de73df3b9a83e3ea755fd0cfe51ca06b61fadf6d84677f95");
var publicKey = null;
function corruptData()
{
debug("Corrupting data...");
data[0] = 0;
data[1] = 0;
}
var extractable = true;
debug("Importing RSA public key...");
crypto.subtle.importKey("jwk", publicKeyJSON, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, extractable, ["verify"]).then(function(result) {
publicKey = result;
// This algorithm has a custom getter that modifies |data|.
var algorithm = {
get name() {
debug("Accessed name property");
corruptData();
return "RSASSA-PKCS1-v1_5";
}
};
debug("\nVerifying the signature...");
return crypto.subtle.verify(algorithm, publicKey, signature, data);
}).then(function(result) {
// Despite modifying the data, verification should succeed.
verificationResult = result;
shouldBe("verificationResult", "true");
debug("\nVerifying the signature (again)...");
return crypto.subtle.verify("RSASSA-PKCS1-v1_5", publicKey, signature, data);
}).then(function(result) {
// This time around expect verification to have failed.
verificationResult = result;
shouldBe("verificationResult", "false");
}).then(finishJSTest, failAndFinishJSTest);
</script>
</body>
</html>
...@@ -282,16 +282,16 @@ ScriptPromise SubtleCrypto::verifySignature(ScriptState* scriptState, const Algo ...@@ -282,16 +282,16 @@ ScriptPromise SubtleCrypto::verifySignature(ScriptState* scriptState, const Algo
// held by the signature parameter passed to the verify method. // held by the signature parameter passed to the verify method.
WebVector<uint8_t> signature = copyBytes(rawSignature); WebVector<uint8_t> signature = copyBytes(rawSignature);
// 14.3.4.3: Let normalizedAlgorithm be the result of normalizing an // 14.3.4.3: Let data be the result of getting a copy of the bytes held by
// the data parameter passed to the verify method.
WebVector<uint8_t> data = copyBytes(rawData);
// 14.3.4.4: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to "verify". // algorithm, with alg set to algorithm and op set to "verify".
WebCryptoAlgorithm normalizedAlgorithm; WebCryptoAlgorithm normalizedAlgorithm;
if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationVerify, normalizedAlgorithm, result)) if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationVerify, normalizedAlgorithm, result))
return promise; return promise;
// 14.3.4.5: Let data be the result of getting a copy of the bytes held by
// the data parameter passed to the verify method.
WebVector<uint8_t> data = copyBytes(rawData);
// 14.3.4.9: If the name member of normalizedAlgorithm is not equal to the // 14.3.4.9: If the name member of normalizedAlgorithm is not equal to the
// name attribute of the [[algorithm]] internal slot of key then throw an // name attribute of the [[algorithm]] internal slot of key then throw an
// InvalidAccessError. // InvalidAccessError.
...@@ -379,19 +379,12 @@ ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& ra ...@@ -379,19 +379,12 @@ ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& ra
if (!CryptoKey::parseUsageMask(rawKeyUsages, keyUsages, result)) if (!CryptoKey::parseUsageMask(rawKeyUsages, keyUsages, result))
return promise; return promise;
// 14.3.9.2: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "importKey".
WebCryptoAlgorithm normalizedAlgorithm;
if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationImportKey, normalizedAlgorithm, result))
return promise;
// In the case of JWK keyData will hold the UTF8-encoded JSON for the // In the case of JWK keyData will hold the UTF8-encoded JSON for the
// JsonWebKey, otherwise it holds a copy of the BufferSource. // JsonWebKey, otherwise it holds a copy of the BufferSource.
WebVector<uint8_t> keyData; WebVector<uint8_t> keyData;
switch (format) { switch (format) {
// 14.3.9.6: If format is equal to the string "raw", "pkcs8", or "spki": // 14.3.9.2: If format is equal to the string "raw", "pkcs8", or "spki":
// //
// (1) If the keyData parameter passed to the importKey method is a // (1) If the keyData parameter passed to the importKey method is a
// JsonWebKey dictionary, throw a TypeError. // JsonWebKey dictionary, throw a TypeError.
...@@ -410,7 +403,7 @@ ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& ra ...@@ -410,7 +403,7 @@ ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& ra
return promise; return promise;
} }
break; break;
// 14.3.9.6: If format is equal to the string "jwk": // 14.3.9.2: If format is equal to the string "jwk":
// //
// (1) If the keyData parameter passed to the importKey method is not a // (1) If the keyData parameter passed to the importKey method is not a
// JsonWebKey dictionary, throw a TypeError. // JsonWebKey dictionary, throw a TypeError.
...@@ -430,6 +423,14 @@ ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& ra ...@@ -430,6 +423,14 @@ ScriptPromise SubtleCrypto::importKey(ScriptState* scriptState, const String& ra
} }
break; break;
} }
// 14.3.9.3: Let normalizedAlgorithm be the result of normalizing an
// algorithm, with alg set to algorithm and op set to
// "importKey".
WebCryptoAlgorithm normalizedAlgorithm;
if (!parseAlgorithm(rawAlgorithm, WebCryptoOperationImportKey, normalizedAlgorithm, result))
return promise;
histogramAlgorithm(scriptState->getExecutionContext(), normalizedAlgorithm); histogramAlgorithm(scriptState->getExecutionContext(), normalizedAlgorithm);
Platform::current()->crypto()->importKey(format, std::move(keyData), normalizedAlgorithm, extractable, keyUsages, result->result()); Platform::current()->crypto()->importKey(format, std::move(keyData), normalizedAlgorithm, extractable, keyUsages, result->result());
return promise; return promise;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment