From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- testing/web-platform/tests/WebCryptoAPI/OWNERS | 4 + testing/web-platform/tests/WebCryptoAPI/README.md | 1 + .../tests/WebCryptoAPI/WebCryptoAPI.idl | 277 ++++++++++++ .../WebCryptoAPI/derive_bits_keys/ecdh_bits.js | 269 ++++++++++++ .../derive_bits_keys/ecdh_bits.worker.js | 4 + .../WebCryptoAPI/derive_bits_keys/ecdh_keys.js | 238 ++++++++++ .../derive_bits_keys/ecdh_keys.worker.js | 4 + .../tests/WebCryptoAPI/derive_bits_keys/hkdf.js | 312 ++++++++++++++ .../WebCryptoAPI/derive_bits_keys/hkdf.worker.js | 5 + .../WebCryptoAPI/derive_bits_keys/hkdf_vectors.js | 184 ++++++++ .../tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js | 310 +++++++++++++ .../WebCryptoAPI/derive_bits_keys/pbkdf2.worker.js | 5 + .../derive_bits_keys/pbkdf2_vectors.js | 269 ++++++++++++ .../derive_bits_keys/test_ecdh_bits.html | 17 + .../derive_bits_keys/test_ecdh_keys.html | 17 + .../WebCryptoAPI/derive_bits_keys/test_hkdf.html | 19 + .../WebCryptoAPI/derive_bits_keys/test_pbkdf2.html | 19 + .../tests/WebCryptoAPI/digest/digest.js | 154 +++++++ .../tests/WebCryptoAPI/digest/digest.worker.js | 4 + .../tests/WebCryptoAPI/digest/test_digest.html | 17 + .../tests/WebCryptoAPI/encrypt_decrypt/aes.js | 323 ++++++++++++++ .../WebCryptoAPI/encrypt_decrypt/aes_cbc.worker.js | 5 + .../encrypt_decrypt/aes_cbc_vectors.js | 261 +++++++++++ .../WebCryptoAPI/encrypt_decrypt/aes_ctr.worker.js | 5 + .../encrypt_decrypt/aes_ctr_vectors.js | 123 ++++++ .../WebCryptoAPI/encrypt_decrypt/aes_gcm.worker.js | 5 + .../encrypt_decrypt/aes_gcm_vectors.js | 262 +++++++++++ .../tests/WebCryptoAPI/encrypt_decrypt/rsa.js | 376 ++++++++++++++++ .../WebCryptoAPI/encrypt_decrypt/rsa.worker.js | 5 + .../WebCryptoAPI/encrypt_decrypt/rsa_vectors.js | 204 +++++++++ .../WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html | 18 + .../WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html | 18 + .../WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html | 18 + .../encrypt_decrypt/test_rsa_oaep.html | 18 + .../tests/WebCryptoAPI/generateKey/failures.js | 216 ++++++++++ .../WebCryptoAPI/generateKey/failures.worker.js | 5 + .../generateKey/failures_AES-CBC.worker.js | 6 + .../generateKey/failures_AES-CTR.worker.js | 6 + .../generateKey/failures_AES-GCM.worker.js | 6 + .../generateKey/failures_AES-KW.worker.js | 6 + .../generateKey/failures_ECDH.worker.js | 6 + .../generateKey/failures_ECDSA.worker.js | 6 + .../generateKey/failures_HMAC.worker.js | 6 + .../generateKey/failures_RSA-OAEP.worker.js | 6 + .../generateKey/failures_RSA-PSS.worker.js | 6 + .../failures_RSASSA-PKCS1-v1_5.worker.js | 6 + .../tests/WebCryptoAPI/generateKey/successes.js | 88 ++++ .../WebCryptoAPI/generateKey/successes.worker.js | 6 + .../generateKey/successes_AES-CBC.worker.js | 7 + .../generateKey/successes_AES-CTR.worker.js | 7 + .../generateKey/successes_AES-GCM.worker.js | 7 + .../generateKey/successes_AES-KW.worker.js | 7 + .../generateKey/successes_ECDH.worker.js | 7 + .../generateKey/successes_ECDSA.worker.js | 7 + .../generateKey/successes_HMAC.worker.js | 7 + .../generateKey/successes_RSA-OAEP.worker.js | 7 + .../generateKey/successes_RSA-PSS.worker.js | 7 + .../successes_RSASSA-PKCS1-v1_5.worker.js | 7 + .../WebCryptoAPI/generateKey/test_aes-cbc.html | 23 + .../WebCryptoAPI/generateKey/test_aes-ctr.html | 23 + .../WebCryptoAPI/generateKey/test_failures.html | 18 + .../generateKey/test_failures_AES-CBC.html | 18 + .../generateKey/test_failures_AES-CTR.html | 18 + .../generateKey/test_failures_AES-GCM.html | 18 + .../generateKey/test_failures_AES-KW.html | 18 + .../generateKey/test_failures_ECDH.html | 18 + .../generateKey/test_failures_ECDSA.html | 18 + .../generateKey/test_failures_HMAC.html | 18 + .../generateKey/test_failures_RSA-OAEP.html | 18 + .../generateKey/test_failures_RSA-PSS.html | 18 + .../test_failures_RSASSA-PKCS1-v1_5.html | 18 + .../WebCryptoAPI/generateKey/test_successes.html | 23 + .../generateKey/test_successes_AES-CBC.html | 23 + .../generateKey/test_successes_AES-CTR.html | 23 + .../generateKey/test_successes_AES-GCM.html | 23 + .../generateKey/test_successes_AES-KW.html | 23 + .../generateKey/test_successes_ECDH.html | 23 + .../generateKey/test_successes_ECDSA.html | 23 + .../generateKey/test_successes_HMAC.html | 23 + .../generateKey/test_successes_RSA-OAEP.html | 23 + .../generateKey/test_successes_RSA-PSS.html | 23 + .../test_successes_RSASSA-PKCS1-v1_5.html | 23 + .../tests/WebCryptoAPI/getRandomValues.js | 50 +++ .../tests/WebCryptoAPI/getRandomValues.worker.js | 4 + .../tests/WebCryptoAPI/idlharness.html | 45 ++ .../tests/WebCryptoAPI/idlharness.worker.js | 22 + .../WebCryptoAPI/import_export/ec_importKey.js | 279 ++++++++++++ .../import_export/ec_importKey.worker.js | 4 + .../WebCryptoAPI/import_export/rsa_importKey.js | 296 +++++++++++++ .../import_export/rsa_importKey.worker.js | 4 + .../import_export/symmetric_importKey.js | 242 +++++++++++ .../import_export/symmetric_importKey.worker.js | 4 + .../import_export/test_ec_importKey.html | 12 + .../import_export/test_rsa_importKey.html | 12 + .../import_export/test_symmetric_importKey.html | 12 + .../tests/WebCryptoAPI/sign_verify/ecdsa.js | 479 +++++++++++++++++++++ .../tests/WebCryptoAPI/sign_verify/ecdsa.worker.js | 5 + .../WebCryptoAPI/sign_verify/ecdsa_vectors.js | 105 +++++ .../tests/WebCryptoAPI/sign_verify/hmac.js | 347 +++++++++++++++ .../tests/WebCryptoAPI/sign_verify/hmac.worker.js | 5 + .../tests/WebCryptoAPI/sign_verify/hmac_vectors.js | 39 ++ .../tests/WebCryptoAPI/sign_verify/rsa.js | 399 +++++++++++++++++ .../WebCryptoAPI/sign_verify/rsa_pkcs.worker.js | 5 + .../WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js | 92 ++++ .../WebCryptoAPI/sign_verify/rsa_pss.worker.js | 5 + .../WebCryptoAPI/sign_verify/rsa_pss_vectors.js | 147 +++++++ .../tests/WebCryptoAPI/sign_verify/test_ecdsa.html | 19 + .../tests/WebCryptoAPI/sign_verify/test_hmac.html | 19 + .../WebCryptoAPI/sign_verify/test_rsa_pkcs.html | 19 + .../WebCryptoAPI/sign_verify/test_rsa_pss.html | 19 + .../tests/WebCryptoAPI/test_getRandomValues.html | 12 + .../tests/WebCryptoAPI/tools/generate.py | 76 ++++ .../tests/WebCryptoAPI/util/helpers.js | 230 ++++++++++ .../wrapKey_unwrapKey/test_wrapKey_unwrapKey.html | 17 + .../wrapKey_unwrapKey/wrapKey_unwrapKey.js | 266 ++++++++++++ .../wrapKey_unwrapKey/wrapKey_unwrapKey.worker.js | 5 + 116 files changed, 8008 insertions(+) create mode 100644 testing/web-platform/tests/WebCryptoAPI/OWNERS create mode 100644 testing/web-platform/tests/WebCryptoAPI/README.md create mode 100644 testing/web-platform/tests/WebCryptoAPI/WebCryptoAPI.idl create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/hkdf.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/hkdf.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/hkdf_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/digest/digest.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/digest/digest.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/digest/test_digest.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes_cbc.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes_cbc_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes_ctr.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes_ctr_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes_gcm.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/rsa.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/rsa.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/rsa_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_cbc.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-KW.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDH.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDSA.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_HMAC.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-KW.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDH.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDSA.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_HMAC.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/getRandomValues.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/getRandomValues.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/idlharness.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/idlharness.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/ec_importKey.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/ec_importKey.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/rsa_importKey.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/rsa_importKey.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/symmetric_importKey.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/symmetric_importKey.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/test_ec_importKey.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/hmac_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pkcs_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss.worker.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/rsa_pss_vectors.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/test_ecdsa.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/test_getRandomValues.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/tools/generate.py create mode 100644 testing/web-platform/tests/WebCryptoAPI/util/helpers.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.html create mode 100644 testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.js create mode 100644 testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.worker.js (limited to 'testing/web-platform/tests/WebCryptoAPI') diff --git a/testing/web-platform/tests/WebCryptoAPI/OWNERS b/testing/web-platform/tests/WebCryptoAPI/OWNERS new file mode 100644 index 000000000..6924cd943 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/OWNERS @@ -0,0 +1,4 @@ +@Wafflespeanut +@Ms2ger +@jimsch +@engelke diff --git a/testing/web-platform/tests/WebCryptoAPI/README.md b/testing/web-platform/tests/WebCryptoAPI/README.md new file mode 100644 index 000000000..5546cf2b6 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/README.md @@ -0,0 +1 @@ +Directory for Crypto API tests diff --git a/testing/web-platform/tests/WebCryptoAPI/WebCryptoAPI.idl b/testing/web-platform/tests/WebCryptoAPI/WebCryptoAPI.idl new file mode 100644 index 000000000..132c6d076 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/WebCryptoAPI.idl @@ -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 encrypt(AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data); + Promise decrypt(AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data); + Promise sign(AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource data); + Promise verify(AlgorithmIdentifier algorithm, + CryptoKey key, + BufferSource signature, + BufferSource data); + Promise digest(AlgorithmIdentifier algorithm, + BufferSource data); + + Promise generateKey(AlgorithmIdentifier algorithm, + boolean extractable, + sequence keyUsages ); + Promise deriveKey(AlgorithmIdentifier algorithm, + CryptoKey baseKey, + AlgorithmIdentifier derivedKeyType, + boolean extractable, + sequence keyUsages ); + Promise deriveBits(AlgorithmIdentifier algorithm, + CryptoKey baseKey, + unsigned long length); + + Promise importKey(KeyFormat format, + (BufferSource or JsonWebKey) keyData, + AlgorithmIdentifier algorithm, + boolean extractable, + sequence keyUsages ); + Promise exportKey(KeyFormat format, CryptoKey key); + + Promise wrapKey(KeyFormat format, + CryptoKey key, + CryptoKey wrappingKey, + AlgorithmIdentifier wrapAlgorithm); + Promise unwrapKey(KeyFormat format, + BufferSource wrappedKey, + CryptoKey unwrappingKey, + AlgorithmIdentifier unwrapAlgorithm, + AlgorithmIdentifier unwrappedKeyAlgorithm, + boolean extractable, + sequence 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 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 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; +}; diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.js new file mode 100644 index 000000000..fe82ffe57 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.js @@ -0,0 +1,269 @@ + +function run_test() { + // May want to test prefixed implementations. + var subtle = self.crypto.subtle; + + var pkcs8 = { + "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]), + "P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]), + "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196]) + }; + + var spki = { + "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]), + "P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]), + "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245]) + }; + + var sizes = { + "P-521": 66, + "P-256": 32, + "P-384": 48 + }; + + var derivations = { + "P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]), + "P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]), + "P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45]) + }; + + importKeys(pkcs8, spki, sizes) + .then(function(results) { + publicKeys = results.publicKeys; + privateKeys = results.privateKeys; + ecdsaKeyPairs = results.ecdsaKeyPairs; + noDeriveBitsKeys = results.noDeriveBitsKeys; + + Object.keys(sizes).forEach(function(namedCurve) { + // Basic success case + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " good parameters"); + + // Case insensitivity check + promise_test(function(test) { + return subtle.deriveBits({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " mixed case parameters"); + + // Null length + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], null) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[namedCurve]), "Derived correct bits"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " with null length"); + + // Shorter than entire derivation per algorithm + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 32) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 32), "Derived correct bits"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " short result"); + + // Non-multiple of 8 + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 11) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 11), "Derived correct bits"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " non-multiple of 8 bits"); + + // Errors to test: + + // - missing public property TypeError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH"}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with TypeError"); + }, function(err) { + assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " missing public curve"); + + // - Non CryptoKey public property TypeError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with TypeError"); + }, function(err) { + assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " public property of algorithm is not a CryptoKey"); + + // - wrong named curve + promise_test(function(test) { + publicKey = publicKeys["P-256"]; + if (namedCurve === "P-256") { + publicKey = publicKeys["P-384"]; + } + return subtle.deriveBits({name: "ECDH", public: publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " mismatched curves"); + + // - not ECDH public property InvalidAccessError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " public property of algorithm is not an ECDSA public key"); + + // - No deriveBits usage in baseKey InvalidAccessError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveBitsKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " no deriveBits usage for base key"); + + // - Use public key for baseKey InvalidAccessError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " base key is not a private key"); + + // - Use private key for public property InvalidAccessError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " public property value is a private key"); + + // - Use secret key for public property InvalidAccessError + promise_test(function(test) { + return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"]) + .then(function(secretKey) { + subtle.deriveBits({name: "ECDH", public: secretKey}, privateKeys[namedCurve], 8 * sizes[namedCurve]) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }); + }, namedCurve + " public property value is a secret key"); + + // - Length greater than 256, 384, 521 for particular curves OperationError + promise_test(function(test) { + return subtle.deriveBits({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] + 8) + .then(function(derivation) { + assert_unreached("deriveBits succeeded but should have failed with OperationError"); + }, function(err) { + assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " asking for too many bits"); + }); + done() + }); + + function importKeys(pkcs8, spki, sizes) { + var privateKeys = {}; + var publicKeys = {}; + var ecdsaKeyPairs = {}; + var noDeriveBitsKeys = {}; + + var promises = []; + Object.keys(pkcs8).forEach(function(namedCurve) { + var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], + {name: "ECDH", namedCurve: namedCurve}, + false, ["deriveBits", "deriveKey"]) + .then(function(key) { + privateKeys[namedCurve] = key; + }); + promises.push(operation); + }); + Object.keys(pkcs8).forEach(function(namedCurve) { + var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], + {name: "ECDH", namedCurve: namedCurve}, + false, ["deriveKey"]) + .then(function(key) { + noDeriveBitsKeys[namedCurve] = key; + }); + promises.push(operation); + }); + Object.keys(spki).forEach(function(namedCurve) { + var operation = subtle.importKey("spki", spki[namedCurve], + {name: "ECDH", namedCurve: namedCurve}, + false, []) + .then(function(key) { + publicKeys[namedCurve] = key; + }); + promises.push(operation); + }); + Object.keys(sizes).forEach(function(namedCurve) { + var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"]) + .then(function(keyPair) { + ecdsaKeyPairs[namedCurve] = keyPair; + }); + promises.push(operation); + }); + + return Promise.all(promises) + .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveBitsKeys: noDeriveBitsKeys}}); + } + + // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is + // omitted, the two values must be the same length and have the same contents + // in every byte. If bitCount is included, only that leading number of bits + // have to match. + function equalBuffers(a, b, bitCount) { + var remainder; + + if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + var length = a.byteLength; + if (typeof bitCount !== "undefined") { + length = Math.floor(bitCount / 8); + } + + for (var i=0; i> (8 - remainder) === bBytes[length] >> (8 - remainder); + } + + return true; + } + +} diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.worker.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.worker.js new file mode 100644 index 000000000..8ff0ac305 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.worker.js @@ -0,0 +1,4 @@ +importScripts("/resources/testharness.js"); +importScripts("ecdh_bits.js"); + +run_test(); diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.js new file mode 100644 index 000000000..b1a0bcd48 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.js @@ -0,0 +1,238 @@ + +function run_test() { + // May want to test prefixed implementations. + var subtle = self.crypto.subtle; + + var pkcs8 = { + "P-521": new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 1, 166, 126, 211, 33, 145, 90, 100, 170, 53, 155, 125, 100, 141, 220, 38, 24, 250, 142, 141, 24, 103, 232, 247, 24, 48, 177, 13, 37, 237, 40, 145, 250, 241, 47, 60, 126, 117, 66, 26, 46, 162, 100, 249, 169, 21, 50, 13, 39, 79, 225, 71, 7, 66, 185, 132, 233, 107, 152, 145, 32, 129, 250, 205, 71, 141, 161, 129, 137, 3, 129, 134, 0, 4, 0, 32, 157, 72, 63, 40, 102, 104, 129, 198, 100, 31, 58, 18, 111, 64, 15, 81, 228, 101, 17, 112, 254, 103, 140, 117, 232, 87, 18, 226, 134, 138, 220, 133, 8, 36, 153, 123, 235, 240, 188, 130, 180, 48, 40, 166, 210, 236, 23, 119, 202, 69, 39, 159, 114, 6, 163, 234, 139, 92, 210, 7, 63, 73, 62, 69, 0, 12, 181, 76, 58, 90, 202, 162, 104, 197, 103, 16, 66, 136, 120, 217, 139, 138, 251, 246, 138, 97, 33, 83, 99, 40, 70, 216, 7, 233, 38, 114, 105, 143, 27, 156, 97, 29, 231, 211, 142, 52, 205, 108, 115, 136, 144, 146, 197, 110, 82, 214, 128, 241, 223, 208, 146, 184, 122, 200, 239, 159, 243, 200, 251, 72]), + "P-256": new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 15, 247, 79, 232, 241, 202, 175, 97, 92, 206, 241, 29, 217, 53, 114, 87, 98, 217, 216, 65, 236, 186, 185, 94, 170, 38, 68, 123, 52, 100, 245, 113, 161, 68, 3, 66, 0, 4, 140, 96, 11, 44, 102, 25, 45, 97, 158, 39, 210, 37, 107, 59, 151, 118, 178, 141, 30, 5, 246, 13, 234, 189, 98, 174, 123, 154, 211, 157, 224, 217, 59, 4, 102, 109, 199, 119, 14, 126, 207, 13, 211, 203, 203, 211, 110, 221, 107, 94, 220, 153, 81, 7, 55, 161, 237, 104, 46, 205, 112, 244, 10, 47]), + "P-384": new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 248, 113, 165, 102, 101, 137, 193, 74, 87, 71, 38, 62, 248, 91, 49, 156, 192, 35, 219, 110, 53, 103, 108, 61, 120, 30, 239, 139, 5, 95, 207, 190, 134, 250, 13, 6, 208, 86, 181, 25, 95, 177, 50, 58, 248, 222, 37, 179, 161, 100, 3, 98, 0, 4, 241, 25, 101, 223, 125, 212, 89, 77, 4, 25, 197, 8, 100, 130, 163, 184, 38, 185, 121, 127, 155, 224, 189, 13, 16, 156, 158, 30, 153, 137, 193, 185, 169, 43, 143, 38, 159, 152, 225, 122, 209, 132, 186, 115, 193, 247, 151, 98, 175, 69, 175, 129, 65, 96, 38, 66, 218, 39, 26, 107, 176, 255, 235, 12, 180, 71, 143, 207, 112, 126, 102, 26, 166, 214, 205, 245, 21, 73, 200, 140, 63, 19, 11, 233, 232, 32, 31, 111, 106, 9, 244, 24, 90, 175, 149, 196]) + }; + + var spki = { + "P-521": new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 0, 238, 105, 249, 71, 21, 215, 1, 233, 226, 1, 19, 51, 212, 244, 249, 108, 186, 125, 145, 248, 139, 17, 43, 175, 117, 207, 9, 204, 31, 138, 202, 151, 97, 141, 169, 56, 152, 34, 210, 155, 111, 233, 153, 106, 97, 32, 62, 247, 82, 183, 113, 232, 149, 143, 196, 103, 123, 179, 119, 133, 101, 171, 96, 214, 237, 0, 222, 171, 103, 97, 137, 91, 147, 94, 58, 211, 37, 251, 133, 73, 229, 111, 19, 120, 106, 167, 63, 136, 162, 236, 254, 64, 147, 52, 115, 216, 174, 242, 64, 196, 223, 215, 213, 6, 242, 44, 221, 14, 85, 85, 143, 63, 191, 5, 235, 247, 239, 239, 122, 114, 215, 143, 70, 70, 155, 132, 72, 242, 110, 39, 18]), + "P-256": new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 154, 116, 32, 120, 126, 95, 77, 105, 211, 232, 34, 114, 115, 1, 109, 56, 224, 71, 129, 133, 223, 127, 238, 156, 142, 103, 60, 202, 211, 79, 126, 128, 254, 49, 141, 182, 221, 107, 119, 218, 99, 32, 165, 246, 151, 89, 9, 68, 23, 177, 52, 239, 138, 139, 116, 193, 101, 4, 57, 198, 115, 0, 90, 61]), + "P-384": new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 145, 130, 45, 194, 175, 89, 193, 143, 91, 103, 248, 13, 246, 26, 38, 3, 194, 168, 240, 179, 192, 175, 130, 45, 99, 194, 121, 112, 26, 130, 69, 96, 64, 68, 1, 221, 233, 165, 110, 229, 39, 87, 234, 139, 199, 72, 212, 200, 43, 83, 55, 180, 141, 123, 101, 88, 58, 61, 87, 36, 56, 136, 0, 54, 186, 198, 115, 15, 66, 202, 82, 120, 150, 107, 213, 242, 30, 134, 226, 29, 48, 197, 166, 208, 70, 62, 197, 19, 221, 80, 159, 252, 220, 175, 31, 245]) + }; + + var sizes = { + "P-521": 66, + "P-256": 32, + "P-384": 48 + }; + + var derivations = { + "P-521": new Uint8Array([0, 156, 43, 206, 87, 190, 128, 173, 171, 59, 7, 56, 91, 142, 89, 144, 235, 125, 111, 222, 189, 176, 27, 243, 83, 113, 164, 246, 7, 94, 157, 40, 138, 193, 42, 109, 254, 3, 170, 87, 67, 188, 129, 112, 157, 73, 168, 34, 148, 2, 25, 182, 75, 118, 138, 205, 82, 15, 161, 54, 142, 160, 175, 141, 71, 93]), + "P-256": new Uint8Array([14, 143, 60, 77, 177, 178, 162, 131, 115, 90, 0, 220, 87, 31, 26, 232, 151, 28, 227, 35, 250, 17, 131, 137, 203, 95, 65, 196, 59, 61, 181, 161]), + "P-384": new Uint8Array([224, 189, 107, 206, 10, 239, 140, 164, 136, 56, 166, 226, 252, 197, 126, 103, 185, 197, 232, 134, 12, 95, 11, 233, 218, 190, 197, 62, 69, 78, 24, 160, 161, 116, 196, 136, 136, 162, 100, 136, 17, 91, 45, 201, 241, 223, 165, 45]) + }; + + importKeys(pkcs8, spki, sizes) + .then(function(results) { + publicKeys = results.publicKeys; + privateKeys = results.privateKeys; + ecdsaKeyPairs = results.ecdsaKeyPairs; + noDeriveKeyKeys = results.noDeriveKeyKeys; + + Object.keys(sizes).forEach(function(namedCurve) { + // Basic success case + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_true(equalBuffers(exportedKey, derivations[namedCurve], 8 * exportedKey.length), "Derived correct key"); + }, function(err) { + assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " good parameters"); + + // Case insensitivity check + promise_test(function(test) { + return subtle.deriveKey({name: "EcDh", public: publicKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_true(equalBuffers(exportedKey, derivations[namedCurve], 8 * exportedKey.length), "Derived correct key"); + }, function(err) { + assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); + }); + }, namedCurve + " mixed case parameters"); + // Errors to test: + + // - missing public property TypeError + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH"}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with TypeError"); + }, function(err) { + assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " missing public curve"); + + // - Non CryptoKey public property TypeError + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH", public: {message: "Not a CryptoKey"}}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with TypeError"); + }, function(err) { + assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " public property of algorithm is not a CryptoKey"); + + // - wrong named curve + promise_test(function(test) { + publicKey = publicKeys["P-256"]; + if (namedCurve === "P-256") { + publicKey = publicKeys["P-384"]; + } + return subtle.deriveKey({name: "ECDH", public: publicKey}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " mismatched curves"); + + // - not ECDH public property InvalidAccessError + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH", public: ecdsaKeyPairs[namedCurve].publicKey}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " public property of algorithm is not an ECDSA public key"); + + // - No deriveKey usage in baseKey InvalidAccessError + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, noDeriveKeyKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " no deriveKey usage for base key"); + + // - Use public key for baseKey InvalidAccessError + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH", public: publicKeys[namedCurve]}, publicKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " base key is not a private key"); + + // - Use private key for public property InvalidAccessError + promise_test(function(test) { + return subtle.deriveKey({name: "ECDH", public: privateKeys[namedCurve]}, privateKeys[namedCurve], {name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, namedCurve + " public property value is a private key"); + + // - Use secret key for public property InvalidAccessError + promise_test(function(test) { + return subtle.generateKey({name: "HMAC", hash: "SHA-256", length: 256}, true, ["sign", "verify"]) + .then(function(secretKey) { + subtle.deriveKey({name: "ECDH", public: secretKey}, privateKeys[namedCurve], {name: "AES-CBC", length: 256}, true, ["sign", "verify"]) + .then(function(key) {return crypto.subtle.exportKey("raw", key);}) + .then(function(exportedKey) { + assert_unreached("deriveKey succeeded but should have failed with InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }); + }, namedCurve + " public property value is a secret key"); + }); + done(); + }); + + function importKeys(pkcs8, spki, sizes) { + var privateKeys = {}; + var publicKeys = {}; + var ecdsaKeyPairs = {}; + var noDeriveKeyKeys = {}; + + var promises = []; + Object.keys(pkcs8).forEach(function(namedCurve) { + var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], + {name: "ECDH", namedCurve: namedCurve}, + false, ["deriveBits", "deriveKey"]) + .then(function(key) { + privateKeys[namedCurve] = key; + }); + promises.push(operation); + }); + Object.keys(pkcs8).forEach(function(namedCurve) { + var operation = subtle.importKey("pkcs8", pkcs8[namedCurve], + {name: "ECDH", namedCurve: namedCurve}, + false, ["deriveBits"]) + .then(function(key) { + noDeriveKeyKeys[namedCurve] = key; + }); + promises.push(operation); + }); + Object.keys(spki).forEach(function(namedCurve) { + var operation = subtle.importKey("spki", spki[namedCurve], + {name: "ECDH", namedCurve: namedCurve}, + false, []) + .then(function(key) { + publicKeys[namedCurve] = key; + }); + promises.push(operation); + }); + Object.keys(sizes).forEach(function(namedCurve) { + var operation = subtle.generateKey({name: "ECDSA", namedCurve: namedCurve}, false, ["sign", "verify"]) + .then(function(keyPair) { + ecdsaKeyPairs[namedCurve] = keyPair; + }); + promises.push(operation); + }); + + return Promise.all(promises) + .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, ecdsaKeyPairs: ecdsaKeyPairs, noDeriveKeyKeys: noDeriveKeyKeys}}); + } + + // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is + // omitted, the two values must be the same length and have the same contents + // in every byte. If bitCount is included, only that leading number of bits + // have to match. + function equalBuffers(a, b, bitCount) { + var remainder; + + if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + var length = a.byteLength; + if (typeof bitCount !== "undefined") { + length = Math.floor(bitCount / 8); + } + + for (var i=0; i> (8 - remainder) === bBytes[length] >> (8 - remainder); + } + + return true; + } + +} diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.worker.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.worker.js new file mode 100644 index 000000000..488d60216 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.worker.js @@ -0,0 +1,4 @@ +importScripts("/resources/testharness.js"); +importScripts("ecdh_keys.js"); + +run_test(); diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/hkdf.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/hkdf.js new file mode 100644 index 000000000..016740abf --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/hkdf.js @@ -0,0 +1,312 @@ + +function run_test() { + // May want to test prefixed implementations. + var subtle = self.crypto.subtle; + + // hkdf2_vectors sets up test data with the correct derivations for each + // test case. + var testData = getTestData(); + var derivedKeys = testData.derivedKeys; + var salts = testData.salts; + var derivations = testData.derivations; + var infos = testData.infos; + + // What kinds of keys can be created with deriveKey? The following: + var derivedKeyTypes = testData.derivedKeyTypes; + + setUpBaseKeys(derivedKeys) + .then(function(allKeys) { + // We get several kinds of base keys. Normal ones that can be used for + // derivation operations, ones that lack the deriveBits usage, ones + // that lack the deriveKeys usage, and one key that is for the wrong + // algorithm (not HKDF in this case). + var baseKeys = allKeys.baseKeys; + var noBits = allKeys.noBits; + var noKey = allKeys.noKey; + var wrongKey = allKeys.wrongKey; + + // Test each combination of derivedKey size, salt size, hash function, + // and number of iterations. The derivations object is structured in + // that way, so navigate it to run tests and compare with correct results. + Object.keys(derivations).forEach(function(derivedKeySize) { + Object.keys(derivations[derivedKeySize]).forEach(function(saltSize) { + Object.keys(derivations[derivedKeySize][saltSize]).forEach(function(hashName) { + Object.keys(derivations[derivedKeySize][saltSize][hashName]).forEach(function(infoSize) { + var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info"; + var algorithm = {name: "HKDF", salt: salts[saltSize], info: infos[infoSize], hash: hashName}; + + // Check for correct deriveBits result + promise_test(function(test) { + return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 256) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[derivedKeySize][saltSize][hashName][infoSize]), "Derived correct key"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, testName); + + // 0 length (OperationError) + promise_test(function(test) { + return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 0) + .then(function(derivation) { + assert_equals(derivation.byteLength, 0, "Derived correctly empty key"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with 0 length correctly threw OperationError: " + err.message); + }); + }, testName + " with 0 length"); + + // Check for correct deriveKey results for every kind of + // key that can be created by the deriveKeys operation. + derivedKeyTypes.forEach(function(derivedKeyType) { + var testName = "Derived key of type "; + Object.keys(derivedKeyType.algorithm).forEach(function(prop) { + testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + }); + testName += " using " + derivedKeySize + " derivedKey, " + saltSize + " salt, " + hashName + ", with " + infoSize + " info"; + + // Test the particular key derivation. + promise_test(function(test) { + return subtle.deriveKey(algorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + // Need to export the key to see that the correct bits were set. + return subtle.exportKey("raw", key) + .then(function(buffer) { + assert_true(equalBuffers(buffer, derivations[derivedKeySize][saltSize][hashName][infoSize].slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value"); + }, function(err) { + assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message); + }); + }, function(err) { + assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); + + }); + }, testName); + + // Test various error conditions for deriveKey: + + // - illegal name for hash algorithm (NotSupportedError) + var badHash = hashName.substring(0, 3) + hashName.substring(4); + promise_test(function(test) { + var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash}; + return subtle.deriveKey(badAlgorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("bad hash name should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with bad hash name " + badHash); + + // - baseKey usages missing "deriveKey" (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveKey(algorithm, noKey[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with missing deriveKey usage"); + + // - baseKey algorithm does not match HKDF (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveKey(algorithm, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with wrong (ECDH) key"); + + }); + + // Test various error conditions for deriveBits below: + + // missing salt (TypeError) + promise_test(function(test) { + return subtle.deriveBits({name: "HKDF", info: infos[infoSize], hash: hashName}, baseKeys[derivedKeySize], 0) + .then(function(derivation) { + assert_equals(derivation.byteLength, 0, "Derived even with missing salt"); + }, function(err) { + assert_equals(err.name, "TypeError", "deriveBits missing salt correctly threw OperationError: " + err.message); + }); + }, testName + " with missing salt"); + + // missing info (TypeError) + promise_test(function(test) { + return subtle.deriveBits({name: "HKDF", salt: salts[saltSize], hash: hashName}, baseKeys[derivedKeySize], 0) + .then(function(derivation) { + assert_equals(derivation.byteLength, 0, "Derived even with missing info"); + }, function(err) { + assert_equals(err.name, "TypeError", "deriveBits missing info correctly threw OperationError: " + err.message); + }); + }, testName + " with missing info"); + + // length null (OperationError) + promise_test(function(test) { + return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], null) + .then(function(derivation) { + assert_unreached("null length should have thrown an TypeError"); + }, function(err) { + assert_equals(err.name, "TypeError", "deriveBits with null length correctly threw OperationError: " + err.message); + }); + }, testName + " with null length"); + + // length not multiple of 8 (OperationError) + promise_test(function(test) { + return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 44) + .then(function(derivation) { + assert_unreached("non-multiple of 8 length should have thrown an OperationError"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message); + }); + }, testName + " with non-multiple of 8 length"); + + // - illegal name for hash algorithm (NotSupportedError) + var badHash = hashName.substring(0, 3) + hashName.substring(4); + promise_test(function(test) { + var badAlgorithm = {name: "HKDF", salt: salts[saltSize], hash: badHash}; + return subtle.deriveBits(badAlgorithm, baseKeys[derivedKeySize], 256) + .then(function(derivation) { + assert_unreached("bad hash name should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with bad hash name " + badHash); + + // - baseKey usages missing "deriveBits" (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveBits(algorithm, noBits[derivedKeySize], 256) + .then(function(derivation) { + assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with missing deriveBits usage"); + + // - baseKey algorithm does not match HKDF (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveBits(algorithm, wrongKey, 256) + .then(function(derivation) { + assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with wrong (ECDH) key"); + }); + }); + + // - legal algorithm name but not digest one (e.g., PBKDF2) (NotSupportedError) + var nonDigestHash = "PBKDF2"; + Object.keys(infos).forEach(function(infoSize) { + var testName = derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info"; + var algorithm = {name: "HKDF", salt: salts[saltSize], hash: nonDigestHash}; + if (infoSize !== "missing") { + algorithm.info = infos[infoSize]; + } + + promise_test(function(test) { + return subtle.deriveBits(algorithm, baseKeys[derivedKeySize], 256) + .then(function(derivation) { + assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with non-digest algorithm " + nonDigestHash); + + derivedKeyTypes.forEach(function(derivedKeyType) { + var testName = "Derived key of type "; + Object.keys(derivedKeyType.algorithm).forEach(function(prop) { + testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + }); + testName += " using " + derivedKeySize + " derivedKey, " + saltSize + " salt, " + nonDigestHash + ", with " + infoSize + " info"; + + promise_test(function(test) { + return subtle.deriveKey(algorithm, baseKeys[derivedKeySize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(derivation) { + assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message); + }); + }, testName); + }); + + }); + + }); + }); + + done(); + }, function(err) { + test(function(test) { + assert_unreached("setUpBaseKeys failed with error '" + err.message + "'"); + }, "setUpBaseKeys"); + done(); + }); + + // Deriving bits and keys requires starting with a base key, which is created + // by importing a derivedKey. setUpBaseKeys returns a promise that yields the + // necessary base keys. + function setUpBaseKeys(derivedKeys) { + var promises = []; + + var baseKeys = {}; + var noBits = {}; + var noKey = {}; + var wrongKey = null; + + Object.keys(derivedKeys).forEach(function(derivedKeySize) { + var promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveKey", "deriveBits"]) + .then(function(baseKey) { + baseKeys[derivedKeySize] = baseKey; + }, function(err) { + baseKeys[derivedKeySize] = null; + }); + promises.push(promise); + + promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveBits"]) + .then(function(baseKey) { + noKey[derivedKeySize] = baseKey; + }, function(err) { + noKey[derivedKeySize] = null; + }); + promises.push(promise); + + promise = subtle.importKey("raw", derivedKeys[derivedKeySize], {name: "HKDF"}, false, ["deriveKey"]) + .then(function(baseKey) { + noBits[derivedKeySize] = baseKey; + }, function(err) { + noBits[derivedKeySize] = null; + }); + promises.push(promise); + }); + + var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) + .then(function(baseKey) { + wrongKey = baseKey.privateKey; + }, function(err) { + wrongKey = null; + }); + promises.push(promise); + + + return Promise.all(promises).then(function() { + return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey}; + }); + } + + function equalBuffers(a, b) { + if (a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + for (var i=0; in + + // Variations to test: + // - empty, short, and fairly long derivedKey + // - empty, short, and fairly long salt + // - SHA-1, SHA-256, SHA-384, SHA-512 hash + // - 1, 1000, and 100000 million iterations + + // Test cases to generate: 3 * 3 * 4 * 3 = 108 + + // Error conditions to test: + // - length null (OperationError) + // - length not a multiple of 8 (OperationError) + // - illegal name for hash algorithm (NotSupportedError) + // - legal algorithm name but not digest one (e.g., AES-CBC) (NotSupportedError) + // - baseKey usages missing "deriveBits" (InvalidAccessError) + // - baseKey algorithm does not match HKDF (InvalidAccessError) + // - 0 iterations + + var derivedKeyTypes = [ + {algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CBC", length: 192}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CBC", length: 256}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CTR", length: 192}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CTR", length: 256}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 192}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 256}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-KW", length: 128}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "AES-KW", length: 192}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "AES-KW", length: 256}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "HMAC", hash: "SHA-1", length: 256}, usages: ["sign", "verify"]}, + {algorithm: {name: "HMAC", hash: "SHA-256", length: 256}, usages: ["sign", "verify"]}, + {algorithm: {name: "HMAC", hash: "SHA-384", length: 256}, usages: ["sign", "verify"]}, + {algorithm: {name: "HMAC", hash: "SHA-512", length: 256}, usages: ["sign", "verify"]} + ]; + + var derivedKeys = { + "short": new Uint8Array([80, 64, 115, 115, 119, 48, 114, 100]), + "long": new Uint8Array([85, 115, 101, 114, 115, 32, 115, 104, 111, 117, 108, 100, 32, 112, 105, 99, 107, 32, 108, 111, 110, 103, 32, 112, 97, 115, 115, 112, 104, 114, 97, 115, 101, 115, 32, 40, 110, 111, 116, 32, 117, 115, 101, 32, 115, 104, 111, 114, 116, 32, 112, 97, 115, 115, 119, 111, 114, 100, 115, 41, 33]), + "empty": new Uint8Array([]) + }; + + var salts = { + "normal": new Uint8Array([83, 111, 100, 105, 117, 109, 32, 67, 104, 108, 111, 114, 105, 100, 101, 32, 99, 111, 109, 112, 111, 117, 110, 100]), + "empty": new Uint8Array([]) + }; + + var infos = { + "normal": new Uint8Array([72, 75, 68, 70, 32, 101, 120, 116, 114, 97, 32, 105, 110, 102, 111]), + "empty": new Uint8Array([]) + }; + + var derivations = { + "short": { + "normal": { + "SHA-384": { + "normal": new Uint8Array([25, 186, 116, 54, 142, 107, 153, 51, 144, 242, 127, 233, 167, 208, 43, 195, 56, 23, 63, 114, 190, 113, 161, 159, 199, 68, 252, 219, 63, 212, 184, 75]), + "empty": new Uint8Array([151, 96, 31, 78, 12, 83, 165, 211, 243, 162, 129, 0, 153, 188, 104, 32, 236, 80, 8, 52, 52, 118, 155, 89, 252, 36, 164, 23, 169, 84, 55, 52]) + }, + "SHA-512": { + "normal": new Uint8Array([75, 189, 109, 178, 67, 95, 182, 150, 21, 127, 96, 137, 201, 119, 195, 199, 63, 62, 172, 94, 243, 221, 107, 170, 230, 4, 203, 83, 191, 187, 21, 62]), + "empty": new Uint8Array([47, 49, 87, 231, 254, 12, 16, 176, 18, 152, 200, 240, 136, 106, 144, 237, 207, 128, 171, 222, 245, 219, 193, 223, 43, 20, 130, 83, 43, 82, 185, 52]) + }, + "SHA-1": { + "normal": new Uint8Array([5, 173, 34, 237, 33, 56, 201, 96, 14, 77, 158, 39, 37, 222, 211, 1, 245, 210, 135, 251, 251, 87, 2, 249, 153, 188, 101, 54, 211, 237, 239, 152]), + "empty": new Uint8Array([213, 27, 111, 183, 229, 153, 202, 48, 197, 238, 38, 69, 147, 228, 184, 95, 34, 32, 199, 195, 171, 0, 49, 87, 191, 248, 203, 79, 54, 156, 117, 96]) + }, + "SHA-256": { + "normal": new Uint8Array([42, 245, 144, 30, 40, 132, 156, 40, 68, 56, 87, 56, 106, 161, 172, 59, 177, 39, 233, 38, 49, 193, 192, 81, 72, 45, 102, 144, 148, 23, 114, 180]), + "empty": new Uint8Array([158, 75, 113, 144, 51, 116, 33, 1, 233, 15, 26, 214, 30, 47, 243, 180, 37, 104, 99, 102, 114, 150, 215, 67, 137, 241, 240, 42, 242, 196, 230, 166]) + } + }, + "empty": { + "SHA-384": { + "normal": new Uint8Array([251, 72, 47, 242, 44, 79, 141, 70, 108, 77, 254, 110, 41, 242, 204, 46, 205, 171, 245, 136, 67, 40, 251, 240, 138, 115, 143, 217, 69, 241, 102, 203]), + "empty": new Uint8Array([30, 2, 60, 23, 179, 64, 83, 60, 234, 239, 57, 35, 12, 184, 179, 187, 219, 246, 99, 161, 61, 96, 117, 208, 221, 50, 108, 4, 148, 120, 251, 165]) + }, + "SHA-512": { + "normal": new Uint8Array([241, 123, 91, 220, 216, 215, 211, 212, 96, 16, 54, 161, 148, 54, 49, 125, 22, 68, 249, 164, 224, 149, 110, 252, 14, 55, 43, 131, 172, 218, 207, 219]), + "empty": new Uint8Array([199, 180, 116, 148, 47, 49, 248, 63, 175, 93, 20, 115, 24, 2, 177, 189, 73, 71, 133, 73, 203, 58, 143, 61, 191, 237, 196, 211, 32, 156, 245, 182]) + }, + "SHA-1": { + "normal": new Uint8Array([193, 38, 241, 230, 242, 90, 157, 228, 44, 247, 212, 39, 5, 154, 82, 237, 150, 1, 242, 154, 88, 21, 203, 251, 198, 75, 199, 246, 104, 198, 163, 65]), + "empty": new Uint8Array([50, 21, 195, 240, 141, 231, 5, 73, 176, 81, 183, 3, 55, 69, 168, 24, 79, 140, 186, 166, 177, 115, 83, 48, 210, 188, 182, 177, 111, 70, 66, 239]) + }, + "SHA-256": { + "normal": new Uint8Array([115, 60, 139, 107, 207, 172, 135, 92, 127, 8, 152, 42, 110, 63, 251, 86, 10, 206, 166, 241, 101, 71, 110, 184, 52, 96, 185, 53, 62, 212, 29, 254]), + "empty": new Uint8Array([200, 225, 39, 116, 19, 83, 5, 201, 20, 127, 44, 196, 118, 110, 94, 173, 37, 216, 244, 87, 185, 161, 149, 61, 82, 103, 115, 97, 206, 213, 88, 251]) + } + } + }, + "long": { + "normal": { + "SHA-384": { + "normal": new Uint8Array([249, 21, 113, 181, 33, 247, 238, 241, 62, 87, 58, 164, 99, 120, 101, 158, 243, 183, 243, 111, 253, 209, 187, 5, 93, 178, 205, 119, 210, 96, 196, 103]), + "empty": new Uint8Array([104, 175, 28, 44, 246, 185, 55, 13, 32, 84, 52, 71, 152, 189, 187, 24, 71, 204, 244, 7, 183, 101, 43, 121, 61, 209, 54, 212, 100, 14, 3, 72]) + }, + "SHA-512": { + "normal": new Uint8Array([113, 10, 174, 47, 223, 136, 158, 69, 254, 15, 185, 149, 178, 194, 107, 51, 235, 152, 134, 80, 236, 15, 174, 241, 103, 2, 138, 122, 108, 203, 54, 56]), + "empty": new Uint8Array([229, 222, 86, 128, 129, 199, 30, 86, 39, 80, 130, 152, 113, 195, 66, 117, 129, 4, 118, 94, 214, 243, 6, 240, 97, 60, 157, 75, 179, 54, 242, 170]) + }, + "SHA-1": { + "normal": new Uint8Array([127, 149, 126, 220, 188, 227, 203, 11, 112, 86, 110, 30, 182, 14, 253, 30, 64, 90, 19, 48, 76, 102, 29, 54, 99, 119, 129, 9, 191, 6, 137, 156]), + "empty": new Uint8Array([48, 98, 243, 207, 26, 115, 11, 156, 239, 81, 240, 44, 29, 250, 200, 94, 217, 30, 75, 0, 101, 235, 80, 202, 159, 216, 176, 16, 126, 114, 135, 51]) + }, + "SHA-256": { + "normal": new Uint8Array([49, 183, 214, 133, 48, 168, 99, 231, 23, 192, 129, 202, 105, 23, 182, 134, 80, 179, 221, 154, 41, 243, 6, 6, 226, 202, 209, 153, 190, 193, 77, 19]), + "empty": new Uint8Array([229, 121, 209, 249, 231, 240, 142, 111, 153, 15, 252, 252, 206, 30, 210, 1, 197, 227, 126, 98, 205, 246, 6, 240, 186, 74, 202, 128, 66, 127, 188, 68]) + } + }, + "empty": { + "SHA-384": { + "normal": new Uint8Array([97, 158, 182, 249, 40, 115, 149, 187, 213, 237, 106, 103, 201, 104, 70, 90, 216, 43, 108, 85, 159, 60, 56, 182, 4, 187, 176, 143, 88, 50, 11, 3]), + "empty": new Uint8Array([255, 68, 123, 66, 61, 131, 254, 118, 131, 108, 50, 51, 114, 40, 181, 107, 91, 217, 191, 104, 213, 142, 125, 202, 75, 124, 202, 132, 42, 69, 225, 26]) + }, + "SHA-512": { + "normal": new Uint8Array([19, 62, 138, 127, 127, 244, 51, 105, 12, 200, 132, 50, 194, 163, 56, 194, 119, 229, 193, 55, 86, 255, 135, 143, 70, 117, 63, 230, 165, 100, 227, 229]), + "empty": new Uint8Array([222, 84, 247, 238, 200, 12, 156, 198, 109, 52, 159, 201, 135, 248, 13, 70, 29, 178, 239, 79, 244, 225, 133, 5, 210, 139, 216, 12, 180, 44, 125, 118]) + }, + "SHA-1": { + "normal": new Uint8Array([173, 185, 60, 219, 206, 121, 183, 213, 17, 89, 182, 192, 19, 26, 43, 98, 242, 56, 40, 210, 106, 205, 104, 94, 52, 192, 101, 53, 230, 247, 116, 150]), + "empty": new Uint8Array([71, 113, 13, 42, 117, 7, 224, 90, 29, 220, 200, 122, 124, 47, 144, 97, 119, 162, 102, 239, 185, 230, 34, 81, 12, 204, 179, 113, 60, 208, 141, 88]) + }, + "SHA-256": { + "normal": new Uint8Array([164, 1, 215, 201, 21, 138, 41, 229, 199, 25, 58, 185, 115, 15, 7, 72, 133, 28, 197, 186, 173, 180, 44, 173, 2, 75, 98, 144, 254, 33, 52, 54]), + "empty": new Uint8Array([180, 247, 231, 85, 118, 116, 213, 1, 203, 251, 192, 20, 138, 216, 0, 192, 117, 1, 137, 254, 41, 90, 42, 202, 94, 27, 244, 18, 44, 133, 237, 249]) + } + } + }, + "empty": { + "normal": { + "SHA-384": { + "normal": new Uint8Array([106, 134, 50, 228, 134, 137, 157, 194, 100, 241, 161, 249, 32, 89, 63, 40, 128, 128, 78, 14, 26, 218, 207, 148, 235, 78, 213, 229, 248, 61, 13, 18]), + "empty": new Uint8Array([234, 80, 18, 254, 181, 135, 81, 213, 188, 142, 182, 78, 13, 234, 205, 89, 126, 215, 16, 201, 243, 82, 88, 174, 107, 154, 8, 122, 237, 7, 37, 174]) + }, + "SHA-512": { + "normal": new Uint8Array([199, 151, 225, 209, 242, 202, 183, 242, 138, 95, 67, 69, 92, 16, 89, 127, 148, 51, 133, 237, 251, 66, 140, 254, 43, 152, 190, 212, 169, 85, 215, 161]), + "empty": new Uint8Array([224, 140, 220, 196, 197, 166, 170, 121, 157, 134, 188, 3, 169, 84, 117, 39, 110, 187, 128, 29, 154, 222, 1, 110, 20, 168, 250, 91, 100, 5, 22, 81]) + }, + "SHA-1": { + "normal": new Uint8Array([171, 103, 158, 103, 188, 180, 48, 95, 238, 66, 239, 148, 14, 80, 156, 221, 212, 6, 227, 73, 143, 133, 116, 24, 169, 121, 171, 57, 207, 49, 95, 81]), + "empty": new Uint8Array([254, 66, 33, 135, 24, 140, 134, 54, 211, 109, 170, 213, 142, 242, 132, 49, 164, 51, 191, 15, 239, 114, 209, 202, 231, 53, 160, 75, 219, 190, 185, 211]) + }, + "SHA-256": { + "normal": new Uint8Array([223, 146, 185, 169, 250, 156, 1, 184, 152, 206, 234, 161, 49, 52, 131, 46, 49, 203, 28, 8, 29, 22, 165, 35, 92, 105, 216, 86, 81, 227, 23, 172]), + "empty": new Uint8Array([230, 13, 67, 43, 6, 238, 136, 157, 250, 183, 41, 154, 32, 236, 35, 105, 117, 49, 209, 25, 252, 247, 102, 208, 152, 141, 10, 203, 12, 0, 199, 247]) + } + }, + "empty": { + "SHA-384": { + "normal": new Uint8Array([234, 203, 157, 102, 112, 255, 59, 25, 4, 119, 154, 65, 145, 1, 177, 255, 170, 189, 109, 101, 16, 189, 80, 133, 104, 1, 116, 106, 135, 31, 123, 49]), + "empty": new Uint8Array([71, 12, 198, 83, 135, 202, 74, 16, 199, 166, 138, 59, 81, 72, 200, 229, 19, 218, 166, 49, 1, 0, 7, 57, 196, 198, 101, 155, 134, 17, 136, 132]) + }, + "SHA-512": { + "normal": new Uint8Array([87, 3, 145, 116, 241, 111, 84, 24, 168, 104, 86, 218, 235, 119, 246, 157, 75, 77, 80, 0, 51, 75, 109, 209, 244, 244, 179, 231, 179, 220, 185, 211]), + "empty": new Uint8Array([157, 115, 201, 142, 121, 30, 128, 235, 229, 180, 203, 69, 105, 58, 163, 47, 221, 68, 181, 250, 62, 218, 179, 236, 130, 249, 208, 244, 214, 105, 5, 226]) + }, + "SHA-1": { + "normal": new Uint8Array([161, 189, 216, 195, 50, 198, 70, 74, 75, 182, 162, 242, 49, 174, 201, 164, 68, 35, 126, 171, 224, 77, 47, 85, 242, 171, 37, 212, 12, 84, 235, 238]), + "empty": new Uint8Array([136, 95, 192, 41, 179, 34, 75, 137, 110, 9, 224, 187, 229, 235, 52, 126, 197, 158, 104, 39, 200, 232, 87, 179, 148, 245, 79, 244, 155, 136, 168, 246]) + }, + "SHA-256": { + "normal": new Uint8Array([183, 184, 110, 66, 42, 209, 200, 165, 113, 253, 165, 40, 218, 22, 160, 102, 244, 36, 134, 221, 64, 86, 121, 47, 217, 51, 98, 8, 142, 93, 212, 194]), + "empty": new Uint8Array([235, 112, 240, 29, 237, 233, 175, 175, 164, 73, 238, 225, 177, 40, 101, 4, 225, 246, 35, 136, 179, 247, 221, 79, 149, 102, 151, 176, 232, 40, 254, 24]) + } + } + } + }; + + return {derivedKeys: derivedKeys, salts: salts, derivations: derivations, derivedKeyTypes: derivedKeyTypes, infos: infos}; +} diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js new file mode 100644 index 000000000..ced14d932 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/pbkdf2.js @@ -0,0 +1,310 @@ + +function run_test() { + // May want to test prefixed implementations. + var subtle = self.crypto.subtle; + + // pbkdf2_vectors sets up test data with the correct derivations for each + // test case. + var testData = getTestData(); + var passwords = testData.passwords; + var salts = testData.salts; + var derivations = testData.derivations; + + // What kinds of keys can be created with deriveKey? The following: + var derivedKeyTypes = testData.derivedKeyTypes; + + setUpBaseKeys(passwords) + .then(function(allKeys) { + // We get several kinds of base keys. Normal ones that can be used for + // derivation operations, ones that lack the deriveBits usage, ones + // that lack the deriveKeys usage, and one key that is for the wrong + // algorithm (not PBKDF2 in this case). + var baseKeys = allKeys.baseKeys; + var noBits = allKeys.noBits; + var noKey = allKeys.noKey; + var wrongKey = allKeys.wrongKey; + + // Test each combination of password size, salt size, hash function, + // and number of iterations. The derivations object is structured in + // that way, so navigate it to run tests and compare with correct results. + Object.keys(derivations).forEach(function(passwordSize) { + Object.keys(derivations[passwordSize]).forEach(function(saltSize) { + Object.keys(derivations[passwordSize][saltSize]).forEach(function(hashName) { + Object.keys(derivations[passwordSize][saltSize][hashName]).forEach(function(iterations) { + var testName = passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations"; + + // Check for correct deriveBits result + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256) + .then(function(derivation) { + assert_true(equalBuffers(derivation, derivations[passwordSize][saltSize][hashName][iterations]), "Derived correct key"); + }, function(err) { + assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); + }); + }, testName); + + // Check for correct deriveKey results for every kind of + // key that can be created by the deriveKeys operation. + derivedKeyTypes.forEach(function(derivedKeyType) { + var testName = "Derived key of type "; + Object.keys(derivedKeyType.algorithm).forEach(function(prop) { + testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + }); + testName += " using " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with " + iterations + " iterations"; + + // Test the particular key derivation. + promise_test(function(test) { + return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + // Need to export the key to see that the correct bits were set. + return subtle.exportKey("raw", key) + .then(function(buffer) { + assert_true(equalBuffers(buffer, derivations[passwordSize][saltSize][hashName][iterations].slice(0, derivedKeyType.algorithm.length/8)), "Exported key matches correct value"); + }, function(err) { + assert_unreached("Exporting derived key failed with error " + err.name + ": " + err.message); + }); + }, function(err) { + assert_unreached("deriveKey failed with error " + err.name + ": " + err.message); + + }); + }, testName); + + // Test various error conditions for deriveKey: + + // - illegal name for hash algorithm (NotSupportedError) + var badHash = hashName.substring(0, 3) + hashName.substring(4); + promise_test(function(test) { + return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("bad hash name should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveKey with bad hash name correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with bad hash name " + badHash); + + // - baseKey usages missing "deriveKey" (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noKey[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("missing deriveKey usage should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveKey with missing deriveKey usage correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with missing deriveKey usage"); + + // - baseKey algorithm does not match PBKDF2 (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(key) { + assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveKey with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with wrong (ECDH) key"); + + }); + + // Test various error conditions for deriveBits below: + // length null (OperationError) + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], null) + .then(function(derivation) { + assert_unreached("null length should have thrown an OperationError"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with null length correctly threw OperationError: " + err.message); + }); + }, testName + " with null length"); + + // 0 length (OperationError) + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 0) + .then(function(derivation) { + assert_unreached("0 length should have thrown an OperationError"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with 0 length correctly threw OperationError: " + err.message); + }); + }, testName + " with 0 length"); + + // length not multiple of 8 (OperationError) + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 44) + .then(function(derivation) { + assert_unreached("non-multiple of 8 length should have thrown an OperationError"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with non-multiple of 8 length correctly threw OperationError: " + err.message); + }); + }, testName + " with non-multiple of 8 length"); + + // - illegal name for hash algorithm (NotSupportedError) + var badHash = hashName.substring(0, 3) + hashName.substring(4); + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256) + .then(function(derivation) { + assert_unreached("bad hash name should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveBits with bad hash name correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with bad hash name " + badHash); + + // - baseKey usages missing "deriveBits" (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noBits[passwordSize], 256) + .then(function(derivation) { + assert_unreached("missing deriveBits usage should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveBits with missing deriveBits usage correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with missing deriveBits usage"); + + // - baseKey algorithm does not match PBKDF2 (InvalidAccessError) + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, 256) + .then(function(derivation) { + assert_unreached("wrong (ECDH) key should have thrown an InvalidAccessError"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "deriveBits with wrong (ECDH) key correctly threw InvalidAccessError: " + err.message); + }); + }, testName + " with wrong (ECDH) key"); + }); + + // Check that 0 iterations throws proper error + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], 256) + .then(function(derivation) { + assert_unreached("0 iterations should have thrown an error"); + }, function(err) { + assert_equals(err.name, "OperationError", "deriveBits with 0 iterations correctly threw OperationError: " + err.message); + }); + }, passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations"); + + derivedKeyTypes.forEach(function(derivedKeyType) { + var testName = "Derived key of type "; + Object.keys(derivedKeyType.algorithm).forEach(function(prop) { + testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + }); + testName += " using " + passwordSize + " password, " + saltSize + " salt, " + hashName + ", with 0 iterations"; + + promise_test(function(test) { + return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(derivation) { + assert_unreached("0 iterations should have thrown an error"); + }, function(err) { + assert_equals(err.name, "OperationError", "derivekey with 0 iterations correctly threw OperationError: " + err.message); + }); + }, testName); + }); + }); + + // - legal algorithm name but not digest one (e.g., PBKDF2) (NotSupportedError) + var nonDigestHash = "PBKDF2"; + [1, 1000, 100000].forEach(function(iterations) { + var testName = passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations"; + + promise_test(function(test) { + return subtle.deriveBits({name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256) + .then(function(derivation) { + assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "deriveBits with non-digest algorithm correctly threw NotSupportedError: " + err.message); + }); + }, testName + " with non-digest algorithm " + nonDigestHash); + + derivedKeyTypes.forEach(function(derivedKeyType) { + var testName = "Derived key of type "; + Object.keys(derivedKeyType.algorithm).forEach(function(prop) { + testName += prop + ": " + derivedKeyType.algorithm[prop] + " "; + }); + testName += " using " + passwordSize + " password, " + saltSize + " salt, " + nonDigestHash + ", with " + iterations + " iterations"; + + promise_test(function(test) { + return subtle.deriveKey({name: "PBKDF2", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages) + .then(function(derivation) { + assert_unreached("non-digest algorithm should have thrown an NotSupportedError"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "derivekey with non-digest algorithm correctly threw NotSupportedError: " + err.message); + }); + }, testName); + }); + + }); + + }); + }); + + done(); + }, function(err) { + test(function(test) { + assert_unreached("setUpBaseKeys failed with error '" + err.message + "'"); + }, "setUpBaseKeys"); + done(); + }); + + // Deriving bits and keys requires starting with a base key, which is created + // by importing a password. setUpBaseKeys returns a promise that yields the + // necessary base keys. + function setUpBaseKeys(passwords) { + var promises = []; + + var baseKeys = {}; + var noBits = {}; + var noKey = {}; + var wrongKey = null; + + Object.keys(passwords).forEach(function(passwordSize) { + var promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveKey", "deriveBits"]) + .then(function(baseKey) { + baseKeys[passwordSize] = baseKey; + }, function(err) { + baseKeys[passwordSize] = null; + }); + promises.push(promise); + + promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveBits"]) + .then(function(baseKey) { + noKey[passwordSize] = baseKey; + }, function(err) { + noKey[passwordSize] = null; + }); + promises.push(promise); + + promise = subtle.importKey("raw", passwords[passwordSize], {name: "PBKDF2"}, false, ["deriveKey"]) + .then(function(baseKey) { + noBits[passwordSize] = baseKey; + }, function(err) { + noBits[passwordSize] = null; + }); + promises.push(promise); + }); + + var promise = subtle.generateKey({name: "ECDH", namedCurve: "P-256"}, false, ["deriveKey", "deriveBits"]) + .then(function(baseKey) { + wrongKey = baseKey.privateKey; + }, function(err) { + wrongKey = null; + }); + promises.push(promise); + + + return Promise.all(promises).then(function() { + return {baseKeys: baseKeys, noBits: noBits, noKey: noKey, wrongKey: wrongKey}; + }); + } + + function equalBuffers(a, b) { + if (a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + for (var i=0; in + + // Variations to test: + // - empty, short, and fairly long password + // - empty, short, and fairly long salt + // - SHA-1, SHA-256, SHA-384, SHA-512 hash + // - 1, 1000, and 100000 million iterations + + // Test cases to generate: 3 * 3 * 4 * 3 = 108 + + // Error conditions to test: + // - length null (OperationError) + // - length not a multiple of 8 (OperationError) + // - illegal name for hash algorithm (NotSupportedError) + // - legal algorithm name but not digest one (e.g., AES-CBC) (NotSupportedError) + // - baseKey usages missing "deriveBits" (InvalidAccessError) + // - baseKey algorithm does not match PBKDF2 (InvalidAccessError) + // - 0 iterations + + var derivedKeyTypes = [ + {algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CBC", length: 192}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CBC", length: 256}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CTR", length: 192}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CTR", length: 256}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 192}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 256}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-KW", length: 128}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "AES-KW", length: 192}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "AES-KW", length: 256}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "HMAC", hash: "SHA-1", length: 256}, usages: ["sign", "verify"]}, + {algorithm: {name: "HMAC", hash: "SHA-256", length: 256}, usages: ["sign", "verify"]}, + {algorithm: {name: "HMAC", hash: "SHA-384", length: 256}, usages: ["sign", "verify"]}, + {algorithm: {name: "HMAC", hash: "SHA-512", length: 256}, usages: ["sign", "verify"]} + ]; + + var passwords = { + "short": new Uint8Array([80, 64, 115, 115, 119, 48, 114, 100]), + "long": new Uint8Array([85, 115, 101, 114, 115, 32, 115, 104, 111, 117, 108, 100, 32, 112, 105, 99, 107, 32, 108, 111, 110, 103, 32, 112, 97, 115, 115, 112, 104, 114, 97, 115, 101, 115, 32, 40, 110, 111, 116, 32, 117, 115, 101, 32, 115, 104, 111, 114, 116, 32, 112, 97, 115, 115, 119, 111, 114, 100, 115, 41, 33]), + "empty": new Uint8Array([]) + }; + + var salts = { + "short": new Uint8Array([78, 97, 67, 108]), + "long": new Uint8Array([83, 111, 100, 105, 117, 109, 32, 67, 104, 108, 111, 114, 105, 100, 101, 32, 99, 111, 109, 112, 111, 117, 110, 100]), + "empty": new Uint8Array([]) + }; + + var derivations = { + "short": { + "short": { + "SHA-384": { + "1000": new Uint8Array([170, 236, 90, 151, 109, 77, 53, 203, 32, 36, 72, 111, 201, 249, 187, 154, 163, 234, 231, 206, 242, 188, 230, 38, 100, 181, 179, 117, 28, 245, 15, 241]), + "1": new Uint8Array([128, 205, 15, 21, 54, 67, 102, 167, 37, 81, 195, 121, 117, 247, 182, 55, 186, 137, 194, 155, 70, 57, 236, 114, 15, 105, 167, 13, 187, 237, 81, 92]), + "100000": new Uint8Array([111, 94, 163, 198, 198, 245, 228, 131, 52, 103, 180, 124, 58, 103, 30, 101, 113, 78, 135, 7, 27, 209, 227, 109, 113, 111, 132, 107, 92, 210, 137, 128]) + }, + "SHA-512": { + "1000": new Uint8Array([134, 92, 89, 69, 225, 31, 91, 243, 221, 240, 2, 231, 203, 23, 72, 246, 34, 77, 38, 113, 232, 6, 218, 212, 170, 240, 144, 160, 67, 103, 218, 41]), + "1": new Uint8Array([105, 244, 213, 206, 245, 199, 216, 186, 147, 142, 136, 3, 136, 200, 246, 59, 107, 36, 72, 178, 98, 109, 19, 67, 252, 92, 182, 139, 189, 127, 39, 178]), + "100000": new Uint8Array([72, 59, 167, 242, 226, 254, 56, 44, 246, 29, 32, 178, 152, 18, 226, 212, 150, 16, 166, 0, 65, 174, 64, 236, 249, 252, 126, 241, 56, 233, 56, 118]) + }, + "SHA-1": { + "1000": new Uint8Array([83, 136, 234, 94, 98, 225, 181, 87, 152, 26, 190, 92, 228, 19, 33, 39, 88, 170, 106, 157, 44, 91, 240, 140, 1, 157, 69, 157, 186, 102, 107, 144]), + "1": new Uint8Array([70, 36, 219, 210, 19, 115, 238, 86, 89, 193, 37, 177, 132, 238, 218, 162, 106, 51, 183, 124, 161, 19, 20, 185, 240, 201, 218, 225, 228, 78, 155, 4]), + "100000": new Uint8Array([245, 143, 67, 95, 188, 92, 5, 134, 92, 145, 79, 217, 114, 16, 138, 9, 69, 125, 95, 154, 72, 241, 78, 117, 228, 204, 2, 217, 137, 131, 3, 138]) + }, + "SHA-256": { + "1000": new Uint8Array([78, 108, 165, 121, 87, 67, 155, 227, 167, 83, 112, 66, 66, 37, 226, 33, 29, 85, 240, 90, 240, 5, 97, 223, 63, 62, 254, 233, 17, 107, 195, 76]), + "1": new Uint8Array([198, 188, 85, 164, 4, 173, 206, 163, 106, 26, 181, 103, 152, 8, 94, 10, 175, 105, 127, 107, 178, 193, 106, 80, 114, 248, 56, 241, 125, 254, 108, 182]), + "100000": new Uint8Array([171, 37, 121, 101, 152, 231, 75, 41, 195, 36, 245, 186, 77, 144, 234, 125, 200, 159, 198, 137, 16, 65, 180, 213, 108, 148, 21, 101, 5, 247, 34, 192]) + } + }, + "long": { + "SHA-384": { + "1000": new Uint8Array([163, 16, 239, 60, 107, 58, 149, 230, 216, 202, 102, 68, 227, 220, 253, 136, 34, 42, 89, 254, 142, 0, 197, 45, 106, 18, 99, 29, 130, 193, 210, 75]), + "1": new Uint8Array([104, 7, 52, 108, 197, 62, 222, 209, 203, 150, 74, 114, 98, 133, 137, 166, 189, 72, 53, 89, 144, 191, 223, 231, 70, 81, 9, 113, 2, 7, 5, 157]), + "100000": new Uint8Array([44, 140, 102, 116, 200, 121, 207, 24, 80, 188, 155, 127, 189, 204, 110, 167, 171, 176, 161, 82, 33, 150, 168, 102, 135, 83, 5, 222, 165, 116, 134, 243]) + }, + "SHA-512": { + "1000": new Uint8Array([156, 23, 254, 150, 137, 94, 173, 191, 209, 204, 9, 95, 193, 187, 131, 79, 40, 229, 204, 201, 236, 150, 202, 129, 76, 255, 148, 26, 75, 244, 7, 39]), + "1": new Uint8Array([87, 119, 2, 122, 255, 64, 81, 251, 155, 67, 193, 241, 239, 4, 99, 189, 103, 117, 17, 117, 212, 40, 161, 61, 163, 218, 132, 90, 89, 19, 50, 205]), + "100000": new Uint8Array([180, 121, 201, 113, 92, 66, 22, 56, 220, 224, 167, 5, 252, 11, 123, 167, 213, 111, 163, 6, 49, 136, 6, 53, 128, 224, 112, 223, 241, 219, 73, 124]) + }, + "SHA-1": { + "1000": new Uint8Array([137, 211, 178, 123, 95, 110, 138, 240, 21, 242, 248, 124, 243, 104, 161, 67, 138, 32, 108, 78, 207, 95, 230, 129, 252, 59, 249, 76, 86, 33, 62, 246]), + "1": new Uint8Array([87, 111, 124, 22, 88, 37, 190, 249, 239, 20, 180, 188, 44, 130, 70, 157, 30, 64, 143, 248, 231, 186, 48, 102, 148, 121, 127, 158, 69, 183, 102, 237]), + "100000": new Uint8Array([30, 57, 232, 191, 102, 118, 252, 211, 21, 102, 85, 69, 122, 250, 20, 190, 231, 113, 219, 203, 252, 208, 114, 65, 199, 206, 226, 9, 167, 203, 31, 233]) + }, + "SHA-256": { + "1000": new Uint8Array([177, 167, 183, 220, 32, 223, 23, 74, 74, 14, 65, 13, 191, 175, 3, 180, 195, 117, 196, 80, 168, 157, 122, 158, 211, 73, 180, 229, 46, 100, 223, 216]), + "1": new Uint8Array([18, 185, 15, 89, 79, 9, 8, 207, 145, 45, 101, 92, 148, 143, 156, 42, 30, 171, 133, 87, 101, 188, 18, 120, 94, 241, 138, 160, 43, 142, 126, 220]), + "100000": new Uint8Array([212, 89, 77, 138, 27, 89, 82, 10, 72, 135, 137, 34, 166, 93, 102, 61, 40, 246, 165, 250, 73, 233, 49, 211, 0, 216, 249, 186, 249, 61, 10, 235]) + } + }, + "empty": { + "SHA-384": { + "1000": new Uint8Array([174, 181, 249, 125, 102, 39, 238, 188, 222, 107, 19, 154, 0, 137, 85, 0, 48, 247, 64, 28, 103, 224, 28, 5, 122, 51, 56, 23, 94, 63, 58, 23]), + "1": new Uint8Array([79, 16, 137, 192, 30, 67, 139, 222, 100, 154, 55, 159, 164, 24, 251, 195, 184, 86, 37, 135, 114, 223, 233, 17, 128, 111, 155, 208, 128, 159, 188, 126]), + "100000": new Uint8Array([215, 104, 125, 246, 199, 129, 220, 136, 214, 78, 249, 203, 175, 149, 211, 213, 209, 21, 95, 102, 178, 48, 35, 158, 110, 129, 193, 85, 12, 136, 64, 207]) + }, + "SHA-512": { + "1000": new Uint8Array([181, 172, 114, 11, 122, 190, 8, 50, 252, 81, 163, 27, 30, 197, 103, 59, 235, 30, 65, 132, 10, 223, 211, 214, 6, 232, 99, 143, 64, 6, 235, 72]), + "1": new Uint8Array([143, 123, 125, 69, 156, 117, 47, 100, 191, 18, 190, 98, 91, 101, 212, 150, 172, 36, 234, 54, 81, 107, 22, 142, 22, 251, 2, 104, 69, 180, 232, 46]), + "100000": new Uint8Array([186, 26, 15, 54, 186, 215, 113, 82, 101, 100, 5, 30, 185, 202, 32, 125, 161, 155, 98, 229, 55, 98, 52, 153, 118, 169, 163, 209, 176, 239, 126, 32]) + }, + "SHA-1": { + "1000": new Uint8Array([115, 111, 60, 61, 110, 188, 194, 167, 185, 112, 64, 62, 38, 150, 192, 235, 76, 209, 119, 15, 85, 241, 150, 252, 112, 137, 230, 102, 193, 31, 119, 218]), + "1": new Uint8Array([192, 207, 251, 12, 229, 219, 53, 31, 170, 36, 218, 213, 144, 37, 131, 207, 195, 10, 159, 84, 217, 170, 105, 145, 254, 130, 29, 3, 18, 33, 39, 233]), + "100000": new Uint8Array([28, 80, 149, 172, 154, 123, 212, 16, 239, 15, 114, 201, 147, 236, 169, 27, 176, 229, 113, 233, 178, 251, 171, 112, 79, 140, 19, 17, 145, 250, 209, 108]) + }, + "SHA-256": { + "1000": new Uint8Array([185, 210, 242, 33, 123, 78, 229, 168, 191, 3, 69, 243, 107, 44, 152, 135, 51, 245, 3, 169, 117, 223, 234, 199, 183, 19, 95, 84, 165, 242, 153, 113]), + "1": new Uint8Array([1, 158, 84, 171, 66, 240, 4, 133, 211, 170, 27, 38, 252, 222, 33, 174, 95, 82, 203, 15, 9, 96, 255, 201, 118, 127, 37, 198, 94, 45, 178, 249]), + "100000": new Uint8Array([167, 162, 134, 152, 41, 121, 120, 7, 179, 229, 118, 193, 120, 120, 180, 102, 68, 158, 137, 230, 4, 71, 213, 65, 119, 90, 150, 235, 124, 26, 93, 237]) + } + } + }, + "long": { + "short": { + "SHA-384": { + "1000": new Uint8Array([250, 164, 66, 251, 171, 244, 5, 140, 198, 83, 104, 181, 61, 126, 197, 17, 60, 9, 234, 126, 94, 55, 67, 49, 47, 75, 235, 237, 217, 128, 186, 55]), + "1": new Uint8Array([94, 222, 136, 54, 253, 171, 238, 197, 211, 115, 59, 67, 74, 186, 196, 67, 212, 21, 25, 59, 89, 158, 9, 38, 25, 59, 0, 15, 64, 106, 90, 125]), + "100000": new Uint8Array([246, 42, 230, 199, 135, 27, 24, 26, 167, 18, 50, 245, 235, 136, 55, 36, 152, 239, 50, 172, 10, 125, 113, 81, 25, 232, 240, 82, 235, 16, 45, 41]) + }, + "SHA-512": { + "1000": new Uint8Array([240, 146, 143, 80, 161, 85, 242, 106, 140, 156, 27, 199, 243, 181, 203, 83, 28, 83, 168, 245, 16, 64, 201, 206, 95, 199, 157, 67, 15, 240, 192, 244]), + "1": new Uint8Array([62, 156, 18, 179, 246, 223, 182, 68, 21, 148, 236, 112, 99, 252, 169, 98, 255, 218, 16, 182, 207, 48, 184, 152, 163, 30, 249, 241, 48, 107, 17, 25]), + "100000": new Uint8Array([151, 74, 207, 187, 15, 15, 32, 200, 30, 201, 40, 41, 243, 140, 61, 175, 8, 106, 125, 245, 139, 145, 43, 133, 109, 31, 94, 204, 147, 85, 239, 27]) + }, + "SHA-1": { + "1000": new Uint8Array([83, 180, 33, 97, 19, 78, 21, 200, 113, 171, 215, 26, 186, 19, 144, 208, 31, 76, 106, 148, 12, 170, 245, 193, 121, 37, 141, 143, 27, 29, 104, 11]), + "1": new Uint8Array([138, 231, 47, 148, 230, 252, 213, 79, 203, 252, 166, 98, 0, 162, 17, 165, 27, 47, 132, 103, 135, 210, 11, 104, 8, 190, 223, 21, 108, 228, 108, 160]), + "100000": new Uint8Array([167, 253, 164, 199, 157, 211, 186, 26, 135, 95, 101, 233, 36, 139, 33, 8, 153, 202, 8, 20, 174, 56, 153, 93, 140, 229, 165, 53, 96, 203, 172, 49]) + }, + "SHA-256": { + "1000": new Uint8Array([238, 235, 119, 20, 66, 10, 0, 177, 138, 206, 194, 181, 151, 157, 29, 166, 19, 115, 32, 43, 127, 139, 167, 27, 8, 98, 147, 170, 184, 89, 224, 160]), + "1": new Uint8Array([255, 161, 233, 167, 39, 169, 44, 39, 174, 111, 116, 177, 199, 151, 143, 158, 26, 248, 96, 225, 6, 55, 99, 64, 172, 67, 217, 105, 209, 54, 64, 91]), + "100000": new Uint8Array([222, 172, 112, 203, 227, 241, 114, 14, 53, 59, 78, 128, 22, 221, 181, 148, 117, 239, 183, 11, 106, 35, 133, 231, 53, 210, 214, 234, 109, 98, 74, 77]) + } + }, + "long": { + "SHA-384": { + "1000": new Uint8Array([53, 101, 133, 81, 240, 236, 19, 57, 138, 123, 69, 224, 38, 28, 253, 101, 76, 30, 82, 65, 30, 110, 69, 125, 238, 104, 244, 174, 171, 233, 37, 167]), + "1": new Uint8Array([207, 85, 66, 44, 239, 110, 27, 196, 158, 109, 8, 43, 34, 115, 212, 128, 232, 242, 232, 130, 45, 173, 209, 70, 156, 42, 50, 217, 101, 125, 18, 241]), + "100000": new Uint8Array([26, 186, 181, 241, 228, 97, 223, 55, 139, 136, 192, 162, 43, 231, 110, 242, 241, 98, 125, 247, 74, 199, 203, 251, 132, 189, 204, 179, 84, 188, 136, 137]) + }, + "SHA-512": { + "1000": new Uint8Array([67, 225, 32, 36, 196, 211, 84, 114, 127, 126, 88, 132, 44, 203, 96, 51, 161, 97, 214, 13, 197, 174, 81, 111, 7, 110, 74, 88, 161, 136, 13, 56]), + "1": new Uint8Array([222, 74, 251, 192, 173, 211, 228, 211, 47, 75, 198, 225, 34, 168, 138, 228, 74, 43, 60, 207, 1, 72, 231, 118, 43, 172, 5, 196, 62, 148, 239, 127]), + "100000": new Uint8Array([249, 169, 35, 132, 164, 234, 223, 195, 86, 6, 73, 179, 127, 182, 118, 232, 60, 69, 60, 187, 217, 159, 128, 187, 166, 240, 161, 14, 189, 21, 11, 82]) + }, + "SHA-1": { + "1000": new Uint8Array([110, 144, 200, 110, 224, 123, 135, 62, 150, 80, 113, 2, 86, 115, 255, 5, 66, 159, 103, 140, 48, 249, 27, 55, 225, 226, 218, 81, 32, 54, 211, 32]), + "1": new Uint8Array([29, 16, 78, 165, 210, 53, 0, 106, 18, 168, 15, 113, 184, 14, 229, 40, 4, 139, 100, 204, 26, 122, 15, 48, 247, 223, 75, 162, 107, 131, 32, 199]), + "100000": new Uint8Array([20, 16, 48, 118, 59, 249, 131, 200, 86, 77, 93, 76, 147, 95, 227, 202, 53, 73, 96, 129, 89, 172, 25, 52, 193, 89, 144, 64, 102, 140, 35, 99]) + }, + "SHA-256": { + "1000": new Uint8Array([63, 213, 135, 201, 75, 169, 70, 184, 185, 220, 205, 221, 42, 91, 116, 246, 119, 141, 79, 97, 230, 145, 248, 58, 196, 122, 47, 169, 88, 11, 253, 248]), + "1": new Uint8Array([253, 92, 174, 184, 179, 171, 229, 137, 188, 21, 156, 78, 81, 248, 0, 87, 14, 116, 246, 67, 151, 166, 197, 238, 19, 29, 254, 217, 63, 5, 17, 170]), + "100000": new Uint8Array([17, 153, 45, 139, 129, 51, 17, 36, 76, 84, 75, 98, 41, 41, 69, 226, 8, 212, 3, 206, 189, 107, 149, 82, 161, 165, 98, 6, 93, 153, 88, 234]) + } + }, + "empty": { + "SHA-384": { + "1000": new Uint8Array([249, 202, 20, 139, 12, 4, 24, 144, 191, 248, 131, 29, 182, 23, 71, 25, 126, 148, 206, 104, 241, 144, 237, 242, 105, 105, 75, 77, 100, 72, 97, 202]), + "1": new Uint8Array([73, 171, 63, 159, 136, 47, 219, 158, 82, 139, 77, 159, 27, 62, 140, 113, 210, 99, 154, 191, 23, 1, 213, 110, 185, 155, 213, 18, 1, 228, 32, 255]), + "100000": new Uint8Array([23, 73, 223, 205, 119, 229, 37, 133, 25, 234, 34, 49, 186, 44, 214, 84, 59, 7, 51, 57, 172, 155, 21, 69, 187, 100, 49, 83, 250, 246, 209, 123]) + }, + "SHA-512": { + "1000": new Uint8Array([69, 122, 121, 85, 235, 236, 236, 113, 165, 30, 251, 98, 55, 229, 177, 214, 47, 77, 234, 181, 201, 61, 123, 61, 17, 209, 231, 15, 175, 250, 65, 126]), + "1": new Uint8Array([209, 191, 161, 166, 184, 169, 119, 131, 159, 140, 63, 157, 82, 221, 2, 16, 78, 32, 41, 192, 235, 42, 98, 8, 204, 64, 136, 22, 231, 118, 138, 140]), + "100000": new Uint8Array([232, 5, 172, 156, 193, 216, 65, 44, 66, 68, 109, 35, 125, 27, 80, 79, 149, 64, 179, 98, 189, 27, 117, 228, 81, 83, 30, 133, 62, 36, 117, 61]) + }, + "SHA-1": { + "1000": new Uint8Array([231, 55, 93, 229, 3, 103, 102, 196, 12, 184, 95, 67, 181, 63, 206, 79, 250, 64, 42, 182, 190, 53, 113, 0, 126, 245, 213, 84, 83, 253, 127, 10]), + "1": new Uint8Array([164, 106, 98, 152, 109, 156, 57, 9, 244, 16, 20, 221, 114, 207, 227, 74, 38, 18, 71, 133, 77, 115, 18, 207, 79, 190, 173, 96, 185, 182, 158, 221]), + "100000": new Uint8Array([122, 64, 61, 154, 19, 174, 216, 22, 78, 156, 7, 44, 84, 84, 98, 37, 31, 217, 66, 241, 115, 106, 107, 240, 60, 225, 200, 131, 48, 4, 142, 4]) + }, + "SHA-256": { + "1000": new Uint8Array([126, 102, 200, 75, 234, 136, 143, 146, 195, 72, 217, 20, 85, 133, 24, 108, 174, 71, 43, 18, 251, 167, 240, 173, 40, 23, 149, 117, 193, 170, 129, 90]), + "1": new Uint8Array([79, 81, 12, 81, 129, 172, 92, 44, 95, 212, 189, 20, 31, 151, 18, 73, 91, 236, 162, 121, 98, 71, 66, 180, 214, 211, 13, 8, 185, 108, 10, 105]), + "100000": new Uint8Array([95, 26, 106, 196, 165, 109, 151, 150, 167, 48, 154, 120, 218, 170, 249, 24, 186, 218, 245, 237, 30, 236, 195, 240, 184, 163, 164, 76, 61, 56, 214, 84]) + } + } + }, + "empty": { + "short": { + "SHA-384": { + "1000": new Uint8Array([127, 247, 149, 74, 237, 223, 65, 121, 95, 200, 48, 6, 102, 120, 109, 73, 116, 38, 154, 169, 28, 199, 233, 56, 17, 201, 83, 51, 29, 86, 214, 9]), + "1": new Uint8Array([233, 240, 218, 30, 151, 223, 164, 85, 248, 88, 206, 107, 154, 241, 236, 192, 41, 159, 18, 95, 241, 168, 71, 235, 93, 73, 85, 134, 111, 67, 230, 4]), + "100000": new Uint8Array([28, 115, 19, 43, 106, 85, 233, 217, 222, 44, 219, 254, 31, 85, 191, 10, 181, 159, 217, 31, 120, 241, 9, 197, 0, 150, 3, 139, 133, 87, 177, 71]) + }, + "SHA-512": { + "1000": new Uint8Array([213, 97, 196, 200, 78, 156, 96, 186, 71, 82, 162, 211, 131, 191, 85, 239, 246, 67, 252, 158, 69, 34, 82, 214, 130, 30, 57, 68, 147, 80, 207, 114]), + "1": new Uint8Array([231, 226, 180, 31, 72, 135, 66, 27, 203, 118, 78, 180, 165, 111, 99, 210, 80, 46, 51, 199, 100, 251, 223, 96, 98, 106, 212, 46, 217, 103, 35, 66]), + "100000": new Uint8Array([239, 208, 7, 82, 188, 159, 250, 251, 90, 57, 157, 209, 213, 131, 78, 141, 44, 43, 103, 110, 205, 75, 32, 99, 251, 31, 229, 129, 208, 241, 56, 11]) + }, + "SHA-1": { + "1000": new Uint8Array([114, 201, 43, 189, 61, 218, 180, 120, 158, 136, 228, 42, 209, 205, 168, 60, 192, 114, 158, 108, 181, 16, 106, 87, 126, 80, 213, 207, 97, 120, 36, 129]), + "1": new Uint8Array([166, 103, 218, 71, 184, 248, 87, 183, 198, 95, 112, 166, 200, 231, 160, 108, 224, 210, 82, 17, 162, 182, 235, 175, 88, 220, 170, 242, 104, 180, 107, 29]), + "100000": new Uint8Array([6, 225, 158, 27, 131, 230, 72, 11, 21, 84, 223, 43, 49, 162, 201, 45, 27, 252, 249, 188, 27, 219, 200, 117, 31, 248, 104, 91, 222, 239, 125, 201]) + }, + "SHA-256": { + "1000": new Uint8Array([40, 53, 243, 237, 83, 86, 84, 32, 201, 9, 81, 80, 155, 12, 17, 115, 182, 69, 23, 79, 21, 70, 171, 58, 195, 230, 200, 92, 180, 113, 181, 59]), + "1": new Uint8Array([45, 219, 73, 36, 62, 179, 181, 145, 44, 178, 96, 205, 216, 127, 176, 78, 240, 209, 17, 191, 164, 77, 64, 164, 94, 2, 168, 165, 195, 193, 81, 141]), + "100000": new Uint8Array([128, 174, 217, 5, 202, 50, 174, 11, 178, 169, 216, 245, 50, 240, 72, 160, 230, 114, 70, 62, 239, 159, 131, 223, 167, 216, 139, 202, 114, 101, 83, 234]) + } + }, + "long": { + "SHA-384": { + "1000": new Uint8Array([139, 184, 156, 247, 25, 114, 254, 90, 204, 22, 253, 197, 248, 207, 253, 44, 46, 113, 120, 192, 134, 179, 187, 230, 28, 193, 49, 70, 25, 19, 89, 88]), + "1": new Uint8Array([123, 11, 204, 168, 29, 214, 55, 163, 179, 57, 134, 102, 97, 151, 22, 197, 242, 177, 244, 165, 194, 78, 133, 193, 138, 153, 85, 85, 158, 77, 118, 146]), + "100000": new Uint8Array([38, 198, 168, 174, 75, 209, 251, 231, 21, 174, 71, 142, 255, 243, 236, 174, 131, 175, 166, 23, 237, 53, 189, 74, 63, 99, 195, 218, 118, 164, 45, 34]) + }, + "SHA-512": { + "1000": new Uint8Array([92, 172, 193, 108, 223, 190, 5, 44, 253, 115, 169, 137, 27, 140, 14, 120, 177, 155, 46, 7, 234, 226, 66, 61, 72, 254, 213, 224, 138, 168, 73, 75]), + "1": new Uint8Array([187, 115, 248, 22, 138, 143, 57, 29, 61, 84, 202, 137, 47, 183, 43, 142, 96, 53, 227, 127, 137, 30, 90, 112, 73, 27, 148, 220, 5, 81, 11, 196]), + "100000": new Uint8Array([135, 253, 252, 41, 51, 146, 203, 243, 62, 204, 155, 81, 65, 162, 254, 250, 116, 209, 80, 73, 151, 86, 134, 60, 72, 76, 10, 120, 182, 39, 77, 127]) + }, + "SHA-1": { + "1000": new Uint8Array([204, 87, 72, 236, 196, 18, 136, 160, 225, 51, 104, 84, 58, 170, 46, 246, 44, 151, 186, 117, 24, 250, 136, 246, 225, 28, 53, 118, 63, 201, 48, 180]), + "1": new Uint8Array([31, 70, 180, 12, 242, 251, 61, 196, 26, 61, 156, 237, 136, 151, 184, 97, 5, 3, 104, 16, 226, 191, 172, 112, 64, 129, 75, 214, 93, 66, 141, 103]), + "100000": new Uint8Array([51, 226, 153, 59, 244, 114, 157, 201, 147, 255, 246, 110, 105, 204, 85, 119, 113, 53, 235, 250, 188, 229, 51, 87, 91, 206, 74, 150, 100, 90, 116, 44]) + }, + "SHA-256": { + "1000": new Uint8Array([19, 83, 247, 69, 130, 55, 171, 51, 46, 224, 82, 226, 159, 130, 154, 42, 185, 14, 114, 99, 14, 161, 4, 147, 180, 238, 207, 251, 159, 248, 158, 29]), + "1": new Uint8Array([97, 201, 53, 196, 98, 195, 50, 28, 137, 102, 53, 69, 209, 58, 79, 107, 82, 181, 25, 28, 251, 116, 121, 229, 141, 207, 230, 68, 77, 67, 16, 108]), + "100000": new Uint8Array([121, 186, 248, 14, 197, 130, 146, 5, 56, 128, 30, 157, 146, 156, 224, 112, 132, 39, 121, 135, 72, 141, 115, 58, 2, 104, 82, 196, 82, 240, 111, 180]) + } + }, + "empty": { + "SHA-384": { + "1000": new Uint8Array([156, 191, 231, 45, 25, 77, 163, 78, 23, 200, 33, 221, 21, 105, 239, 80, 168, 110, 180, 216, 147, 89, 23, 118, 173, 198, 165, 194, 30, 0, 49, 207]), + "1": new Uint8Array([75, 176, 66, 165, 194, 140, 238, 111, 102, 249, 145, 199, 23, 253, 119, 2, 103, 120, 126, 43, 179, 3, 30, 174, 39, 13, 135, 214, 58, 217, 149, 52]), + "100000": new Uint8Array([237, 107, 215, 40, 37, 103, 171, 228, 141, 84, 45, 6, 125, 9, 244, 4, 189, 4, 74, 226, 206, 254, 17, 218, 204, 83, 28, 71, 100, 205, 53, 205]) + }, + "SHA-512": { + "1000": new Uint8Array([203, 147, 9, 108, 58, 2, 190, 235, 28, 95, 172, 54, 118, 92, 144, 17, 254, 153, 248, 216, 234, 98, 54, 96, 72, 252, 152, 203, 152, 223, 234, 143]), + "1": new Uint8Array([109, 46, 203, 187, 251, 46, 109, 205, 112, 86, 250, 249, 175, 106, 160, 110, 174, 89, 67, 145, 219, 152, 50, 121, 166, 191, 39, 224, 235, 34, 134, 20]), + "100000": new Uint8Array([137, 225, 98, 84, 235, 173, 92, 186, 114, 224, 174, 190, 22, 20, 199, 249, 183, 149, 167, 80, 95, 38, 55, 32, 108, 225, 10, 52, 73, 162, 184, 187]) + }, + "SHA-1": { + "1000": new Uint8Array([110, 64, 145, 10, 192, 46, 200, 156, 235, 185, 216, 152, 177, 58, 9, 209, 205, 122, 223, 111, 140, 192, 140, 196, 115, 48, 44, 137, 115, 170, 46, 25]), + "1": new Uint8Array([30, 67, 122, 28, 121, 215, 91, 230, 30, 145, 20, 29, 174, 32, 175, 252, 72, 146, 204, 153, 171, 204, 63, 231, 83, 136, 123, 204, 200, 146, 1, 118]), + "100000": new Uint8Array([169, 225, 190, 187, 54, 188, 38, 215, 201, 151, 213, 72, 60, 188, 141, 228, 164, 25, 209, 231, 6, 87, 19, 66, 99, 37, 134, 236, 51, 10, 114, 144]) + }, + "SHA-256": { + "1000": new Uint8Array([79, 197, 138, 33, 193, 0, 206, 24, 53, 184, 249, 153, 29, 115, 139, 86, 150, 93, 20, 178, 78, 23, 97, 251, 223, 252, 105, 172, 94, 11, 102, 122]), + "1": new Uint8Array([247, 206, 11, 101, 61, 45, 114, 164, 16, 140, 245, 171, 233, 18, 255, 221, 119, 118, 22, 219, 187, 39, 167, 14, 130, 4, 243, 174, 45, 15, 111, 173]), + "100000": new Uint8Array([100, 168, 104, 212, 178, 58, 246, 150, 211, 115, 77, 11, 129, 77, 4, 205, 209, 172, 40, 1, 40, 233, 118, 83, 160, 95, 50, 180, 156, 19, 162, 154]) + } + } + } + }; + + return {passwords: passwords, salts: salts, derivations: derivations, derivedKeyTypes: derivedKeyTypes}; +} diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html new file mode 100644 index 000000000..a18903821 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.html @@ -0,0 +1,17 @@ + + + +WebCryptoAPI: deriveBits() Using ECDH + + + + + + + +

deriveBits Tests for ECDH

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html new file mode 100644 index 000000000..b303295f4 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.html @@ -0,0 +1,17 @@ + + + +WebCryptoAPI:deriveKey() Using ECDH + + + + + + + +

deriveKey Tests for ECDH

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.html new file mode 100644 index 000000000..23143bdbc --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_hkdf.html @@ -0,0 +1,19 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using HKDF + + + + + + + + + +

deriveBits and deriveKey Tests for HKDF

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html new file mode 100644 index 000000000..0658b1a2f --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/derive_bits_keys/test_pbkdf2.html @@ -0,0 +1,19 @@ + + + +WebCryptoAPI: deriveBits() and deriveKey() Using PBKDF2 + + + + + + + + + +

deriveBits and deriveKey Tests for PBKDF2

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/digest/digest.js b/testing/web-platform/tests/WebCryptoAPI/digest/digest.js new file mode 100644 index 000000000..84394ecbd --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/digest/digest.js @@ -0,0 +1,154 @@ + +function run_test() { + var subtle = crypto.subtle; // Change to test prefixed implementations + + var sourceData = { + empty: new Uint8Array(0), + short: new Uint8Array([21, 110, 234, 124, 193, 76, 86, 203, 148, 219, 3, 10, 74, 157, 149, 255]), + medium: new Uint8Array([182, 200, 249, 223, 100, 140, 208, 136, 183, 15, 56, 231, 65, 151, 177, 140, 184, 30, 30, 67, 80, 213, 11, 204, 184, 251, 90, 115, 121, 200, 123, 178, 227, 214, 237, 84, 97, 237, 30, 159, 54, 243, 64, 163, 150, 42, 68, 107, 129, 91, 121, 75, 75, 212, 58, 68, 3, 80, 32, 119, 178, 37, 108, 200, 7, 131, 127, 58, 172, 209, 24, 235, 75, 156, 43, 174, 184, 151, 6, 134, 37, 171, 172, 161, 147]) + }; + + sourceData.long = new Uint8Array(1024 * sourceData.medium.byteLength); + for (var i=0; i<1024; i++) { + sourceData.long.set(sourceData.medium, i * sourceData.medium.byteLength); + } + + var digestedData = { + "sha-1": { + empty: new Uint8Array([218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9]), + short: new Uint8Array([201, 19, 24, 205, 242, 57, 106, 1, 94, 63, 78, 106, 134, 160, 186, 101, 184, 99, 89, 68]), + medium: new Uint8Array([229, 65, 6, 8, 112, 235, 22, 191, 51, 182, 142, 81, 245, 19, 82, 104, 147, 152, 103, 41]), + long: new Uint8Array([48, 152, 181, 0, 55, 236, 208, 46, 189, 101, 118, 83, 178, 191, 160, 30, 238, 39, 162, 234]) + }, + "sha-256": { + empty: new Uint8Array([227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85]), + short: new Uint8Array([162, 131, 17, 134, 152, 71, 146, 199, 211, 45, 89, 200, 151, 64, 104, 127, 25, 173, 220, 27, 149, 158, 113, 161, 204, 83, 138, 59, 126, 216, 67, 242]), + medium: new Uint8Array([83, 83, 103, 135, 126, 240, 20, 215, 252, 113, 126, 92, 183, 132, 62, 89, 182, 26, 238, 98, 199, 2, 156, 236, 126, 198, 193, 47, 217, 36, 224, 228]), + long: new Uint8Array([20, 205, 234, 157, 199, 95, 90, 98, 116, 217, 252, 30, 100, 0, 153, 18, 241, 220, 211, 6, 180, 143, 232, 233, 207, 18, 45, 230, 113, 87, 23, 129]) + }, + "sha-384": { + empty: new Uint8Array([56, 176, 96, 167, 81, 172, 150, 56, 76, 217, 50, 126, 177, 177, 227, 106, 33, 253, 183, 17, 20, 190, 7, 67, 76, 12, 199, 191, 99, 246, 225, 218, 39, 78, 222, 191, 231, 111, 101, 251, 213, 26, 210, 241, 72, 152, 185, 91]), + short: new Uint8Array([107, 245, 234, 101, 36, 209, 205, 220, 67, 247, 207, 59, 86, 238, 5, 146, 39, 64, 74, 47, 83, 143, 2, 42, 61, 183, 68, 122, 120, 44, 6, 193, 237, 5, 232, 171, 79, 94, 220, 23, 243, 113, 20, 64, 223, 233, 119, 49]), + medium: new Uint8Array([203, 194, 197, 136, 254, 91, 37, 249, 22, 218, 40, 180, 228, 122, 72, 74, 230, 252, 31, 228, 144, 45, 213, 201, 147, 154, 107, 253, 3, 74, 179, 180, 139, 57, 8, 116, 54, 1, 31, 106, 153, 135, 157, 39, 149, 64, 233, 119]), + long: new Uint8Array([73, 244, 253, 179, 152, 25, 104, 249, 125, 87, 55, 15, 133, 52, 80, 103, 205, 82, 150, 169, 125, 209, 161, 142, 6, 145, 30, 117, 110, 150, 8, 73, 37, 41, 135, 14, 26, 209, 48, 153, 141, 87, 203, 251, 183, 193, 208, 158]) + }, + "sha-512": { + empty: new Uint8Array([207, 131, 225, 53, 126, 239, 184, 189, 241, 84, 40, 80, 214, 109, 128, 7, 214, 32, 228, 5, 11, 87, 21, 220, 131, 244, 169, 33, 211, 108, 233, 206, 71, 208, 209, 60, 93, 133, 242, 176, 255, 131, 24, 210, 135, 126, 236, 47, 99, 185, 49, 189, 71, 65, 122, 129, 165, 56, 50, 122, 249, 39, 218, 62]), + short: new Uint8Array([55, 82, 72, 190, 95, 243, 75, 231, 76, 171, 79, 241, 195, 188, 141, 198, 139, 213, 248, 223, 244, 2, 62, 152, 248, 123, 134, 92, 255, 44, 114, 66, 146, 223, 24, 148, 67, 166, 79, 244, 19, 74, 101, 205, 70, 53, 185, 212, 245, 220, 13, 63, 182, 117, 40, 0, 42, 99, 172, 242, 108, 157, 165, 117]), + medium: new Uint8Array([185, 16, 159, 131, 158, 142, 164, 60, 137, 15, 41, 60, 225, 29, 198, 226, 121, 141, 30, 36, 49, 241, 228, 185, 25, 227, 178, 12, 79, 54, 48, 59, 163, 156, 145, 109, 179, 6, 196, 90, 59, 101, 118, 31, 245, 190, 133, 50, 142, 234, 244, 44, 56, 48, 241, 217, 94, 122, 65, 22, 91, 125, 45, 54]), + long: new Uint8Array([75, 2, 202, 246, 80, 39, 96, 48, 234, 86, 23, 229, 151, 197, 213, 63, 217, 218, 166, 139, 120, 191, 230, 11, 34, 170, 184, 211, 106, 76, 42, 58, 255, 219, 113, 35, 79, 73, 39, 103, 55, 197, 117, 221, 247, 77, 20, 5, 76, 189, 111, 219, 152, 253, 13, 220, 188, 180, 111, 145, 173, 118, 182, 238]) + }, + } + + // Try every combination of hash with source data size. Variations tested are + // hash name in upper, lower, or mixed case, and upper-case version with the + // source buffer altered after call. + Object.keys(sourceData).forEach(function(size) { + Object.keys(digestedData).forEach(function(alg) { + var upCase = alg.toUpperCase(); + var downCase = alg.toLowerCase(); + var mixedCase = upCase.substr(0, 1) + downCase.substr(1); + + promise_test(function(test) { + var promise = subtle.digest({name: upCase}, sourceData[size]) + .then(function(result) { + assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); + }, function(err) { + assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); + }); + + return promise; + }, upCase + " with " + size + " source data"); + + promise_test(function(test) { + var promise = subtle.digest({name: mixedCase}, sourceData[size]) + .then(function(result) { + assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); + }, function(err) { + assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message);mixedCase + }); + + return promise; + }, downCase + " with " + size + " source data"); + + promise_test(function(test) { + var promise = subtle.digest({name: mixedCase}, sourceData[size]) + .then(function(result) { + assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); + }, function(err) { + assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); + }); + + return promise; + }, mixedCase + " with " + size + " source data"); + + promise_test(function(test) { + var copiedBuffer = copyBuffer(sourceData[size]); + var promise = subtle.digest({name: upCase}, copiedBuffer) + .then(function(result) { + assert_true(equalBuffers(result, digestedData[alg][size]), "digest() yielded expected result for " + alg + ":" + size); + }, function(err) { + assert_unreached("digest() threw an error for " + alg + ":" + size + " - " + err.message); + }); + + copiedBuffer[0] = 255 - copiedBuffer; + return promise; + }, upCase + " with " + size + " source data and altered buffer after call"); + + }); + }); + + // Call digest() with bad algorithm names to get an error + var badNames = ["AES-GCM", "RSA-OAEP", "PBKDF2", "AES-KW"]; + Object.keys(sourceData).forEach(function(size) { + badNames.forEach(function(badName) { + + promise_test(function(test) { + var promise = subtle.digest({name: badName}, sourceData[size]) + .then(function(result) { + assert_unreached("digest() should not have worked for " + alg + ":" + size); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "Bad algorithm name should cause NotSupportedError") + }); + + return promise; + }, badName + " with " + size); + + }); + }); + + + done(); + + + // Returns a copy of the sourceBuffer it is sent. + function copyBuffer(sourceBuffer) { + var source = new Uint8Array(sourceBuffer); + var copy = new Uint8Array(sourceBuffer.byteLength) + + for (var i=0; i + + +WebCryptoAPI: digest() + + + + + + + +

encrypt Tests for digest method

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes.js b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes.js new file mode 100644 index 000000000..e064353b8 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/aes.js @@ -0,0 +1,323 @@ + +function run_test() { + var subtle = self.crypto.subtle; // Change to test prefixed implementations + + // When are all these tests really done? When all the promises they use have resolved. + var all_promises = []; + + // Source file aes_XXX_vectors.js provides the getTestVectors method + // for the AES-XXX algorithm that drives these tests. + var vectors = getTestVectors(); + var passingVectors = vectors.passing; + var failingVectors = vectors.failing; + var decryptionFailingVectors = vectors.decryptionFailing; + + // Check for successful encryption. + passingVectors.forEach(function(vector) { + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.encrypt(vector.algorithm, vector.key, vector.plaintext) + .then(function(result) { + assert_true(equalBuffers(result, vector.result), "Should return expected result"); + }, function(err) { + assert_unreached("encrypt error for test " + vector.name + ": " + err.message); + }); + }, vector.name); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: " + vector.name); + }); + + all_promises.push(promise); + }); + + // Check for successful encryption even if the buffer is changed after calling encrypt. + passingVectors.forEach(function(vector) { + var plaintext = copyBuffer(vector.plaintext); + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + var operation = subtle.encrypt(vector.algorithm, vector.key, plaintext) + .then(function(result) { + assert_true(equalBuffers(result, vector.result), "Should return expected result"); + }, function(err) { + assert_unreached("encrypt error for test " + vector.name + ": " + err.message); + }); + plaintext[0] = 255 - plaintext[0]; + return operation; + }, vector.name + " with altered plaintext"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: " + vector.name + " with altered plaintext"); + }); + + all_promises.push(promise); + }); + + // Check for successful decryption. + passingVectors.forEach(function(vector) { + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.decrypt(vector.algorithm, vector.key, vector.result) + .then(function(result) { + assert_true(equalBuffers(result, vector.plaintext), "Should return expected result"); + }, function(err) { + assert_unreached("decrypt error for test " + vector.name + ": " + err.message); + }); + }, vector.name + " decryption"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step for decryption: " + vector.name); + }); + + all_promises.push(promise); + }); + + // Check for successful decryption even if ciphertext is altered. + passingVectors.forEach(function(vector) { + var ciphertext = copyBuffer(vector.result); + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + var operation = subtle.decrypt(vector.algorithm, vector.key, ciphertext) + .then(function(result) { + assert_true(equalBuffers(result, vector.plaintext), "Should return expected result"); + }, function(err) { + assert_unreached("decrypt error for test " + vector.name + ": " + err.message); + }); + ciphertext[0] = 255 - ciphertext[0]; + return operation; + }, vector.name + " decryption with altered ciphertext"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step for decryption: " + vector.name + " with altered ciphertext"); + }); + + all_promises.push(promise); + }); + + // Everything that succeeded should fail if no "encrypt" usage. + passingVectors.forEach(function(vector) { + // Don't want to overwrite key being used for success tests! + var badVector = Object.assign({}, vector); + badVector.key = null; + + var promise = importVectorKey(badVector, ["decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.encrypt(vector.algorithm, vector.key, vector.plaintext) + .then(function(result) { + assert_unreached("should have thrown exception for test " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw an InvalidAccessError instead of " + err.message) + }); + }, vector.name + " without encrypt usage"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: " + vector.name + " without encrypt usage"); + }); + + all_promises.push(promise); + }); + + // Encryption should fail if algorithm of key doesn't match algorithm of function call. + passingVectors.forEach(function(vector) { + var algorithm = Object.assign({}, vector.algorithm); + if (algorithm.name === "AES-CBC") { + algorithm.name = "AES-CTR"; + algorithm.counter = new Uint8Array(16); + algorithm.length = 64; + } else { + algorithm.name = "AES-CBC"; + algorithm.iv = new Uint8Array(16); // Need syntactically valid parameter to get to error being checked. + } + + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.encrypt(algorithm, vector.key, vector.plaintext) + .then(function(result) { + assert_unreached("encrypt succeeded despite mismatch " + vector.name + ": " + err.message); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Mismatch should cause InvalidAccessError instead of " + err.message); + }); + }, vector.name + " with mismatched key and algorithm"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: " + vector.name + " with mismatched key and algorithm"); + }); + + all_promises.push(promise); + }); + + // Everything that succeeded decrypting should fail if no "decrypt" usage. + passingVectors.forEach(function(vector) { + // Don't want to overwrite key being used for success tests! + var badVector = Object.assign({}, vector); + badVector.key = null; + + var promise = importVectorKey(badVector, ["encrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.decrypt(vector.algorithm, vector.key, vector.result) + .then(function(result) { + assert_unreached("should have thrown exception for test " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw an InvalidAccessError instead of " + err.message) + }); + }, vector.name + " without decrypt usage"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: " + vector.name + " without decrypt usage"); + }); + + all_promises.push(promise); + }); + + // Check for OperationError due to data lengths. + failingVectors.forEach(function(vector) { + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.encrypt(vector.algorithm, vector.key, vector.plaintext) + .then(function(result) { + assert_unreached("should have thrown exception for test " + vector.name); + }, function(err) { + assert_equals(err.name, "OperationError", "Should throw an OperationError instead of " + err.message) + }); + }, vector.name); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: " + vector.name); + }); + + all_promises.push(promise); + }); + + // Check for OperationError due to data lengths for decryption, too. + failingVectors.forEach(function(vector) { + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.decrypt(vector.algorithm, vector.key, vector.result) + .then(function(result) { + assert_unreached("should have thrown exception for test " + vector.name); + }, function(err) { + assert_equals(err.name, "OperationError", "Should throw an OperationError instead of " + err.message) + }); + }, vector.name + " decryption"); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: decryption " + vector.name); + }); + + all_promises.push(promise); + }); + + // Check for decryption failing for algorithm-specific reasons (such as bad + // padding for AES-CBC). + decryptionFailingVectors.forEach(function(vector) { + var promise = importVectorKey(vector, ["encrypt", "decrypt"]) + .then(function(vector) { + promise_test(function(test) { + return subtle.decrypt(vector.algorithm, vector.key, vector.result) + .then(function(result) { + assert_unreached("should have thrown exception for test " + vector.name); + }, function(err) { + assert_equals(err.name, "OperationError", "Should throw an OperationError instead of " + err.message) + }); + }, vector.name); + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested encryption + promise_test(function(test) { + assert_unreached("importKey failed for " + vector.name); + }, "importKey step: decryption " + vector.name); + }); + + all_promises.push(promise); + }); + + Promise.all(all_promises) + .then(function() {done();}) + .catch(function() {done();}) + + // A test vector has all needed fields for encryption, EXCEPT that the + // key field may be null. This function replaces that null with the Correct + // CryptoKey object. + // + // Returns a Promise that yields an updated vector on success. + function importVectorKey(vector, usages) { + if (vector.key !== null) { + return new Promise(function(resolve, reject) { + resolve(vector); + }); + } else { + return subtle.importKey("raw", vector.keyBuffer, {name: vector.algorithm.name}, false, usages) + .then(function(key) { + vector.key = key; + return vector; + }); + } + } + + // Returns a copy of the sourceBuffer it is sent. + function copyBuffer(sourceBuffer) { + var source = new Uint8Array(sourceBuffer); + var copy = new Uint8Array(sourceBuffer.byteLength) + + for (var i=0; i + + +WebCryptoAPI: encrypt() Using AES-CBC + + + + + + + + +

encrypt Tests for AES-CBC

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html new file mode 100644 index 000000000..a48dfd3fd --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_ctr.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: encrypt() Using AES-CTR + + + + + + + + +

encrypt Tests for AES-CTR

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html new file mode 100644 index 000000000..9f8b8bdf9 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: encrypt() Using AES-GCM + + + + + + + + +

encrypt Tests for AES-GCM

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html new file mode 100644 index 000000000..df8d8f42a --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/encrypt_decrypt/test_rsa_oaep.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: encrypt() Using RSA-OAEP + + + + + + + + +

encrypt Tests for RSA-OAEP

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures.js new file mode 100644 index 000000000..23fb28018 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures.js @@ -0,0 +1,216 @@ +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 = []; + if (algorithmNames && !Array.isArray(algorithmNames)) { + algorithmNames = [algorithmNames]; + }; + 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"); + }); + }); + }); + + +} diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures.worker.js new file mode 100644 index 000000000..705664c2d --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures.worker.js @@ -0,0 +1,5 @@ +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(); +done(); diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js new file mode 100644 index 000000000..2094bef58 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CBC.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["AES-CBC"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js new file mode 100644 index 000000000..233dae790 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-CTR.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["AES-CTR"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js new file mode 100644 index 000000000..4119c1ebd --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-GCM.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["AES-GCM"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-KW.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-KW.worker.js new file mode 100644 index 000000000..e3098e196 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_AES-KW.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["AES-KW"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDH.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDH.worker.js new file mode 100644 index 000000000..ac95099ac --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDH.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["ECDH"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDSA.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDSA.worker.js new file mode 100644 index 000000000..48852dcf9 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_ECDSA.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["ECDSA"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_HMAC.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_HMAC.worker.js new file mode 100644 index 000000000..94cdb731f --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_HMAC.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["HMAC"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js new file mode 100644 index 000000000..90523a9fb --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["RSA-OAEP"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js new file mode 100644 index 000000000..8ea8b92a4 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["RSA-PSS"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js new file mode 100644 index 000000000..d36368015 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.js @@ -0,0 +1,6 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test(["RSASSA-PKCS1-v1_5"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js new file mode 100644 index 000000000..db4aae085 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.js @@ -0,0 +1,88 @@ + +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 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 = []; + if (algorithmNames && !Array.isArray(algorithmNames)) { + algorithmNames = [algorithmNames]; + }; + allTestVectors.forEach(function(vector) { + if (!algorithmNames || algorithmNames.includes(vector.name)) { + testVectors.push(vector); + } + }); + + 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"); + }); + }); + }); + }); + }); + +} diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.worker.js new file mode 100644 index 000000000..52e34946e --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes.worker.js @@ -0,0 +1,6 @@ +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(); +done(); diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js new file mode 100644 index 000000000..c91244a98 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CBC.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["AES-CBC"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js new file mode 100644 index 000000000..a5a3fcd03 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-CTR.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["AES-CTR"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js new file mode 100644 index 000000000..5960bb452 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-GCM.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["AES-GCM"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-KW.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-KW.worker.js new file mode 100644 index 000000000..6771e09cb --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_AES-KW.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["AES-KW"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDH.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDH.worker.js new file mode 100644 index 000000000..0531cd6f7 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDH.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["ECDH"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDSA.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDSA.worker.js new file mode 100644 index 000000000..20e6df2cb --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_ECDSA.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["ECDSA"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_HMAC.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_HMAC.worker.js new file mode 100644 index 000000000..9dfd30a0d --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_HMAC.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["HMAC"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js new file mode 100644 index 000000000..a9ed367a2 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["RSA-OAEP"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js new file mode 100644 index 000000000..05de5a90e --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["RSA-PSS"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js new file mode 100644 index 000000000..3e48cfccb --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js @@ -0,0 +1,7 @@ +// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test(["RSASSA-PKCS1-v1_5"]); +done(); \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.html new file mode 100644 index 000000000..a3054a57a --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-cbc.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.html new file mode 100644 index 000000000..bb1abf0d9 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_aes-ctr.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.html new file mode 100644 index 000000000..14e57b25c --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.html new file mode 100644 index 000000000..7650908c0 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CBC.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.html new file mode 100644 index 000000000..f08737c39 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-CTR.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.html new file mode 100644 index 000000000..4ef6a7771 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-GCM.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.html new file mode 100644 index 000000000..7cbb4f8bf --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_AES-KW.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.html new file mode 100644 index 000000000..c606a5b90 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDH.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.html new file mode 100644 index 000000000..8b742e80b --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_ECDSA.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.html new file mode 100644 index 000000000..e037f0d07 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_HMAC.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html new file mode 100644 index 000000000..ddd63beb3 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-OAEP.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html new file mode 100644 index 000000000..2814b34e9 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSA-PSS.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html new file mode 100644 index 000000000..0e28914af --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_failures_RSASSA-PKCS1-v1_5.html @@ -0,0 +1,18 @@ + + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html new file mode 100644 index 000000000..384db1cd1 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.html new file mode 100644 index 000000000..af8093539 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CBC.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.html new file mode 100644 index 000000000..3608a4fde --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-CTR.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.html new file mode 100644 index 000000000..eb7c6b5d0 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-GCM.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.html new file mode 100644 index 000000000..9beab2083 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_AES-KW.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.html new file mode 100644 index 000000000..9871f572b --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDH.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.html new file mode 100644 index 000000000..f32a556bb --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_ECDSA.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.html new file mode 100644 index 000000000..819b35df0 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_HMAC.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html new file mode 100644 index 000000000..db58fd669 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html new file mode 100644 index 000000000..d6a3c1b02 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSA-PSS.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html new file mode 100644 index 000000000..35678798b --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/generateKey/test_successes_RSASSA-PKCS1-v1_5.html @@ -0,0 +1,23 @@ + + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+ \ No newline at end of file diff --git a/testing/web-platform/tests/WebCryptoAPI/getRandomValues.js b/testing/web-platform/tests/WebCryptoAPI/getRandomValues.js new file mode 100644 index 000000000..0649d9596 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/getRandomValues.js @@ -0,0 +1,50 @@ +function run_test() { + // Step 1. + test(function() { + assert_throws("TypeMismatchError", function() { + self.crypto.getRandomValues(new Float32Array(6)) + }, "Float32Array") + assert_throws("TypeMismatchError", function() { + self.crypto.getRandomValues(new Float64Array(6)) + }, "Float64Array") + + assert_throws("TypeMismatchError", function() { + self.crypto.getRandomValues(new Float32Array(65537)) + }, "Float32Array (too long)") + assert_throws("TypeMismatchError", function() { + self.crypto.getRandomValues(new Float64Array(65537)) + }, "Float64Array (too long)") + }, "Float arrays") + + var arrays = { + 'Int8Array': Int8Array, + 'Int16Array': Int16Array, + 'Int32Array': Int32Array, + 'Uint8Array': Uint8Array, + 'Uint8ClampedArray': Uint8ClampedArray, + 'Uint16Array': Uint16Array, + 'Uint32Array': Uint32Array, + }; + + test(function() { + for (var array in arrays) { + assert_equals(self.crypto.getRandomValues(new arrays[array](8)).constructor, + arrays[array], "crypto.getRandomValues(new " + array + "(8))") + } + }, "Integer array") + + test(function() { + for (var array in arrays) { + var maxlength = 65536 / (arrays[array].BYTES_PER_ELEMENT); + assert_throws("QuotaExceededError", function() { + self.crypto.getRandomValues(new arrays[array](maxlength + 1)) + }, "crypto.getRandomValues length over 65536") + } + }, "Large length") + + test(function() { + for (var array in arrays) { + assert_true(self.crypto.getRandomValues(new arrays[array](0)).length == 0) + } + }, "Null arrays") +} diff --git a/testing/web-platform/tests/WebCryptoAPI/getRandomValues.worker.js b/testing/web-platform/tests/WebCryptoAPI/getRandomValues.worker.js new file mode 100644 index 000000000..cc2635630 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/getRandomValues.worker.js @@ -0,0 +1,4 @@ +importScripts("/resources/testharness.js"); +importScripts("getRandomValues.js"); +run_test(); +done(); diff --git a/testing/web-platform/tests/WebCryptoAPI/idlharness.html b/testing/web-platform/tests/WebCryptoAPI/idlharness.html new file mode 100644 index 000000000..81e1e04f9 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/idlharness.html @@ -0,0 +1,45 @@ + + + + +IDL check of WebCrypto + + + + + + + + + +

Description

+ +

This test verifies that the implementations of the WebCrypto API match with its WebIDL definition.

+ +
+ + diff --git a/testing/web-platform/tests/WebCryptoAPI/idlharness.worker.js b/testing/web-platform/tests/WebCryptoAPI/idlharness.worker.js new file mode 100644 index 000000000..ba033014e --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/idlharness.worker.js @@ -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(); +}; diff --git a/testing/web-platform/tests/WebCryptoAPI/import_export/ec_importKey.js b/testing/web-platform/tests/WebCryptoAPI/import_export/ec_importKey.js new file mode 100644 index 000000000..277851d01 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/import_export/ec_importKey.js @@ -0,0 +1,279 @@ +// Test importKey and exportKey for EC algorithms. Only "happy paths" are +// currently tested - those where the operation should succeed. + +function run_test() { + var subtle = crypto.subtle; + + var curves = ['P-256', 'P-384', 'P-521']; + + var keyData = { + "P-521": { + spki: new Uint8Array([48, 129, 155, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + pkcs8: new Uint8Array([48, 129, 238, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 35, 4, 129, 214, 48, 129, 211, 2, 1, 1, 4, 66, 0, 244, 8, 117, 131, 104, 186, 147, 15, 48, 247, 106, 224, 84, 254, 92, 210, 206, 127, 218, 44, 159, 118, 166, 212, 54, 207, 117, 214, 108, 68, 11, 254, 99, 49, 199, 193, 114, 161, 36, 120, 25, 60, 130, 81, 72, 123, 201, 18, 99, 250, 80, 33, 127, 133, 255, 99, 111, 89, 205, 84, 110, 58, 180, 131, 180, 161, 129, 137, 3, 129, 134, 0, 4, 1, 86, 244, 121, 248, 223, 30, 32, 167, 255, 192, 76, 228, 32, 195, 225, 84, 174, 37, 25, 150, 190, 228, 47, 3, 75, 132, 212, 27, 116, 63, 52, 228, 95, 49, 27, 129, 58, 156, 222, 200, 205, 165, 155, 187, 189, 49, 212, 96, 179, 41, 37, 33, 231, 193, 183, 34, 229, 102, 124, 3, 219, 47, 174, 117, 63, 1, 80, 23, 54, 207, 226, 71, 57, 67, 32, 216, 228, 175, 194, 253, 57, 181, 169, 51, 16, 97, 184, 30, 34, 65, 40, 43, 158, 23, 137, 24, 34, 181, 183, 158, 5, 47, 69, 151, 181, 150, 67, 253, 57, 55, 156, 81, 189, 81, 37, 196, 244, 139, 195, 240, 37, 206, 60, 211, 105, 83, 40, 108, 203, 56, 251]), + jwk: { + kty: "EC", + crv: "P-521", + x: "AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_", + y: "AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7", + d: "APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0" + } + }, + + "P-256": { + spki: new Uint8Array([48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + pkcs8: new Uint8Array([48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58, 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231, 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97, 232]), + jwk: { + kty: "EC", + crv: "P-256", + x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE", + y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg", + d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo" + } + }, + + "P-384": { + spki: new Uint8Array([48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + pkcs8: new Uint8Array([48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 69, 55, 181, 153, 7, 132, 211, 194, 210, 46, 150, 168, 249, 47, 161, 170, 73, 46, 232, 115, 229, 118, 164, 21, 130, 225, 68, 24, 60, 152, 136, 209, 14, 107, 158, 180, 206, 212, 178, 204, 64, 18, 228, 172, 94, 168, 64, 115, 161, 100, 3, 98, 0, 4, 33, 156, 20, 214, 102, 23, 179, 110, 198, 216, 133, 107, 56, 91, 115, 167, 77, 52, 79, 216, 174, 117, 239, 4, 100, 53, 221, 165, 78, 59, 68, 189, 95, 189, 235, 209, 208, 141, 214, 158, 45, 125, 193, 220, 33, 140, 180, 53, 189, 40, 19, 140, 199, 120, 51, 122, 132, 47, 107, 214, 27, 36, 14, 116, 36, 159, 36, 102, 124, 42, 88, 16, 167, 107, 252, 40, 224, 51, 95, 136, 166, 80, 29, 236, 1, 151, 109, 168, 90, 251, 0, 134, 156, 182, 172, 232]), + jwk: { + kty: "EC", + crv: "P-384", + x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1", + y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo", + d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz" + } + }, + + }; + + // combinations to test + var testVectors = [ + {name: "ECDSA", privateUsages: ["sign"], publicUsages: ["verify"]}, + {name: "ECDH", privateUsages: ["deriveKey", "deriveBits"], publicUsages: []} + ]; + + // TESTS ARE HERE: + // Test every test vector, along with all available key data + testVectors.forEach(function(vector) { + curves.forEach(function(curve) { + + [true, false].forEach(function(extractable) { + + // Test public keys first + [[]].forEach(function(usages) { // Only valid usages argument is empty array + ['spki', 'jwk'].forEach(function(format) { + var algorithm = {name: vector.name, namedCurve: curve}; + var data = keyData[curve]; + if (format === "jwk") { // Not all fields used for public keys + data = {jwk: {kty: keyData[curve].jwk.kty, crv: keyData[curve].jwk.crv, x: keyData[curve].jwk.x, y: keyData[curve].jwk.y}}; + } + + testFormat(format, algorithm, data, curve, usages, extractable); + }); + + }); + + // 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]; + + testFormat(format, algorithm, data, curve, usages, extractable); + }); + }); + }); + + }); + }); + + + // Test importKey with a given key format and other parameters. If + // extrable is true, export the key and verify that it matches the input. + function testFormat(format, algorithm, keyData, keySize, usages, extractable) { + promise_test(function(test) { + return subtle.importKey(format, keyData[format], algorithm, extractable, usages). + then(function(key) { + assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object"); + if (!extractable) { + return; + } + + return subtle.exportKey(format, key). + then(function(result) { + if (format !== "jwk") { + assert_true(equalBuffers(keyData[format], result), "Round trip works"); + } else { + assert_true(equalJwk(keyData[format], result), "Round trip works"); + } + }, function(err) { + assert_unreached("Threw an unexpected error: " + err.toString()); + }); + }, function(err) { + assert_unreached("Threw an unexpected error: " + err.toString()); + }); + }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], algorithm, extractable, usages)); + } + + + + // Helper methods follow: + + // Are two array buffers the same? + function equalBuffers(a, b) { + if (a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + for (var i=0; i 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 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 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 + +WebCryptoAPI: importKey() for EC keys + + + + + +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.html b/testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.html new file mode 100644 index 000000000..219ad2d3b --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/import_export/test_rsa_importKey.html @@ -0,0 +1,12 @@ + + +WebCryptoAPI: importKey() for RSA keys + + + + + +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.html b/testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.html new file mode 100644 index 000000000..e82c4d78f --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/import_export/test_symmetric_importKey.html @@ -0,0 +1,12 @@ + + +WebCryptoAPI: importKey() for symmetric keys + + + + + +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js new file mode 100644 index 000000000..869fb7965 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/ecdsa.js @@ -0,0 +1,479 @@ + +function run_test() { + var subtle = self.crypto.subtle; // Change to test prefixed implementations + + // When are all these tests really done? When all the promises they use have resolved. + var all_promises = []; + + // Source file [algorithm_name]_vectors.js provides the getTestVectors method + // for the algorithm that drives these tests. + var testVectors = getTestVectors(); + + // Test verification first, because signing tests rely on that working + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification"); + }); + + all_promises.push(promise); + }); + + // Test verification with an altered buffer after call + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + signature[0] = 255 - signature[0]; + return operation; + }, vector.name + " verification with altered signature after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); + }); + + all_promises.push(promise); + }); + + // Check for successful verification even if plaintext is altered after call. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + plaintext[0] = 255 - plaintext[0]; + return operation; + }, vector.name + " with altered plaintext after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to using privateKey to verify. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.verify(algorithm, vector.privateKey, vector.signature, vector.plaintext) + .then(function(plaintext) { + assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": " + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " using privateKey to verify"); + + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " using privateKey to verify"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to using publicKey to sign. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.sign(algorithm, vector.publicKey, vector.plaintext) + .then(function(signature) { + assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": " + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " using publicKey to sign"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " using publicKey to sign"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to no "verify" usage. + testVectors.forEach(function(originalVector) { + var vector = Object.assign({}, originalVector); + + var promise = importVectorKeys(vector, [], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(plaintext) { + assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": " + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " no verify usage"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " no verify usage"); + }); + + all_promises.push(promise); + }); + + // Check for successful signing and verification. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.sign(algorithm, vector.privateKey, vector.plaintext) + .then(function(signature) { + // Can we verify the signature? + return subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Round trip verification works"); + return signature; + }, function(err) { + assert_unreached("verify error for test " + vector.name + ": " + err.message + "'"); + }); + }, function(err) { + assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'"); + }); + }, vector.name + " round trip"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested signing or verifying + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " round trip"); + }); + + all_promises.push(promise); + }); + + // Test signing with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) + .then(function(wrongKey) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + return importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + var operation = subtle.sign(algorithm, wrongKey, vector.plaintext) + .then(function(signature) { + assert_unreached("Signing should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " signing with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Test verification with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) + .then(function(wrongKey) { + return importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, wrongKey, vector.signature, vector.plaintext) + .then(function(signature) { + assert_unreached("Verifying should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verifying with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with wrong signature + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + var signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to altered signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to altered signature"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with wrong hash + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var hashName = "SHA-1"; + if (vector.hashName === "SHA-1") { + hashName = "SHA-256" + } + var algorithm = {name: vector.algorithmName, hash: hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to wrong hash"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to wrong hash"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with bad hash name + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + // use the wrong name for the hash + var hashName = vector.hashName.substring(0, 3) + vector.hashName.substring(4); + var algorithm = {name: vector.algorithmName, hash: hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_unreached("Verification should throw an error"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "Correctly throws NotSupportedError for illegal hash name") + }); + + return operation; + }, vector.name + " verification failure due to bad hash name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to bad hash name"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with short (odd length) signature + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + var signature = vector.signature.slice(1); // Skip the first byte + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to shortened signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to shortened signature"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with wrong plaintext + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + var plaintext = copyBuffer(vector.plaintext); + plaintext[0] = 255 - plaintext[0]; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to altered plaintext"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to altered plaintext"); + }); + + all_promises.push(promise); + }); + + + Promise.all(all_promises) + .then(function() {done();}) + .catch(function() {done();}) + return; + + // A test vector has all needed fields for signing and verifying, EXCEPT that the + // key field may be null. This function replaces that null with the Correct + // CryptoKey object. + // + // Returns a Promise that yields an updated vector on success. + function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) { + var publicPromise, privatePromise; + + if (vector.publicKey !== null) { + publicPromise = new Promise(function(resolve, reject) { + resolve(vector); + }); + } else { + publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, publicKeyUsages) + .then(function(key) { + vector.publicKey = key; + return vector; + }); // Returns a copy of the sourceBuffer it is sent. + } + + if (vector.privateKey !== null) { + privatePromise = new Promise(function(resolve, reject) { + resolve(vector); + }); + } else { + privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, privateKeyUsages) + .then(function(key) { + vector.privateKey = key; + return vector; + }); + } + + return Promise.all([publicPromise, privatePromise]); + } + + // Returns a copy of the sourceBuffer it is sent. + function copyBuffer(sourceBuffer) { + var source = new Uint8Array(sourceBuffer); + var copy = new Uint8Array(sourceBuffer.byteLength) + + for (var i=0; i 0) { + assert_false(equalBuffers(priorSignature, signature), "Two signings with a salt give different signatures") + } else { + assert_true(equalBuffers(priorSignature, signature), "Two signings with empty salt give same signature") + } + }, function(err) { + assert_unreached("second time verify error for test " + vector.name + ": '" + err.message + "'"); + }); + }, function(err) { + assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'"); + }); + }, vector.name + " round trip"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested signing or verifying + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " round trip"); + }); + + all_promises.push(promise); + }); + + + // Test signing with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var alteredVector = Object.assign({}, vector); + alteredVector.algorithm = Object.assign({}, vector.algorithm); + if (vector.algorithm.name === "RSA-PSS") { + alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5"; + } else { + alteredVector.algorithm.name = "RSA-PSS"; + } + + var promise = importVectorKeys(alteredVector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + var operation = subtle.sign(vector.algorithm, alteredVector.privateKey, vector.plaintext) + .then(function(signature) { + assert_unreached("Signing should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " signing with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Test verification with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var alteredVector = Object.assign({}, vector); + alteredVector.algorithm = Object.assign({}, vector.algorithm); + if (vector.algorithm.name === "RSA-PSS") { + alteredVector.algorithm.name = "RSASSA-PKCS1-v1_5"; + } else { + alteredVector.algorithm.name = "RSA-PSS"; + } + + var promise = importVectorKeys(alteredVector, ["verify"], ["sign"]) + .then(function(vectors) { + // Some tests are sign only + if (!("signature" in vector)) { + return; + } + promise_test(function(test) { + var operation = subtle.verify(vector.algorithm, alteredVector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_unreached("Verification should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verification with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Verification should fail with wrong signature + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure with altered signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure with altered signature"); + }); + + all_promises.push(promise); + }); + + // Verification should fail with wrong plaintext + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + plaintext[0] = 255 - plaintext[0]; + var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure with altered plaintext"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure with altered plaintext"); + }); + + all_promises.push(promise); + }); + + + Promise.all(all_promises) + .then(function() {done();}) + .catch(function() {done();}) + + // A test vector has all needed fields for signing and verifying, EXCEPT that the + // key field may be null. This function replaces that null with the Correct + // CryptoKey object. + // + // Returns a Promise that yields an updated vector on success. + function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) { + var publicPromise, privatePromise; + + if (vector.publicKey !== null) { + publicPromise = new Promise(function(resolve, reject) { + resolve(vector); + }); + } else { + publicPromise = subtle.importKey(vector.publicKeyFormat, vector.publicKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, publicKeyUsages) + .then(function(key) { + vector.publicKey = key; + return vector; + }); // Returns a copy of the sourceBuffer it is sent. + } + + if (vector.privateKey !== null) { + privatePromise = new Promise(function(resolve, reject) { + resolve(vector); + }); + } else { + privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithm.name, hash: vector.hash}, false, privateKeyUsages) + .then(function(key) { + vector.privateKey = key; + return vector; + }); + } + + return Promise.all([publicPromise, privatePromise]); + } + + // Returns a copy of the sourceBuffer it is sent. + function copyBuffer(sourceBuffer) { + var source = new Uint8Array(sourceBuffer); + var copy = new Uint8Array(sourceBuffer.byteLength) + + for (var i=0; i + + +WebCryptoAPI: sign() and verify() Using ECDSA + + + + + + + + + +

sign and verify Tests for ECDSA

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.html new file mode 100644 index 000000000..6d5ff926f --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_hmac.html @@ -0,0 +1,19 @@ + + + +WebCryptoAPI: sign() and verify() Using HMAC + + + + + + + + + +

sign and verify Tests for HMAC

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.html new file mode 100644 index 000000000..de428c0fc --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pkcs.html @@ -0,0 +1,19 @@ + + + +WebCryptoAPI: sign() and verify() Using RSASSA-PKCS1-v1_5 + + + + + + + + + +

sign and verify Tests for RSASSA-PKCS1-v1_5

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.html b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.html new file mode 100644 index 000000000..3a2034feb --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/sign_verify/test_rsa_pss.html @@ -0,0 +1,19 @@ + + + +WebCryptoAPI: sign() and verify() Using RSA-PSS + + + + + + + + + +

sign and verify Tests for RSA-PSS

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/test_getRandomValues.html b/testing/web-platform/tests/WebCryptoAPI/test_getRandomValues.html new file mode 100644 index 000000000..a5cd53709 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/test_getRandomValues.html @@ -0,0 +1,12 @@ + + +WebCryptoAPI: getRandomValues() + + + + + +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/tools/generate.py b/testing/web-platform/tests/WebCryptoAPI/tools/generate.py new file mode 100644 index 000000000..0d3696128 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/tools/generate.py @@ -0,0 +1,76 @@ +# script to generate the generateKey tests + +import os + +here = os.path.dirname(__file__) + +successes_html = """ + + +WebCryptoAPI: generateKey() Successful Calls + + + + + + + + +

generateKey Tests for Good Parameters

+

+ Warning! RSA key generation is intrinsically + very slow, so the related tests can take up to + several minutes to complete, depending on browser! +

+ +
+""" + +failures_html = """ + + +WebCryptoAPI: generateKey() for Failures + + + + + + + + +

generateKey Tests for Bad Parameters

+ +
+ +""" + +successes_worker = """// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("successes.js"); + +run_test([%s]); +done();""" + +failures_worker = """// timeout=long +importScripts("/resources/testharness.js"); +importScripts("../util/helpers.js"); +importScripts("failures.js"); +run_test([%s]); +done();""" + +names = ["AES-CTR", "AES-CBC", "AES-GCM", "AES-KW", "HMAC", "RSASSA-PKCS1-v1_5", + "RSA-PSS", "RSA-OAEP", "ECDSA", "ECDH"] + +for filename_pattern, template in [("test_successes_%s.html", successes_html), + ("test_failures_%s.html", failures_html), + ("successes_%s.worker.js", successes_worker), + ("failures_%s.worker.js", failures_worker)]: + for name in names: + path = os.path.join(here, os.pardir, "generateKey", filename_pattern % name) + with open(path, "w") as f: + f.write(template % '"%s"' % name) diff --git a/testing/web-platform/tests/WebCryptoAPI/util/helpers.js b/testing/web-platform/tests/WebCryptoAPI/util/helpers.js new file mode 100644 index 000000000..fb723c3f7 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/util/helpers.js @@ -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 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 + + +WebCryptoAPI: wrapKey() and unwrapKey() + + + + + + + +

wrapKey and unwrapKey Tests

+ +
+ diff --git a/testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.js b/testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.js new file mode 100644 index 000000000..12bd696a7 --- /dev/null +++ b/testing/web-platform/tests/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.js @@ -0,0 +1,266 @@ +// Tests for wrapKey and unwrapKey round tripping + +function run_test() { + var subtle = self.crypto.subtle; + + var wrappers = []; // Things we wrap (and upwrap) keys with + var keys = []; // Things to wrap and unwrap + + // Generate all the keys needed, then iterate over all combinations + // to test wrapping and unwrapping. + Promise.all([generateWrappingKeys(), generateKeysToWrap()]) + .then(function(results) { + wrappers.forEach(function(wrapper) { + keys.forEach(function(key) { + testWrapping(wrapper, key); + }) + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("A key failed to generate: " + err.name + ": " + err.message) + }, "Could not run all tests") + }) + .then(function() { + done(); + }, function(error) { + promise_test(function(test) { + assert_unreached("A test failed to run: " + err.name + ": " + err.message) + }, "Could not run all tests") + }); + + + function generateWrappingKeys() { + // There are five algorithms that can be used for wrapKey/unwrapKey. + // Generate one key with typical parameters for each kind. + // + // Note: we don't need cryptographically strong parameters for things + // like IV - just any legal value will do. + var parameters = [ + { + name: "RSA-OAEP", + generateParameters: {name: "RSA-OAEP", modulusLength: 4096, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, + wrapParameters: {name: "RSA-OAEP", label: new Uint8Array(8)} + }, + { + name: "AES-CTR", + generateParameters: {name: "AES-CTR", length: 128}, + wrapParameters: {name: "AES-CTR", counter: new Uint8Array(16), length: 64} + }, + { + name: "AES-CBC", + generateParameters: {name: "AES-CBC", length: 128}, + wrapParameters: {name: "AES-CBC", iv: new Uint8Array(16)} + }, + { + name: "AES-GCM", + generateParameters: {name: "AES-GCM", length: 128}, + wrapParameters: {name: "AES-GCM", iv: new Uint8Array(16), additionalData: new Uint8Array(16), tagLength: 64} + }, + { + name: "AES-KW", + generateParameters: {name: "AES-KW", length: 128}, + wrapParameters: {name: "AES-KW"} + } + ]; + + return Promise.all(parameters.map(function(params) { + return subtle.generateKey(params.generateParameters, true, ["wrapKey", "unwrapKey"]) + .then(function(key) { + var wrapper; + if (params.name === "RSA-OAEP") { // we have a key pair, not just a key + wrapper = {wrappingKey: key.publicKey, unwrappingKey: key.privateKey, parameters: params}; + } else { + wrapper = {wrappingKey: key, unwrappingKey: key, parameters: params}; + } + wrappers.push(wrapper); + return true; + }) + })); + } + + + function generateKeysToWrap() { + var parameters = [ + {algorithm: {name: "RSASSA-PKCS1-v1_5", modulusLength: 1024, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, privateUsages: ["sign"], publicUsages: ["verify"]}, + {algorithm: {name: "RSA-PSS", modulusLength: 1024, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, privateUsages: ["sign"], publicUsages: ["verify"]}, + {algorithm: {name: "RSA-OAEP", modulusLength: 1024, publicExponent: new Uint8Array([1,0,1]), hash: "SHA-256"}, privateUsages: ["decrypt"], publicUsages: ["encrypt"]}, + {algorithm: {name: "ECDSA", namedCurve: "P-256"}, privateUsages: ["sign"], publicUsages: ["verify"]}, + {algorithm: {name: "ECDH", namedCurve: "P-256"}, privateUsages: ["deriveBits"], publicUsages: []}, + {algorithm: {name: "AES-CTR", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-CBC", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-GCM", length: 128}, usages: ["encrypt", "decrypt"]}, + {algorithm: {name: "AES-KW", length: 128}, usages: ["wrapKey", "unwrapKey"]}, + {algorithm: {name: "HMAC", length: 128, hash: "SHA-256"}, usages: ["sign", "verify"]} + ]; + + return Promise.all(parameters.map(function(params) { + var usages; + if ("usages" in params) { + usages = params.usages; + } else { + usages = params.publicUsages.concat(params.privateUsages); + } + + return subtle.generateKey(params.algorithm, true, usages) + .then(function(result) { + if (result.constructor === CryptoKey) { + keys.push({name: params.algorithm.name, algorithm: params.algorithm, usages: params.usages, key: result}); + } else { + keys.push({name: params.algorithm.name + " public key", algorithm: params.algorithm, usages: params.publicUsages, key: result.publicKey}); + keys.push({name: params.algorithm.name + " private key", algorithm: params.algorithm, usages: params.privateUsages, key: result.privateKey}); + } + return true; + }); + })); + } + + + // Can we successfully "round-trip" (wrap, then unwrap, a key)? + function testWrapping(wrapper, toWrap) { + var formats; + + if (toWrap.name.includes("private")) { + formats = ["pkcs8", "jwk"]; + } else if (toWrap.name.includes("public")) { + formats = ["spki", "jwk"] + } else { + formats = ["raw", "jwk"] + } + + formats.forEach(function(fmt) { + var originalExport; + + promise_test(function(test) { + return subtle.exportKey(fmt, toWrap.key) + .then(function(exportedKey) { + originalExport = exportedKey; + return exportedKey; + }).then(function(exportedKey) { + return subtle.wrapKey(fmt, toWrap.key, wrapper.wrappingKey, wrapper.parameters.wrapParameters); + }).then(function(wrappedResult) { + return subtle.unwrapKey(fmt, wrappedResult, wrapper.unwrappingKey, wrapper.parameters.wrapParameters, toWrap.algorithm, true, toWrap.usages) + }).then(function(unwrappedResult) { + return subtle.exportKey(fmt, unwrappedResult) + }).then(function(roundTripExport) { + if ("byteLength" in originalExport) { + assert_true(equalBuffers(originalExport, roundTripExport), "Post-wrap export matches original export"); + } else { + assert_true(equalJwk(originalExport, roundTripExport), "Post-wrap export matches original export."); + } + }, function(err) { + if (wrappingIsPossible(originalExport, wrapper.parameters.name)) { + assert_unreached("Round trip threw an error - " + err.name + ': "' + err.message + '"'); + } else { + assert_true(true, "Skipped test due to key length restrictions"); + } + }) + }, "Can wrap and unwrap " + toWrap.name + " keys using " + fmt + " and " + wrapper.parameters.name); + + }); + + } + + + // RSA-OAEP can only wrap relatively small payloads. AES-KW can only + // wrap payloads a multiple of 8 bytes long. + // + // Note that JWK payloads will be converted to ArrayBuffer for wrapping, + // and should automatically be padded if needed for AES-KW. + function wrappingIsPossible(exportedKey, algorithmName) { + if ("byteLength" in exportedKey && algorithmName === "AES-KW") { + return exportedKey.byteLength % 8 === 0; + } + + if ("byteLength" in exportedKey && algorithmName === "RSA-OAEP") { + // RSA-OAEP can only encrypt payloads with lengths shorter + // than modulusLength - 2*hashLength - 1 bytes long. For + // a 4096 bit modulus and SHA-256, that comes to + // 4096/8 - 2*(256/8) - 1 = 512 - 2*32 - 1 = 447 bytes. + return exportedKey.byteLength <= 446; + } + + if ("kty" in exportedKey && algorithmName === "RSA-OAEP") { + return JSON.stringify(exportedKey).length <= 478; + } + + return true; + } + + + // Helper methods follow: + + // Are two array buffers the same? + function equalBuffers(a, b) { + if (a.byteLength !== b.byteLength) { + return false; + } + + var aBytes = new Uint8Array(a); + var bBytes = new Uint8Array(b); + + for (var i=0; i timeout=long +importScripts("/resources/testharness.js"); +importScripts("wrapKey_unwrapKey.js"); + +run_test(); -- cgit v1.2.3