Automatic update from web-platform-tests [WebCryptoAPI] Expand supports() validation coverage Keep ECDH mismatched-curve cases independent of the existing overlength deriveBits tests. Add supports() coverage for RSA, HKDF, HMAC, EC derivation and import, ML-DSA contexts, and ML-KEM imported keys. Refs: https://github.com/w3c/webcrypto/issues/560 Refs: https://github.com/w3c/webcrypto/pull/558 Refs: https://github.com/WICG/webcrypto-modern-algos/pull/76 Refs: https://github.com/WICG/webcrypto-modern-algos/pull/77 -- wpt-commits: e235e089b4e44a598f2d61e93732e0c4d9f03e04 wpt-pr: 62115
734 lines
20 KiB
JavaScript
734 lines
20 KiB
JavaScript
// META: title=WebCrypto API: supports method tests
|
|
// META: script=util/helpers.js
|
|
// META: script=util/supports.js
|
|
|
|
'use strict';
|
|
|
|
const standardAlgorithms = {
|
|
// Asymmetric algorithms
|
|
'RSASSA-PKCS1-v1_5': {
|
|
operations: ['generateKey', 'importKey', 'sign', 'verify', 'getPublicKey'],
|
|
keyGenParams: {
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-256',
|
|
},
|
|
importParams: { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },
|
|
signParams: { name: 'RSASSA-PKCS1-v1_5' },
|
|
},
|
|
'RSA-PSS': {
|
|
operations: ['generateKey', 'importKey', 'sign', 'verify', 'getPublicKey'],
|
|
keyGenParams: {
|
|
name: 'RSA-PSS',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-256',
|
|
},
|
|
importParams: { name: 'RSA-PSS', hash: 'SHA-256' },
|
|
signParams: { name: 'RSA-PSS', saltLength: 32 },
|
|
},
|
|
'RSA-OAEP': {
|
|
operations: ['generateKey', 'importKey', 'encrypt', 'decrypt', 'getPublicKey'],
|
|
keyGenParams: {
|
|
name: 'RSA-OAEP',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-256',
|
|
},
|
|
importParams: { name: 'RSA-OAEP', hash: 'SHA-256' },
|
|
encryptParams: { name: 'RSA-OAEP' },
|
|
},
|
|
ECDSA: {
|
|
operations: ['generateKey', 'importKey', 'sign', 'verify', 'getPublicKey'],
|
|
keyGenParams: { name: 'ECDSA', namedCurve: 'P-256' },
|
|
importParams: { name: 'ECDSA', namedCurve: 'P-256' },
|
|
signParams: { name: 'ECDSA', hash: 'SHA-256' },
|
|
},
|
|
ECDH: {
|
|
operations: ['generateKey', 'importKey', 'deriveBits', 'getPublicKey'],
|
|
keyGenParams: { name: 'ECDH', namedCurve: 'P-256' },
|
|
importParams: { name: 'ECDH', namedCurve: 'P-256' },
|
|
deriveBitsParamsFactory: async () => {
|
|
const {publicKey} = await crypto.subtle.generateKey(
|
|
{name: 'ECDH', namedCurve: 'P-256'}, false, ['deriveBits']);
|
|
return {name: 'ECDH', public: publicKey};
|
|
},
|
|
},
|
|
Ed25519: {
|
|
operations: ['generateKey', 'importKey', 'sign', 'verify', 'getPublicKey'],
|
|
keyGenParams: null,
|
|
signParams: { name: 'Ed25519' },
|
|
},
|
|
X25519: {
|
|
operations: ['generateKey', 'importKey', 'deriveBits', 'getPublicKey'],
|
|
keyGenParams: null,
|
|
deriveBitsParamsFactory: async () => {
|
|
const {publicKey} = await crypto.subtle.generateKey(
|
|
'X25519', false, ['deriveBits']);
|
|
return {name: 'X25519', public: publicKey};
|
|
},
|
|
},
|
|
|
|
// Symmetric algorithms
|
|
'AES-CBC': {
|
|
operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'],
|
|
keyGenParams: { name: 'AES-CBC', length: 256 },
|
|
encryptParams: { name: 'AES-CBC', iv: new Uint8Array(16) },
|
|
},
|
|
'AES-CTR': {
|
|
operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'],
|
|
keyGenParams: { name: 'AES-CTR', length: 256 },
|
|
encryptParams: {
|
|
name: 'AES-CTR',
|
|
counter: new Uint8Array(16),
|
|
length: 128,
|
|
},
|
|
},
|
|
'AES-GCM': {
|
|
operations: ['generateKey', 'importKey', 'encrypt', 'decrypt'],
|
|
keyGenParams: { name: 'AES-GCM', length: 256 },
|
|
encryptParams: { name: 'AES-GCM', iv: new Uint8Array(12) },
|
|
},
|
|
'AES-KW': {
|
|
operations: ['generateKey', 'importKey'], // wrapKey/unwrapKey not in requested operations
|
|
keyGenParams: { name: 'AES-KW', length: 256 },
|
|
},
|
|
HMAC: {
|
|
operations: ['generateKey', 'importKey', 'sign', 'verify'],
|
|
keyGenParams: { name: 'HMAC', hash: 'SHA-256' },
|
|
importParams: { name: 'HMAC', hash: 'SHA-256' },
|
|
signParams: { name: 'HMAC' },
|
|
},
|
|
|
|
// Hash algorithms
|
|
'SHA-1': {
|
|
operations: ['digest'],
|
|
keyGenParams: null,
|
|
},
|
|
'SHA-256': {
|
|
operations: ['digest'],
|
|
keyGenParams: null,
|
|
},
|
|
'SHA-384': {
|
|
operations: ['digest'],
|
|
keyGenParams: null,
|
|
},
|
|
'SHA-512': {
|
|
operations: ['digest'],
|
|
keyGenParams: null,
|
|
},
|
|
|
|
// Key derivation algorithms
|
|
HKDF: {
|
|
operations: ['importKey', 'deriveBits'],
|
|
keyGenParams: null,
|
|
deriveBitsParams: {
|
|
name: 'HKDF',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
info: new Uint8Array(0),
|
|
},
|
|
},
|
|
PBKDF2: {
|
|
operations: ['importKey', 'deriveBits'],
|
|
keyGenParams: null,
|
|
deriveBitsParams: {
|
|
name: 'PBKDF2',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
iterations: 100000,
|
|
},
|
|
},
|
|
};
|
|
|
|
const operations = [
|
|
'generateKey',
|
|
'importKey',
|
|
'sign',
|
|
'verify',
|
|
'encrypt',
|
|
'decrypt',
|
|
'deriveBits',
|
|
'digest',
|
|
'getPublicKey',
|
|
];
|
|
|
|
// Test that supports method exists and is a static method
|
|
testSupportsMethod();
|
|
|
|
// Test invalid operation names
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports('invalidOperation', 'AES-GCM'),
|
|
'Invalid operation should return false'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('', 'AES-GCM'),
|
|
'Empty operation should return false'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('GENERATEKEY', 'AES-GCM'),
|
|
'Case-sensitive operation check'
|
|
);
|
|
}, 'supports returns false for invalid operations');
|
|
|
|
// Test invalid algorithm identifiers
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', 'InvalidAlgorithm'),
|
|
'Invalid algorithm should return false'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', ''),
|
|
'Empty algorithm should return false'
|
|
);
|
|
}, 'supports returns false for invalid algorithms');
|
|
|
|
// Test standard WebCrypto algorithms for requested operations
|
|
runSupportsTests(standardAlgorithms, operations);
|
|
|
|
// Test algorithm objects (not just strings)
|
|
test(() => {
|
|
assert_true(
|
|
SubtleCrypto.supports('generateKey', { name: 'AES-GCM', length: 256 }),
|
|
'Algorithm object should be supported'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('generateKey', { name: 'HMAC', hash: 'SHA-256' }),
|
|
'Algorithm object with parameters should be supported'
|
|
);
|
|
}, 'supports works with algorithm objects');
|
|
|
|
// Test with algorithm objects that have invalid parameters
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', { name: 'AES-GCM', length: 100 }),
|
|
'Invalid key length should return false'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'HMAC',
|
|
hash: 'INVALID-HASH',
|
|
}),
|
|
'Invalid hash parameter should return false'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'encrypt', {name: 'AES-CBC', iv: new Uint8Array(10)}),
|
|
'Invalid IV for AES-CBC should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('encrypt', {
|
|
name: 'AES-CTR',
|
|
counter: new Uint8Array(10),
|
|
length: 128,
|
|
}),
|
|
'Invalid IV for AES-CTR should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('encrypt', {
|
|
name: 'AES-CTR',
|
|
counter: new Uint8Array(16),
|
|
length: 0,
|
|
}),
|
|
'Invalid length=0 for AES-CTR should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('encrypt', {
|
|
name: 'AES-CTR',
|
|
counter: new Uint8Array(16),
|
|
length: 129,
|
|
}),
|
|
'Invalid length=129 for AES-CTR should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('encrypt', {
|
|
name: 'AES-GCM',
|
|
iv: new Uint8Array(16),
|
|
tagLength: 100,
|
|
}),
|
|
'Invalid tag length for AES-GCM should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('decrypt', {
|
|
name: 'AES-GCM',
|
|
iv: new Uint8Array(16),
|
|
tagLength: 100,
|
|
}),
|
|
'Invalid tag length for AES-GCM should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {name: 'ECDH', namedCurve: 'P-51'}),
|
|
'Invalid curve for ECDH should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {
|
|
name: 'HKDF',
|
|
hash: 'SHA-25',
|
|
salt: new Uint8Array(16),
|
|
info: new Uint8Array(0),
|
|
},
|
|
8),
|
|
'Invalid hash for HKDF should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {
|
|
name: 'HKDF',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
info: new Uint8Array(0),
|
|
},
|
|
11),
|
|
'Invalid length for HKDF should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {
|
|
name: 'HKDF',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
info: new Uint8Array(0),
|
|
}),
|
|
'null length for HKDF should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'HMAC',
|
|
hash: 'SHA-25',
|
|
}),
|
|
'Invalid hash for HMAC should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'HMAC',
|
|
hash: 'SHA-256',
|
|
length: 0,
|
|
}),
|
|
'Invalid length for HMAC should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {
|
|
name: 'PBKDF2',
|
|
hash: 'SHA-25',
|
|
salt: new Uint8Array(16),
|
|
iterations: 100000,
|
|
},
|
|
8),
|
|
'Invalid hash for PBKDF2 should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {
|
|
name: 'PBKDF2',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
iterations: 100000,
|
|
},
|
|
11),
|
|
'Invalid length for PBKDF2 should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {
|
|
name: 'PBKDF2',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
iterations: 100000,
|
|
}),
|
|
'null length for PBKDF2 should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-56',
|
|
}),
|
|
'Invalid hash for RSA PKCS1 should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'RSA-PSS',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-56',
|
|
}),
|
|
'Invalid hash for RSA PSS should return false');
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'RSA-OAEP',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-26',
|
|
}),
|
|
'Invalid hash for RSA OAEP should return false');
|
|
|
|
}, 'supports returns false for algorithm objects with invalid parameters');
|
|
|
|
[
|
|
['SHA-1', 160],
|
|
['SHA-256', 256],
|
|
['SHA-384', 384],
|
|
['SHA-512', 512],
|
|
].forEach(([hash, hashLength]) => {
|
|
test(() => {
|
|
const algorithm = {
|
|
name: 'HKDF',
|
|
hash,
|
|
salt: new Uint8Array(),
|
|
info: new Uint8Array(),
|
|
};
|
|
const maximumLength = 255 * hashLength;
|
|
|
|
assert_true(
|
|
SubtleCrypto.supports('deriveBits', algorithm, maximumLength),
|
|
`HKDF with ${hash} supports its maximum output length`
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('deriveBits', algorithm, maximumLength + 8),
|
|
`HKDF with ${hash} rejects output longer than its maximum`
|
|
);
|
|
}, `supports validates HKDF ${hash} output length`);
|
|
});
|
|
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveKey',
|
|
{
|
|
name: 'HKDF',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(),
|
|
info: new Uint8Array(),
|
|
},
|
|
{name: 'HMAC', hash: 'SHA-256', length: 65288}
|
|
),
|
|
'HKDF rejects a derived key longer than 255 hash blocks'
|
|
);
|
|
}, 'supports validates HKDF output length for deriveKey');
|
|
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports('importKey', {
|
|
name: 'HMAC',
|
|
hash: 'SHA-256',
|
|
length: 0,
|
|
}),
|
|
'HMAC rejects an explicitly zero-length imported key'
|
|
);
|
|
}, 'supports validates HMAC import length');
|
|
|
|
const invalidRsaKeyGenParameters = [
|
|
{
|
|
description: 'a modulus shorter than 4 bits',
|
|
modulusLength: 3,
|
|
publicExponent: Uint8Array.of(3),
|
|
},
|
|
{
|
|
description: 'a public exponent less than 3',
|
|
modulusLength: 2048,
|
|
publicExponent: Uint8Array.of(1),
|
|
},
|
|
{
|
|
description: 'an even public exponent',
|
|
modulusLength: 2048,
|
|
publicExponent: Uint8Array.of(4),
|
|
},
|
|
{
|
|
description: 'a public exponent equal to 2^modulusLength - 1',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array(256).fill(0xff),
|
|
},
|
|
];
|
|
|
|
[
|
|
'RSASSA-PKCS1-v1_5',
|
|
'RSA-PSS',
|
|
'RSA-OAEP',
|
|
].forEach(name => {
|
|
invalidRsaKeyGenParameters.forEach(({description, ...parameters}) => {
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name,
|
|
...parameters,
|
|
hash: 'SHA-256',
|
|
}),
|
|
`${name} rejects ${description}`
|
|
);
|
|
}, `supports rejects ${name} generateKey with ${description}`);
|
|
});
|
|
});
|
|
|
|
['ECDSA', 'ECDH'].forEach(name => {
|
|
test(() => {
|
|
assert_false(
|
|
SubtleCrypto.supports('importKey', {
|
|
name,
|
|
namedCurve: 'not-a-curve',
|
|
}),
|
|
`${name} rejects an unknown named curve`
|
|
);
|
|
}, `supports validates ${name} import namedCurve`);
|
|
});
|
|
|
|
[
|
|
['P-256', 256],
|
|
['P-384', 384],
|
|
['P-521', 528],
|
|
].forEach(([namedCurve, maximumLength]) => {
|
|
promise_test(async () => {
|
|
const {publicKey} = await crypto.subtle.generateKey(
|
|
{name: 'ECDH', namedCurve}, false, ['deriveBits']);
|
|
const algorithm = {name: 'ECDH', public: publicKey};
|
|
|
|
assert_true(
|
|
SubtleCrypto.supports('deriveBits', algorithm, maximumLength),
|
|
`ECDH ${namedCurve} supports its maximum output length`
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('deriveBits', algorithm, maximumLength + 1),
|
|
`ECDH ${namedCurve} rejects output longer than its maximum`
|
|
);
|
|
}, `supports validates ECDH ${namedCurve} deriveBits length`);
|
|
});
|
|
|
|
promise_test(async () => {
|
|
const {publicKey} = await crypto.subtle.generateKey(
|
|
'X25519', false, ['deriveBits']);
|
|
const algorithm = {name: 'X25519', public: publicKey};
|
|
|
|
assert_true(
|
|
SubtleCrypto.supports('deriveBits', algorithm, 256),
|
|
'X25519 supports its maximum output length'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('deriveBits', algorithm, 257),
|
|
'X25519 rejects output longer than its maximum'
|
|
);
|
|
}, 'supports validates X25519 deriveBits length');
|
|
|
|
promise_test(async () => {
|
|
const [ecdhKeyPair, x25519KeyPair] = await Promise.all([
|
|
crypto.subtle.generateKey(
|
|
{name: 'ECDH', namedCurve: 'P-256'}, false, ['deriveBits']),
|
|
crypto.subtle.generateKey('X25519', false, ['deriveBits']),
|
|
]);
|
|
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {name: 'ECDH', public: ecdhKeyPair.privateKey}, 256),
|
|
'ECDH rejects a private public property'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {name: 'ECDH', public: x25519KeyPair.publicKey}, 256),
|
|
'ECDH rejects a public property for another algorithm'
|
|
);
|
|
}, 'supports validates the ECDH public key');
|
|
|
|
promise_test(async () => {
|
|
const [x25519KeyPair, ecdhKeyPair] = await Promise.all([
|
|
crypto.subtle.generateKey('X25519', false, ['deriveBits']),
|
|
crypto.subtle.generateKey(
|
|
{name: 'ECDH', namedCurve: 'P-256'}, false, ['deriveBits']),
|
|
]);
|
|
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {name: 'X25519', public: x25519KeyPair.privateKey}, 256),
|
|
'X25519 rejects a private public property'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveBits', {name: 'X25519', public: ecdhKeyPair.publicKey}, 256),
|
|
'X25519 rejects a public property for another algorithm'
|
|
);
|
|
}, 'supports validates the X25519 public key');
|
|
|
|
promise_test(async () => {
|
|
const [p256KeyPair, p521KeyPair] = await Promise.all([
|
|
crypto.subtle.generateKey(
|
|
{name: 'ECDH', namedCurve: 'P-256'}, false, ['deriveBits']),
|
|
crypto.subtle.generateKey(
|
|
{name: 'ECDH', namedCurve: 'P-521'}, false, ['deriveBits']),
|
|
]);
|
|
const derivedKeyAlgorithm = {name: 'HMAC', hash: 'SHA-256'};
|
|
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveKey',
|
|
{name: 'ECDH', public: p256KeyPair.publicKey},
|
|
derivedKeyAlgorithm
|
|
),
|
|
'ECDH P-256 cannot derive a 512-bit HMAC key'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports(
|
|
'deriveKey',
|
|
{name: 'ECDH', public: p521KeyPair.publicKey},
|
|
derivedKeyAlgorithm
|
|
),
|
|
'ECDH P-521 can derive a 512-bit HMAC key'
|
|
);
|
|
}, 'supports derives the ECDH output limit from the public curve');
|
|
|
|
// Test some specific combinations that should work
|
|
test(() => {
|
|
// RSA algorithms
|
|
assert_true(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'RSASSA-PKCS1-v1_5',
|
|
modulusLength: 2048,
|
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
hash: 'SHA-256',
|
|
}),
|
|
'RSASSA-PKCS1-v1_5 generateKey'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('sign', { name: 'RSASSA-PKCS1-v1_5' }),
|
|
'RSASSA-PKCS1-v1_5 sign'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('verify', { name: 'RSASSA-PKCS1-v1_5' }),
|
|
'RSASSA-PKCS1-v1_5 verify'
|
|
);
|
|
|
|
// ECDSA
|
|
assert_true(
|
|
SubtleCrypto.supports('generateKey', {
|
|
name: 'ECDSA',
|
|
namedCurve: 'P-256',
|
|
}),
|
|
'ECDSA generateKey'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('sign', { name: 'ECDSA', hash: 'SHA-256' }),
|
|
'ECDSA sign'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('verify', { name: 'ECDSA', hash: 'SHA-256' }),
|
|
'ECDSA verify'
|
|
);
|
|
|
|
// AES-GCM
|
|
assert_true(
|
|
SubtleCrypto.supports('generateKey', { name: 'AES-GCM', length: 256 }),
|
|
'AES-GCM generateKey'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('encrypt', {
|
|
name: 'AES-GCM',
|
|
iv: new Uint8Array(12),
|
|
}),
|
|
'AES-GCM encrypt'
|
|
);
|
|
assert_true(
|
|
SubtleCrypto.supports('decrypt', {
|
|
name: 'AES-GCM',
|
|
iv: new Uint8Array(12),
|
|
}),
|
|
'AES-GCM decrypt'
|
|
);
|
|
|
|
// HMAC
|
|
assert_true(
|
|
SubtleCrypto.supports('generateKey', { name: 'HMAC', hash: 'SHA-256' }),
|
|
'HMAC generateKey'
|
|
);
|
|
assert_true(SubtleCrypto.supports('sign', { name: 'HMAC' }), 'HMAC sign');
|
|
assert_true(SubtleCrypto.supports('verify', { name: 'HMAC' }), 'HMAC verify');
|
|
}, 'Common algorithm and operation combinations work');
|
|
|
|
// Test some specific combinations that should not work
|
|
test(() => {
|
|
// Hash algorithms don't support key operations
|
|
assert_false(
|
|
SubtleCrypto.supports('generateKey', 'SHA-256'),
|
|
'SHA-256 generateKey should fail'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('sign', 'SHA-256'),
|
|
'SHA-256 sign should fail'
|
|
);
|
|
|
|
// AES can't sign/verify (these require algorithm parameters due to normalization)
|
|
assert_false(
|
|
SubtleCrypto.supports('sign', 'AES-GCM'),
|
|
'AES-GCM sign should fail'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('verify', 'AES-GCM'),
|
|
'AES-GCM verify should fail'
|
|
);
|
|
|
|
// ECDSA can't encrypt/decrypt
|
|
assert_false(
|
|
SubtleCrypto.supports('encrypt', 'ECDSA'),
|
|
'ECDSA encrypt should fail'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('decrypt', 'ECDSA'),
|
|
'ECDSA decrypt should fail'
|
|
);
|
|
|
|
// HMAC can't encrypt/decrypt
|
|
assert_false(
|
|
SubtleCrypto.supports('encrypt', 'HMAC'),
|
|
'HMAC encrypt should fail'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('decrypt', 'HMAC'),
|
|
'HMAC decrypt should fail'
|
|
);
|
|
|
|
// Non-hash algorithms can't digest
|
|
assert_false(
|
|
SubtleCrypto.supports('digest', 'AES-GCM'),
|
|
'AES-GCM digest should fail'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('digest', 'ECDSA'),
|
|
'ECDSA digest should fail'
|
|
);
|
|
assert_false(
|
|
SubtleCrypto.supports('digest', 'HMAC'),
|
|
'HMAC digest should fail'
|
|
);
|
|
}, 'Invalid algorithm and operation combinations fail');
|
|
|
|
// Test supports for deriveKey op
|
|
test(() => {
|
|
assert_true(
|
|
SubtleCrypto.supports(
|
|
'deriveKey', {
|
|
name: 'HKDF',
|
|
hash: 'SHA-256',
|
|
salt: new Uint8Array(16),
|
|
info: new Uint8Array(0),
|
|
},
|
|
{name: 'HMAC', hash: 'SHA-256'}),
|
|
|
|
'deriveKey HKDF-HMAC should pass');
|
|
}, 'deriveKey tests');
|
|
|
|
promise_test(async (t) => {
|
|
let keypair = await crypto.subtle.generateKey(
|
|
{
|
|
name: 'X25519',
|
|
},
|
|
false, ['deriveKey', 'deriveBits']);
|
|
|
|
assert_true(
|
|
SubtleCrypto.supports(
|
|
'deriveKey', {
|
|
name: 'X25519',
|
|
public: keypair.publicKey,
|
|
},
|
|
{name: 'AES-GCM', length: 256}),
|
|
|
|
'deriveKey X25519-AES-GCM-256 should pass');
|
|
|
|
assert_false(
|
|
SubtleCrypto.supports(
|
|
'deriveKey', {
|
|
name: 'X25519',
|
|
public: keypair.publicKey,
|
|
},
|
|
{name: 'HMAC', hash: 'SHA-256'}),
|
|
|
|
'deriveKey X25519-HMAC-SHA-256 should fail');
|
|
}, 'deriveKey promise tests');
|
|
|
|
|
|
|
|
done();
|