mirror of
https://github.com/servo/servo.git
synced 2025-08-11 00:15:32 +01:00
Update web-platform-tests to revision bda2059150dca8ab47f088b4cc619fcdc1f262fa
This commit is contained in:
parent
3535f3f6c2
commit
7c4281f3da
182 changed files with 7692 additions and 1042 deletions
|
@ -1,2 +1,4 @@
|
|||
@Wafflespeanut
|
||||
@Ms2ger
|
||||
@jimsch
|
||||
@engelke
|
||||
|
|
277
tests/wpt/web-platform-tests/WebCryptoAPI/WebCryptoAPI.idl
Normal file
277
tests/wpt/web-platform-tests/WebCryptoAPI/WebCryptoAPI.idl
Normal file
|
@ -0,0 +1,277 @@
|
|||
[NoInterfaceObject]
|
||||
interface GlobalCrypto {
|
||||
readonly attribute Crypto crypto;
|
||||
};
|
||||
|
||||
//Window implements GlobalCrypto;
|
||||
//WorkerGlobalScope implements GlobalCrypto;
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface Crypto {
|
||||
readonly attribute SubtleCrypto subtle;
|
||||
ArrayBufferView getRandomValues(ArrayBufferView array);
|
||||
};
|
||||
|
||||
typedef (object or DOMString) AlgorithmIdentifier;
|
||||
|
||||
typedef AlgorithmIdentifier HashAlgorithmIdentifier;
|
||||
|
||||
dictionary Algorithm {
|
||||
required DOMString name;
|
||||
};
|
||||
|
||||
dictionary KeyAlgorithm {
|
||||
required DOMString name;
|
||||
};
|
||||
|
||||
enum KeyType { "public", "private", "secret" };
|
||||
|
||||
enum KeyUsage { "encrypt", "decrypt", "sign", "verify", "deriveKey", "deriveBits", "wrapKey", "unwrapKey" };
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface CryptoKey {
|
||||
readonly attribute KeyType type;
|
||||
readonly attribute boolean extractable;
|
||||
readonly attribute object algorithm;
|
||||
readonly attribute object usages;
|
||||
};
|
||||
|
||||
|
||||
enum KeyFormat { "raw", "spki", "pkcs8", "jwk" };
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface SubtleCrypto {
|
||||
Promise<any> encrypt(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
BufferSource data);
|
||||
Promise<any> decrypt(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
BufferSource data);
|
||||
Promise<any> sign(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
BufferSource data);
|
||||
Promise<any> verify(AlgorithmIdentifier algorithm,
|
||||
CryptoKey key,
|
||||
BufferSource signature,
|
||||
BufferSource data);
|
||||
Promise<any> digest(AlgorithmIdentifier algorithm,
|
||||
BufferSource data);
|
||||
|
||||
Promise<any> generateKey(AlgorithmIdentifier algorithm,
|
||||
boolean extractable,
|
||||
sequence<KeyUsage> keyUsages );
|
||||
Promise<any> deriveKey(AlgorithmIdentifier algorithm,
|
||||
CryptoKey baseKey,
|
||||
AlgorithmIdentifier derivedKeyType,
|
||||
boolean extractable,
|
||||
sequence<KeyUsage> keyUsages );
|
||||
Promise<any> deriveBits(AlgorithmIdentifier algorithm,
|
||||
CryptoKey baseKey,
|
||||
unsigned long length);
|
||||
|
||||
Promise<any> importKey(KeyFormat format,
|
||||
(BufferSource or JsonWebKey) keyData,
|
||||
AlgorithmIdentifier algorithm,
|
||||
boolean extractable,
|
||||
sequence<KeyUsage> keyUsages );
|
||||
Promise<any> exportKey(KeyFormat format, CryptoKey key);
|
||||
|
||||
Promise<any> wrapKey(KeyFormat format,
|
||||
CryptoKey key,
|
||||
CryptoKey wrappingKey,
|
||||
AlgorithmIdentifier wrapAlgorithm);
|
||||
Promise<any> unwrapKey(KeyFormat format,
|
||||
BufferSource wrappedKey,
|
||||
CryptoKey unwrappingKey,
|
||||
AlgorithmIdentifier unwrapAlgorithm,
|
||||
AlgorithmIdentifier unwrappedKeyAlgorithm,
|
||||
boolean extractable,
|
||||
sequence<KeyUsage> keyUsages );
|
||||
};
|
||||
|
||||
dictionary RsaOtherPrimesInfo {
|
||||
// The following fields are defined in Section 6.3.2.7 of JSON Web Algorithms
|
||||
DOMString r;
|
||||
DOMString d;
|
||||
DOMString t;
|
||||
};
|
||||
|
||||
dictionary JsonWebKey {
|
||||
// The following fields are defined in Section 3.1 of JSON Web Key
|
||||
DOMString kty;
|
||||
DOMString use;
|
||||
sequence<DOMString> key_ops;
|
||||
DOMString alg;
|
||||
|
||||
// The following fields are defined in JSON Web Key Parameters Registration
|
||||
boolean ext;
|
||||
|
||||
// The following fields are defined in Section 6 of JSON Web Algorithms
|
||||
DOMString crv;
|
||||
DOMString x;
|
||||
DOMString y;
|
||||
DOMString d;
|
||||
DOMString n;
|
||||
DOMString e;
|
||||
DOMString p;
|
||||
DOMString q;
|
||||
DOMString dp;
|
||||
DOMString dq;
|
||||
DOMString qi;
|
||||
sequence<RsaOtherPrimesInfo> oth;
|
||||
DOMString k;
|
||||
};
|
||||
|
||||
typedef Uint8Array BigInteger;
|
||||
|
||||
dictionary CryptoKeyPair {
|
||||
CryptoKey publicKey;
|
||||
CryptoKey privateKey;
|
||||
};
|
||||
|
||||
dictionary RsaKeyGenParams : Algorithm {
|
||||
// The length, in bits, of the RSA modulus
|
||||
[EnforceRange] required unsigned long modulusLength;
|
||||
// The RSA public exponent
|
||||
required BigInteger publicExponent;
|
||||
};
|
||||
|
||||
dictionary RsaHashedKeyGenParams : RsaKeyGenParams {
|
||||
// The hash algorithm to use
|
||||
required HashAlgorithmIdentifier hash;
|
||||
};
|
||||
|
||||
dictionary RsaKeyAlgorithm : KeyAlgorithm {
|
||||
// The length, in bits, of the RSA modulus
|
||||
required unsigned long modulusLength;
|
||||
// The RSA public exponent
|
||||
required BigInteger publicExponent;
|
||||
};
|
||||
|
||||
dictionary RsaHashedKeyAlgorithm : RsaKeyAlgorithm {
|
||||
// The hash algorithm that is used with this key
|
||||
required KeyAlgorithm hash;
|
||||
};
|
||||
|
||||
dictionary RsaHashedImportParams {
|
||||
// The hash algorithm to use
|
||||
required HashAlgorithmIdentifier hash;
|
||||
};
|
||||
|
||||
dictionary RsaPssParams : Algorithm {
|
||||
// The desired length of the random salt
|
||||
[EnforceRange] required unsigned long saltLength;
|
||||
};
|
||||
|
||||
dictionary RsaOaepParams : Algorithm {
|
||||
// The optional label/application data to associate with the message
|
||||
BufferSource label;
|
||||
};
|
||||
|
||||
dictionary EcdsaParams : Algorithm {
|
||||
// The hash algorithm to use
|
||||
required HashAlgorithmIdentifier hash;
|
||||
};
|
||||
|
||||
typedef DOMString NamedCurve;
|
||||
|
||||
dictionary EcKeyGenParams : Algorithm {
|
||||
// A named curve
|
||||
required NamedCurve namedCurve;
|
||||
};
|
||||
|
||||
dictionary EcKeyAlgorithm : KeyAlgorithm {
|
||||
// The named curve that the key uses
|
||||
required NamedCurve namedCurve;
|
||||
};
|
||||
|
||||
dictionary EcKeyImportParams : Algorithm {
|
||||
// A named curve
|
||||
required NamedCurve namedCurve;
|
||||
};
|
||||
|
||||
dictionary EcdhKeyDeriveParams : Algorithm {
|
||||
// The peer's EC public key.
|
||||
required CryptoKey public;
|
||||
};
|
||||
|
||||
dictionary AesCtrParams : Algorithm {
|
||||
// The initial value of the counter block. counter MUST be 16 bytes
|
||||
// (the AES block size). The counter bits are the rightmost length
|
||||
// bits of the counter block. The rest of the counter block is for
|
||||
// the nonce. The counter bits are incremented using the standard
|
||||
// incrementing function specified in NIST SP 800-38A Appendix B.1:
|
||||
// the counter bits are interpreted as a big-endian integer and
|
||||
// incremented by one.
|
||||
required BufferSource counter;
|
||||
// The length, in bits, of the rightmost part of the counter block
|
||||
// that is incremented.
|
||||
[EnforceRange] required octet length;
|
||||
};
|
||||
|
||||
dictionary AesKeyAlgorithm : KeyAlgorithm {
|
||||
// The length, in bits, of the key.
|
||||
required unsigned short length;
|
||||
};
|
||||
|
||||
dictionary AesKeyGenParams : Algorithm {
|
||||
// The length, in bits, of the key.
|
||||
[EnforceRange] required unsigned short length;
|
||||
};
|
||||
|
||||
dictionary AesDerivedKeyParams : Algorithm {
|
||||
// The length, in bits, of the key.
|
||||
[EnforceRange] required unsigned short length;
|
||||
};
|
||||
|
||||
dictionary AesCbcParams : Algorithm {
|
||||
// The initialization vector. MUST be 16 bytes.
|
||||
required BufferSource iv;
|
||||
};
|
||||
|
||||
dictionary AesGcmParams : Algorithm {
|
||||
// The initialization vector to use. May be up to 2^64-1 bytes long.
|
||||
required BufferSource iv;
|
||||
// The additional authentication data to include.
|
||||
BufferSource additionalData;
|
||||
// The desired length of the authentication tag. May be 0 - 128.
|
||||
[EnforceRange] octet tagLength;
|
||||
};
|
||||
|
||||
dictionary HmacImportParams : Algorithm {
|
||||
// The inner hash function to use.
|
||||
HashAlgorithmIdentifier hash;
|
||||
// The length (in bits) of the key.
|
||||
[EnforceRange] unsigned long length;
|
||||
};
|
||||
|
||||
dictionary HmacKeyAlgorithm : KeyAlgorithm {
|
||||
// The inner hash function to use.
|
||||
required KeyAlgorithm hash;
|
||||
// The length (in bits) of the key.
|
||||
required unsigned long length;
|
||||
};
|
||||
|
||||
dictionary HmacKeyGenParams : Algorithm {
|
||||
// The inner hash function to use.
|
||||
required HashAlgorithmIdentifier hash;
|
||||
// The length (in bits) of the key to generate. If unspecified, the
|
||||
// recommended length will be used, which is the size of the associated hash function's block
|
||||
// size.
|
||||
[EnforceRange] unsigned long length;
|
||||
};
|
||||
|
||||
dictionary HkdfCtrParams : Algorithm {
|
||||
// The algorithm to use with HMAC (e.g.: SHA-256)
|
||||
required HashAlgorithmIdentifier hash;
|
||||
// A bit string that corresponds to the label that identifies the purpose for the derived keying material.
|
||||
required BufferSource label;
|
||||
// A bit string that corresponds to the context of the key derivation, as described in Section 5 of [NIST SP800-108]
|
||||
required BufferSource context;
|
||||
};
|
||||
|
||||
dictionary Pbkdf2Params : Algorithm {
|
||||
required BufferSource salt;
|
||||
[EnforceRange] required unsigned long iterations;
|
||||
required HashAlgorithmIdentifier hash;
|
||||
};
|
|
@ -0,0 +1,213 @@
|
|||
function run_test(algorithmNames) {
|
||||
var subtle = crypto.subtle; // Change to test prefixed implementations
|
||||
|
||||
setup({explicit_timeout: true});
|
||||
|
||||
// These tests check that generateKey throws an error, and that
|
||||
// the error is of the right type, for a wide set of incorrect parameters.
|
||||
//
|
||||
// Error testing occurs by setting the parameter that should trigger the
|
||||
// error to an invalid value, then combining that with all valid
|
||||
// parameters that should be checked earlier by generateKey, and all
|
||||
// valid and invalid parameters that should be checked later by
|
||||
// generateKey.
|
||||
//
|
||||
// There are a lot of combinations of possible parameters for both
|
||||
// success and failure modes, resulting in a very large number of tests
|
||||
// performed.
|
||||
|
||||
|
||||
// Setup: define the correct behaviors that should be sought, and create
|
||||
// helper functions that generate all possible test parameters for
|
||||
// different situations.
|
||||
|
||||
var allTestVectors = [ // Parameters that should work for generateKey
|
||||
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
|
||||
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
|
||||
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}
|
||||
];
|
||||
|
||||
var testVectors = [];
|
||||
allTestVectors.forEach(function(vector) {
|
||||
if (!algorithmNames || algorithmNames.includes(vector.name)) {
|
||||
testVectors.push(vector);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function parameterString(algorithm, extractable, usages) {
|
||||
if (typeof algorithm !== "object" && typeof algorithm !== "string") {
|
||||
alert(algorithm);
|
||||
}
|
||||
|
||||
var result = "(" +
|
||||
objectToString(algorithm) + ", " +
|
||||
objectToString(extractable) + ", " +
|
||||
objectToString(usages) +
|
||||
")";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Test that a given combination of parameters results in an error,
|
||||
// AND that it is the correct kind of error.
|
||||
//
|
||||
// Expected error is either a number, tested against the error code,
|
||||
// or a string, tested against the error name.
|
||||
function testError(algorithm, extractable, usages, expectedError, testTag) {
|
||||
promise_test(function(test) {
|
||||
return crypto.subtle.generateKey(algorithm, extractable, usages)
|
||||
.then(function(result) {
|
||||
assert_unreached("Operation succeeded, but should not have");
|
||||
}, function(err) {
|
||||
if (typeof expectedError === "number") {
|
||||
assert_equals(err.code, expectedError, testTag + " not supported");
|
||||
} else {
|
||||
assert_equals(err.name, expectedError, testTag + " not supported");
|
||||
}
|
||||
});
|
||||
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
|
||||
}
|
||||
|
||||
|
||||
// Given an algorithm name, create several invalid parameters.
|
||||
function badAlgorithmPropertySpecifiersFor(algorithmName) {
|
||||
var results = [];
|
||||
|
||||
if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
|
||||
// Specifier properties are name and length
|
||||
[64, 127, 129, 255, 257, 512].forEach(function(length) {
|
||||
results.push({name: algorithmName, length: length});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
|
||||
[new Uint8Array([1]), new Uint8Array([1,0,0])].forEach(function(publicExponent) {
|
||||
results.push({name: algorithmName, hash: "SHA-256", modulusLength: 1024, publicExponent: publicExponent});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
|
||||
["P-512", "Curve25519"].forEach(function(curveName) {
|
||||
results.push({name: algorithmName, namedCurve: curveName});
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
// Don't create an exhaustive list of all invalid usages,
|
||||
// because there would usually be nearly 2**8 of them,
|
||||
// way too many to test. Instead, create every singleton
|
||||
// of an illegal usage, and "poison" every valid usage
|
||||
// with an illegal one.
|
||||
function invalidUsages(validUsages, mandatoryUsages) {
|
||||
var results = [];
|
||||
|
||||
var illegalUsages = [];
|
||||
["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
|
||||
if (!validUsages.includes(usage)) {
|
||||
illegalUsages.push(usage);
|
||||
}
|
||||
});
|
||||
|
||||
var goodUsageCombinations = allValidUsages(validUsages, false, mandatoryUsages);
|
||||
|
||||
illegalUsages.forEach(function(illegalUsage) {
|
||||
results.push([illegalUsage]);
|
||||
goodUsageCombinations.forEach(function(usageCombination) {
|
||||
results.push(usageCombination.concat([illegalUsage]));
|
||||
});
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
// Now test for properly handling errors
|
||||
// - Unsupported algorithm
|
||||
// - Bad usages for algorithm
|
||||
// - Bad key lengths
|
||||
|
||||
// Algorithm normalization should fail with "Not supported"
|
||||
var badAlgorithmNames = [
|
||||
"AES",
|
||||
{name: "AES"},
|
||||
{name: "AES", length: 128},
|
||||
{name: "AES-CMAC", length: 128}, // Removed after CR
|
||||
{name: "AES-CFB", length: 128}, // Removed after CR
|
||||
{name: "HMAC", hash: "MD5"},
|
||||
{name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
|
||||
{name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
|
||||
{name: "EC", namedCurve: "P521"}
|
||||
];
|
||||
|
||||
|
||||
// Algorithm normalization failures should be found first
|
||||
// - all other parameters can be good or bad, should fail
|
||||
// due to NotSupportedError.
|
||||
badAlgorithmNames.forEach(function(algorithm) {
|
||||
allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
|
||||
.forEach(function(usages) {
|
||||
[false, true, "RED", 7].forEach(function(extractable){
|
||||
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Algorithms normalize okay, but usages bad (though not empty).
|
||||
// It shouldn't matter what other extractable is. Should fail
|
||||
// due to SyntaxError
|
||||
testVectors.forEach(function(vector) {
|
||||
var name = vector.name;
|
||||
|
||||
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
|
||||
invalidUsages(vector.usages, vector.mandatoryUsages).forEach(function(usages) {
|
||||
[true].forEach(function(extractable) {
|
||||
testError(algorithm, extractable, usages, "SyntaxError", "Bad usages");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Other algorithm properties should be checked next, so try good
|
||||
// algorithm names and usages, but bad algorithm properties next.
|
||||
// - Special case: normally bad usage [] isn't checked until after properties,
|
||||
// so it's included in this test case. It should NOT cause an error.
|
||||
testVectors.forEach(function(vector) {
|
||||
var name = vector.name;
|
||||
badAlgorithmPropertySpecifiersFor(name).forEach(function(algorithm) {
|
||||
allValidUsages(vector.usages, true, vector.mandatoryUsages)
|
||||
.forEach(function(usages) {
|
||||
[false, true].forEach(function(extractable) {
|
||||
if (name.substring(0,2) === "EC") {
|
||||
testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm property");
|
||||
} else {
|
||||
testError(algorithm, extractable, usages, "OperationError", "Bad algorithm property");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// The last thing that should be checked is an empty usages (for secret keys).
|
||||
testVectors.forEach(function(vector) {
|
||||
var name = vector.name;
|
||||
|
||||
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
|
||||
var usages = [];
|
||||
[false, true].forEach(function(extractable) {
|
||||
testError(algorithm, extractable, usages, "SyntaxError", "Empty usages");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("../util/helpers.js");
|
||||
importScripts("failures.js");
|
||||
run_test();
|
||||
done();
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
function run_test(algorithmNames) {
|
||||
var subtle = crypto.subtle; // Change to test prefixed implementations
|
||||
|
||||
setup({explicit_timeout: true});
|
||||
|
||||
// These tests check that generateKey successfully creates keys
|
||||
// when provided any of a wide set of correct parameters.
|
||||
//
|
||||
// There are a lot of combinations of possible parameters,
|
||||
// resulting in a very large number of tests
|
||||
// performed.
|
||||
|
||||
|
||||
// Setup: define the correct behaviors that should be sought, and create
|
||||
// helper functions that generate all possible test parameters for
|
||||
// different situations.
|
||||
|
||||
var testVectors = [ // Parameters that should work for generateKey
|
||||
{name: "AES-CTR", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "AES-CBC", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "AES-GCM", resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "AES-KW", resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
|
||||
{name: "HMAC", resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
|
||||
{name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "RSA-PSS", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
|
||||
{name: "ECDSA", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
|
||||
{name: "ECDH", resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}
|
||||
];
|
||||
|
||||
|
||||
function parameterString(algorithm, extractable, usages) {
|
||||
var result = "(" +
|
||||
objectToString(algorithm) + ", " +
|
||||
objectToString(extractable) + ", " +
|
||||
objectToString(usages) +
|
||||
")";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Test that a given combination of parameters is successful
|
||||
function testSuccess(algorithm, extractable, usages, resultType, testTag) {
|
||||
// algorithm, extractable, and usages are the generateKey parameters
|
||||
// resultType is the expected result, either the CryptoKey object or "CryptoKeyPair"
|
||||
// testTag is a string to prepend to the test name.
|
||||
|
||||
promise_test(function(test) {
|
||||
return subtle.generateKey(algorithm, extractable, usages)
|
||||
.then(function(result) {
|
||||
if (resultType === "CryptoKeyPair") {
|
||||
assert_goodCryptoKey(result.privateKey, algorithm, extractable, usages, "private");
|
||||
assert_goodCryptoKey(result.publicKey, algorithm, extractable, usages, "public");
|
||||
} else {
|
||||
assert_goodCryptoKey(result, algorithm, extractable, usages, "secret");
|
||||
}
|
||||
}, function(err) {
|
||||
assert_unreached("Threw an unexpected error: " + err.toString());
|
||||
});
|
||||
}, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
|
||||
}
|
||||
|
||||
|
||||
// Test all valid sets of parameters for successful
|
||||
// key generation.
|
||||
testVectors.forEach(function(vector) {
|
||||
allNameVariants(vector.name).forEach(function(name) {
|
||||
allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
|
||||
allValidUsages(vector.usages, false, vector.mandatoryUsages).forEach(function(usages) {
|
||||
[false, true].forEach(function(extractable) {
|
||||
testSuccess(algorithm, extractable, usages, vector.resultType, "Success");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("../util/helpers.js");
|
||||
importScripts("successes.js");
|
||||
|
||||
run_test();
|
||||
done();
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: generateKey() for Failures</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/WebCryptoAPI/#dfn-SubtleCrypto-method-generateKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="/WebCryptoAPI/util/helpers.js"></script>
|
||||
<script src="failures.js"></script>
|
||||
|
||||
<h1>generateKey Tests for Bad Parameters</h1>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>WebCryptoAPI: generateKey() Successful Calls</title>
|
||||
<link rel="author" title="Charles Engelke" href="mailto:w3c@engelke.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/WebCryptoAPI/#dfn-SubtleCrypto-method-generateKey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script src="/WebCryptoAPI/util/helpers.js"></script>
|
||||
<script src="successes.js"></script>
|
||||
|
||||
<h1>generateKey Tests for Good Parameters</h1>
|
||||
<p>
|
||||
<strong>Warning!</strong> RSA key generation is intrinsically
|
||||
very slow, so the related tests can take up to
|
||||
several minutes to complete, depending on browser!
|
||||
</p>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
run_test();
|
||||
</script>
|
45
tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.html
Normal file
45
tests/wpt/web-platform-tests/WebCryptoAPI/idlharness.html
Normal file
|
@ -0,0 +1,45 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>IDL check of WebCrypto</title>
|
||||
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#crypto-interface">
|
||||
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/resources/WebIDLParser.js></script>
|
||||
<script src=/resources/idlharness.js></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1 class="instructions">Description</h1>
|
||||
|
||||
<p class="instructions">This test verifies that the implementations of the WebCrypto API match with its WebIDL definition.</p>
|
||||
|
||||
<div id='log'></div>
|
||||
|
||||
<script>
|
||||
var file_input;
|
||||
setup(function() {
|
||||
var idl_array = new IdlArray();
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", "WebCryptoAPI.idl");
|
||||
request.send();
|
||||
request.onload = function() {
|
||||
var idls = request.responseText;
|
||||
|
||||
idl_array.add_untested_idls("[PrimaryGlobal] interface Window { };");
|
||||
|
||||
idl_array.add_untested_idls("interface ArrayBuffer {};");
|
||||
idl_array.add_untested_idls("interface ArrayBufferView {};");
|
||||
|
||||
idl_array.add_idls(idls);
|
||||
|
||||
idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]});
|
||||
|
||||
idl_array.test();
|
||||
done();
|
||||
};
|
||||
}, {explicit_done: true});
|
||||
</script>
|
|
@ -0,0 +1,22 @@
|
|||
importScripts("/resources/testharness.js");
|
||||
importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js");
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", "WebCryptoAPI.idl");
|
||||
request.send();
|
||||
request.onload = function() {
|
||||
var idl_array = new IdlArray();
|
||||
var idls = request.responseText;
|
||||
|
||||
idl_array.add_untested_idls("[Global] interface Window { };");
|
||||
|
||||
idl_array.add_untested_idls("interface ArrayBuffer {};");
|
||||
idl_array.add_untested_idls("interface ArrayBufferView {};");
|
||||
|
||||
idl_array.add_idls(idls);
|
||||
|
||||
idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]});
|
||||
|
||||
idl_array.test();
|
||||
done();
|
||||
};
|
230
tests/wpt/web-platform-tests/WebCryptoAPI/util/helpers.js
Normal file
230
tests/wpt/web-platform-tests/WebCryptoAPI/util/helpers.js
Normal file
|
@ -0,0 +1,230 @@
|
|||
//
|
||||
// helpers.js
|
||||
//
|
||||
// Helper functions used by several WebCryptoAPI tests
|
||||
//
|
||||
|
||||
var registeredAlgorithmNames = [
|
||||
"RSASSA-PKCS1-v1_5",
|
||||
"RSA-PSS",
|
||||
"RSA-OAEP",
|
||||
"ECDSA",
|
||||
"ECDH",
|
||||
"AES-CTR",
|
||||
"AES-CBC",
|
||||
"AES-GCM",
|
||||
"AES-KW",
|
||||
"HMAC",
|
||||
"SHA-1",
|
||||
"SHA-256",
|
||||
"SHA-384",
|
||||
"SHA-512",
|
||||
"HKDF-CTR",
|
||||
"PBKDF2"
|
||||
];
|
||||
|
||||
|
||||
// Treats an array as a set, and generates an array of all non-empty
|
||||
// subsets (which are themselves arrays).
|
||||
//
|
||||
// The order of members of the "subsets" is not guaranteed.
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// Create a string representation of keyGeneration parameters for
|
||||
// test names and labels.
|
||||
function objectToString(obj) {
|
||||
var keyValuePairs = [];
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else if (typeof obj === "object") {
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
|
||||
});
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
} else if (typeof obj === "undefined") {
|
||||
return "undefined";
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
var keyValuePairs = [];
|
||||
|
||||
Object.keys(obj).sort().forEach(function(keyName) {
|
||||
var value = obj[keyName];
|
||||
if (typeof value === "object") {
|
||||
value = objectToString(value);
|
||||
} else if (typeof value === "array") {
|
||||
value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
|
||||
} else {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
keyValuePairs.push(keyName + ": " + value);
|
||||
});
|
||||
|
||||
return "{" + keyValuePairs.join(", ") + "}";
|
||||
}
|
||||
|
||||
// Is key a CryptoKey object with correct algorithm, extractable, and usages?
|
||||
// Is it a secret, private, or public kind of key?
|
||||
function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {
|
||||
var correctUsages = [];
|
||||
|
||||
var registeredAlgorithmName;
|
||||
registeredAlgorithmNames.forEach(function(name) {
|
||||
if (name.toUpperCase() === algorithm.name.toUpperCase()) {
|
||||
registeredAlgorithmName = name;
|
||||
}
|
||||
});
|
||||
|
||||
assert_equals(key.constructor, CryptoKey, "Is a CryptoKey");
|
||||
assert_equals(key.type, kind, "Is a " + kind + " key");
|
||||
if (key.type === "public") {
|
||||
extractable = true; // public keys are always extractable
|
||||
}
|
||||
assert_equals(key.extractable, extractable, "Extractability is correct");
|
||||
|
||||
assert_equals(key.algorithm.name, registeredAlgorithmName, "Correct algorithm name");
|
||||
assert_equals(key.algorithm.length, algorithm.length, "Correct length");
|
||||
if (["HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS"].includes(registeredAlgorithmName)) {
|
||||
assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), "Correct hash function");
|
||||
}
|
||||
|
||||
// usages is expected to be provided for a key pair, but we are checking
|
||||
// only a single key. The publicKey and privateKey portions of a key pair
|
||||
// recognize only some of the usages appropriate for a key pair.
|
||||
if (key.type === "public") {
|
||||
["encrypt", "verify", "wrapKey"].forEach(function(usage) {
|
||||
if (usages.includes(usage)) {
|
||||
correctUsages.push(usage);
|
||||
}
|
||||
});
|
||||
} else if (key.type === "private") {
|
||||
["decrypt", "sign", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
|
||||
if (usages.includes(usage)) {
|
||||
correctUsages.push(usage);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
correctUsages = usages;
|
||||
}
|
||||
|
||||
assert_equals((typeof key.usages), "object", key.type + " key.usages is an object");
|
||||
assert_not_equals(key.usages, null, key.type + " key.usages isn't null");
|
||||
|
||||
// The usages parameter could have repeats, but the usages
|
||||
// property of the result should not.
|
||||
var usageCount = 0;
|
||||
key.usages.forEach(function(usage) {
|
||||
usageCount += 1;
|
||||
assert_in_array(usage, correctUsages, "Has " + usage + " usage");
|
||||
});
|
||||
assert_equals(key.usages.length, usageCount, "usages property is correct");
|
||||
}
|
||||
|
||||
|
||||
// The algorithm parameter is an object with a name and other
|
||||
// properties. Given the name, generate all valid parameters.
|
||||
function allAlgorithmSpecifiersFor(algorithmName) {
|
||||
var results = [];
|
||||
|
||||
// RSA key generation is slow. Test a minimal set of parameters
|
||||
var hashes = ["SHA-1", "SHA-256"];
|
||||
|
||||
// EC key generation is a lot faster. Check all curves in the spec
|
||||
var curves = ["P-256", "P-384", "P-521"];
|
||||
|
||||
if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
|
||||
// Specifier properties are name and length
|
||||
[128, 192, 256].forEach(function(length) {
|
||||
results.push({name: algorithmName, length: length});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase() === "HMAC") {
|
||||
[
|
||||
{name: "SHA-1", length: 160},
|
||||
{name: "SHA-256", length: 256},
|
||||
{name: "SHA-384", length: 384},
|
||||
{name: "SHA-512", length: 512}
|
||||
].forEach(function(hashAlgorithm) {
|
||||
results.push({name: algorithmName, hash: hashAlgorithm.name, length: hashAlgorithm.length});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
|
||||
hashes.forEach(function(hashName) {
|
||||
results.push({name: algorithmName, hash: hashName, modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])});
|
||||
});
|
||||
} else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
|
||||
curves.forEach(function(curveName) {
|
||||
results.push({name: algorithmName, namedCurve: curveName});
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
// Create every possible valid usages parameter, given legal
|
||||
// usages. Note that an empty usages parameter is not always valid.
|
||||
//
|
||||
// There is an optional parameter - mandatoryUsages. If provided,
|
||||
// it should be an array containing those usages of which one must be
|
||||
// included.
|
||||
function allValidUsages(validUsages, emptyIsValid, mandatoryUsages) {
|
||||
if (typeof mandatoryUsages === "undefined") {
|
||||
mandatoryUsages = [];
|
||||
}
|
||||
|
||||
okaySubsets = [];
|
||||
allNonemptySubsetsOf(validUsages).forEach(function(subset) {
|
||||
if (mandatoryUsages.length === 0) {
|
||||
okaySubsets.push(subset);
|
||||
} else {
|
||||
for (var i=0; i<mandatoryUsages.length; i++) {
|
||||
if (subset.includes(mandatoryUsages[i])) {
|
||||
okaySubsets.push(subset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (emptyIsValid) {
|
||||
okaySubsets.push([]);
|
||||
}
|
||||
|
||||
okaySubsets.push(validUsages.concat(mandatoryUsages).concat(validUsages)); // Repeated values are allowed
|
||||
return okaySubsets;
|
||||
}
|
||||
|
||||
|
||||
// Algorithm name specifiers are case-insensitive. Generate several
|
||||
// case variations of a given name.
|
||||
function allNameVariants(name) {
|
||||
var upCaseName = name.toUpperCase();
|
||||
var lowCaseName = name.toLowerCase();
|
||||
var mixedCaseName = upCaseName.substring(0, 1) + lowCaseName.substring(1);
|
||||
|
||||
return [upCaseName, lowCaseName, mixedCaseName];
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue