From e05ee9d2974dbad65bf6b9ad065eace7ea13a506 Mon Sep 17 00:00:00 2001 From: devgianlu Date: Wed, 25 Dec 2024 23:47:06 +0100 Subject: [PATCH] LibWeb: Support `RSA-PSS` in WebCryptoAPI --- Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp | 592 ++++++++++++++++++ Libraries/LibWeb/Crypto/CryptoAlgorithms.h | 33 + Libraries/LibWeb/Crypto/SubtleCrypto.cpp | 10 +- .../import_export/rsa_importKey.https.any.txt | 100 +-- .../sign_verify/rsa_pss.https.any.txt | 102 +++ .../wrapKey_unwrapKey.https.any.txt | 29 +- .../WebCryptoAPI/sign_verify/rsa.js | 438 +++++++++++++ .../sign_verify/rsa_pss.https.any.html | 17 + .../sign_verify/rsa_pss.https.any.js | 6 + .../sign_verify/rsa_pss_vectors.js | 147 +++++ 10 files changed, 1417 insertions(+), 57 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa.js create mode 100644 Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.js create mode 100644 Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss_vectors.js diff --git a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp index 9ba824203ad..126998e6dd0 100644 --- a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp +++ b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp @@ -512,6 +512,19 @@ JS::ThrowCompletionOr> RsaOaepParams::from_value( return adopt_own(*new RsaOaepParams { move(label) }); } +RsaPssParams::~RsaPssParams() = default; + +// https://w3c.github.io/webcrypto/#RsaPssParams-dictionary +JS::ThrowCompletionOr> RsaPssParams::from_value(JS::VM& vm, JS::Value value) +{ + auto& object = value.as_object(); + + auto salt_length_value = TRY(object.get("saltLength")); + auto salt_length = TRY(salt_length_value.to_u32(vm)); + + return adopt_own(*new RsaPssParams { salt_length }); +} + EcdsaParams::~EcdsaParams() = default; JS::ThrowCompletionOr> EcdsaParams::from_value(JS::VM& vm, JS::Value value) @@ -1228,6 +1241,585 @@ WebIDL::ExceptionOr> RSAOAEP::export_key(Bindings::KeyFormat return GC::Ref { *result }; } +// https://w3c.github.io/webcrypto/#rsa-pss-operations +WebIDL::ExceptionOr, GC::Ref>> RSAPSS::generate_key(AlgorithmParams const& params, bool extractable, Vector const& key_usages) +{ + // 1. If usages contains a value which is not one of "sign" or "verify", then throw a SyntaxError. + for (auto const& usage : key_usages) { + if (usage != Bindings::KeyUsage::Sign && usage != Bindings::KeyUsage::Verify) { + return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage)))); + } + } + + // 2. Generate an RSA key pair, as defined in [RFC3447], with RSA modulus length equal to the modulusLength member of normalizedAlgorithm + // and RSA public exponent equal to the publicExponent member of normalizedAlgorithm. + // 3. If performing the operation results in an error, then throw an OperationError. + auto const& normalized_algorithm = static_cast(params); + auto maybe_key_pair = ::Crypto::PK::RSA::generate_key_pair(normalized_algorithm.modulus_length, normalized_algorithm.public_exponent); + if (maybe_key_pair.is_error()) + return WebIDL::OperationError::create(m_realm, "Failed to generate RSA key pair"_string); + + auto key_pair = maybe_key_pair.release_value(); + + // 4. Let algorithm be a new RsaHashedKeyAlgorithm object. + auto algorithm = RsaHashedKeyAlgorithm::create(m_realm); + + // 5. Set the name attribute of algorithm to "RSA-PSS". + algorithm->set_name("RSA-PSS"_string); + + // 6. Set the modulusLength attribute of algorithm to equal the modulusLength member of normalizedAlgorithm. + algorithm->set_modulus_length(normalized_algorithm.modulus_length); + + // 7. Set the publicExponent attribute of algorithm to equal the publicExponent member of normalizedAlgorithm. + TRY(algorithm->set_public_exponent(normalized_algorithm.public_exponent)); + + // 8. Set the hash attribute of algorithm to equal the hash member of normalizedAlgorithm. + algorithm->set_hash(normalized_algorithm.hash); + + // 9. Let publicKey be a new CryptoKey representing the public key of the generated key pair. + auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_pair.public_key }); + + // 10. Set the [[type]] internal slot of publicKey to "public" + public_key->set_type(Bindings::KeyType::Public); + + // 11. Set the [[algorithm]] internal slot of publicKey to algorithm. + public_key->set_algorithm(algorithm); + + // 12. Set the [[extractable]] internal slot of publicKey to true. + public_key->set_extractable(true); + + // 13. Set the [[usages]] internal slot of publicKey to be the usage intersection of usages and [ "verify" ]. + public_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Verify } })); + + // 14. Let privateKey be a new CryptoKey representing the private key of the generated key pair. + auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_pair.private_key }); + + // 15. Set the [[type]] internal slot of privateKey to "private" + private_key->set_type(Bindings::KeyType::Private); + + // 16. Set the [[algorithm]] internal slot of privateKey to algorithm. + private_key->set_algorithm(algorithm); + + // 17. Set the [[extractable]] internal slot of privateKey to extractable. + private_key->set_extractable(extractable); + + // 18. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "sign" ]. + private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Sign } })); + + // 19. Let result be a new CryptoKeyPair dictionary. + // 20. Set the publicKey attribute of result to be publicKey. + // 21. Set the privateKey attribute of result to be privateKey. + // 22. Return result. + return Variant, GC::Ref> { CryptoKeyPair::create(m_realm, public_key, private_key) }; +} + +// https://w3c.github.io/webcrypto/#rsa-pss-operations +WebIDL::ExceptionOr> RSAPSS::sign(AlgorithmParams const& params, GC::Ref key, ByteBuffer const& message) +{ + auto& realm = *m_realm; + auto& vm = realm.vm(); + + // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError. + if (key->type() != Bindings::KeyType::Private) + return WebIDL::InvalidAccessError::create(realm, "Key is not a private key"_string); + + auto const& private_key = key->handle().get<::Crypto::PK::RSAPrivateKey<>>(); + auto pss_params = static_cast(params); + auto hash = TRY(verify_cast(*key->algorithm()).hash().name(vm)); + + // 3. Perform the signature generation operation defined in Section 8.1 of [RFC3447] with the key represented by the [[handle]] internal slot + // of key as the signer's private key, K, and the contents of message as the message to be signed, M, and using the hash function specified + // by the hash attribute of the [[algorithm]] internal slot of key as the Hash option, MGF1 (defined in Section B.2.1 of [RFC3447]) + // as the MGF option and the saltLength member of normalizedAlgorithm as the salt length option for the EMSA-PSS-ENCODE operation. + Optional<::Crypto::Hash::HashKind> hash_kind = {}; + if (hash == "SHA-1") + hash_kind = ::Crypto::Hash::HashKind::SHA1; + else if (hash == "SHA-256") + hash_kind = ::Crypto::Hash::HashKind::SHA256; + else if (hash == "SHA-384") + hash_kind = ::Crypto::Hash::HashKind::SHA384; + else if (hash == "SHA-512") + hash_kind = ::Crypto::Hash::HashKind::SHA512; + + // 4. If performing the operation results in an error, then throw an OperationError. + if (!hash_kind.has_value()) { + auto error_message = MUST(String::formatted("Invalid hash function '{}'", hash)); + return WebIDL::OperationError::create(realm, error_message); + } + + // 5. Let signature be the signature, S, that results from performing the operation. + auto rsa = ::Crypto::PK::RSA_PSS_EMSA { *hash_kind, private_key }; + rsa.set_salt_length(pss_params.salt_length); + + auto maybe_signature = rsa.sign(message); + if (maybe_signature.is_error()) + return WebIDL::OperationError::create(realm, "Failed to sign message"_string); + + // 6. Return signature. + return JS::ArrayBuffer::create(realm, maybe_signature.release_value()); +} + +// https://w3c.github.io/webcrypto/#rsa-pss-operations +WebIDL::ExceptionOr RSAPSS::verify(AlgorithmParams const& params, GC::Ref key, ByteBuffer const& signature, ByteBuffer const& message) +{ + auto& realm = *m_realm; + auto& vm = realm.vm(); + + // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError. + if (key->type() != Bindings::KeyType::Public) + return WebIDL::InvalidAccessError::create(realm, "Key is not a public key"_string); + + auto const& public_key = key->handle().get<::Crypto::PK::RSAPublicKey<>>(); + auto pss_params = static_cast(params); + auto hash = TRY(verify_cast(*key->algorithm()).hash().name(vm)); + + // 2. Perform the signature verification operation defined in Section 8.1 of [RFC3447] with the key represented by the [[handle]] internal slot + // of key as the signer's RSA public key and the contents of message as M and the contents of signature as S and using the hash function specified + // by the hash attribute of the [[algorithm]] internal slot of key as the Hash option, MGF1 (defined in Section B.2.1 of [RFC3447]) + // as the MGF option and the saltLength member of normalizedAlgorithm as the salt length option for the EMSA-PSS-VERIFY operation. + Optional<::Crypto::Hash::HashKind> hash_kind = {}; + if (hash == "SHA-1") + hash_kind = ::Crypto::Hash::HashKind::SHA1; + else if (hash == "SHA-256") + hash_kind = ::Crypto::Hash::HashKind::SHA256; + else if (hash == "SHA-384") + hash_kind = ::Crypto::Hash::HashKind::SHA384; + else if (hash == "SHA-512") + hash_kind = ::Crypto::Hash::HashKind::SHA512; + + if (!hash_kind.has_value()) { + auto error_message = MUST(String::formatted("Invalid hash function '{}'", hash)); + return WebIDL::OperationError::create(realm, error_message); + } + + // 3. Let result be a boolean with the value true if the result of the operation was "valid signature" and the value false otherwise. + auto rsa = ::Crypto::PK::RSA_PSS_EMSA { *hash_kind, public_key }; + rsa.set_salt_length(pss_params.salt_length); + + auto maybe_verification = rsa.verify(message, signature); + if (maybe_verification.is_error()) + return WebIDL::OperationError::create(realm, "Failed to verify message"_string); + + return JS::Value { maybe_verification.release_value() }; +} + +// https://w3c.github.io/webcrypto/#rsa-pss-operations +WebIDL::ExceptionOr> RSAPSS::import_key(AlgorithmParams const& params, Bindings::KeyFormat key_format, CryptoKey::InternalKeyData key_data, bool extractable, Vector const& usages) +{ + auto& realm = *m_realm; + + // 1. Let keyData be the key data to be imported. + + GC::Ptr key = nullptr; + auto const& normalized_algorithm = static_cast(params); + + // 2. -> If format is "spki": + if (key_format == Bindings::KeyFormat::Spki) { + // 1. If usages contains an entry which is not "verify" then throw a SyntaxError. + for (auto const& usage : usages) { + if (usage != Bindings::KeyUsage::Verify) { + return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage)))); + } + } + + VERIFY(key_data.has()); + + // 2. Let spki be the result of running the parse a subjectPublicKeyInfo algorithm over keyData. + // 3. If an error occurred while parsing, then throw a DataError. + auto spki = TRY(parse_a_subject_public_key_info(m_realm, key_data.get())); + + // 4. If the algorithm object identifier field of the algorithm AlgorithmIdentifier field of spki + // is not equal to the rsaEncryption object identifier defined in [RFC3447], then throw a DataError. + if (spki.algorithm.identifier != ::Crypto::ASN1::rsa_encryption_oid) + return WebIDL::DataError::create(m_realm, "Algorithm object identifier is not the rsaEncryption object identifier"_string); + + // 5. Let publicKey be the result of performing the parse an ASN.1 structure algorithm, + // with data as the subjectPublicKeyInfo field of spki, structure as the RSAPublicKey structure + // specified in Section A.1.1 of [RFC3447], and exactData set to true. + // NOTE: We already did this in parse_a_subject_public_key_info + auto& public_key = spki.rsa; + + // 6. If an error occurred while parsing, or it can be determined that publicKey is not + // a valid public key according to [RFC3447], then throw a DataError. + // FIXME: Validate the public key + + // 7. Let key be a new CryptoKey that represents the RSA public key identified by publicKey. + key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key }); + + // 8. Set the [[type]] internal slot of key to "public" + key->set_type(Bindings::KeyType::Public); + } + + // -> If format is "pkcs8": + else if (key_format == Bindings::KeyFormat::Pkcs8) { + // 1. If usages contains an entry which is not "sign" then throw a SyntaxError. + for (auto const& usage : usages) { + if (usage != Bindings::KeyUsage::Sign) { + return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage)))); + } + } + + VERIFY(key_data.has()); + + // 2. Let privateKeyInfo be the result of running the parse a privateKeyInfo algorithm over keyData. + // 3. If an error occurred while parsing, then throw a DataError. + auto private_key_info = TRY(parse_a_private_key_info(m_realm, key_data.get())); + + // 4. If the algorithm object identifier field of the privateKeyAlgorithm PrivateKeyAlgorithm field of privateKeyInfo + // is not equal to the rsaEncryption object identifier defined in [RFC3447], then throw a DataError. + if (private_key_info.algorithm.identifier != ::Crypto::ASN1::rsa_encryption_oid) + return WebIDL::DataError::create(m_realm, "Algorithm object identifier is not the rsaEncryption object identifier"_string); + + // 5. Let rsaPrivateKey be the result of performing the parse an ASN.1 structure algorithm, + // with data as the privateKey field of privateKeyInfo, structure as the RSAPrivateKey structure + // specified in Section A.1.2 of [RFC3447], and exactData set to true. + // NOTE: We already did this in parse_a_private_key_info + auto& rsa_private_key = private_key_info.rsa; + + // 6. If an error occurred while parsing, or if rsaPrivateKey is not + // a valid RSA private key according to [RFC3447], then throw a DataError. + // FIXME: Validate the private key + + // 7. Let key be a new CryptoKey that represents the RSA private key identified by rsaPrivateKey. + key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { rsa_private_key }); + + // 8. Set the [[type]] internal slot of key to "private" + key->set_type(Bindings::KeyType::Private); + } + + // -> If format is "jwk": + else if (key_format == Bindings::KeyFormat::Jwk) { + // 1. -> If keyData is a JsonWebKey dictionary: + // Let jwk equal keyData. + // -> Otherwise: + // Throw a DataError. + if (!key_data.has()) + return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string); + auto& jwk = key_data.get(); + + // 2. If the d field of jwk is present and usages contains an entry which is not "sign", or, + // if the d field of jwk is not present and usages contains an entry which is not "verify" + // then throw a SyntaxError. + if (jwk.d.has_value()) { + for (auto const& usage : usages) { + if (usage != Bindings::KeyUsage::Sign) { + return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", Bindings::idl_enum_to_string(usage)))); + } + } + } else { + for (auto const& usage : usages) { + if (usage != Bindings::KeyUsage::Verify) { + return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", Bindings::idl_enum_to_string(usage)))); + } + } + } + + // 3. If the kty field of jwk is not a case-sensitive string match to "RSA", then throw a DataError. + if (jwk.kty != "RSA"_string) + return WebIDL::DataError::create(m_realm, "Invalid key type"_string); + + // 4. If usages is non-empty and the use field of jwk is present and is not a case-sensitive string match to "sig", then throw a DataError. + if (!usages.is_empty() && jwk.use.has_value() && *jwk.use != "sig"_string) + return WebIDL::DataError::create(m_realm, "Invalid use field"_string); + + // 5. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK] + // or does not contain all of the specified usages values, then throw a DataError. + TRY(validate_jwk_key_ops(realm, jwk, usages)); + + // 6. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError. + if (jwk.ext.has_value() && !*jwk.ext && extractable) + return WebIDL::DataError::create(m_realm, "Invalid ext field"_string); + + Optional hash = {}; + // 7. -> If the alg field of jwk is not present: + if (!jwk.alg.has_value()) { + // Let hash be undefined. + } + // -> If the alg field of jwk is equal to "PS1": + else if (jwk.alg == "PS1"sv) { + // Let hash be the string "SHA-1". + hash = "SHA-1"_string; + } + // -> If the alg field of jwk is equal to "PS256": + else if (jwk.alg == "PS256"sv) { + // Let hash be the string "SHA-256". + hash = "SHA-256"_string; + } + // -> If the alg field of jwk is equal to "PS384": + else if (jwk.alg == "PS384"sv) { + // Let hash be the string "SHA-384". + hash = "SHA-384"_string; + } + // -> If the alg field of jwk is equal to "PS512": + else if (jwk.alg == "PS512"sv) { + // Let hash be the string "SHA-512". + hash = "SHA-512"_string; + } + // -> Otherwise: + else { + // FIXME: Support 'other applicable specifications' + // 1. Perform any key import steps defined by other applicable specifications, passing format, jwk and obtaining hash. + // 2. If an error occurred or there are no applicable specifications, throw a DataError. + return WebIDL::DataError::create(m_realm, "Invalid alg field"_string); + } + + // 8. If hash is not undefined: + if (hash.has_value()) { + // 1. Let normalizedHash be the result of normalize an algorithm with alg set to hash and op set to digest. + auto normalized_hash = TRY(normalize_an_algorithm(m_realm, AlgorithmIdentifier { *hash }, "digest"_string)); + + // 2. If normalizedHash is not equal to the hash member of normalizedAlgorithm, throw a DataError. + if (normalized_hash.parameter->name != TRY(normalized_algorithm.hash.name(realm.vm()))) + return WebIDL::DataError::create(m_realm, "Invalid hash"_string); + } + + // 9. -> If the d field of jwk is present: + if (jwk.d.has_value()) { + // 1. If jwk does not meet the requirements of Section 6.3.2 of JSON Web Algorithms [JWA], then throw a DataError. + bool meets_requirements = jwk.e.has_value() && jwk.n.has_value() && jwk.d.has_value(); + if (jwk.p.has_value() || jwk.q.has_value() || jwk.dp.has_value() || jwk.dq.has_value() || jwk.qi.has_value()) + meets_requirements |= jwk.p.has_value() && jwk.q.has_value() && jwk.dp.has_value() && jwk.dq.has_value() && jwk.qi.has_value(); + + if (jwk.oth.has_value()) { + // FIXME: We don't support > 2 primes in RSA keys + meets_requirements = false; + } + + if (!meets_requirements) + return WebIDL::DataError::create(m_realm, "Invalid JWK private key"_string); + + // FIXME: Spec error, it should say 'the RSA private key identified by interpreting jwk according to section 6.3.2' + // 2. Let privateKey represent the RSA public key identified by interpreting jwk according to Section 6.3.1 of JSON Web Algorithms [JWA]. + auto private_key = TRY(parse_jwk_rsa_private_key(realm, jwk)); + + // FIXME: Spec error, it should say 'not to be a valid RSA private key' + // 3. If privateKey can be determined to not be a valid RSA public key according to [RFC3447], then throw a DataError. + // FIXME: Validate the private key + + // 4. Let key be a new CryptoKey representing privateKey. + key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key }); + + // 5. Set the [[type]] internal slot of key to "private" + key->set_type(Bindings::KeyType::Private); + } + + // -> Otherwise: + else { + // 1. If jwk does not meet the requirements of Section 6.3.1 of JSON Web Algorithms [JWA], then throw a DataError. + if (!jwk.e.has_value() || !jwk.n.has_value()) + return WebIDL::DataError::create(m_realm, "Invalid JWK public key"_string); + + // 2. Let publicKey represent the RSA public key identified by interpreting jwk according to Section 6.3.1 of JSON Web Algorithms [JWA]. + auto public_key = TRY(parse_jwk_rsa_public_key(realm, jwk)); + + // 3. If publicKey can be determined to not be a valid RSA public key according to [RFC3447], then throw a DataError. + // FIXME: Validate the public key + + // 4. Let key be a new CryptoKey representing publicKey. + key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key }); + + // 5. Set the [[type]] internal slot of key to "public" + key->set_type(Bindings::KeyType::Public); + } + } + + // -> Otherwise: throw a NotSupportedError. + else { + return WebIDL::NotSupportedError::create(m_realm, "Unsupported key format"_string); + } + + // 3. Let algorithm be a new RsaHashedKeyAlgorithm. + auto algorithm = RsaHashedKeyAlgorithm::create(m_realm); + + // 4. Set the name attribute of algorithm to "RSA-PSS" + algorithm->set_name("RSA-PSS"_string); + + // 5. Set the modulusLength attribute of algorithm to the length, in bits, of the RSA public modulus. + // 6. Set the publicExponent attribute of algorithm to the BigInteger representation of the RSA public exponent. + TRY(key->handle().visit( + [&](::Crypto::PK::RSAPublicKey<> const& public_key) -> WebIDL::ExceptionOr { + algorithm->set_modulus_length(public_key.modulus().trimmed_byte_length() * 8); + TRY(algorithm->set_public_exponent(public_key.public_exponent())); + return {}; + }, + [&](::Crypto::PK::RSAPrivateKey<> const& private_key) -> WebIDL::ExceptionOr { + algorithm->set_modulus_length(private_key.modulus().trimmed_byte_length() * 8); + TRY(algorithm->set_public_exponent(private_key.public_exponent())); + return {}; + }, + [](auto) -> WebIDL::ExceptionOr { VERIFY_NOT_REACHED(); })); + + // 7. Set the hash attribute of algorithm to the hash member of normalizedAlgorithm. + algorithm->set_hash(normalized_algorithm.hash); + + // 8. Set the [[algorithm]] internal slot of key to algorithm + key->set_algorithm(algorithm); + + // 9. Return key. + return GC::Ref { *key }; +} + +// https://w3c.github.io/webcrypto/#rsa-pss-operations +WebIDL::ExceptionOr> RSAPSS::export_key(Bindings::KeyFormat format, GC::Ref key) +{ + auto& realm = *m_realm; + auto& vm = realm.vm(); + + // 1. Let key be the key to be exported. + + // 2. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError. + // Note: In our impl this is always accessible + auto const& handle = key->handle(); + + GC::Ptr result = nullptr; + + // 3. If format is "spki" + if (format == Bindings::KeyFormat::Spki) { + // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError. + if (key->type() != Bindings::KeyType::Public) + return WebIDL::InvalidAccessError::create(realm, "Key is not public"_string); + + // 2. Let data be an instance of the subjectPublicKeyInfo ASN.1 structure defined in [RFC5280] with the following properties: + // - Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the following properties: + // - Set the algorithm field to the OID rsaEncryption defined in [RFC3447]. + // - Set the params field to the ASN.1 type NULL. + // - Set the subjectPublicKey field to the result of DER-encoding an RSAPublicKey ASN.1 type, as defined in [RFC3447], Appendix A.1.1, + // that represents the RSA public key represented by the [[handle]] internal slot of key + auto maybe_data = handle.visit( + [&](::Crypto::PK::RSAPublicKey<> const& public_key) -> ErrorOr { + return TRY(::Crypto::PK::wrap_in_subject_public_key_info(public_key, ::Crypto::ASN1::rsa_encryption_oid, nullptr)); + }, + [](auto) -> ErrorOr { + VERIFY_NOT_REACHED(); + }); + // FIXME: clang-format butchers the visit if we do the TRY inline + auto data = TRY_OR_THROW_OOM(vm, maybe_data); + + // 3. Let result be the result of creating an ArrayBuffer containing data. + result = JS::ArrayBuffer::create(realm, data); + } + + // If format is "pkcs8" + else if (format == Bindings::KeyFormat::Pkcs8) { + // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError. + if (key->type() != Bindings::KeyType::Private) + return WebIDL::InvalidAccessError::create(realm, "Key is not private"_string); + + // 2. Let data be the result of encoding a privateKeyInfo structure with the following properties: + // - Set the version field to 0. + // - Set the privateKeyAlgorithm field to an PrivateKeyAlgorithmIdentifier ASN.1 type with the following properties: + // - - Set the algorithm field to the OID rsaEncryption defined in [RFC3447]. + // - - Set the params field to the ASN.1 type NULL. + // - Set the privateKey field to the result of DER-encoding an RSAPrivateKey ASN.1 type, as defined in [RFC3447], Appendix A.1.2, + // that represents the RSA private key represented by the [[handle]] internal slot of key + auto maybe_data = handle.visit( + [&](::Crypto::PK::RSAPrivateKey<> const& private_key) -> ErrorOr { + return TRY(::Crypto::PK::wrap_in_private_key_info(private_key, ::Crypto::ASN1::rsa_encryption_oid, nullptr)); + }, + [](auto) -> ErrorOr { + VERIFY_NOT_REACHED(); + }); + + // FIXME: clang-format butchers the visit if we do the TRY inline + auto data = TRY_OR_THROW_OOM(vm, maybe_data); + + // 3. Let result be the result of creating an ArrayBuffer containing data. + result = JS::ArrayBuffer::create(realm, data); + } + + // If format is "jwk" + else if (format == Bindings::KeyFormat::Jwk) { + // 1. Let jwk be a new JsonWebKey dictionary. + Bindings::JsonWebKey jwk = {}; + + // 2. Set the kty attribute of jwk to the string "RSA". + jwk.kty = "RSA"_string; + + // 3. Let hash be the name attribute of the hash attribute of the [[algorithm]] internal slot of key. + auto hash = TRY(verify_cast(*key->algorithm()).hash().name(vm)); + + // 4. If hash is "SHA-1": + // - Set the alg attribute of jwk to the string "PS1". + if (hash == "SHA-1"sv) { + jwk.alg = "PS1"_string; + } + // If hash is "SHA-256": + // - Set the alg attribute of jwk to the string "PS256". + else if (hash == "SHA-256"sv) { + jwk.alg = "PS256"_string; + } + // If hash is "SHA-384": + // - Set the alg attribute of jwk to the string "PS384". + else if (hash == "SHA-384"sv) { + jwk.alg = "PS384"_string; + } + // If hash is "SHA-512": + // - Set the alg attribute of jwk to the string "PS512". + else if (hash == "SHA-512"sv) { + jwk.alg = "PS512"_string; + } else { + // FIXME: Support 'other applicable specifications' + // - Perform any key export steps defined by other applicable specifications, + // passing format and the hash attribute of the [[algorithm]] internal slot of key and obtaining alg. + // - Set the alg attribute of jwk to alg. + return WebIDL::NotSupportedError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("Unsupported hash algorithm '{}'", hash))); + } + + // 5. Set the attributes n and e of jwk according to the corresponding definitions in JSON Web Algorithms [JWA], Section 6.3.1. + auto maybe_error = handle.visit( + [&](::Crypto::PK::RSAPublicKey<> const& public_key) -> ErrorOr { + jwk.n = TRY(base64_url_uint_encode(public_key.modulus())); + jwk.e = TRY(base64_url_uint_encode(public_key.public_exponent())); + return {}; + }, + // 6. If the [[type]] internal slot of key is "private": + [&](::Crypto::PK::RSAPrivateKey<> const& private_key) -> ErrorOr { + jwk.n = TRY(base64_url_uint_encode(private_key.modulus())); + jwk.e = TRY(base64_url_uint_encode(private_key.public_exponent())); + + // 1. Set the attributes named d, p, q, dp, dq, and qi of jwk according to the corresponding definitions + // in JSON Web Algorithms [JWA], Section 6.3.2. + jwk.d = TRY(base64_url_uint_encode(private_key.private_exponent())); + jwk.p = TRY(base64_url_uint_encode(private_key.prime1())); + jwk.q = TRY(base64_url_uint_encode(private_key.prime2())); + jwk.dp = TRY(base64_url_uint_encode(private_key.exponent1())); + jwk.dq = TRY(base64_url_uint_encode(private_key.exponent2())); + jwk.qi = TRY(base64_url_uint_encode(private_key.coefficient())); + + // 2. If the underlying RSA private key represented by the [[handle]] internal slot of key is represented by more than two primes, + // set the attribute named oth of jwk according to the corresponding definition in JSON Web Algorithms [JWA], Section 6.3.2.7 + // FIXME: We don't support more than 2 primes on RSA keys + return {}; + }, + [](auto) -> ErrorOr { + VERIFY_NOT_REACHED(); + }); + // FIXME: clang-format butchers the visit if we do the TRY inline + TRY_OR_THROW_OOM(vm, maybe_error); + + // 7. Set the key_ops attribute of jwk to the usages attribute of key. + jwk.key_ops = Vector {}; + jwk.key_ops->ensure_capacity(key->internal_usages().size()); + for (auto const& usage : key->internal_usages()) { + jwk.key_ops->append(Bindings::idl_enum_to_string(usage)); + } + + // 8. Set the ext attribute of jwk to the [[extractable]] internal slot of key. + jwk.ext = key->extractable(); + + // 9. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL]. + result = TRY(jwk.to_object(realm)); + } + + // Otherwise throw a NotSupportedError. + else { + return WebIDL::NotSupportedError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("Exporting to format {} is not supported", Bindings::idl_enum_to_string(format)))); + } + + // 8. Return result + return GC::Ref { *result }; +} + // https://w3c.github.io/webcrypto/#aes-cbc-operations WebIDL::ExceptionOr> AesCbc::encrypt(AlgorithmParams const& params, GC::Ref key, ByteBuffer const& plaintext) { diff --git a/Libraries/LibWeb/Crypto/CryptoAlgorithms.h b/Libraries/LibWeb/Crypto/CryptoAlgorithms.h index 24dc9eed4f3..797b2fb39d9 100644 --- a/Libraries/LibWeb/Crypto/CryptoAlgorithms.h +++ b/Libraries/LibWeb/Crypto/CryptoAlgorithms.h @@ -195,6 +195,20 @@ struct RsaOaepParams : public AlgorithmParams { static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); }; +// https://w3c.github.io/webcrypto/#dfn-RsaPssParams +struct RsaPssParams : public AlgorithmParams { + virtual ~RsaPssParams() override; + + RsaPssParams(WebIDL::UnsignedLong salt_length) + : salt_length(salt_length) + { + } + + WebIDL::UnsignedLong salt_length; + + static JS::ThrowCompletionOr> from_value(JS::VM&, JS::Value); +}; + // https://w3c.github.io/webcrypto/#dfn-EcdsaParams struct EcdsaParams : public AlgorithmParams { virtual ~EcdsaParams() override; @@ -377,6 +391,25 @@ private: } }; +class RSAPSS : public AlgorithmMethods { +public: + virtual WebIDL::ExceptionOr> sign(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; + virtual WebIDL::ExceptionOr verify(AlgorithmParams const&, GC::Ref, ByteBuffer const&, ByteBuffer const&) override; + + virtual WebIDL::ExceptionOr, GC::Ref>> generate_key(AlgorithmParams const&, bool, Vector const&) override; + + virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) override; + virtual WebIDL::ExceptionOr> export_key(Bindings::KeyFormat, GC::Ref) override; + + static NonnullOwnPtr create(JS::Realm& realm) { return adopt_own(*new RSAPSS(realm)); } + +private: + explicit RSAPSS(JS::Realm& realm) + : AlgorithmMethods(realm) + { + } +}; + class AesCbc : public AlgorithmMethods { public: virtual WebIDL::ExceptionOr> encrypt(AlgorithmParams const&, GC::Ref, ByteBuffer const&) override; diff --git a/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index 112bdafc151..38274b8438f 100644 --- a/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -1079,11 +1079,11 @@ SupportedAlgorithmsMap const& supported_algorithms() // FIXME: define_an_algorithm("exportKey"_string, "RSASSA-PKCS1-v1_5"_string); // https://w3c.github.io/webcrypto/#rsa-pss-registration - // FIXME: define_an_algorithm("sign"_string, "RSA-PSS"_string); - // FIXME: define_an_algorithm("verify"_string, "RSA-PSS"_string); - // FIXME: define_an_algorithm("generateKey"_string, "RSA-PSS"_string); - // FIXME: define_an_algorithm("importKey"_string, "RSA-PSS"_string); - // FIXME: define_an_algorithm("exportKey"_string, "RSA-PSS"_string); + define_an_algorithm("sign"_string, "RSA-PSS"_string); + define_an_algorithm("verify"_string, "RSA-PSS"_string); + define_an_algorithm("generateKey"_string, "RSA-PSS"_string); + define_an_algorithm("importKey"_string, "RSA-PSS"_string); + define_an_algorithm("exportKey"_string, "RSA-PSS"_string); // https://w3c.github.io/webcrypto/#rsa-oaep-registration define_an_algorithm("encrypt"_string, "RSA-OAEP"_string); diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/rsa_importKey.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/rsa_importKey.https.any.txt index 2f73f5c8509..c4b45657b9f 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/rsa_importKey.https.any.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/rsa_importKey.https.any.txt @@ -2,8 +2,8 @@ Harness status: OK Found 1056 tests -480 Pass -576 Fail +528 Pass +528 Fail Pass Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSA-OAEP}, true, [encrypt]) Pass Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-OAEP}, true, [encrypt]) Pass Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSA-OAEP}, true, [wrapKey, encrypt]) @@ -492,10 +492,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSA-PSS} Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-1, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-1, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSA-PSS}, false, []) @@ -504,10 +504,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSA-PSS} Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-1, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-1, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-256, name: RSA-PSS}, true, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, true, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-256, name: RSA-PSS}, true, []) @@ -516,10 +516,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-256, name: RSA-PS Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-256, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-256, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-256, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-256, name: RSA-PSS}, false, []) @@ -528,10 +528,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-256, name: RSA-PS Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-256, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-256, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-384, name: RSA-PSS}, true, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, true, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-384, name: RSA-PSS}, true, []) @@ -540,10 +540,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-384, name: RSA-PS Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-384, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-384, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-384, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-384, name: RSA-PSS}, false, []) @@ -552,10 +552,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-384, name: RSA-PS Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-384, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-384, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-512, name: RSA-PSS}, true, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, true, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-512, name: RSA-PSS}, true, []) @@ -564,10 +564,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-512, name: RSA-PS Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-512, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-512, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, true, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-512, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, false, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-512, name: RSA-PSS}, false, []) @@ -576,10 +576,10 @@ Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-512, name: RSA-PS Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-512, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (pkcs8, buffer(636), {hash: SHA-512, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, false, [sign]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) +Pass Empty Usages: 1024 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-1, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-1, name: RSA-PSS}, true, []) @@ -588,10 +588,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-1, name: RSA-PSS} Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-1, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-1, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-1, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-1, name: RSA-PSS}, false, []) @@ -600,10 +600,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-1, name: RSA-PSS} Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-1, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-1, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-256, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-256, name: RSA-PSS}, true, []) @@ -612,10 +612,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-256, name: RSA-PS Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-256, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-256, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-256, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-256, name: RSA-PSS}, false, []) @@ -624,10 +624,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-256, name: RSA-PS Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-256, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-256, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-384, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-384, name: RSA-PSS}, true, []) @@ -636,10 +636,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-384, name: RSA-PS Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-384, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-384, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-384, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-384, name: RSA-PSS}, false, []) @@ -648,10 +648,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-384, name: RSA-PS Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-384, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-384, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-512, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, true, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-512, name: RSA-PSS}, true, []) @@ -660,10 +660,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-512, name: RSA-PS Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-512, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-512, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, true, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-512, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, false, [verify]) Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-512, name: RSA-PSS}, false, []) @@ -672,10 +672,10 @@ Fail Good parameters: 2048 bits (spki, buffer(294), {hash: SHA-512, name: RSA-PS Fail Good parameters: 2048 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-512, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (pkcs8, buffer(1218), {hash: SHA-512, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, false, [sign]) Fail Good parameters: 2048 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) +Pass Empty Usages: 2048 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-1, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-1, name: RSA-PSS}, true, []) @@ -684,10 +684,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-1, name: RSA-PSS} Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-1, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-1, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-1, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-1, name: RSA-PSS}, false, []) @@ -696,10 +696,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-1, name: RSA-PSS} Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-1, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-1, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-1, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-1, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-256, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-256, name: RSA-PSS}, true, []) @@ -708,10 +708,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-256, name: RSA-PS Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-256, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-256, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-256, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-256, name: RSA-PSS}, false, []) @@ -720,10 +720,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-256, name: RSA-PS Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-256, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-256, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-256, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-256, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-256, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-384, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-384, name: RSA-PSS}, true, []) @@ -732,10 +732,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-384, name: RSA-PS Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-384, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-384, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-384, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-384, name: RSA-PSS}, false, []) @@ -744,10 +744,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-384, name: RSA-PS Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-384, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-384, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-384, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-384, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-384, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-512, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, true, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-512, name: RSA-PSS}, true, []) @@ -756,10 +756,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-512, name: RSA-PS Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, true, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-512, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-512, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, true, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, true, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, true, []) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-512, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, false, [verify]) Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-512, name: RSA-PSS}, false, []) @@ -768,10 +768,10 @@ Fail Good parameters: 4096 bits (spki, buffer(550), {hash: SHA-512, name: RSA-PS Fail Good parameters: 4096 bits (jwk, object(kty, n, e), {hash: SHA-512, name: RSA-PSS}, false, [verify, verify]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-512, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (pkcs8, buffer(2376), {hash: SHA-512, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (pkcs8, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, false, [sign]) Fail Good parameters: 4096 bits (jwk, object(kty, n, e, d, p, q, dp, dq, qi), {hash: SHA-512, name: RSA-PSS}, false, [sign, sign]) -Fail Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) +Pass Empty Usages: 4096 bits (jwk, object(spki, pkcs8, jwk), {hash: SHA-512, name: RSA-PSS}, false, []) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSASSA-PKCS1-v1_5}, true, [verify]) Fail Good parameters: 1024 bits (jwk, object(kty, n, e), {hash: SHA-1, name: RSASSA-PKCS1-v1_5}, true, [verify]) Fail Good parameters: 1024 bits (spki, buffer(162), {hash: SHA-1, name: RSASSA-PKCS1-v1_5}, true, []) diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.txt new file mode 100644 index 00000000000..48b00b3a97f --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.txt @@ -0,0 +1,102 @@ +Harness status: OK + +Found 97 tests + +97 Pass +Pass setup +Pass RSA-PSS with SHA-1 and no salt verification +Pass RSA-PSS with SHA-256 and no salt verification +Pass RSA-PSS with SHA-384 and no salt verification +Pass RSA-PSS with SHA-512 and no salt verification +Pass RSA-PSS with SHA-1, salted verification +Pass RSA-PSS with SHA-256, salted verification +Pass RSA-PSS with SHA-384, salted verification +Pass RSA-PSS with SHA-512, salted verification +Pass RSA-PSS with SHA-1 and no salt verification with altered signature after call +Pass RSA-PSS with SHA-256 and no salt verification with altered signature after call +Pass RSA-PSS with SHA-384 and no salt verification with altered signature after call +Pass RSA-PSS with SHA-512 and no salt verification with altered signature after call +Pass RSA-PSS with SHA-1, salted verification with altered signature after call +Pass RSA-PSS with SHA-256, salted verification with altered signature after call +Pass RSA-PSS with SHA-384, salted verification with altered signature after call +Pass RSA-PSS with SHA-512, salted verification with altered signature after call +Pass RSA-PSS with SHA-1 and no salt with altered plaintext after call +Pass RSA-PSS with SHA-256 and no salt with altered plaintext after call +Pass RSA-PSS with SHA-384 and no salt with altered plaintext after call +Pass RSA-PSS with SHA-512 and no salt with altered plaintext after call +Pass RSA-PSS with SHA-1, salted with altered plaintext after call +Pass RSA-PSS with SHA-256, salted with altered plaintext after call +Pass RSA-PSS with SHA-384, salted with altered plaintext after call +Pass RSA-PSS with SHA-512, salted with altered plaintext after call +Pass RSA-PSS with SHA-1 and no salt using privateKey to verify +Pass RSA-PSS with SHA-256 and no salt using privateKey to verify +Pass RSA-PSS with SHA-384 and no salt using privateKey to verify +Pass RSA-PSS with SHA-512 and no salt using privateKey to verify +Pass RSA-PSS with SHA-1, salted using privateKey to verify +Pass RSA-PSS with SHA-256, salted using privateKey to verify +Pass RSA-PSS with SHA-384, salted using privateKey to verify +Pass RSA-PSS with SHA-512, salted using privateKey to verify +Pass RSA-PSS with SHA-1 and no salt using publicKey to sign +Pass RSA-PSS with SHA-256 and no salt using publicKey to sign +Pass RSA-PSS with SHA-384 and no salt using publicKey to sign +Pass RSA-PSS with SHA-512 and no salt using publicKey to sign +Pass RSA-PSS with SHA-1, salted using publicKey to sign +Pass RSA-PSS with SHA-256, salted using publicKey to sign +Pass RSA-PSS with SHA-384, salted using publicKey to sign +Pass RSA-PSS with SHA-512, salted using publicKey to sign +Pass RSA-PSS with SHA-1 and no salt no verify usage +Pass RSA-PSS with SHA-256 and no salt no verify usage +Pass RSA-PSS with SHA-384 and no salt no verify usage +Pass RSA-PSS with SHA-512 and no salt no verify usage +Pass RSA-PSS with SHA-1, salted no verify usage +Pass RSA-PSS with SHA-256, salted no verify usage +Pass RSA-PSS with SHA-384, salted no verify usage +Pass RSA-PSS with SHA-512, salted no verify usage +Pass RSA-PSS with SHA-1 and no salt round trip +Pass RSA-PSS with SHA-256 and no salt round trip +Pass RSA-PSS with SHA-384 and no salt round trip +Pass RSA-PSS with SHA-512 and no salt round trip +Pass RSA-PSS with SHA-1, salted round trip +Pass RSA-PSS with SHA-256, salted round trip +Pass RSA-PSS with SHA-384, salted round trip +Pass RSA-PSS with SHA-512, salted round trip +Pass RSA-PSS with SHA-1 and no salt signing with wrong algorithm name +Pass RSA-PSS with SHA-256 and no salt signing with wrong algorithm name +Pass RSA-PSS with SHA-384 and no salt signing with wrong algorithm name +Pass RSA-PSS with SHA-512 and no salt signing with wrong algorithm name +Pass RSA-PSS with SHA-1, salted signing with wrong algorithm name +Pass RSA-PSS with SHA-256, salted signing with wrong algorithm name +Pass RSA-PSS with SHA-384, salted signing with wrong algorithm name +Pass RSA-PSS with SHA-512, salted signing with wrong algorithm name +Pass RSA-PSS with SHA-1 and no salt verification with wrong algorithm name +Pass RSA-PSS with SHA-256 and no salt verification with wrong algorithm name +Pass RSA-PSS with SHA-384 and no salt verification with wrong algorithm name +Pass RSA-PSS with SHA-512 and no salt verification with wrong algorithm name +Pass RSA-PSS with SHA-1, salted verification with wrong algorithm name +Pass RSA-PSS with SHA-256, salted verification with wrong algorithm name +Pass RSA-PSS with SHA-384, salted verification with wrong algorithm name +Pass RSA-PSS with SHA-512, salted verification with wrong algorithm name +Pass RSA-PSS with SHA-1 and no salt verification failure with altered signature +Pass RSA-PSS with SHA-256 and no salt verification failure with altered signature +Pass RSA-PSS with SHA-384 and no salt verification failure with altered signature +Pass RSA-PSS with SHA-512 and no salt verification failure with altered signature +Pass RSA-PSS with SHA-1, salted verification failure with altered signature +Pass RSA-PSS with SHA-256, salted verification failure with altered signature +Pass RSA-PSS with SHA-384, salted verification failure with altered signature +Pass RSA-PSS with SHA-512, salted verification failure with altered signature +Pass RSA-PSS with SHA-1 and no salt verification failure with wrong saltLength +Pass RSA-PSS with SHA-256 and no salt verification failure with wrong saltLength +Pass RSA-PSS with SHA-384 and no salt verification failure with wrong saltLength +Pass RSA-PSS with SHA-512 and no salt verification failure with wrong saltLength +Pass RSA-PSS with SHA-1, salted verification failure with wrong saltLength +Pass RSA-PSS with SHA-256, salted verification failure with wrong saltLength +Pass RSA-PSS with SHA-384, salted verification failure with wrong saltLength +Pass RSA-PSS with SHA-512, salted verification failure with wrong saltLength +Pass RSA-PSS with SHA-1 and no salt verification failure with altered plaintext +Pass RSA-PSS with SHA-256 and no salt verification failure with altered plaintext +Pass RSA-PSS with SHA-384 and no salt verification failure with altered plaintext +Pass RSA-PSS with SHA-512 and no salt verification failure with altered plaintext +Pass RSA-PSS with SHA-1, salted verification failure with altered plaintext +Pass RSA-PSS with SHA-256, salted verification failure with altered plaintext +Pass RSA-PSS with SHA-384, salted verification failure with altered plaintext +Pass RSA-PSS with SHA-512, salted verification failure with altered plaintext \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.txt index c9256f6d8ea..fe6b1b3bcd9 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.txt @@ -1,9 +1,12 @@ Harness status: OK -Found 309 tests +Found 333 tests -309 Pass +312 Pass +21 Fail Pass setup +Fail Can wrap and unwrap RSA-PSS public key keys using spki and RSA-OAEP +Fail Can wrap and unwrap RSA-PSS public key keys using jwk and RSA-OAEP Pass Can wrap and unwrap RSA-OAEP public key keys using spki and RSA-OAEP Pass Can wrap and unwrap RSA-OAEP public key keys using jwk and RSA-OAEP Pass Can wrap and unwrap ECDSA public key keys using spki and RSA-OAEP @@ -73,6 +76,13 @@ Pass Can wrap and unwrap HMAC keys as non-extractable using raw and RSA-OAEP Pass Can wrap and unwrap HMAC keys using jwk and RSA-OAEP Pass Can wrap and unwrap HMAC keys as non-extractable using jwk and RSA-OAEP Pass Can unwrap HMAC non-extractable keys using jwk and RSA-OAEP +Fail Can wrap and unwrap RSA-PSS public key keys using spki and AES-CTR +Fail Can wrap and unwrap RSA-PSS public key keys using jwk and AES-CTR +Fail Can wrap and unwrap RSA-PSS private key keys using pkcs8 and AES-CTR +Fail Can wrap and unwrap RSA-PSS private key keys as non-extractable using pkcs8 and AES-CTR +Fail Can wrap and unwrap RSA-PSS private key keys using jwk and AES-CTR +Fail Can wrap and unwrap RSA-PSS private key keys as non-extractable using jwk and AES-CTR +Pass Can unwrap RSA-PSS private key non-extractable keys using jwk and AES-CTR Pass Can wrap and unwrap RSA-OAEP public key keys using spki and AES-CTR Pass Can wrap and unwrap RSA-OAEP public key keys using jwk and AES-CTR Pass Can wrap and unwrap RSA-OAEP private key keys using pkcs8 and AES-CTR @@ -147,6 +157,13 @@ Pass Can wrap and unwrap HMAC keys as non-extractable using raw and AES-CTR Pass Can wrap and unwrap HMAC keys using jwk and AES-CTR Pass Can wrap and unwrap HMAC keys as non-extractable using jwk and AES-CTR Pass Can unwrap HMAC non-extractable keys using jwk and AES-CTR +Fail Can wrap and unwrap RSA-PSS public key keys using spki and AES-CBC +Fail Can wrap and unwrap RSA-PSS public key keys using jwk and AES-CBC +Fail Can wrap and unwrap RSA-PSS private key keys using pkcs8 and AES-CBC +Fail Can wrap and unwrap RSA-PSS private key keys as non-extractable using pkcs8 and AES-CBC +Fail Can wrap and unwrap RSA-PSS private key keys using jwk and AES-CBC +Fail Can wrap and unwrap RSA-PSS private key keys as non-extractable using jwk and AES-CBC +Pass Can unwrap RSA-PSS private key non-extractable keys using jwk and AES-CBC Pass Can wrap and unwrap RSA-OAEP public key keys using spki and AES-CBC Pass Can wrap and unwrap RSA-OAEP public key keys using jwk and AES-CBC Pass Can wrap and unwrap RSA-OAEP private key keys using pkcs8 and AES-CBC @@ -221,6 +238,13 @@ Pass Can wrap and unwrap HMAC keys as non-extractable using raw and AES-CBC Pass Can wrap and unwrap HMAC keys using jwk and AES-CBC Pass Can wrap and unwrap HMAC keys as non-extractable using jwk and AES-CBC Pass Can unwrap HMAC non-extractable keys using jwk and AES-CBC +Fail Can wrap and unwrap RSA-PSS public key keys using spki and AES-GCM +Fail Can wrap and unwrap RSA-PSS public key keys using jwk and AES-GCM +Fail Can wrap and unwrap RSA-PSS private key keys using pkcs8 and AES-GCM +Fail Can wrap and unwrap RSA-PSS private key keys as non-extractable using pkcs8 and AES-GCM +Fail Can wrap and unwrap RSA-PSS private key keys using jwk and AES-GCM +Fail Can wrap and unwrap RSA-PSS private key keys as non-extractable using jwk and AES-GCM +Pass Can unwrap RSA-PSS private key non-extractable keys using jwk and AES-GCM Pass Can wrap and unwrap RSA-OAEP public key keys using spki and AES-GCM Pass Can wrap and unwrap RSA-OAEP public key keys using jwk and AES-GCM Pass Can wrap and unwrap RSA-OAEP private key keys using pkcs8 and AES-GCM @@ -295,6 +319,7 @@ Pass Can wrap and unwrap HMAC keys as non-extractable using raw and AES-GCM Pass Can wrap and unwrap HMAC keys using jwk and AES-GCM Pass Can wrap and unwrap HMAC keys as non-extractable using jwk and AES-GCM Pass Can unwrap HMAC non-extractable keys using jwk and AES-GCM +Fail Can wrap and unwrap RSA-PSS public key keys using jwk and AES-KW Pass Can wrap and unwrap RSA-OAEP public key keys using jwk and AES-KW Pass Can wrap and unwrap Ed25519 private key keys using pkcs8 and AES-KW Pass Can wrap and unwrap Ed25519 private key keys as non-extractable using pkcs8 and AES-KW diff --git a/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa.js b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa.js new file mode 100644 index 00000000000..5abadd3d4b8 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa.js @@ -0,0 +1,438 @@ + +function run_test() { + setup({explicit_done: true}); + + 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) { + promise_test(function(test) { + var operation = subtle.verify(vector.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) { + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + var operation = subtle.verify(vector.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) { + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + var operation = subtle.verify(vector.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) { + promise_test(function(test) { + return subtle.verify(vector.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) { + promise_test(function(test) { + return subtle.sign(vector.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) { + promise_test(function(test) { + return subtle.verify(vector.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) { + // RSA signing is deterministic with PKCS#1 v1.5, or PSS with zero-length salts. + const isDeterministic = !("saltLength" in vector.algorithm) || vector.algorithm.saltLength == 0; + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext) + .then(function(signature) { + if (isDeterministic) { + // If deterministic, we can check the output matches. Otherwise, we can only check it verifies. + assert_true(equalBuffers(signature, vector.signature), "Signing did not give the expected output"); + } + // Can we verify the new signature? + return subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Round trip verifies"); + return signature; + }, function(err) { + assert_unreached("verify error for test " + vector.name + ": " + err.message + "'"); + }); + }) + .then(function(priorSignature) { + // Will a second signing give us different signature? It should for PSS with non-empty salt + return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext) + .then(function(signature) { + if (isDeterministic) { + assert_true(equalBuffers(priorSignature, signature), "Two signings with empty salt give same signature") + } else { + assert_false(equalBuffers(priorSignature, signature), "Two signings with a salt give different signatures") + } + }, 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); + }); + + // [RSA-PSS] Verification should fail with wrong saltLength + testVectors.forEach(function(vector) { + if (vector.algorithm.name === "RSA-PSS") { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + const saltLength = vector.algorithm.saltLength === 32 ? 48 : 32; + var operation = subtle.verify({ ...vector.algorithm, saltLength }, 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 with wrong saltLength"); + + }, 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 wrong saltLength"); + }); + + 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_test(function() { + return Promise.all(all_promises) + .then(function() {done();}) + .catch(function() {done();}) + }, "setup"); + + // 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 RSA-PSS + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.js b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.js new file mode 100644 index 00000000000..f02ba2096b7 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss.https.any.js @@ -0,0 +1,6 @@ +// META: title=WebCryptoAPI: sign() and verify() Using RSA-PSS +// META: script=rsa_pss_vectors.js +// META: script=rsa.js +// META: timeout=long + +run_test(); diff --git a/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss_vectors.js b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss_vectors.js new file mode 100644 index 00000000000..c3ce7796062 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/rsa_pss_vectors.js @@ -0,0 +1,147 @@ + +// rsa_pss_vectors.js + +// Data for testing RSA-PSS with a 2048-bit modulus and 65537 public exponent. + +// The following function returns an array of test vectors +// for the subtleCrypto encrypt method. +// +// Each test vector has the following fields: +// name - a unique name for this vector +// publicKeyBuffer - an arrayBuffer with the key data +// publicKeyFormat - "spki" "jwk" +// publicKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it! +// privateKeyBuffer - an arrayBuffer with the key data +// privateKeyFormat - "pkcs8" or "jwk" +// privateKey - a CryptoKey object for the keyBuffer. INITIALLY null! You must fill this in first to use it! +// algorithm - the value of the AlgorithmIdentifier parameter to provide to encrypt +// plaintext - the text to encrypt +// signature - the expected signature +function getTestVectors() { + var pkcs8 = new Uint8Array([48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1, 2, 130, 1, 1, 0, 139, 55, 92, 203, 135, 200, 37, 197, 255, 61, 83, 208, 9, 145, 110, 150, 65, 5, 126, 24, 82, 114, 39, 160, 122, 178, 38, 190, 16, 136, 129, 58, 59, 56, 187, 123, 72, 243, 119, 5, 81, 101, 250, 42, 147, 57, 210, 77, 198, 103, 213, 197, 186, 52, 39, 230, 164, 129, 23, 110, 172, 21, 255, 212, 144, 104, 49, 30, 28, 40, 59, 159, 58, 142, 12, 184, 9, 180, 99, 12, 80, 170, 143, 62, 69, 166, 11, 53, 158, 25, 191, 140, 187, 94, 202, 214, 78, 118, 31, 16, 149, 116, 63, 243, 106, 175, 92, 240, 236, 185, 127, 237, 173, 221, 166, 11, 91, 243, 93, 129, 26, 117, 184, 34, 35, 12, 250, 160, 25, 47, 173, 64, 84, 126, 39, 84, 72, 170, 51, 22, 191, 142, 43, 76, 224, 133, 79, 199, 112, 139, 83, 123, 162, 45, 19, 33, 11, 9, 174, 195, 122, 39, 89, 239, 192, 130, 161, 83, 27, 35, 169, 23, 48, 3, 125, 222, 78, 242, 107, 95, 150, 239, 220, 195, 159, 211, 76, 52, 90, 213, 28, 187, 228, 79, 229, 139, 138, 59, 78, 201, 151, 134, 108, 8, 109, 255, 27, 136, 49, 239, 10, 31, 234, 38, 60, 247, 218, 205, 3, 192, 76, 188, 194, 178, 121, 229, 127, 165, 185, 83, 153, 107, 251, 29, 214, 136, 23, 175, 127, 180, 44, 222, 247, 165, 41, 74, 87, 250, 194, 184, 173, 115, 159, 27, 2, 153, 2, 129, 129, 0, 251, 248, 51, 194, 198, 49, 201, 112, 36, 12, 142, 116, 133, 240, 106, 62, 162, 168, 72, 34, 81, 26, 134, 39, 221, 70, 78, 248, 175, 175, 113, 72, 209, 164, 37, 182, 184, 101, 125, 221, 82, 70, 131, 43, 142, 83, 48, 32, 197, 187, 181, 104, 133, 90, 106, 236, 62, 66, 33, 215, 147, 241, 220, 91, 47, 37, 132, 226, 65, 94, 72, 233, 162, 189, 41, 43, 19, 64, 49, 249, 156, 142, 180, 47, 192, 188, 208, 68, 155, 242, 44, 230, 222, 201, 112, 20, 239, 229, 172, 147, 235, 232, 53, 135, 118, 86, 37, 44, 187, 177, 108, 65, 91, 103, 177, 132, 210, 40, 69, 104, 162, 119, 213, 147, 53, 88, 92, 253, 2, 129, 129, 0, 214, 184, 206, 39, 199, 41, 93, 93, 22, 252, 53, 112, 237, 100, 200, 218, 147, 3, 250, 210, 148, 136, 193, 166, 94, 154, 215, 17, 249, 3, 112, 24, 125, 187, 253, 129, 49, 109, 105, 100, 139, 200, 140, 197, 200, 53, 81, 175, 255, 69, 222, 186, 207, 182, 17, 5, 247, 9, 228, 195, 8, 9, 185, 0, 49, 235, 214, 134, 36, 68, 150, 198, 246, 158, 105, 46, 189, 200, 20, 246, 66, 57, 244, 173, 21, 117, 110, 203, 120, 197, 165, 176, 153, 49, 219, 24, 48, 119, 197, 70, 163, 140, 76, 116, 56, 137, 173, 61, 62, 208, 121, 181, 98, 46, 208, 18, 15, 160, 225, 249, 59, 89, 61, 183, 216, 82, 224, 95, 2, 129, 128, 56, 135, 75, 157, 131, 247, 129, 120, 206, 45, 158, 252, 23, 92, 131, 137, 127, 214, 127, 48, 107, 191, 166, 159, 100, 238, 52, 35, 104, 206, 212, 124, 128, 195, 241, 206, 23, 122, 117, 141, 100, 186, 251, 12, 151, 134, 164, 66, 133, 250, 1, 205, 236, 53, 7, 205, 238, 125, 201, 183, 226, 178, 29, 60, 187, 204, 16, 14, 238, 153, 103, 132, 59, 5, 115, 41, 253, 204, 166, 41, 152, 237, 15, 17, 179, 140, 232, 176, 171, 199, 222, 57, 1, 124, 113, 207, 208, 174, 87, 84, 108, 85, 145, 68, 205, 208, 175, 208, 100, 95, 126, 168, 255, 7, 185, 116, 209, 237, 68, 253, 31, 142, 0, 245, 96, 191, 109, 69, 2, 129, 129, 0, 133, 41, 239, 144, 115, 207, 143, 123, 95, 249, 226, 26, 186, 223, 58, 65, 115, 211, 144, 6, 112, 223, 175, 89, 66, 106, 188, 223, 4, 147, 193, 61, 47, 29, 27, 70, 184, 36, 166, 172, 24, 148, 179, 217, 37, 37, 12, 24, 30, 52, 114, 193, 96, 120, 5, 110, 177, 154, 141, 40, 247, 31, 48, 128, 146, 117, 52, 129, 212, 148, 68, 253, 247, 140, 158, 166, 194, 68, 7, 220, 1, 142, 119, 211, 175, 239, 56, 91, 47, 247, 67, 158, 150, 35, 121, 65, 51, 45, 212, 70, 206, 190, 255, 219, 68, 4, 254, 79, 113, 89, 81, 97, 208, 22, 64, 44, 51, 77, 15, 87, 198, 26, 190, 79, 249, 244, 203, 249, 2, 129, 129, 0, 135, 216, 119, 8, 212, 103, 99, 228, 204, 190, 178, 209, 233, 113, 46, 91, 240, 33, 109, 112, 222, 148, 32, 165, 178, 6, 155, 116, 89, 185, 159, 93, 159, 127, 47, 173, 124, 215, 154, 174, 230, 122, 127, 154, 52, 67, 126, 60, 121, 168, 74, 240, 205, 141, 233, 223, 242, 104, 235, 12, 71, 147, 245, 1, 249, 136, 213, 64, 246, 211, 71, 92, 32, 121, 184, 34, 122, 35, 217, 104, 222, 196, 227, 198, 101, 3, 24, 113, 147, 69, 150, 48, 71, 43, 253, 182, 186, 29, 231, 134, 199, 151, 250, 111, 78, 166, 90, 42, 132, 25, 38, 47, 41, 103, 136, 86, 203, 115, 201, 189, 75, 200, 155, 94, 4, 27, 34, 119]); + var spki = new Uint8Array([48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 211, 87, 96, 146, 230, 41, 87, 54, 69, 68, 231, 228, 35, 59, 123, 219, 41, 61, 178, 8, 81, 34, 196, 121, 50, 133, 70, 249, 240, 247, 18, 246, 87, 196, 177, 120, 104, 201, 48, 144, 140, 197, 148, 247, 237, 0, 192, 20, 66, 193, 175, 4, 194, 246, 120, 164, 139, 162, 200, 15, 209, 113, 62, 48, 181, 172, 80, 120, 122, 195, 81, 101, 137, 241, 113, 150, 127, 99, 134, 173, 163, 73, 0, 166, 187, 4, 238, 206, 164, 43, 240, 67, 206, 217, 160, 249, 77, 12, 192, 158, 145, 155, 157, 113, 102, 192, 138, 182, 206, 32, 70, 64, 174, 164, 196, 146, 13, 182, 216, 110, 185, 22, 208, 220, 192, 244, 52, 26, 16, 56, 4, 41, 231, 225, 3, 33, 68, 234, 148, 157, 232, 246, 192, 204, 191, 149, 250, 142, 146, 141, 112, 216, 163, 140, 225, 104, 219, 69, 246, 241, 52, 102, 61, 111, 101, 111, 92, 234, 188, 114, 93, 168, 192, 42, 171, 234, 170, 19, 172, 54, 167, 92, 192, 186, 225, 53, 223, 49, 20, 182, 101, 137, 199, 237, 60, 182, 21, 89, 174, 90, 56, 79, 22, 43, 250, 128, 219, 228, 97, 127, 134, 195, 241, 208, 16, 201, 79, 226, 201, 191, 1, 154, 110, 99, 179, 239, 192, 40, 212, 60, 238, 97, 28, 133, 236, 38, 60, 144, 108, 70, 55, 114, 198, 145, 27, 25, 238, 192, 150, 202, 118, 236, 94, 49, 225, 227, 2, 3, 1, 0, 1]); + + // plaintext for RSA-PSS + var plaintext = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]); + + // For verification tests. Note that "salted" signatures use a salt length equal to the hash size + var signatures = { + "sha-1, no salt": new Uint8Array([31, 28, 216, 30, 203, 59, 179, 29, 242, 229, 240, 246, 76, 92, 10, 49, 12, 124, 248, 141, 25, 235, 81, 42, 80, 120, 225, 86, 216, 35, 114, 122, 248, 134, 138, 18, 229, 223, 191, 169, 118, 56, 103, 132, 186, 152, 44, 57, 146, 135, 137, 177, 52, 149, 42, 74, 40, 198, 36, 17, 119, 188, 242, 36, 143, 42, 219, 96, 7, 127, 84, 93, 209, 126, 79, 128, 155, 59, 133, 159, 212, 48, 209, 104, 30, 128, 71, 18, 109, 119, 54, 149, 25, 238, 213, 182, 24, 243, 41, 122, 87, 80, 133, 240, 201, 49, 237, 36, 140, 246, 11, 189, 126, 255, 250, 10, 140, 43, 135, 75, 167, 248, 30, 205, 107, 243, 145, 208, 31, 30, 136, 29, 130, 122, 123, 149, 223, 135, 77, 154, 218, 187, 123, 7, 241, 49, 171, 51, 20, 42, 139, 11, 109, 92, 169, 104, 86, 113, 212, 155, 152, 43, 103, 101, 25, 9, 234, 161, 123, 150, 179, 147, 224, 79, 179, 109, 151, 47, 155, 37, 143, 27, 121, 18, 61, 242, 18, 211, 153, 36, 164, 222, 174, 197, 6, 207, 100, 15, 29, 237, 208, 45, 40, 132, 95, 53, 72, 216, 72, 134, 82, 120, 142, 46, 33, 70, 243, 206, 138, 134, 165, 86, 216, 75, 69, 120, 241, 13, 162, 154, 189, 177, 118, 166, 135, 24, 204, 27, 34, 112, 176, 115, 92, 46, 92, 166, 198, 187, 10, 250, 194, 58, 91, 250, 129, 122]), + "sha-256, no salt": new Uint8Array([97, 87, 214, 104, 237, 101, 93, 151, 139, 76, 21, 140, 132, 25, 235, 128, 113, 141, 253, 252, 125, 75, 52, 53, 127, 153, 23, 233, 225, 22, 182, 243, 182, 80, 64, 201, 209, 97, 85, 192, 129, 214, 136, 122, 188, 179, 186, 79, 250, 1, 145, 228, 128, 126, 226, 6, 104, 26, 161, 212, 128, 158, 162, 13, 229, 24, 107, 119, 227, 202, 206, 208, 127, 201, 179, 215, 27, 157, 240, 172, 129, 181, 195, 39, 63, 243, 247, 79, 50, 167, 173, 52, 198, 80, 98, 163, 21, 64, 206, 211, 5, 39, 239, 164, 183, 170, 45, 39, 255, 127, 128, 83, 95, 62, 101, 206, 53, 46, 185, 225, 139, 80, 84, 65, 109, 233, 89, 53, 74, 77, 204, 203, 37, 66, 227, 58, 131, 88, 237, 166, 32, 168, 101, 61, 214, 69, 143, 86, 171, 148, 254, 225, 220, 1, 239, 66, 251, 137, 88, 170, 19, 72, 16, 228, 216, 254, 29, 212, 254, 238, 106, 240, 71, 66, 248, 13, 165, 121, 56, 117, 167, 138, 42, 76, 192, 141, 78, 10, 104, 171, 3, 241, 192, 34, 160, 232, 167, 211, 9, 96, 137, 146, 210, 78, 205, 215, 232, 241, 137, 94, 62, 92, 211, 110, 73, 144, 107, 83, 25, 50, 217, 255, 149, 134, 24, 177, 165, 15, 152, 69, 95, 81, 94, 12, 99, 16, 61, 46, 78, 22, 81, 175, 197, 102, 235, 156, 173, 30, 126, 250, 225, 169, 117, 12, 56, 128]), + "sha-384, no salt": new Uint8Array([123, 149, 170, 182, 179, 76, 9, 98, 210, 40, 64, 158, 48, 223, 155, 4, 60, 27, 11, 170, 218, 8, 231, 61, 136, 116, 34, 85, 43, 143, 21, 34, 226, 228, 43, 242, 185, 255, 44, 108, 154, 163, 235, 12, 210, 55, 6, 24, 232, 241, 163, 104, 115, 89, 94, 0, 189, 231, 90, 156, 224, 98, 236, 50, 181, 246, 57, 79, 34, 103, 163, 245, 193, 24, 64, 255, 146, 230, 225, 91, 243, 28, 197, 62, 145, 124, 168, 239, 192, 137, 95, 177, 18, 194, 239, 143, 104, 28, 187, 106, 65, 1, 82, 246, 233, 48, 202, 255, 31, 38, 14, 49, 249, 131, 84, 46, 104, 205, 21, 222, 161, 126, 211, 19, 156, 172, 115, 81, 6, 251, 5, 252, 22, 59, 46, 208, 90, 13, 237, 147, 144, 89, 161, 12, 92, 215, 97, 158, 33, 178, 210, 6, 144, 121, 148, 39, 75, 52, 164, 218, 239, 161, 206, 89, 182, 179, 25, 247, 57, 85, 160, 145, 138, 94, 35, 126, 27, 191, 218, 219, 69, 201, 7, 165, 0, 131, 87, 126, 113, 146, 129, 136, 69, 153, 91, 74, 109, 63, 241, 151, 142, 15, 154, 66, 105, 88, 83, 40, 46, 53, 195, 183, 129, 51, 179, 224, 198, 36, 18, 90, 255, 20, 161, 135, 61, 25, 143, 99, 4, 255, 236, 127, 193, 207, 42, 222, 204, 108, 209, 75, 31, 137, 177, 166, 55, 247, 46, 209, 255, 93, 231, 198, 180, 217, 101, 153]), + "sha-512, no salt": new Uint8Array([175, 27, 192, 127, 167, 10, 221, 25, 243, 206, 31, 27, 239, 141, 252, 110, 36, 175, 67, 103, 28, 251, 151, 230, 184, 105, 232, 107, 126, 240, 53, 80, 166, 88, 19, 24, 255, 246, 68, 154, 250, 139, 103, 231, 62, 42, 106, 20, 226, 6, 119, 216, 176, 103, 20, 90, 132, 66, 37, 116, 174, 12, 253, 42, 93, 255, 112, 198, 215, 233, 127, 106, 14, 22, 101, 5, 7, 158, 180, 38, 74, 67, 196, 147, 242, 235, 63, 176, 111, 172, 192, 27, 230, 7, 116, 194, 119, 100, 106, 40, 8, 18, 71, 103, 150, 34, 178, 32, 34, 126, 146, 73, 117, 72, 103, 170, 143, 225, 128, 64, 21, 196, 249, 135, 0, 152, 46, 218, 64, 232, 77, 11, 160, 51, 108, 244, 79, 88, 47, 184, 120, 19, 116, 128, 78, 143, 180, 62, 185, 213, 119, 172, 244, 114, 53, 135, 163, 154, 43, 74, 158, 22, 139, 118, 118, 50, 183, 165, 84, 247, 123, 197, 39, 40, 33, 201, 56, 192, 153, 75, 22, 47, 116, 130, 99, 111, 127, 250, 197, 100, 161, 155, 215, 51, 244, 135, 120, 1, 220, 50, 77, 196, 113, 150, 239, 18, 202, 154, 143, 73, 33, 165, 73, 108, 214, 115, 121, 53, 202, 85, 91, 115, 70, 109, 221, 129, 126, 175, 240, 63, 237, 160, 235, 45, 97, 46, 60, 219, 89, 177, 152, 158, 239, 253, 193, 129, 1, 212, 110, 86, 185, 255, 92, 145, 249, 93]), + "sha-1, salted": new Uint8Array([31, 96, 138, 113, 209, 136, 76, 254, 33, 131, 180, 144, 55, 170, 133, 85, 176, 19, 154, 138, 18, 103, 165, 197, 185, 204, 226, 7, 1, 242, 173, 75, 189, 91, 50, 151, 64, 191, 243, 26, 204, 195, 75, 249, 175, 209, 67, 154, 5, 54, 187, 50, 182, 212, 39, 210, 105, 104, 219, 201, 233, 200, 13, 33, 17, 217, 72, 196, 129, 203, 23, 49, 119, 138, 205, 49, 16, 70, 50, 65, 196, 242, 59, 62, 19, 184, 85, 209, 98, 203, 21, 56, 81, 41, 15, 217, 95, 120, 21, 25, 226, 206, 249, 55, 69, 164, 19, 207, 238, 200, 233, 79, 186, 120, 34, 183, 37, 212, 116, 67, 24, 69, 140, 246, 180, 169, 23, 182, 91, 21, 238, 111, 84, 185, 195, 145, 246, 6, 74, 158, 3, 31, 112, 9, 245, 146, 68, 156, 11, 70, 213, 69, 122, 39, 153, 203, 14, 189, 120, 161, 2, 160, 85, 238, 4, 112, 178, 96, 194, 179, 216, 255, 189, 238, 15, 212, 118, 68, 130, 32, 144, 236, 85, 174, 98, 51, 190, 16, 98, 244, 65, 196, 50, 237, 60, 39, 94, 116, 214, 32, 19, 38, 129, 236, 46, 128, 30, 155, 91, 106, 204, 26, 215, 31, 137, 53, 56, 143, 126, 44, 3, 55, 13, 18, 233, 68, 227, 65, 140, 42, 182, 59, 180, 42, 190, 27, 185, 230, 149, 48, 240, 36, 88, 186, 40, 64, 11, 54, 128, 111, 247, 141, 165, 121, 26, 206]), + "sha-256, salted": new Uint8Array([140, 61, 3, 189, 232, 196, 45, 148, 83, 99, 27, 11, 170, 200, 158, 98, 150, 218, 32, 84, 55, 19, 192, 4, 223, 53, 188, 26, 111, 174, 32, 90, 178, 191, 88, 83, 105, 104, 144, 115, 205, 238, 52, 90, 214, 226, 120, 59, 45, 218, 24, 123, 73, 121, 234, 4, 87, 70, 55, 88, 21, 110, 16, 62, 237, 208, 239, 24, 52, 211, 91, 214, 173, 84, 13, 155, 139, 34, 95, 209, 119, 14, 81, 78, 160, 175, 53, 247, 7, 242, 231, 160, 56, 43, 230, 245, 237, 157, 107, 89, 29, 83, 108, 225, 33, 91, 23, 239, 62, 235, 69, 11, 180, 138, 0, 23, 73, 124, 103, 190, 2, 64, 71, 10, 221, 210, 137, 26, 129, 168, 241, 207, 110, 128, 227, 248, 55, 254, 66, 55, 98, 146, 223, 85, 91, 139, 5, 147, 27, 105, 83, 5, 151, 250, 227, 109, 205, 1, 177, 200, 23, 103, 212, 236, 212, 202, 240, 107, 239, 192, 53, 34, 75, 221, 42, 94, 107, 137, 213, 21, 57, 35, 90, 201, 85, 112, 231, 87, 219, 215, 15, 220, 21, 4, 0, 1, 176, 123, 147, 123, 240, 20, 140, 204, 0, 95, 76, 39, 42, 207, 95, 143, 192, 150, 163, 125, 38, 32, 142, 150, 172, 52, 28, 45, 29, 33, 44, 68, 214, 213, 21, 108, 147, 79, 102, 239, 66, 253, 186, 199, 122, 32, 134, 129, 85, 11, 4, 139, 70, 110, 50, 199, 108, 122, 123, 7]), + "sha-384, salted": new Uint8Array([121, 247, 40, 75, 180, 33, 109, 230, 132, 41, 133, 78, 219, 66, 24, 239, 120, 173, 23, 64, 132, 133, 103, 55, 115, 21, 219, 136, 103, 161, 87, 51, 199, 4, 46, 139, 249, 7, 98, 230, 115, 201, 12, 14, 44, 88, 198, 197, 206, 244, 151, 86, 139, 217, 42, 109, 33, 150, 18, 196, 117, 108, 85, 250, 196, 85, 7, 248, 22, 8, 188, 39, 32, 218, 78, 237, 213, 178, 62, 31, 60, 135, 64, 198, 180, 205, 126, 76, 240, 224, 67, 66, 177, 132, 193, 17, 1, 153, 230, 80, 128, 215, 59, 152, 94, 97, 29, 102, 248, 233, 121, 144, 129, 110, 73, 23, 186, 219, 176, 66, 93, 217, 67, 131, 137, 46, 42, 169, 109, 228, 219, 13, 224, 147, 106, 238, 132, 213, 72, 42, 61, 163, 27, 39, 49, 159, 67, 131, 15, 196, 135, 3, 204, 125, 78, 174, 219, 32, 253, 48, 50, 61, 191, 63, 34, 96, 141, 181, 22, 55, 211, 179, 5, 179, 25, 121, 98, 101, 141, 128, 147, 92, 38, 109, 51, 204, 251, 41, 117, 144, 98, 31, 74, 150, 124, 114, 69, 233, 43, 1, 88, 192, 220, 234, 148, 62, 42, 206, 113, 158, 189, 177, 150, 169, 186, 231, 223, 62, 217, 204, 98, 118, 94, 39, 182, 53, 113, 116, 62, 40, 160, 83, 141, 176, 130, 92, 173, 37, 57, 235, 93, 229, 230, 163, 32, 168, 139, 87, 62, 193, 151, 44, 38, 64, 21, 48]), + "sha-512, salted": new Uint8Array([183, 79, 48, 153, 216, 7, 135, 17, 139, 31, 157, 231, 159, 194, 7, 137, 62, 13, 45, 117, 196, 17, 15, 75, 21, 155, 133, 186, 7, 214, 58, 2, 86, 252, 60, 208, 246, 108, 232, 217, 162, 227, 207, 122, 61, 90, 123, 156, 11, 239, 172, 102, 56, 137, 74, 62, 54, 206, 117, 230, 73, 238, 6, 157, 216, 221, 152, 170, 139, 96, 36, 116, 201, 139, 20, 187, 3, 73, 45, 229, 81, 169, 232, 231, 121, 52, 239, 155, 104, 69, 131, 147, 79, 33, 141, 149, 118, 190, 36, 11, 92, 79, 54, 46, 175, 94, 1, 64, 200, 234, 146, 99, 144, 133, 166, 38, 150, 83, 80, 93, 207, 160, 4, 34, 109, 185, 246, 50, 119, 101, 58, 100, 161, 130, 110, 75, 171, 177, 122, 181, 77, 216, 84, 61, 207, 28, 232, 9, 112, 109, 104, 22, 230, 167, 95, 248, 70, 163, 212, 193, 141, 17, 189, 235, 31, 49, 177, 13, 85, 163, 121, 91, 100, 150, 49, 158, 110, 117, 21, 4, 216, 106, 78, 123, 182, 83, 91, 159, 4, 21, 232, 21, 216, 199, 137, 197, 177, 227, 135, 242, 168, 192, 15, 239, 110, 50, 116, 98, 203, 126, 82, 91, 143, 148, 91, 229, 177, 114, 72, 224, 224, 164, 216, 85, 211, 151, 226, 45, 6, 124, 228, 83, 147, 115, 223, 186, 70, 209, 121, 146, 80, 175, 199, 15, 83, 80, 6, 202, 205, 39, 102, 245, 221, 207, 143, 145]) + }; + + var vectors = [ + { + name: "RSA-PSS with SHA-1 and no salt", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 0}, + hash: "SHA-1", + plaintext: plaintext, + signature: signatures["sha-1, no salt"] + }, + { + name: "RSA-PSS with SHA-256 and no salt", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 0}, + hash: "SHA-256", + plaintext: plaintext, + signature: signatures["sha-256, no salt"] + }, + { + name: "RSA-PSS with SHA-384 and no salt", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 0}, + hash: "SHA-384", + plaintext: plaintext, + signature: signatures["sha-384, no salt"] + }, + { + name: "RSA-PSS with SHA-512 and no salt", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 0}, + hash: "SHA-512", + plaintext: plaintext, + signature: signatures["sha-512, no salt"] + }, + { + name: "RSA-PSS with SHA-1, salted", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 20}, + hash: "SHA-1", + plaintext: plaintext, + signature: signatures["sha-1, salted"] + }, + { + name: "RSA-PSS with SHA-256, salted", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 32}, + hash: "SHA-256", + plaintext: plaintext, + signature: signatures["sha-256, salted"] + }, + { + name: "RSA-PSS with SHA-384, salted", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 48}, + hash: "SHA-384", + plaintext: plaintext, + signature: signatures["sha-384, salted"] + }, + { + name: "RSA-PSS with SHA-512, salted", + publicKeyBuffer: spki, + publicKeyFormat: "spki", + privateKey: null, + privateKeyBuffer: pkcs8, + privateKeyFormat: "pkcs8", + publicKey: null, + algorithm: {name: "RSA-PSS", saltLength: 64}, + hash: "SHA-512", + plaintext: plaintext, + signature: signatures["sha-512, salted"] + } + ]; + + return vectors; +}