| // Copyright 2025 The BoringSSL Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include <stdio.h> | |
| #include <vector> | |
| #include <gtest/gtest.h> | |
| #include <openssl/crypto.h> | |
| #include <openssl/ec.h> | |
| #include <openssl/ec_key.h> | |
| #include <openssl/ecdsa.h> | |
| #include <openssl/err.h> | |
| #include <openssl/evp.h> | |
| #include <openssl/rand.h> | |
| #include "../test/file_test.h" | |
| #include "../test/test_util.h" | |
| #include "../test/wycheproof_util.h" | |
| static void RunWycheproofTest(const char *path) { | |
| SCOPED_TRACE(path); | |
| FileTestGTest(path, [](FileTest *t) { | |
| t->IgnoreAllUnusedInstructions(); | |
| const EC_GROUP *group = GetWycheproofCurve(t, "publicKey.curve", true); | |
| ASSERT_TRUE(group); | |
| std::vector<uint8_t> uncompressed; | |
| ASSERT_TRUE( | |
| t->GetInstructionBytes(&uncompressed, "publicKey.uncompressed")); | |
| bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); | |
| ASSERT_TRUE(key); | |
| ASSERT_TRUE(EC_KEY_set_group(key.get(), group)); | |
| ASSERT_TRUE(EC_KEY_oct2key(key.get(), uncompressed.data(), | |
| uncompressed.size(), nullptr)); | |
| const EVP_MD *md = GetWycheproofDigest(t, "sha", true); | |
| ASSERT_TRUE(md); | |
| std::vector<uint8_t> msg; | |
| ASSERT_TRUE(t->GetBytes(&msg, "msg")); | |
| std::vector<uint8_t> sig; | |
| ASSERT_TRUE(t->GetBytes(&sig, "sig")); | |
| WycheproofResult result; | |
| ASSERT_TRUE(GetWycheproofResult(t, &result)); | |
| uint8_t digest[EVP_MAX_MD_SIZE]; | |
| unsigned int digest_len; | |
| ASSERT_TRUE( | |
| EVP_Digest(msg.data(), msg.size(), digest, &digest_len, md, nullptr)); | |
| int ret = ECDSA_verify_p1363(digest, digest_len, sig.data(), sig.size(), | |
| key.get()); | |
| EXPECT_EQ(ret, result.IsValid() ? 1 : 0); | |
| if (!result.IsValid()) { | |
| ERR_clear_error(); | |
| } | |
| }); | |
| } | |
| TEST(ECDSAP1363Test, WycheproofP224) { | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp224r1_sha224_p1363_test.txt"); | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp224r1_sha256_p1363_test.txt"); | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp224r1_sha512_p1363_test.txt"); | |
| } | |
| TEST(ECDSAP1363Test, WycheproofP256) { | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp256r1_sha256_p1363_test.txt"); | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp256r1_sha512_p1363_test.txt"); | |
| } | |
| TEST(ECDSAP1363Test, WycheproofP384) { | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp384r1_sha384_p1363_test.txt"); | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp384r1_sha512_p1363_test.txt"); | |
| } | |
| TEST(ECDSAP1363Test, WycheproofP521) { | |
| RunWycheproofTest( | |
| "third_party/wycheproof_testvectors/" | |
| "ecdsa_secp521r1_sha512_p1363_test.txt"); | |
| } | |
| static void RunSignTest(const EC_GROUP *group) { | |
| // Fill digest values with some random data. | |
| uint8_t digest[20]; | |
| ASSERT_TRUE(RAND_bytes(digest, sizeof(digest))); | |
| bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); | |
| ASSERT_TRUE(key); | |
| ASSERT_TRUE(EC_KEY_set_group(key.get(), group)); | |
| ASSERT_TRUE(EC_KEY_generate_key(key.get())); | |
| size_t sig_len = ECDSA_size_p1363(key.get()); | |
| ASSERT_GT(sig_len, 0u); | |
| std::vector<uint8_t> sig(sig_len); | |
| size_t out_sig_len; | |
| ASSERT_TRUE(ECDSA_sign_p1363(digest, sizeof(digest), sig.data(), &out_sig_len, | |
| sig.size(), key.get())); | |
| ASSERT_EQ(out_sig_len, sig_len); | |
| ASSERT_TRUE(ECDSA_verify_p1363(digest, sizeof(digest), sig.data(), sig.size(), | |
| key.get())); | |
| } | |
| TEST(ECDSAP1363Test, SignP224) { RunSignTest(EC_group_p224()); } | |
| TEST(ECDSAP1363Test, SignP256) { RunSignTest(EC_group_p256()); } | |
| TEST(ECDSAP1363Test, SignP384) { RunSignTest(EC_group_p384()); } | |
| TEST(ECDSAP1363Test, SignP521) { RunSignTest(EC_group_p521()); } | |
| TEST(ECDSAP1363Test, SignFailsWithSmallBuffer) { | |
| // Fill digest values with some random data. | |
| uint8_t digest[20]; | |
| ASSERT_TRUE(RAND_bytes(digest, sizeof(digest))); | |
| bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); | |
| ASSERT_TRUE(key); | |
| ASSERT_TRUE(EC_KEY_set_group(key.get(), EC_group_p256())); | |
| ASSERT_TRUE(EC_KEY_generate_key(key.get())); | |
| size_t sig_len = ECDSA_size_p1363(key.get()); | |
| ASSERT_GT(sig_len, 0u); | |
| std::vector<uint8_t> sig(sig_len - 1); | |
| size_t out_sig_len; | |
| ASSERT_FALSE(ECDSA_sign_p1363(digest, sizeof(digest), sig.data(), | |
| &out_sig_len, sig.size(), key.get())); | |
| } | |
| TEST(ECDSAP1363Test, SignSucceedsWithLargeBuffer) { | |
| // Fill digest values with some random data. | |
| uint8_t digest[20]; | |
| ASSERT_TRUE(RAND_bytes(digest, sizeof(digest))); | |
| bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); | |
| ASSERT_TRUE(key); | |
| ASSERT_TRUE(EC_KEY_set_group(key.get(), EC_group_p256())); | |
| ASSERT_TRUE(EC_KEY_generate_key(key.get())); | |
| size_t sig_len = ECDSA_size_p1363(key.get()); | |
| ASSERT_GT(sig_len, 0u); | |
| std::vector<uint8_t> sig(sig_len + 1, 'x'); | |
| size_t out_sig_len; | |
| ASSERT_TRUE(ECDSA_sign_p1363(digest, sizeof(digest), sig.data(), &out_sig_len, | |
| sig.size(), key.get())); | |
| ASSERT_EQ(out_sig_len, sig_len); | |
| // The extra byte should be untouched. | |
| EXPECT_EQ(sig.back(), 'x'); | |
| ASSERT_TRUE(ECDSA_verify_p1363(digest, sizeof(digest), sig.data(), | |
| out_sig_len, key.get())); | |
| } | |
| TEST(ECDSAP1363Test, SizeWithoutGroup) { | |
| EXPECT_EQ(ECDSA_size_p1363(nullptr), 0u); | |
| bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); | |
| EXPECT_EQ(ECDSA_size_p1363(key.get()), 0u); | |
| } |