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@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@cryptsoft.com). This product includes software written by Tim 51 * Hudson (tjh@cryptsoft.com). */ 52 53#include <openssl/ecdsa.h> 54 55#include <vector> 56 57#include <openssl/bn.h> 58#include <openssl/crypto.h> 59#include <openssl/ec.h> 60#include <openssl/err.h> 61#include <openssl/mem.h> 62#include <openssl/nid.h> 63#include <openssl/rand.h> 64 65enum Api { 66 kEncodedApi, 67 kRawApi, 68}; 69 70// VerifyECDSASig returns true on success, false on failure. 71static bool VerifyECDSASig(Api api, const uint8_t *digest, 72 size_t digest_len, const ECDSA_SIG *ecdsa_sig, 73 EC_KEY *eckey, int expected_result) { 74 int actual_result; 75 76 switch (api) { 77 case kEncodedApi: { 78 uint8_t *der; 79 size_t der_len; 80 if (!ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig)) { 81 return false; 82 } 83 bssl::UniquePtr<uint8_t> delete_der(der); 84 actual_result = ECDSA_verify(0, digest, digest_len, der, der_len, eckey); 85 break; 86 } 87 88 case kRawApi: 89 actual_result = ECDSA_do_verify(digest, digest_len, ecdsa_sig, eckey); 90 break; 91 92 default: 93 return false; 94 } 95 return expected_result == actual_result; 96} 97 98// TestTamperedSig verifies that signature verification fails when a valid 99// signature is tampered with. |ecdsa_sig| must be a valid signature, which will 100// be modified. TestTamperedSig returns true on success, false on failure. 101static bool TestTamperedSig(FILE *out, Api api, const uint8_t *digest, 102 size_t digest_len, ECDSA_SIG *ecdsa_sig, 103 EC_KEY *eckey, const BIGNUM *order) { 104 // Modify a single byte of the signature: to ensure we don't 105 // garble the ASN1 structure, we read the raw signature and 106 // modify a byte in one of the bignums directly. 107 108 // Store the two BIGNUMs in raw_buf. 109 size_t r_len = BN_num_bytes(ecdsa_sig->r); 110 size_t s_len = BN_num_bytes(ecdsa_sig->s); 111 size_t bn_len = BN_num_bytes(order); 112 if (r_len > bn_len || s_len > bn_len) { 113 return false; 114 } 115 size_t buf_len = 2 * bn_len; 116 std::vector<uint8_t> raw_buf(buf_len); 117 // Pad the bignums with leading zeroes. 118 if (!BN_bn2bin_padded(raw_buf.data(), bn_len, ecdsa_sig->r) || 119 !BN_bn2bin_padded(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s)) { 120 return false; 121 } 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 if (BN_bin2bn(raw_buf.data(), bn_len, ecdsa_sig->r) == NULL || 129 BN_bin2bn(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s) == NULL || 130 !VerifyECDSASig(api, digest, digest_len, ecdsa_sig, eckey, 0)) { 131 return false; 132 } 133 134 // Sanity check: Undo the modification and verify signature. 135 raw_buf[offset] ^= dirt; 136 if (BN_bin2bn(raw_buf.data(), bn_len, ecdsa_sig->r) == NULL || 137 BN_bin2bn(raw_buf.data() + bn_len, bn_len, ecdsa_sig->s) == NULL || 138 !VerifyECDSASig(api, digest, digest_len, ecdsa_sig, eckey, 1)) { 139 return false; 140 } 141 142 return true; 143} 144 145static bool TestBuiltin(FILE *out) { 146 // Fill digest values with some random data. 147 uint8_t digest[20], wrong_digest[20]; 148 if (!RAND_bytes(digest, 20) || !RAND_bytes(wrong_digest, 20)) { 149 fprintf(out, "ERROR: unable to get random data\n"); 150 return false; 151 } 152 153 static const struct { 154 int nid; 155 const char *name; 156 } kCurves[] = { 157 { NID_secp224r1, "secp224r1" }, 158 { NID_X9_62_prime256v1, "secp256r1" }, 159 { NID_secp384r1, "secp384r1" }, 160 { NID_secp521r1, "secp521r1" }, 161 { NID_undef, NULL } 162 }; 163 164 // Create and verify ECDSA signatures with every available curve. 165 fputs("\ntesting ECDSA_sign(), ECDSA_verify(), ECDSA_do_sign(), and " 166 "ECDSA_do_verify() with some internal curves:\n", out); 167 168 for (size_t n = 0; kCurves[n].nid != NID_undef; n++) { 169 fprintf(out, "%s: ", kCurves[n].name); 170 171 int nid = kCurves[n].nid; 172 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid)); 173 if (!group) { 174 fprintf(out, " failed\n"); 175 return false; 176 } 177 const BIGNUM *order = EC_GROUP_get0_order(group.get()); 178 if (BN_num_bits(order) < 160) { 179 // Too small to test. 180 fprintf(out, " skipped\n"); 181 continue; 182 } 183 184 // Create a new ECDSA key. 185 bssl::UniquePtr<EC_KEY> eckey(EC_KEY_new()); 186 if (!eckey || !EC_KEY_set_group(eckey.get(), group.get()) || 187 !EC_KEY_generate_key(eckey.get())) { 188 fprintf(out, " failed\n"); 189 return false; 190 } 191 // Create a second key. 192 bssl::UniquePtr<EC_KEY> wrong_eckey(EC_KEY_new()); 193 if (!wrong_eckey || !EC_KEY_set_group(wrong_eckey.get(), group.get()) || 194 !EC_KEY_generate_key(wrong_eckey.get())) { 195 fprintf(out, " failed\n"); 196 return false; 197 } 198 199 fprintf(out, "."); 200 fflush(out); 201 202 // Check the key. 203 if (!EC_KEY_check_key(eckey.get())) { 204 fprintf(out, " failed\n"); 205 return false; 206 } 207 fprintf(out, "."); 208 fflush(out); 209 210 // Test ASN.1-encoded signatures. 211 // Create a signature. 212 unsigned sig_len = ECDSA_size(eckey.get()); 213 std::vector<uint8_t> signature(sig_len); 214 if (!ECDSA_sign(0, digest, 20, signature.data(), &sig_len, eckey.get())) { 215 fprintf(out, " failed\n"); 216 return false; 217 } 218 signature.resize(sig_len); 219 fprintf(out, "."); 220 fflush(out); 221 // Verify the signature. 222 if (!ECDSA_verify(0, digest, 20, signature.data(), signature.size(), 223 eckey.get())) { 224 fprintf(out, " failed\n"); 225 return false; 226 } 227 fprintf(out, "."); 228 fflush(out); 229 // Verify the signature with the wrong key. 230 if (ECDSA_verify(0, digest, 20, signature.data(), signature.size(), 231 wrong_eckey.get())) { 232 fprintf(out, " failed\n"); 233 return false; 234 } 235 fprintf(out, "."); 236 fflush(out); 237 // Verify the signature using the wrong digest. 238 if (ECDSA_verify(0, wrong_digest, 20, signature.data(), signature.size(), 239 eckey.get())) { 240 fprintf(out, " failed\n"); 241 return false; 242 } 243 fprintf(out, "."); 244 fflush(out); 245 // Verify a truncated signature. 246 if (ECDSA_verify(0, digest, 20, signature.data(), signature.size() - 1, 247 eckey.get())) { 248 fprintf(out, " failed\n"); 249 return false; 250 } 251 fprintf(out, "."); 252 fflush(out); 253 // Verify a tampered signature. 254 bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(ECDSA_SIG_from_bytes( 255 signature.data(), signature.size())); 256 if (!ecdsa_sig || 257 !TestTamperedSig(out, kEncodedApi, digest, 20, ecdsa_sig.get(), 258 eckey.get(), order)) { 259 fprintf(out, " failed\n"); 260 return false; 261 } 262 fprintf(out, "."); 263 fflush(out); 264 265 // Test ECDSA_SIG signing and verification. 266 // Create a signature. 267 ecdsa_sig.reset(ECDSA_do_sign(digest, 20, eckey.get())); 268 if (!ecdsa_sig) { 269 fprintf(out, " failed\n"); 270 return false; 271 } 272 fprintf(out, "."); 273 fflush(out); 274 // Verify the signature using the correct key. 275 if (!ECDSA_do_verify(digest, 20, ecdsa_sig.get(), eckey.get())) { 276 fprintf(out, " failed\n"); 277 return false; 278 } 279 fprintf(out, "."); 280 fflush(out); 281 // Verify the signature with the wrong key. 282 if (ECDSA_do_verify(digest, 20, ecdsa_sig.get(), wrong_eckey.get())) { 283 fprintf(out, " failed\n"); 284 return false; 285 } 286 fprintf(out, "."); 287 fflush(out); 288 // Verify the signature using the wrong digest. 289 if (ECDSA_do_verify(wrong_digest, 20, ecdsa_sig.get(), eckey.get())) { 290 fprintf(out, " failed\n"); 291 return false; 292 } 293 fprintf(out, "."); 294 fflush(out); 295 // Verify a tampered signature. 296 if (!TestTamperedSig(out, kRawApi, digest, 20, ecdsa_sig.get(), eckey.get(), 297 order)) { 298 fprintf(out, " failed\n"); 299 return false; 300 } 301 fprintf(out, "."); 302 fflush(out); 303 304 fprintf(out, " ok\n"); 305 // Clear bogus errors. 306 ERR_clear_error(); 307 } 308 309 return true; 310} 311 312static bool TestECDSA_SIG_max_len(size_t order_len) { 313 /* Create the largest possible |ECDSA_SIG| of the given constraints. */ 314 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new()); 315 if (!sig) { 316 return false; 317 } 318 std::vector<uint8_t> bytes(order_len, 0xff); 319 if (!BN_bin2bn(bytes.data(), bytes.size(), sig->r) || 320 !BN_bin2bn(bytes.data(), bytes.size(), sig->s)) { 321 return false; 322 } 323 /* Serialize it. */ 324 uint8_t *der; 325 size_t der_len; 326 if (!ECDSA_SIG_to_bytes(&der, &der_len, sig.get())) { 327 return false; 328 } 329 bssl::UniquePtr<uint8_t> delete_der(der); 330 331 size_t max_len = ECDSA_SIG_max_len(order_len); 332 if (max_len != der_len) { 333 fprintf(stderr, "ECDSA_SIG_max_len(%u) returned %u, wanted %u\n", 334 static_cast<unsigned>(order_len), static_cast<unsigned>(max_len), 335 static_cast<unsigned>(der_len)); 336 return false; 337 } 338 return true; 339} 340 341static size_t BitsToBytes(size_t bits) { 342 return (bits / 8) + (7 + (bits % 8)) / 8; 343} 344 345int main(void) { 346 CRYPTO_library_init(); 347 348 if (!TestBuiltin(stdout) || 349 !TestECDSA_SIG_max_len(BitsToBytes(224)) || 350 !TestECDSA_SIG_max_len(BitsToBytes(256)) || 351 !TestECDSA_SIG_max_len(BitsToBytes(384)) || 352 !TestECDSA_SIG_max_len(BitsToBytes(521)) || 353 !TestECDSA_SIG_max_len(BitsToBytes(10000))) { 354 printf("\nECDSA test failed\n"); 355 ERR_print_errors_fp(stdout); 356 return 1; 357 } 358 359 printf("\nPASS\n"); 360 return 0; 361} 362