Skip to content

Commit

Permalink
Don't add 'deriveBits usage for 'raw' format X25519 keys
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=265315

Reviewed by Žan Doberšek.

When importing X25519 keys in raw format we are assuming that if the key
is non-extractable, it should be imported as private key. This is not
described in the spec and it's the cause of a few WPT failures.

This commit updates also some helper functions used in the import/export
tests and retrieves their latest version.

* LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/ec_importKey.https.any-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/ec_importKey.https.any.worker-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.js:
(testVectors.forEach.):
(testVectors.forEach):
(allValidUsages): Deleted.
(parameterString): Deleted.
* LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/rsa_importKey.https.any-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/rsa_importKey.https.any.worker-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/util/helpers.js:
(assert_goodCryptoKey):
(allValidUsages):
* LayoutTests/platform/glib/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any-expected.txt:
* LayoutTests/platform/glib/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.worker-expected.txt:
* Source/WebCore/crypto/algorithms/CryptoAlgorithmX25519.cpp:
(WebCore::CryptoAlgorithmX25519::importKey):

Canonical link: https://commits.webkit.org/271210@main
  • Loading branch information
javifernandez committed Nov 28, 2023
1 parent 0c5f458 commit a4e3641
Show file tree
Hide file tree
Showing 11 changed files with 543 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function run_test(algorithmNames, slowTest) {
.then(function(result) {
if (resultType === "CryptoKeyPair") {
assert_goodCryptoKey(result.privateKey, algorithm, extractable, usages, "private");
assert_goodCryptoKey(result.publicKey, algorithm, extractable, usages, "public");
assert_goodCryptoKey(result.publicKey, algorithm, true, usages, "public");
} else {
assert_goodCryptoKey(result, algorithm, extractable, usages, "secret");
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// META: title=WebCryptoAPI: importKey() for EC keys
// META: timeout=long
// META: script=../util/helpers.js

// Test importKey and exportKey for EC algorithms. Only "happy paths" are
// currently tested - those where the operation should succeed.
Expand Down Expand Up @@ -70,7 +71,7 @@
[true, false].forEach(function(extractable) {

// Test public keys first
[[]].forEach(function(usages) { // Only valid usages argument is empty array
allValidUsages(vector.publicUsages, true).forEach(function(usages) {
['spki', 'spki_compressed', 'jwk', 'raw', 'raw_compressed'].forEach(function(format) {
var algorithm = {name: vector.name, namedCurve: curve};
var data = keyData[curve];
Expand All @@ -84,13 +85,13 @@
});

// Next, test private keys
allValidUsages(vector.privateUsages, []).forEach(function(usages) {
['pkcs8', 'jwk'].forEach(function(format) {
var algorithm = {name: vector.name, namedCurve: curve};
var data = keyData[curve];

['pkcs8', 'jwk'].forEach(function(format) {
var algorithm = {name: vector.name, namedCurve: curve};
var data = keyData[curve];
allValidUsages(vector.privateUsages).forEach(function(usages) {
testFormat(format, algorithm, data, curve, usages, extractable);
});
testEmptyUsages(format, algorithm, data, curve, extractable);
});
});

Expand All @@ -110,6 +111,7 @@
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object");
assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData.d)) ? 'private' : 'public');
if (!extractable) {
return;
}
Expand All @@ -134,6 +136,21 @@
}, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, compressed, keyData, algorithm, extractable, usages));
}

// Test importKey with a given key format and other parameters but with empty usages.
// Should fail with SyntaxError
function testEmptyUsages(format, algorithm, data, keySize, extractable) {
const keyData = data[format];
const usages = [];
promise_test(function(test) {
return subtle.importKey(format, keyData, algorithm, extractable, usages).
then(function(key) {
assert_unreached("importKey succeeded but should have failed with SyntaxError");
}, function(err) {
assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message);
});
}, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, false, keyData, algorithm, extractable, usages));
}



// Helper methods follow:
Expand Down Expand Up @@ -202,46 +219,6 @@
return base64String.replace(/=/g, "");
}

// Want to test every valid combination of usages. Start by creating a list
// of all non-empty subsets to possible usages.
function allNonemptySubsetsOf(arr) {
var results = [];
var firstElement;
var remainingElements;

for(var i=0; i<arr.length; i++) {
firstElement = arr[i];
remainingElements = arr.slice(i+1);
results.push([firstElement]);

if (remainingElements.length > 0) {
allNonemptySubsetsOf(remainingElements).forEach(function(combination) {
combination.push(firstElement);
results.push(combination);
});
}
}

return results;
}

// Return a list of all valid usage combinations, given the possible ones
// and the ones that are required for a particular operation.
function allValidUsages(possibleUsages, requiredUsages) {
var allUsages = [];

allNonemptySubsetsOf(possibleUsages).forEach(function(usage) {
for (var i=0; i<requiredUsages.length; i++) {
if (!usage.includes(requiredUsages[i])) {
return;
}
}
allUsages.push(usage);
});

return allUsages;
}

// Convert method parameters to a string to uniquely name each test
function parameterString(format, compressed, data, algorithm, extractable, usages) {
if ("byteLength" in data) {
Expand Down Expand Up @@ -294,4 +271,3 @@

return "{" + keyValuePairs.join(", ") + "}";
}

0 comments on commit a4e3641

Please sign in to comment.