1 /* ==================================================================== 2 * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * 3. All advertising materials mentioning features or use of this 17 * software must display the following acknowledgment: 18 * "This product includes software developed by the OpenSSL Project 19 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 20 * 21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 22 * endorse or promote products derived from this software without 23 * prior written permission. For written permission, please contact 24 * openssl-core (at) OpenSSL.org. 25 * 26 * 5. Products derived from this software may not be called "OpenSSL" 27 * nor may "OpenSSL" appear in their names without prior written 28 * permission of the OpenSSL Project. 29 * 30 * 6. Redistributions of any form whatsoever must retain the following 31 * acknowledgment: 32 * "This product includes software developed by the OpenSSL Project 33 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 34 * 35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46 * OF THE POSSIBILITY OF SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This product includes cryptographic software written by Eric Young 50 * (eay (at) cryptsoft.com). This product includes software written by Tim 51 * Hudson (tjh (at) cryptsoft.com). */ 52 53 #include <openssl/ecdsa.h> 54 55 #include <vector> 56 57 #include <gtest/gtest.h> 58 59 #include <openssl/bn.h> 60 #include <openssl/crypto.h> 61 #include <openssl/ec.h> 62 #include <openssl/err.h> 63 #include <openssl/mem.h> 64 #include <openssl/nid.h> 65 #include <openssl/rand.h> 66 67 #include "../../test/file_test.h" 68 69 70 enum Api { 71 kEncodedApi, 72 kRawApi, 73 }; 74 75 // VerifyECDSASig checks that verifying |ecdsa_sig| gives |expected_result|. 76 static void VerifyECDSASig(Api api, const uint8_t *digest, size_t digest_len, 77 const ECDSA_SIG *ecdsa_sig, EC_KEY *eckey, 78 int expected_result) { 79 switch (api) { 80 case kEncodedApi: { 81 uint8_t *der; 82 size_t der_len; 83 ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig)); 84 bssl::UniquePtr<uint8_t> delete_der(der); 85 EXPECT_EQ(expected_result, 86 ECDSA_verify(0, digest, digest_len, der, der_len, eckey)); 87 break; 88 } 89 90 case kRawApi: 91 EXPECT_EQ(expected_result, 92 ECDSA_do_verify(digest, digest_len, ecdsa_sig, eckey)); 93 break; 94 95 default: 96 FAIL() << "Unknown API type."; 97 } 98 } 99 100 // TestTamperedSig verifies that signature verification fails when a valid 101 // signature is tampered with. |ecdsa_sig| must be a valid signature, which will 102 // be modified. 103 static void TestTamperedSig(Api api, const uint8_t *digest, 104 size_t digest_len, ECDSA_SIG *ecdsa_sig, 105 EC_KEY *eckey, const BIGNUM *order) { 106 SCOPED_TRACE(api); 107 // Modify a single byte of the signature: to ensure we don't 108 // garble the ASN1 structure, we read the raw signature and 109 // modify a byte in one of the bignums directly. 110 111 // Store the two BIGNUMs in raw_buf. 112 size_t r_len = BN_num_bytes(ecdsa_sig->r); 113 size_t s_len = BN_num_bytes(ecdsa_sig->s); 114 size_t bn_len = BN_num_bytes(order); 115 ASSERT_LE(r_len, bn_len); 116 ASSERT_LE(s_len, bn_len); 117 size_t buf_len = 2 * bn_len; 118 std::vector<uint8_t> raw_buf(buf_len); 119 // Pad the bignums with leading zeroes. 120 ASSERT_TRUE(BN_bn2bin_padded(raw_buf.data(), bn_len, ecdsa_sig->r)); 121 ASSERT_TRUE(BN_bn2bin_padded(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)); 122 123 // Modify a single byte in the buffer. 124 size_t offset = raw_buf[10] % buf_len; 125 uint8_t dirt = raw_buf[11] ? raw_buf[11] : 1; 126 raw_buf[offset] ^= dirt; 127 // Now read the BIGNUMs back in from raw_buf. 128 ASSERT_TRUE(BN_bin2bn(raw_buf.data(), bn_len, ecdsa_sig->r)); 129 ASSERT_TRUE(BN_bin2bn(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)); 130 VerifyECDSASig(api, digest, digest_len, ecdsa_sig, eckey, 0); 131 132 // Sanity check: Undo the modification and verify signature. 133 raw_buf[offset] ^= dirt; 134 ASSERT_TRUE(BN_bin2bn(raw_buf.data(), bn_len, ecdsa_sig->r)); 135 ASSERT_TRUE(BN_bin2bn(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)); 136 VerifyECDSASig(api, digest, digest_len, ecdsa_sig, eckey, 1); 137 } 138 139 TEST(ECDSATest, BuiltinCurves) { 140 // Fill digest values with some random data. 141 uint8_t digest[20], wrong_digest[20]; 142 ASSERT_TRUE(RAND_bytes(digest, 20)); 143 ASSERT_TRUE(RAND_bytes(wrong_digest, 20)); 144 145 static const struct { 146 int nid; 147 const char *name; 148 } kCurves[] = { 149 { NID_secp224r1, "secp224r1" }, 150 { NID_X9_62_prime256v1, "secp256r1" }, 151 { NID_secp384r1, "secp384r1" }, 152 { NID_secp521r1, "secp521r1" }, 153 }; 154 155 for (const auto &curve : kCurves) { 156 SCOPED_TRACE(curve.name); 157 158 int nid = curve.nid; 159 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid)); 160 ASSERT_TRUE(group); 161 const BIGNUM *order = EC_GROUP_get0_order(group.get()); 162 163 // Create a new ECDSA key. 164 bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new()); 165 ASSERT_TRUE(eckey); 166 ASSERT_TRUE(EC_KEY_set_group(eckey.get(), group.get())); 167 ASSERT_TRUE(EC_KEY_generate_key(eckey.get())); 168 169 // Create a second key. 170 bssl::UniquePtr<EC_KEY> wrong_eckey(EC_KEY_new()); 171 ASSERT_TRUE(wrong_eckey); 172 ASSERT_TRUE(EC_KEY_set_group(wrong_eckey.get(), group.get())); 173 ASSERT_TRUE(EC_KEY_generate_key(wrong_eckey.get())); 174 175 // Check the key. 176 EXPECT_TRUE(EC_KEY_check_key(eckey.get())); 177 178 // Test ASN.1-encoded signatures. 179 // Create a signature. 180 unsigned sig_len = ECDSA_size(eckey.get()); 181 std::vector<uint8_t> signature(sig_len); 182 ASSERT_TRUE( 183 ECDSA_sign(0, digest, 20, signature.data(), &sig_len, eckey.get())); 184 signature.resize(sig_len); 185 186 // Verify the signature. 187 EXPECT_TRUE(ECDSA_verify(0, digest, 20, signature.data(), signature.size(), 188 eckey.get())); 189 190 // Verify the signature with the wrong key. 191 EXPECT_FALSE(ECDSA_verify(0, digest, 20, signature.data(), signature.size(), 192 wrong_eckey.get())); 193 ERR_clear_error(); 194 195 // Verify the signature using the wrong digest. 196 EXPECT_FALSE(ECDSA_verify(0, wrong_digest, 20, signature.data(), 197 signature.size(), eckey.get())); 198 ERR_clear_error(); 199 200 // Verify a truncated signature. 201 EXPECT_FALSE(ECDSA_verify(0, digest, 20, signature.data(), 202 signature.size() - 1, eckey.get())); 203 ERR_clear_error(); 204 205 // Verify a tampered signature. 206 bssl::UniquePtr<ECDSA_SIG> ecdsa_sig( 207 ECDSA_SIG_from_bytes(signature.data(), signature.size())); 208 ASSERT_TRUE(ecdsa_sig); 209 TestTamperedSig(kEncodedApi, digest, 20, ecdsa_sig.get(), eckey.get(), 210 order); 211 212 // Test ECDSA_SIG signing and verification. 213 // Create a signature. 214 ecdsa_sig.reset(ECDSA_do_sign(digest, 20, eckey.get())); 215 ASSERT_TRUE(ecdsa_sig); 216 217 // Verify the signature using the correct key. 218 EXPECT_TRUE(ECDSA_do_verify(digest, 20, ecdsa_sig.get(), eckey.get())); 219 220 // Verify the signature with the wrong key. 221 EXPECT_FALSE( 222 ECDSA_do_verify(digest, 20, ecdsa_sig.get(), wrong_eckey.get())); 223 ERR_clear_error(); 224 225 // Verify the signature using the wrong digest. 226 EXPECT_FALSE( 227 ECDSA_do_verify(wrong_digest, 20, ecdsa_sig.get(), eckey.get())); 228 ERR_clear_error(); 229 230 // Verify a tampered signature. 231 TestTamperedSig(kRawApi, digest, 20, ecdsa_sig.get(), eckey.get(), order); 232 } 233 } 234 235 static size_t BitsToBytes(size_t bits) { 236 return (bits / 8) + (7 + (bits % 8)) / 8; 237 } 238 239 TEST(ECDSATest, MaxSigLen) { 240 static const size_t kBits[] = {224, 256, 384, 521, 10000}; 241 for (size_t bits : kBits) { 242 SCOPED_TRACE(bits); 243 size_t order_len = BitsToBytes(bits); 244 245 /* Create the largest possible |ECDSA_SIG| of the given constraints. */ 246 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); 247 ASSERT_TRUE(sig); 248 std::vector<uint8_t> bytes(order_len, 0xff); 249 ASSERT_TRUE(BN_bin2bn(bytes.data(), bytes.size(), sig->r)); 250 ASSERT_TRUE(BN_bin2bn(bytes.data(), bytes.size(), sig->s)); 251 /* Serialize it. */ 252 uint8_t *der; 253 size_t der_len; 254 ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, sig.get())); 255 OPENSSL_free(der); 256 257 EXPECT_EQ(der_len, ECDSA_SIG_max_len(order_len)); 258 } 259 } 260 261 static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) { 262 std::string curve_name; 263 if (!t->GetAttribute(&curve_name, key)) { 264 return nullptr; 265 } 266 267 if (curve_name == "P-224") { 268 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1)); 269 } 270 if (curve_name == "P-256") { 271 return bssl::UniquePtr<EC_GROUP>( 272 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); 273 } 274 if (curve_name == "P-384") { 275 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1)); 276 } 277 if (curve_name == "P-521") { 278 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1)); 279 } 280 281 ADD_FAILURE() << "Unknown curve: " << curve_name; 282 return nullptr; 283 } 284 285 static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) { 286 std::vector<uint8_t> bytes; 287 if (!t->GetBytes(&bytes, key)) { 288 return nullptr; 289 } 290 291 return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr)); 292 } 293 294 TEST(ECDSATest, VerifyTestVectors) { 295 FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt", 296 [](FileTest *t) { 297 bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve"); 298 ASSERT_TRUE(group); 299 bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X"); 300 ASSERT_TRUE(x); 301 bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y"); 302 ASSERT_TRUE(y); 303 bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R"); 304 ASSERT_TRUE(r); 305 bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S"); 306 ASSERT_TRUE(s); 307 std::vector<uint8_t> digest; 308 ASSERT_TRUE(t->GetBytes(&digest, "Digest")); 309 310 bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); 311 ASSERT_TRUE(key); 312 bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get())); 313 ASSERT_TRUE(pub_key); 314 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); 315 ASSERT_TRUE(sig); 316 ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get())); 317 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(), 318 x.get(), y.get(), nullptr)); 319 ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get())); 320 ASSERT_TRUE(BN_copy(sig->r, r.get())); 321 ASSERT_TRUE(BN_copy(sig->s, s.get())); 322 323 EXPECT_EQ( 324 t->HasAttribute("Invalid") ? 0 : 1, 325 ECDSA_do_verify(digest.data(), digest.size(), sig.get(), key.get())); 326 }); 327 } 328 329 TEST(ECDSATest, SignTestVectors) { 330 FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt", 331 [](FileTest *t) { 332 bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve"); 333 ASSERT_TRUE(group); 334 bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private"); 335 ASSERT_TRUE(priv_key); 336 bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X"); 337 ASSERT_TRUE(x); 338 bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y"); 339 ASSERT_TRUE(y); 340 bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K"); 341 ASSERT_TRUE(k); 342 bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R"); 343 ASSERT_TRUE(r); 344 bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S"); 345 ASSERT_TRUE(s); 346 std::vector<uint8_t> digest; 347 ASSERT_TRUE(t->GetBytes(&digest, "Digest")); 348 349 bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); 350 ASSERT_TRUE(key); 351 bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get())); 352 ASSERT_TRUE(pub_key); 353 ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get())); 354 ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get())); 355 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(), 356 x.get(), y.get(), nullptr)); 357 ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get())); 358 ASSERT_TRUE(EC_KEY_check_key(key.get())); 359 360 // |ECDSA_do_sign_ex| expects |k| to already be inverted. 361 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new()); 362 ASSERT_TRUE(ctx); 363 ASSERT_TRUE(BN_mod_inverse(k.get(), k.get(), 364 EC_GROUP_get0_order(group.get()), ctx.get())); 365 366 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_do_sign_ex( 367 digest.data(), digest.size(), k.get(), r.get(), key.get())); 368 ASSERT_TRUE(sig); 369 370 EXPECT_EQ(0, BN_cmp(r.get(), sig->r)); 371 EXPECT_EQ(0, BN_cmp(s.get(), sig->s)); 372 }); 373 } 374