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 "../ec/internal.h" 68 #include "../../test/file_test.h" 69 70 71 static bssl::UniquePtr<BIGNUM> HexToBIGNUM(const char *hex) { 72 BIGNUM *bn = nullptr; 73 BN_hex2bn(&bn, hex); 74 return bssl::UniquePtr<BIGNUM>(bn); 75 } 76 77 // Though we do not support secp160r1, it is reachable from the deprecated 78 // custom curve APIs and has some unique properties (n is larger than p with the 79 // difference crossing a word boundary on 32-bit), so test it explicitly. 80 static bssl::UniquePtr<EC_GROUP> NewSecp160r1Group() { 81 static const char kP[] = "ffffffffffffffffffffffffffffffff7fffffff"; 82 static const char kA[] = "ffffffffffffffffffffffffffffffff7ffffffc"; 83 static const char kB[] = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45"; 84 static const char kX[] = "4a96b5688ef573284664698968c38bb913cbfc82"; 85 static const char kY[] = "23a628553168947d59dcc912042351377ac5fb32"; 86 static const char kN[] = "0100000000000000000001f4c8f927aed3ca752257"; 87 88 bssl::UniquePtr<BIGNUM> p = HexToBIGNUM(kP), a = HexToBIGNUM(kA), 89 b = HexToBIGNUM(kB), x = HexToBIGNUM(kX), 90 y = HexToBIGNUM(kY), n = HexToBIGNUM(kN); 91 if (!p || !a || !b || !x || !y || !n) { 92 return nullptr; 93 } 94 95 bssl::UniquePtr<EC_GROUP> group( 96 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), nullptr)); 97 if (!group) { 98 return nullptr; 99 } 100 bssl::UniquePtr<EC_POINT> g(EC_POINT_new(group.get())); 101 if (!g || 102 !EC_POINT_set_affine_coordinates_GFp(group.get(), g.get(), x.get(), 103 y.get(), nullptr) || 104 !EC_GROUP_set_generator(group.get(), g.get(), n.get(), BN_value_one())) { 105 return nullptr; 106 } 107 return group; 108 } 109 110 enum API { 111 kEncodedAPI, 112 kRawAPI, 113 }; 114 115 // VerifyECDSASig checks that verifying |ecdsa_sig| gives |expected_result|. 116 static void VerifyECDSASig(API api, const uint8_t *digest, size_t digest_len, 117 const ECDSA_SIG *ecdsa_sig, EC_KEY *eckey, 118 int expected_result) { 119 switch (api) { 120 case kEncodedAPI: { 121 uint8_t *der; 122 size_t der_len; 123 ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig)); 124 bssl::UniquePtr<uint8_t> delete_der(der); 125 EXPECT_EQ(expected_result, 126 ECDSA_verify(0, digest, digest_len, der, der_len, eckey)); 127 break; 128 } 129 130 case kRawAPI: 131 EXPECT_EQ(expected_result, 132 ECDSA_do_verify(digest, digest_len, ecdsa_sig, eckey)); 133 break; 134 135 default: 136 FAIL() << "Unknown API type."; 137 } 138 } 139 140 // TestTamperedSig verifies that signature verification fails when a valid 141 // signature is tampered with. |ecdsa_sig| must be a valid signature, which will 142 // be modified. 143 static void TestTamperedSig(API api, const uint8_t *digest, 144 size_t digest_len, ECDSA_SIG *ecdsa_sig, 145 EC_KEY *eckey, const BIGNUM *order) { 146 SCOPED_TRACE(api); 147 // Modify a single byte of the signature: to ensure we don't 148 // garble the ASN1 structure, we read the raw signature and 149 // modify a byte in one of the bignums directly. 150 151 // Store the two BIGNUMs in raw_buf. 152 size_t r_len = BN_num_bytes(ecdsa_sig->r); 153 size_t s_len = BN_num_bytes(ecdsa_sig->s); 154 size_t bn_len = BN_num_bytes(order); 155 ASSERT_LE(r_len, bn_len); 156 ASSERT_LE(s_len, bn_len); 157 size_t buf_len = 2 * bn_len; 158 std::vector<uint8_t> raw_buf(buf_len); 159 // Pad the bignums with leading zeroes. 160 ASSERT_TRUE(BN_bn2bin_padded(raw_buf.data(), bn_len, ecdsa_sig->r)); 161 ASSERT_TRUE(BN_bn2bin_padded(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)); 162 163 // Modify a single byte in the buffer. 164 size_t offset = raw_buf[10] % buf_len; 165 uint8_t dirt = raw_buf[11] ? raw_buf[11] : 1; 166 raw_buf[offset] ^= dirt; 167 // Now read the BIGNUMs back in from raw_buf. 168 ASSERT_TRUE(BN_bin2bn(raw_buf.data(), bn_len, ecdsa_sig->r)); 169 ASSERT_TRUE(BN_bin2bn(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)); 170 VerifyECDSASig(api, digest, digest_len, ecdsa_sig, eckey, 0); 171 172 // Sanity check: Undo the modification and verify signature. 173 raw_buf[offset] ^= dirt; 174 ASSERT_TRUE(BN_bin2bn(raw_buf.data(), bn_len, ecdsa_sig->r)); 175 ASSERT_TRUE(BN_bin2bn(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)); 176 VerifyECDSASig(api, digest, digest_len, ecdsa_sig, eckey, 1); 177 } 178 179 TEST(ECDSATest, BuiltinCurves) { 180 // Fill digest values with some random data. 181 uint8_t digest[20], wrong_digest[20]; 182 ASSERT_TRUE(RAND_bytes(digest, 20)); 183 ASSERT_TRUE(RAND_bytes(wrong_digest, 20)); 184 185 static const struct { 186 int nid; 187 const char *name; 188 } kCurves[] = { 189 { NID_secp224r1, "secp224r1" }, 190 { NID_X9_62_prime256v1, "secp256r1" }, 191 { NID_secp384r1, "secp384r1" }, 192 { NID_secp521r1, "secp521r1" }, 193 { NID_secp160r1, "secp160r1" }, 194 }; 195 196 for (const auto &curve : kCurves) { 197 SCOPED_TRACE(curve.name); 198 199 bssl::UniquePtr<EC_GROUP> group; 200 if (curve.nid == NID_secp160r1) { 201 group = NewSecp160r1Group(); 202 } else { 203 group.reset(EC_GROUP_new_by_curve_name(curve.nid)); 204 } 205 ASSERT_TRUE(group); 206 const BIGNUM *order = EC_GROUP_get0_order(group.get()); 207 208 // Create a new ECDSA key. 209 bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new()); 210 ASSERT_TRUE(eckey); 211 ASSERT_TRUE(EC_KEY_set_group(eckey.get(), group.get())); 212 ASSERT_TRUE(EC_KEY_generate_key(eckey.get())); 213 214 // Create a second key. 215 bssl::UniquePtr<EC_KEY> wrong_eckey(EC_KEY_new()); 216 ASSERT_TRUE(wrong_eckey); 217 ASSERT_TRUE(EC_KEY_set_group(wrong_eckey.get(), group.get())); 218 ASSERT_TRUE(EC_KEY_generate_key(wrong_eckey.get())); 219 220 // Check the key. 221 EXPECT_TRUE(EC_KEY_check_key(eckey.get())); 222 223 // Test ASN.1-encoded signatures. 224 // Create a signature. 225 unsigned sig_len = ECDSA_size(eckey.get()); 226 std::vector<uint8_t> signature(sig_len); 227 ASSERT_TRUE( 228 ECDSA_sign(0, digest, 20, signature.data(), &sig_len, eckey.get())); 229 signature.resize(sig_len); 230 231 // Verify the signature. 232 EXPECT_TRUE(ECDSA_verify(0, digest, 20, signature.data(), signature.size(), 233 eckey.get())); 234 235 // Verify the signature with the wrong key. 236 EXPECT_FALSE(ECDSA_verify(0, digest, 20, signature.data(), signature.size(), 237 wrong_eckey.get())); 238 ERR_clear_error(); 239 240 // Verify the signature using the wrong digest. 241 EXPECT_FALSE(ECDSA_verify(0, wrong_digest, 20, signature.data(), 242 signature.size(), eckey.get())); 243 ERR_clear_error(); 244 245 // Verify a truncated signature. 246 EXPECT_FALSE(ECDSA_verify(0, digest, 20, signature.data(), 247 signature.size() - 1, eckey.get())); 248 ERR_clear_error(); 249 250 // Verify a tampered signature. 251 bssl::UniquePtr<ECDSA_SIG> ecdsa_sig( 252 ECDSA_SIG_from_bytes(signature.data(), signature.size())); 253 ASSERT_TRUE(ecdsa_sig); 254 TestTamperedSig(kEncodedAPI, digest, 20, ecdsa_sig.get(), eckey.get(), 255 order); 256 257 // Test ECDSA_SIG signing and verification. 258 // Create a signature. 259 ecdsa_sig.reset(ECDSA_do_sign(digest, 20, eckey.get())); 260 ASSERT_TRUE(ecdsa_sig); 261 262 // Verify the signature using the correct key. 263 EXPECT_TRUE(ECDSA_do_verify(digest, 20, ecdsa_sig.get(), eckey.get())); 264 265 // Verify the signature with the wrong key. 266 EXPECT_FALSE( 267 ECDSA_do_verify(digest, 20, ecdsa_sig.get(), wrong_eckey.get())); 268 ERR_clear_error(); 269 270 // Verify the signature using the wrong digest. 271 EXPECT_FALSE( 272 ECDSA_do_verify(wrong_digest, 20, ecdsa_sig.get(), eckey.get())); 273 ERR_clear_error(); 274 275 // Verify a tampered signature. 276 TestTamperedSig(kRawAPI, digest, 20, ecdsa_sig.get(), eckey.get(), order); 277 } 278 } 279 280 static size_t BitsToBytes(size_t bits) { 281 return (bits / 8) + (7 + (bits % 8)) / 8; 282 } 283 284 TEST(ECDSATest, MaxSigLen) { 285 static const size_t kBits[] = {224, 256, 384, 521, 10000}; 286 for (size_t bits : kBits) { 287 SCOPED_TRACE(bits); 288 size_t order_len = BitsToBytes(bits); 289 290 // Create the largest possible |ECDSA_SIG| of the given constraints. 291 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); 292 ASSERT_TRUE(sig); 293 std::vector<uint8_t> bytes(order_len, 0xff); 294 ASSERT_TRUE(BN_bin2bn(bytes.data(), bytes.size(), sig->r)); 295 ASSERT_TRUE(BN_bin2bn(bytes.data(), bytes.size(), sig->s)); 296 // Serialize it. 297 uint8_t *der; 298 size_t der_len; 299 ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, sig.get())); 300 OPENSSL_free(der); 301 302 EXPECT_EQ(der_len, ECDSA_SIG_max_len(order_len)); 303 } 304 } 305 306 static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) { 307 std::string curve_name; 308 if (!t->GetAttribute(&curve_name, key)) { 309 return nullptr; 310 } 311 312 if (curve_name == "P-224") { 313 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1)); 314 } 315 if (curve_name == "P-256") { 316 return bssl::UniquePtr<EC_GROUP>( 317 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); 318 } 319 if (curve_name == "P-384") { 320 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1)); 321 } 322 if (curve_name == "P-521") { 323 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1)); 324 } 325 if (curve_name == "secp160r1") { 326 return NewSecp160r1Group(); 327 } 328 329 ADD_FAILURE() << "Unknown curve: " << curve_name; 330 return nullptr; 331 } 332 333 static bssl::UniquePtr<EC_GROUP> MakeCustomClone(const EC_GROUP *group) { 334 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new()); 335 bssl::UniquePtr<BIGNUM> p(BN_new()), a(BN_new()), b(BN_new()), x(BN_new()), 336 y(BN_new()); 337 if (!ctx || !p || !a || !b || !x || !y || 338 !EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), ctx.get()) || 339 !EC_POINT_get_affine_coordinates_GFp( 340 group, EC_GROUP_get0_generator(group), x.get(), y.get(), ctx.get())) { 341 return nullptr; 342 } 343 bssl::UniquePtr<EC_GROUP> ret( 344 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get())); 345 if (!ret) { 346 return nullptr; 347 } 348 bssl::UniquePtr<EC_POINT> g(EC_POINT_new(ret.get())); 349 if (!g || 350 !EC_POINT_set_affine_coordinates_GFp(ret.get(), g.get(), x.get(), y.get(), 351 ctx.get()) || 352 !EC_GROUP_set_generator(ret.get(), g.get(), EC_GROUP_get0_order(group), 353 BN_value_one())) { 354 return nullptr; 355 } 356 return ret; 357 } 358 359 static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) { 360 std::vector<uint8_t> bytes; 361 if (!t->GetBytes(&bytes, key)) { 362 return nullptr; 363 } 364 365 return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr)); 366 } 367 368 TEST(ECDSATest, VerifyTestVectors) { 369 FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt", 370 [](FileTest *t) { 371 for (bool custom_group : {false, true}) { 372 SCOPED_TRACE(custom_group); 373 bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve"); 374 ASSERT_TRUE(group); 375 if (custom_group) { 376 group = MakeCustomClone(group.get()); 377 ASSERT_TRUE(group); 378 } 379 bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X"); 380 ASSERT_TRUE(x); 381 bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y"); 382 ASSERT_TRUE(y); 383 bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R"); 384 ASSERT_TRUE(r); 385 bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S"); 386 ASSERT_TRUE(s); 387 std::vector<uint8_t> digest; 388 ASSERT_TRUE(t->GetBytes(&digest, "Digest")); 389 390 bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); 391 ASSERT_TRUE(key); 392 bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get())); 393 ASSERT_TRUE(pub_key); 394 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); 395 ASSERT_TRUE(sig); 396 ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get())); 397 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp( 398 group.get(), pub_key.get(), x.get(), y.get(), nullptr)); 399 ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get())); 400 ASSERT_TRUE(BN_copy(sig->r, r.get())); 401 ASSERT_TRUE(BN_copy(sig->s, s.get())); 402 403 EXPECT_EQ( 404 t->HasAttribute("Invalid") ? 0 : 1, 405 ECDSA_do_verify(digest.data(), digest.size(), sig.get(), key.get())); 406 } 407 }); 408 } 409 410 TEST(ECDSATest, SignTestVectors) { 411 FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt", 412 [](FileTest *t) { 413 for (bool custom_group : {false, true}) { 414 SCOPED_TRACE(custom_group); 415 bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve"); 416 ASSERT_TRUE(group); 417 if (custom_group) { 418 group = MakeCustomClone(group.get()); 419 ASSERT_TRUE(group); 420 } 421 bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private"); 422 ASSERT_TRUE(priv_key); 423 bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X"); 424 ASSERT_TRUE(x); 425 bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y"); 426 ASSERT_TRUE(y); 427 bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K"); 428 ASSERT_TRUE(k); 429 bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R"); 430 ASSERT_TRUE(r); 431 bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S"); 432 ASSERT_TRUE(s); 433 std::vector<uint8_t> digest; 434 ASSERT_TRUE(t->GetBytes(&digest, "Digest")); 435 436 bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); 437 ASSERT_TRUE(key); 438 bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get())); 439 ASSERT_TRUE(pub_key); 440 ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get())); 441 ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get())); 442 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp( 443 group.get(), pub_key.get(), x.get(), y.get(), nullptr)); 444 ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get())); 445 ASSERT_TRUE(EC_KEY_check_key(key.get())); 446 447 // Set the fixed k for testing purposes. 448 key->fixed_k = k.release(); 449 bssl::UniquePtr<ECDSA_SIG> sig( 450 ECDSA_do_sign(digest.data(), digest.size(), key.get())); 451 ASSERT_TRUE(sig); 452 453 EXPECT_EQ(0, BN_cmp(r.get(), sig->r)); 454 EXPECT_EQ(0, BN_cmp(s.get(), sig->s)); 455 } 456 }); 457 } 458