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