diff --git a/Libraries/LibCrypto/Curves/SECPxxxr1.h b/Libraries/LibCrypto/Curves/SECPxxxr1.h index b4fd2110ae6..0d1aa6e9305 100644 --- a/Libraries/LibCrypto/Curves/SECPxxxr1.h +++ b/Libraries/LibCrypto/Curves/SECPxxxr1.h @@ -226,6 +226,13 @@ public: return shared_point; } + ErrorOr verify_point(ReadonlyBytes hash, SECPxxxr1Point pubkey, ReadonlyBytes signature) + { + // FIXME: this is very ugly, but it gets the job done. + auto pubkey_bytes = TRY(pubkey.to_uncompressed()); + return verify(hash, pubkey_bytes, signature); + } + ErrorOr verify(ReadonlyBytes hash, ReadonlyBytes pubkey, ReadonlyBytes signature) { Crypto::ASN1::Decoder asn1_decoder(signature); diff --git a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp index b5b74c613d3..93e64b1c39b 100644 --- a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp +++ b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp @@ -2287,8 +2287,8 @@ WebIDL::ExceptionOr, GC::Ref>> ECDSA:: // NOTE: Spec jumps to 6 here for some reason // 6. If performing the key generation operation results in an error, then throw an OperationError. auto maybe_private_key_data = curve.visit( - [](Empty const&) -> ErrorOr { return Error::from_string_literal("noop error"); }, - [](auto instance) { return instance.generate_private_key(); }); + [](Empty const&) -> ErrorOr<::Crypto::UnsignedBigInteger> { return Error::from_string_literal("noop error"); }, + [](auto instance) { return instance.generate_private_key_scalar(); }); if (maybe_private_key_data.is_error()) return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string); @@ -2296,13 +2296,14 @@ WebIDL::ExceptionOr, GC::Ref>> ECDSA:: auto private_key_data = maybe_private_key_data.release_value(); auto maybe_public_key_data = curve.visit( - [](Empty const&) -> ErrorOr { return Error::from_string_literal("noop error"); }, - [&](auto instance) { return instance.generate_public_key(private_key_data); }); + [](Empty const&) -> ErrorOr<::Crypto::Curves::SECPxxxr1Point> { return Error::from_string_literal("noop error"); }, + [&](auto instance) { return instance.generate_public_key_point(private_key_data); }); if (maybe_public_key_data.is_error()) return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string); auto public_key_data = maybe_public_key_data.release_value(); + auto ec_public_key = ::Crypto::PK::ECPublicKey<> { public_key_data.x, public_key_data.y }; // 7. Let algorithm be a new EcKeyAlgorithm object. auto algorithm = EcKeyAlgorithm::create(m_realm); @@ -2314,7 +2315,7 @@ WebIDL::ExceptionOr, GC::Ref>> ECDSA:: algorithm->set_named_curve(normalized_algorithm.named_curve); // 10. Let publicKey be a new CryptoKey representing the public key of the generated key pair. - auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data }); + auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { ec_public_key }); // 11. Set the [[type]] internal slot of publicKey to "public" public_key->set_type(Bindings::KeyType::Public); @@ -2329,7 +2330,8 @@ WebIDL::ExceptionOr, GC::Ref>> ECDSA:: public_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Verify } })); // 15. Let privateKey be a new CryptoKey representing the private key of the generated key pair. - auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data }); + auto ec_private_key = ::Crypto::PK::ECPrivateKey<> { private_key_data, {}, ec_public_key }; + auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { ec_private_key }); // 16. Set the [[type]] internal slot of privateKey to "private" private_key->set_type(Bindings::KeyType::Private); @@ -2425,7 +2427,7 @@ WebIDL::ExceptionOr ECDSA::verify(AlgorithmParams const& params, GC:: auto M = result_buffer.release_value(); // 4. Let Q be the ECDSA public key associated with key. - auto Q = key->handle().get(); + auto Q = key->handle().get<::Crypto::PK::ECPublicKey<>>(); // FIXME: 5. Let params be the EC domain parameters associated with key. @@ -2468,7 +2470,7 @@ WebIDL::ExceptionOr ECDSA::verify(AlgorithmParams const& params, GC:: auto maybe_result = curve.visit( [](Empty const&) -> ErrorOr { return Error::from_string_literal("Failed to create valid crypto instance"); }, - [&](auto instance) { return instance.verify(M, Q, encoded_signature); }); + [&](auto instance) { return instance.verify_point(M, ::Crypto::Curves::SECPxxxr1Point { Q.x(), Q.y() }, encoded_signature); }); if (maybe_result.is_error()) { auto error_message = MUST(String::from_utf8(maybe_result.error().string_literal())); diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.txt new file mode 100644 index 00000000000..eef80604f91 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.txt @@ -0,0 +1,264 @@ +Summary + +Harness status: OK + +Rerun + +Found 253 tests + +176 Pass +77 Fail +Details +Result Test Name MessagePass setup +Pass ECDSA P-256 with SHA-1 verification +Pass ECDSA P-256 with SHA-256 verification +Fail ECDSA P-256 with SHA-384 verification +Fail ECDSA P-256 with SHA-512 verification +Pass ECDSA P-384 with SHA-1 verification +Pass ECDSA P-384 with SHA-256 verification +Pass ECDSA P-384 with SHA-384 verification +Fail ECDSA P-384 with SHA-512 verification +Fail ECDSA P-521 with SHA-1 verification +Fail ECDSA P-521 with SHA-256 verification +Fail ECDSA P-521 with SHA-384 verification +Fail ECDSA P-521 with SHA-512 verification +Pass ECDSA P-256 with SHA-1 verification with altered signature after call +Pass ECDSA P-256 with SHA-256 verification with altered signature after call +Fail ECDSA P-256 with SHA-384 verification with altered signature after call +Fail ECDSA P-256 with SHA-512 verification with altered signature after call +Pass ECDSA P-384 with SHA-1 verification with altered signature after call +Pass ECDSA P-384 with SHA-256 verification with altered signature after call +Pass ECDSA P-384 with SHA-384 verification with altered signature after call +Fail ECDSA P-384 with SHA-512 verification with altered signature after call +Fail ECDSA P-521 with SHA-1 verification with altered signature after call +Fail ECDSA P-521 with SHA-256 verification with altered signature after call +Fail ECDSA P-521 with SHA-384 verification with altered signature after call +Fail ECDSA P-521 with SHA-512 verification with altered signature after call +Pass ECDSA P-256 with SHA-1 with altered plaintext after call +Pass ECDSA P-256 with SHA-256 with altered plaintext after call +Fail ECDSA P-256 with SHA-384 with altered plaintext after call +Fail ECDSA P-256 with SHA-512 with altered plaintext after call +Pass ECDSA P-384 with SHA-1 with altered plaintext after call +Pass ECDSA P-384 with SHA-256 with altered plaintext after call +Pass ECDSA P-384 with SHA-384 with altered plaintext after call +Fail ECDSA P-384 with SHA-512 with altered plaintext after call +Fail ECDSA P-521 with SHA-1 with altered plaintext after call +Fail ECDSA P-521 with SHA-256 with altered plaintext after call +Fail ECDSA P-521 with SHA-384 with altered plaintext after call +Fail ECDSA P-521 with SHA-512 with altered plaintext after call +Pass ECDSA P-256 with SHA-1 using privateKey to verify +Pass ECDSA P-256 with SHA-256 using privateKey to verify +Pass ECDSA P-256 with SHA-384 using privateKey to verify +Pass ECDSA P-256 with SHA-512 using privateKey to verify +Pass ECDSA P-384 with SHA-1 using privateKey to verify +Pass ECDSA P-384 with SHA-256 using privateKey to verify +Pass ECDSA P-384 with SHA-384 using privateKey to verify +Pass ECDSA P-384 with SHA-512 using privateKey to verify +Pass ECDSA P-521 with SHA-1 using privateKey to verify +Pass ECDSA P-521 with SHA-256 using privateKey to verify +Pass ECDSA P-521 with SHA-384 using privateKey to verify +Pass ECDSA P-521 with SHA-512 using privateKey to verify +Pass ECDSA P-256 with SHA-1 using publicKey to sign +Pass ECDSA P-256 with SHA-256 using publicKey to sign +Pass ECDSA P-256 with SHA-384 using publicKey to sign +Pass ECDSA P-256 with SHA-512 using publicKey to sign +Pass ECDSA P-384 with SHA-1 using publicKey to sign +Pass ECDSA P-384 with SHA-256 using publicKey to sign +Pass ECDSA P-384 with SHA-384 using publicKey to sign +Pass ECDSA P-384 with SHA-512 using publicKey to sign +Pass ECDSA P-521 with SHA-1 using publicKey to sign +Pass ECDSA P-521 with SHA-256 using publicKey to sign +Pass ECDSA P-521 with SHA-384 using publicKey to sign +Pass ECDSA P-521 with SHA-512 using publicKey to sign +Pass ECDSA P-256 with SHA-1 no verify usage +Pass ECDSA P-256 with SHA-256 no verify usage +Pass ECDSA P-256 with SHA-384 no verify usage +Pass ECDSA P-256 with SHA-512 no verify usage +Pass ECDSA P-384 with SHA-1 no verify usage +Pass ECDSA P-384 with SHA-256 no verify usage +Pass ECDSA P-384 with SHA-384 no verify usage +Pass ECDSA P-384 with SHA-512 no verify usage +Pass ECDSA P-521 with SHA-1 no verify usage +Pass ECDSA P-521 with SHA-256 no verify usage +Pass ECDSA P-521 with SHA-384 no verify usage +Pass ECDSA P-521 with SHA-512 no verify usage +Fail ECDSA P-256 with SHA-1 round trip +Fail ECDSA P-256 with SHA-256 round trip +Fail ECDSA P-256 with SHA-384 round trip +Fail ECDSA P-256 with SHA-512 round trip +Fail ECDSA P-384 with SHA-1 round trip +Fail ECDSA P-384 with SHA-256 round trip +Fail ECDSA P-384 with SHA-384 round trip +Fail ECDSA P-384 with SHA-512 round trip +Fail ECDSA P-521 with SHA-1 round trip +Fail ECDSA P-521 with SHA-256 round trip +Fail ECDSA P-521 with SHA-384 round trip +Fail ECDSA P-521 with SHA-512 round trip +Pass ECDSA P-256 with SHA-1 signing with wrong algorithm name +Pass ECDSA P-256 with SHA-256 signing with wrong algorithm name +Pass ECDSA P-256 with SHA-384 signing with wrong algorithm name +Pass ECDSA P-256 with SHA-512 signing with wrong algorithm name +Pass ECDSA P-384 with SHA-1 signing with wrong algorithm name +Pass ECDSA P-384 with SHA-256 signing with wrong algorithm name +Pass ECDSA P-384 with SHA-384 signing with wrong algorithm name +Pass ECDSA P-384 with SHA-512 signing with wrong algorithm name +Pass ECDSA P-521 with SHA-1 signing with wrong algorithm name +Pass ECDSA P-521 with SHA-256 signing with wrong algorithm name +Pass ECDSA P-521 with SHA-384 signing with wrong algorithm name +Pass ECDSA P-521 with SHA-512 signing with wrong algorithm name +Pass ECDSA P-256 with SHA-1 verifying with wrong algorithm name +Pass ECDSA P-256 with SHA-256 verifying with wrong algorithm name +Pass ECDSA P-256 with SHA-384 verifying with wrong algorithm name +Pass ECDSA P-256 with SHA-512 verifying with wrong algorithm name +Pass ECDSA P-384 with SHA-1 verifying with wrong algorithm name +Pass ECDSA P-384 with SHA-256 verifying with wrong algorithm name +Pass ECDSA P-384 with SHA-384 verifying with wrong algorithm name +Pass ECDSA P-384 with SHA-512 verifying with wrong algorithm name +Pass ECDSA P-521 with SHA-1 verifying with wrong algorithm name +Pass ECDSA P-521 with SHA-256 verifying with wrong algorithm name +Pass ECDSA P-521 with SHA-384 verifying with wrong algorithm name +Pass ECDSA P-521 with SHA-512 verifying with wrong algorithm name +Pass ECDSA P-256 with SHA-1 verification failure due to altered signature +Pass ECDSA P-256 with SHA-256 verification failure due to altered signature +Pass ECDSA P-256 with SHA-384 verification failure due to altered signature +Pass ECDSA P-256 with SHA-512 verification failure due to altered signature +Pass ECDSA P-384 with SHA-1 verification failure due to altered signature +Pass ECDSA P-384 with SHA-256 verification failure due to altered signature +Pass ECDSA P-384 with SHA-384 verification failure due to altered signature +Pass ECDSA P-384 with SHA-512 verification failure due to altered signature +Fail ECDSA P-521 with SHA-1 verification failure due to altered signature +Fail ECDSA P-521 with SHA-256 verification failure due to altered signature +Fail ECDSA P-521 with SHA-384 verification failure due to altered signature +Fail ECDSA P-521 with SHA-512 verification failure due to altered signature +Pass ECDSA P-256 with SHA-1 verification failure due to wrong hash +Pass ECDSA P-256 with SHA-256 verification failure due to wrong hash +Pass ECDSA P-256 with SHA-384 verification failure due to wrong hash +Pass ECDSA P-256 with SHA-512 verification failure due to wrong hash +Pass ECDSA P-384 with SHA-1 verification failure due to wrong hash +Pass ECDSA P-384 with SHA-256 verification failure due to wrong hash +Pass ECDSA P-384 with SHA-384 verification failure due to wrong hash +Pass ECDSA P-384 with SHA-512 verification failure due to wrong hash +Fail ECDSA P-521 with SHA-1 verification failure due to wrong hash +Fail ECDSA P-521 with SHA-256 verification failure due to wrong hash +Fail ECDSA P-521 with SHA-384 verification failure due to wrong hash +Fail ECDSA P-521 with SHA-512 verification failure due to wrong hash +Pass ECDSA P-256 with SHA-1 verification failure due to bad hash name +Pass ECDSA P-256 with SHA-256 verification failure due to bad hash name +Pass ECDSA P-256 with SHA-384 verification failure due to bad hash name +Pass ECDSA P-256 with SHA-512 verification failure due to bad hash name +Pass ECDSA P-384 with SHA-1 verification failure due to bad hash name +Pass ECDSA P-384 with SHA-256 verification failure due to bad hash name +Pass ECDSA P-384 with SHA-384 verification failure due to bad hash name +Pass ECDSA P-384 with SHA-512 verification failure due to bad hash name +Pass ECDSA P-521 with SHA-1 verification failure due to bad hash name +Pass ECDSA P-521 with SHA-256 verification failure due to bad hash name +Pass ECDSA P-521 with SHA-384 verification failure due to bad hash name +Pass ECDSA P-521 with SHA-512 verification failure due to bad hash name +Pass ECDSA P-256 with SHA-1 verification failure due to shortened signature +Pass ECDSA P-256 with SHA-256 verification failure due to shortened signature +Pass ECDSA P-256 with SHA-384 verification failure due to shortened signature +Pass ECDSA P-256 with SHA-512 verification failure due to shortened signature +Pass ECDSA P-384 with SHA-1 verification failure due to shortened signature +Pass ECDSA P-384 with SHA-256 verification failure due to shortened signature +Pass ECDSA P-384 with SHA-384 verification failure due to shortened signature +Pass ECDSA P-384 with SHA-512 verification failure due to shortened signature +Fail ECDSA P-521 with SHA-1 verification failure due to shortened signature +Fail ECDSA P-521 with SHA-256 verification failure due to shortened signature +Fail ECDSA P-521 with SHA-384 verification failure due to shortened signature +Fail ECDSA P-521 with SHA-512 verification failure due to shortened signature +Pass ECDSA P-256 with SHA-1 verification failure due to altered plaintext +Pass ECDSA P-256 with SHA-256 verification failure due to altered plaintext +Pass ECDSA P-256 with SHA-384 verification failure due to altered plaintext +Pass ECDSA P-256 with SHA-512 verification failure due to altered plaintext +Pass ECDSA P-384 with SHA-1 verification failure due to altered plaintext +Pass ECDSA P-384 with SHA-256 verification failure due to altered plaintext +Pass ECDSA P-384 with SHA-384 verification failure due to altered plaintext +Pass ECDSA P-384 with SHA-512 verification failure due to altered plaintext +Fail ECDSA P-521 with SHA-1 verification failure due to altered plaintext +Fail ECDSA P-521 with SHA-256 verification failure due to altered plaintext +Fail ECDSA P-521 with SHA-384 verification failure due to altered plaintext +Fail ECDSA P-521 with SHA-512 verification failure due to altered plaintext +Pass ECDSA P-256 with SHA-1 - The signature was truncated by 1 byte verification +Pass ECDSA P-256 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-256 verification +Pass ECDSA P-256 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-384 verification +Pass ECDSA P-256 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-512 verification +Pass ECDSA P-256 with SHA-1 - Signature has excess padding verification +Pass ECDSA P-256 with SHA-1 - The signature is empty verification +Pass ECDSA P-256 with SHA-1 - The signature is all zeroes verification +Pass ECDSA P-256 with SHA-256 - The signature was truncated by 1 byte verification +Pass ECDSA P-256 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-1 verification +Pass ECDSA P-256 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-384 verification +Pass ECDSA P-256 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-512 verification +Pass ECDSA P-256 with SHA-256 - Signature has excess padding verification +Pass ECDSA P-256 with SHA-256 - The signature is empty verification +Pass ECDSA P-256 with SHA-256 - The signature is all zeroes verification +Pass ECDSA P-256 with SHA-384 - The signature was truncated by 1 byte verification +Pass ECDSA P-256 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-1 verification +Pass ECDSA P-256 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-256 verification +Pass ECDSA P-256 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-512 verification +Pass ECDSA P-256 with SHA-384 - Signature has excess padding verification +Pass ECDSA P-256 with SHA-384 - The signature is empty verification +Pass ECDSA P-256 with SHA-384 - The signature is all zeroes verification +Pass ECDSA P-256 with SHA-512 - The signature was truncated by 1 byte verification +Pass ECDSA P-256 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-1 verification +Pass ECDSA P-256 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-256 verification +Pass ECDSA P-256 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-384 verification +Pass ECDSA P-256 with SHA-512 - Signature has excess padding verification +Pass ECDSA P-256 with SHA-512 - The signature is empty verification +Pass ECDSA P-256 with SHA-512 - The signature is all zeroes verification +Pass ECDSA P-384 with SHA-1 - The signature was truncated by 1 byte verification +Pass ECDSA P-384 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-256 verification +Pass ECDSA P-384 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-384 verification +Pass ECDSA P-384 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-512 verification +Pass ECDSA P-384 with SHA-1 - Signature has excess padding verification +Pass ECDSA P-384 with SHA-1 - The signature is empty verification +Pass ECDSA P-384 with SHA-1 - The signature is all zeroes verification +Pass ECDSA P-384 with SHA-256 - The signature was truncated by 1 byte verification +Pass ECDSA P-384 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-1 verification +Pass ECDSA P-384 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-384 verification +Pass ECDSA P-384 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-512 verification +Pass ECDSA P-384 with SHA-256 - Signature has excess padding verification +Pass ECDSA P-384 with SHA-256 - The signature is empty verification +Pass ECDSA P-384 with SHA-256 - The signature is all zeroes verification +Pass ECDSA P-384 with SHA-384 - The signature was truncated by 1 byte verification +Pass ECDSA P-384 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-1 verification +Pass ECDSA P-384 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-256 verification +Pass ECDSA P-384 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-512 verification +Pass ECDSA P-384 with SHA-384 - Signature has excess padding verification +Pass ECDSA P-384 with SHA-384 - The signature is empty verification +Pass ECDSA P-384 with SHA-384 - The signature is all zeroes verification +Pass ECDSA P-384 with SHA-512 - The signature was truncated by 1 byte verification +Pass ECDSA P-384 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-1 verification +Pass ECDSA P-384 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-256 verification +Pass ECDSA P-384 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-384 verification +Pass ECDSA P-384 with SHA-512 - Signature has excess padding verification +Pass ECDSA P-384 with SHA-512 - The signature is empty verification +Pass ECDSA P-384 with SHA-512 - The signature is all zeroes verification +Fail ECDSA P-521 with SHA-1 - The signature was truncated by 1 byte verification +Fail ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-256 verification +Fail ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-384 verification +Fail ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-512 verification +Fail ECDSA P-521 with SHA-1 - Signature has excess padding verification +Fail ECDSA P-521 with SHA-1 - The signature is empty verification +Fail ECDSA P-521 with SHA-1 - The signature is all zeroes verification +Fail ECDSA P-521 with SHA-256 - The signature was truncated by 1 byte verification +Fail ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-1 verification +Fail ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-384 verification +Fail ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-512 verification +Fail ECDSA P-521 with SHA-256 - Signature has excess padding verification +Fail ECDSA P-521 with SHA-256 - The signature is empty verification +Fail ECDSA P-521 with SHA-256 - The signature is all zeroes verification +Fail ECDSA P-521 with SHA-384 - The signature was truncated by 1 byte verification +Fail ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-1 verification +Fail ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-256 verification +Fail ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-512 verification +Fail ECDSA P-521 with SHA-384 - Signature has excess padding verification +Fail ECDSA P-521 with SHA-384 - The signature is empty verification +Fail ECDSA P-521 with SHA-384 - The signature is all zeroes verification +Fail ECDSA P-521 with SHA-512 - The signature was truncated by 1 byte verification +Fail ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-1 verification +Fail ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-256 verification +Fail ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-384 verification +Fail ECDSA P-521 with SHA-512 - Signature has excess padding verification +Fail ECDSA P-521 with SHA-512 - The signature is empty verification +Fail ECDSA P-521 with SHA-512 - The signature is all zeroes verification \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.html b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.html new file mode 100644 index 00000000000..da6000ccc3c --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.html @@ -0,0 +1,17 @@ + + +WebCryptoAPI: sign() and verify() Using ECDSA + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.js b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.js new file mode 100644 index 00000000000..9764cc33540 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.https.any.js @@ -0,0 +1,6 @@ +// META: title=WebCryptoAPI: sign() and verify() Using ECDSA +// META: script=ecdsa_vectors.js +// META: script=ecdsa.js +// META: timeout=long + +run_test(); diff --git a/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.js b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.js new file mode 100644 index 00000000000..6bf662adcc5 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/sign_verify/ecdsa.js @@ -0,0 +1,509 @@ + +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(); + var invalidTestVectors = getInvalidTestVectors(); + + // Test verification first, because signing tests rely on that working + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification"); + }); + + all_promises.push(promise); + }); + + // Test verification with an altered buffer after call + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var signature = copyBuffer(vector.signature); + var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + signature[0] = 255 - signature[0]; + return operation; + }, vector.name + " verification with altered signature after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification with altered signature after call"); + }); + + all_promises.push(promise); + }); + + // Check for successful verification even if plaintext is altered after call. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var plaintext = copyBuffer(vector.plaintext); + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Signature verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + plaintext[0] = 255 - plaintext[0]; + return operation; + }, vector.name + " with altered plaintext after call"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " with altered plaintext after call"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to using privateKey to verify. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.verify(algorithm, vector.privateKey, vector.signature, vector.plaintext) + .then(function(plaintext) { + assert_unreached("Should have thrown error for using privateKey to verify in " + vector.name + ": " + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " using privateKey to verify"); + + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " using privateKey to verify"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to using publicKey to sign. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.sign(algorithm, vector.publicKey, vector.plaintext) + .then(function(signature) { + assert_unreached("Should have thrown error for using publicKey to sign in " + vector.name + ": " + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " using publicKey to sign"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " using publicKey to sign"); + }); + + all_promises.push(promise); + }); + + // Check for failures due to no "verify" usage. + testVectors.forEach(function(originalVector) { + var vector = Object.assign({}, originalVector); + + var promise = importVectorKeys(vector, [], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(plaintext) { + assert_unreached("Should have thrown error for no verify usage in " + vector.name + ": " + err.message + "'"); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should throw InvalidAccessError instead of '" + err.message + "'"); + }); + }, vector.name + " no verify usage"); + }, function(err) { + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " no verify usage"); + }); + + all_promises.push(promise); + }); + + // Check for successful signing and verification. + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + return subtle.sign(algorithm, vector.privateKey, vector.plaintext) + .then(function(signature) { + // Can we verify the signature? + return subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_true(is_verified, "Round trip verification works"); + return signature; + }, function(err) { + assert_unreached("verify error for test " + vector.name + ": " + err.message + "'"); + }); + }, function(err) { + assert_unreached("sign error for test " + vector.name + ": '" + err.message + "'"); + }); + }, vector.name + " round trip"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested signing or verifying + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " round trip"); + }); + + all_promises.push(promise); + }); + + // Test signing with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) + .then(function(wrongKey) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + return importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + promise_test(function(test) { + var operation = subtle.sign(algorithm, wrongKey, vector.plaintext) + .then(function(signature) { + assert_unreached("Signing should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " signing with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " signing with wrong algorithm name"); + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + }, "generate wrong key step: " + vector.name + " signing with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Test verification with the wrong algorithm + testVectors.forEach(function(vector) { + // Want to get the key for the wrong algorithm + var promise = subtle.generateKey({name: "HMAC", hash: "SHA-1"}, false, ["sign", "verify"]) + .then(function(wrongKey) { + return importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, wrongKey, vector.signature, vector.plaintext) + .then(function(signature) { + assert_unreached("Verifying should not have succeeded for " + vector.name); + }, function(err) { + assert_equals(err.name, "InvalidAccessError", "Should have thrown InvalidAccessError instead of '" + err.message + "'"); + }); + + return operation; + }, vector.name + " verifying with wrong algorithm name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verifying with wrong algorithm name"); + }); + }, function(err) { + promise_test(function(test) { + assert_unreached("Generate wrong key for test " + vector.name + " failed: '" + err.message + "'"); + }, "generate wrong key step: " + vector.name + " verifying with wrong algorithm name"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with wrong signature + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + var signature = copyBuffer(vector.signature); + signature[0] = 255 - signature[0]; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to altered signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to altered signature"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with wrong hash + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var hashName = "SHA-1"; + if (vector.hashName === "SHA-1") { + hashName = "SHA-256" + } + var algorithm = {name: vector.algorithmName, hash: hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to wrong hash"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to wrong hash"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with bad hash name + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + // use the wrong name for the hash + var hashName = vector.hashName.substring(0, 3) + vector.hashName.substring(4); + var algorithm = {name: vector.algorithmName, hash: hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_unreached("Verification should throw an error"); + }, function(err) { + assert_equals(err.name, "NotSupportedError", "Correctly throws NotSupportedError for illegal hash name") + }); + + return operation; + }, vector.name + " verification failure due to bad hash name"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to bad hash name"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with short (odd length) signature + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + var signature = vector.signature.slice(1); // Skip the first byte + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to shortened signature"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to shortened signature"); + }); + + all_promises.push(promise); + }); + + // Test verification fails with wrong plaintext + testVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + var plaintext = copyBuffer(vector.plaintext); + plaintext[0] = 255 - plaintext[0]; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature NOT verified"); + }, function(err) { + assert_unreached("Verification should not throw error " + vector.name + ": " + err.message + "'"); + }); + + return operation; + }, vector.name + " verification failure due to altered plaintext"); + + }, function(err) { + // We need a failed test if the importVectorKey operation fails, so + // we know we never tested verification. + promise_test(function(test) { + assert_unreached("importVectorKeys failed for " + vector.name + ". Message: ''" + err.message + "''"); + }, "importVectorKeys step: " + vector.name + " verification failure due to altered plaintext"); + }); + + all_promises.push(promise); + }); + + // Test invalid signatures + invalidTestVectors.forEach(function(vector) { + var promise = importVectorKeys(vector, ["verify"], ["sign"]) + .then(function(vectors) { + var algorithm = {name: vector.algorithmName, hash: vector.hashName}; + promise_test(function(test) { + var operation = subtle.verify(algorithm, vector.publicKey, vector.signature, vector.plaintext) + .then(function(is_verified) { + assert_false(is_verified, "Signature unexpectedly 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); + }); + + 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.algorithmName, namedCurve: vector.namedCurve}, false, publicKeyUsages) + .then(function(key) { + vector.publicKey = key; + return vector; + }); // Returns a copy of the sourceBuffer it is sent. + } + + if (vector.privateKey !== null) { + privatePromise = new Promise(function(resolve, reject) { + resolve(vector); + }); + } else { + privatePromise = subtle.importKey(vector.privateKeyFormat, vector.privateKeyBuffer, {name: vector.algorithmName, namedCurve: vector.namedCurve}, false, privateKeyUsages) + .then(function(key) { + vector.privateKey = key; + return vector; + }); + } + + return Promise.all([publicPromise, privatePromise]); + } + + // Returns a copy of the sourceBuffer it is sent. + function copyBuffer(sourceBuffer) { + var source = new Uint8Array(sourceBuffer); + var copy = new Uint8Array(sourceBuffer.byteLength) + + for (var i=0; i