/****************************************************** * ECDSA tests * * * * (C) 2007 Falko Strenzke * * Manuel Hartl * * 2008 Jack Lloyd * ******************************************************/ #include "validate.h" #if defined(BOTAN_HAS_ECDSA) #include #include #include #include #include #include #include #include #include "common.h" using namespace Botan; #define TEST_DATA_DIR "checks/ecc_testdata" #define CHECK_MESSAGE(expr, print) try { if(!(expr)) std::cout << print << "\n"; } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; } #define CHECK(expr) try { if(!(expr)) std::cout << #expr << "\n"; } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; } namespace { std::string to_hex(const SecureVector& bin) { return hex_encode(bin.begin(), bin.size()); } /** * Tests whether the the signing routine will work correctly in case the integer e * that is constructed from the message (thus the hash value) is larger than n, the order of the base point. * Tests the signing function of the pk signer object */ void test_hash_larger_than_n(RandomNumberGenerator& rng) { std::cout << "." << std::flush; EC_Domain_Params dom_pars(OID("1.3.132.0.8")); // n: // 0x0100000000000000000001f4c8f927aed3ca752257 // 21 bytes // -> shouldn't work with SHA224 which outputs 23 bytes ECDSA_PrivateKey priv_key(rng, dom_pars); SecureVector message; for (unsigned j= 0; j<20; j++) { message.append(j); } for (int i = 0; i<3; i++) { //cout << "i = " << i << endl; std::string format; if(i==1) { format = "EMSA1_BSI(SHA-224)"; } else { format = "EMSA1_BSI(SHA-1)"; } std::auto_ptr pk_signer(get_pk_signer(priv_key, format)); SecureVector signature; bool sig_exc = false; try { signature = pk_signer->sign_message(message, rng); } catch(Encoding_Error e) { sig_exc = true; } if(i==1) { CHECK(sig_exc); } if(i==0) { CHECK(!sig_exc); } if(i==0) // makes no sense to check for sha224 { std::auto_ptr pk_verifier(get_pk_verifier(priv_key, format)); bool ver = pk_verifier->verify_message(message, signature); CHECK(ver); } } // for // now check that verification alone fails // sign it with the normal EMSA1 std::auto_ptr pk_signer(get_pk_signer(priv_key, "EMSA1(SHA-224)")); SecureVector signature = pk_signer->sign_message(message, rng); std::auto_ptr pk_verifier(get_pk_verifier(priv_key, "EMSA1_BSI(SHA-224)")); // verify against EMSA1_BSI // we make sure it doesn't fail because of the invalid signature, // but because of the Encoding_Error if(pk_verifier->verify_message(message, signature)) std::cout << "Corrupt ECDSA signature verified, should not have\n"; } void test_decode_ecdsa_X509() { std::cout << "." << std::flush; X509_Certificate cert(TEST_DATA_DIR "/CSCA.CSCA.csca-germany.1.crt"); CHECK_MESSAGE(OIDS::lookup(cert.signature_algorithm().oid) == "ECDSA/EMSA1(SHA-224)", "error reading signature algorithm from x509 ecdsa certificate"); CHECK_MESSAGE(to_hex(cert.serial_number()) == "01", "error reading serial from x509 ecdsa certificate"); CHECK_MESSAGE(to_hex(cert.authority_key_id()) == "0096452DE588F966C4CCDF161DD1F3F5341B71E7", "error reading authority key id from x509 ecdsa certificate"); CHECK_MESSAGE(to_hex(cert.subject_key_id()) == "0096452DE588F966C4CCDF161DD1F3F5341B71E7", "error reading Subject key id from x509 ecdsa certificate"); std::auto_ptr pubkey(cert.subject_public_key()); bool ver_ec = cert.check_signature(*pubkey); CHECK_MESSAGE(ver_ec, "could not positively verify correct selfsigned x509-ecdsa certificate"); } void test_decode_ver_link_SHA256() { std::cout << "." << std::flush; X509_Certificate root_cert(TEST_DATA_DIR "/root2_SHA256.cer"); X509_Certificate link_cert(TEST_DATA_DIR "/link_SHA256.cer"); std::auto_ptr pubkey(root_cert.subject_public_key()); bool ver_ec = link_cert.check_signature(*pubkey); CHECK_MESSAGE(ver_ec, "could not positively verify correct SHA256 link x509-ecdsa certificate"); } void test_decode_ver_link_SHA1() { std::cout << "." << std::flush; X509_Certificate root_cert(TEST_DATA_DIR "/root_SHA1.163.crt"); X509_Certificate link_cert(TEST_DATA_DIR "/link_SHA1.166.crt"); std::auto_ptr pubkey(root_cert.subject_public_key()); bool ver_ec = link_cert.check_signature(*pubkey); CHECK_MESSAGE(ver_ec, "could not positively verify correct SHA1 link x509-ecdsa certificate"); } void test_sign_then_ver(RandomNumberGenerator& rng) { std::cout << '.' << std::flush; EC_Domain_Params dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey ecdsa(rng, dom_pars); std::auto_ptr signer(get_pk_signer(ecdsa, "EMSA1(SHA-1)")); SecureVector msg = decode_hex("12345678901234567890abcdef12"); SecureVector sig = signer->sign_message(msg, rng); std::auto_ptr verifier(get_pk_verifier(ecdsa, "EMSA1(SHA-1)")); bool ok = verifier->verify_message(msg, sig); if(!ok) std::cout << "ERROR: Could not verify ECDSA signature\n"; sig[0]++; ok = verifier->verify_message(msg, sig); if(ok) std::cout << "ERROR: Bogus ECDSA signature verified anyway\n"; } bool test_ec_sign(RandomNumberGenerator& rng) { std::cout << "." << std::flush; try { EC_Domain_Params dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey priv_key(rng, dom_pars); std::string pem_encoded_key = PKCS8::PEM_encode(priv_key); std::auto_ptr signer(get_pk_signer(priv_key, "EMSA1(SHA-224)")); std::auto_ptr verifier(get_pk_verifier(priv_key, "EMSA1(SHA-224)")); for(u32bit i = 0; i != 256; ++i) signer->update((byte)i); SecureVector sig = signer->signature(rng); for(u32bit i = 0; i != 256; ++i) verifier->update((byte)i); if(!verifier->check_signature(sig)) { std::cout << "ECDSA self-test failed!"; return false; } // now check valid signature, different input for(u32bit i = 1; i != 256; ++i) //starting from 1 verifier->update((byte)i); if(verifier->check_signature(sig)) { std::cout << "ECDSA with bad input passed validation"; return false; } // now check with original input, modified signature sig[sig.size()/2]++; for(u32bit i = 0; i != 256; ++i) verifier->update((byte)i); if(verifier->check_signature(sig)) { std::cout << "ECDSA with bad signature passed validation"; return false; } } catch (std::exception& e) { std::cout << "Exception in test_ec_sign - " << e.what() << "\n"; return false; } return true; } void test_create_pkcs8(RandomNumberGenerator& rng) { std::cout << "." << std::flush; try { RSA_PrivateKey rsa_key(rng, 1024); //RSA_PrivateKey rsa_key2(1024); //cout << "\nequal: " << (rsa_key == rsa_key2) << "\n"; //DSA_PrivateKey key(DL_Group("dsa/jce/1024")); std::ofstream rsa_priv_key(TEST_DATA_DIR "/rsa_private.pkcs8.pem"); rsa_priv_key << PKCS8::PEM_encode(rsa_key); EC_Domain_Params dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey key(rng, dom_pars); // later used by other tests :( std::ofstream priv_key(TEST_DATA_DIR "/wo_dompar_private.pkcs8.pem"); priv_key << PKCS8::PEM_encode(key); } catch (std::exception& e) { std::cout << "Exception: " << e.what() << std::endl; } } void test_create_and_verify(RandomNumberGenerator& rng) { std::cout << "." << std::flush; EC_Domain_Params dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey key(rng, dom_pars); std::ofstream priv_key(TEST_DATA_DIR "/dompar_private.pkcs8.pem"); priv_key << PKCS8::PEM_encode(key); std::auto_ptr loaded_key(PKCS8::load_key(TEST_DATA_DIR "/wo_dompar_private.pkcs8.pem", rng)); ECDSA_PrivateKey* loaded_ec_key = dynamic_cast(loaded_key.get()); CHECK_MESSAGE(loaded_ec_key, "the loaded key could not be converted into an ECDSA_PrivateKey"); std::auto_ptr loaded_key_1(PKCS8::load_key(TEST_DATA_DIR "/rsa_private.pkcs8.pem", rng)); ECDSA_PrivateKey* loaded_rsa_key = dynamic_cast(loaded_key_1.get()); CHECK_MESSAGE(!loaded_rsa_key, "the loaded key is ECDSA_PrivateKey -> shouldn't be, is a RSA-Key"); //calc a curve which is not in the registry // string p_secp = "2117607112719756483104013348936480976596328609518055062007450442679169492999007105354629105748524349829824407773719892437896937279095106809"; std::string a_secp = "0a377dede6b523333d36c78e9b0eaa3bf48ce93041f6d4fc34014d08f6833807498deedd4290101c5866e8dfb589485d13357b9e78c2d7fbe9fe"; std::string b_secp = "0a9acf8c8ba617777e248509bcb4717d4db346202bf9e352cd5633731dd92a51b72a4dc3b3d17c823fcc8fbda4da08f25dea89046087342595a7"; std::string G_secp_comp = "04081523d03d4f12cd02879dea4bf6a4f3a7df26ed888f10c5b2235a1274c386a2f218300dee6ed217841164533bcdc903f07a096f9fbf4ee95bac098a111f296f5830fe5c35b3e344d5df3a2256985f64fbe6d0edcc4c61d18bef681dd399df3d0194c5a4315e012e0245ecea56365baa9e8be1f7"; std::string order_g = "0e1a16196e6000000000bc7f1618d867b15bb86474418f"; // ::SecureVector sv_p_secp = decode_hex ( p_secp ); SecureVector sv_a_secp = decode_hex ( a_secp ); SecureVector sv_b_secp = decode_hex ( b_secp ); SecureVector sv_G_secp_comp = decode_hex ( G_secp_comp ); SecureVector sv_order_g = decode_hex ( order_g ); // BigInt bi_p_secp = BigInt::decode ( sv_p_secp.begin(), sv_p_secp.size() ); BigInt bi_p_secp("2117607112719756483104013348936480976596328609518055062007450442679169492999007105354629105748524349829824407773719892437896937279095106809"); BigInt bi_a_secp = BigInt::decode ( sv_a_secp.begin(), sv_a_secp.size() ); BigInt bi_b_secp = BigInt::decode ( sv_b_secp.begin(), sv_b_secp.size() ); BigInt bi_order_g = BigInt::decode ( sv_order_g.begin(), sv_order_g.size() ); CurveGFp curve(bi_p_secp, bi_a_secp, bi_b_secp); PointGFp p_G = OS2ECP ( sv_G_secp_comp, curve ); EC_Domain_Params dom_params(curve, p_G, bi_order_g, BigInt(1)); p_G.check_invariants(); ECDSA_PrivateKey key_odd_oid(rng, dom_params); std::string key_odd_oid_str = PKCS8::PEM_encode(key_odd_oid); DataSource_Memory key_data_src(key_odd_oid_str); std::auto_ptr loaded_key2(PKCS8::load_key(key_data_src, rng)); if(!dynamic_cast(loaded_key.get())) { std::cout << "Failed to reload an ECDSA key with unusual parameter set\n"; } } void test_curve_registry(RandomNumberGenerator& rng) { std::vector oids; oids.push_back("1.3.132.0.8"); oids.push_back("1.2.840.10045.3.1.1"); oids.push_back("1.2.840.10045.3.1.2"); oids.push_back("1.2.840.10045.3.1.3"); oids.push_back("1.2.840.10045.3.1.4"); oids.push_back("1.2.840.10045.3.1.5"); oids.push_back("1.2.840.10045.3.1.6"); oids.push_back("1.2.840.10045.3.1.7"); oids.push_back("1.3.132.0.6"); oids.push_back("1.3.132.0.7"); oids.push_back("1.3.132.0.28"); oids.push_back("1.3.132.0.29"); oids.push_back("1.3.132.0.9"); oids.push_back("1.3.132.0.30"); oids.push_back("1.3.132.0.31"); oids.push_back("1.3.132.0.32"); oids.push_back("1.3.132.0.33"); oids.push_back("1.3.132.0.10"); oids.push_back("1.3.132.0.34"); oids.push_back("1.3.132.0.35"); oids.push_back("1.3.6.1.4.1.8301.3.1.2.9.0.38"); oids.push_back("1.3.36.3.3.2.8.1.1.1"); oids.push_back("1.3.36.3.3.2.8.1.1.3"); oids.push_back("1.3.36.3.3.2.8.1.1.5"); oids.push_back("1.3.36.3.3.2.8.1.1.7"); oids.push_back("1.3.36.3.3.2.8.1.1.9"); oids.push_back("1.3.36.3.3.2.8.1.1.11"); oids.push_back("1.3.36.3.3.2.8.1.1.13"); unsigned int i; for (i = 0; i < oids.size(); i++) { std::cout << "." << std::flush; try { OID oid(oids[i]); EC_Domain_Params dom_pars(oid); dom_pars.get_base_point().check_invariants(); ECDSA_PrivateKey ecdsa(rng, dom_pars); std::auto_ptr signer(get_pk_signer(ecdsa, "EMSA1(SHA-1)")); std::auto_ptr verifier(get_pk_verifier(ecdsa, "EMSA1(SHA-1)")); SecureVector msg = decode_hex("12345678901234567890abcdef12"); SecureVector sig = signer->sign_message(msg, rng); if(!verifier->verify_message(msg, sig)) std::cout << "Failed testing ECDSA sig for curve " << oids[i] << "\n"; } catch(Invalid_Argument& e) { std::cout << "Error testing curve " << oids[i] << " - " << e.what() << "\n"; } } // std::cout << "test_curve_registry finished" << endl; } void test_read_pkcs8(RandomNumberGenerator& rng) { std::cout << "." << std::flush; try { std::auto_ptr loaded_key(PKCS8::load_key(TEST_DATA_DIR "/wo_dompar_private.pkcs8.pem", rng)); ECDSA_PrivateKey* ecdsa = dynamic_cast(loaded_key.get()); CHECK_MESSAGE(ecdsa, "the loaded key could not be converted into an ECDSA_PrivateKey"); std::auto_ptr signer(get_pk_signer(*ecdsa, "EMSA1(SHA-1)")); SecureVector msg = decode_hex("12345678901234567890abcdef12"); SecureVector sig = signer->sign_message(msg, rng); std::auto_ptr verifier(get_pk_verifier(*ecdsa, "EMSA1(SHA-1)")); bool ok = verifier->verify_message(msg, sig); CHECK_MESSAGE(ok, "generated sig could not be verified positively"); std::auto_ptr loaded_key_nodp(PKCS8::load_key(TEST_DATA_DIR "/nodompar_private.pkcs8.pem", rng)); // anew in each test with unregistered domain-parameters ECDSA_PrivateKey* ecdsa_nodp = dynamic_cast(loaded_key_nodp.get()); CHECK_MESSAGE(ecdsa_nodp, "the loaded key could not be converted into an ECDSA_PrivateKey"); signer.reset(get_pk_signer(*ecdsa_nodp, "EMSA1(SHA-1)")); verifier.reset(get_pk_verifier(*ecdsa_nodp, "EMSA1(SHA-1)")); SecureVector signature_nodp = signer->sign_message(msg, rng); ok = verifier->verify_message(msg, signature_nodp); CHECK_MESSAGE(ok, "generated signature could not be verified positively (no_dom)"); try { std::auto_ptr loaded_key_withdp( PKCS8::load_key(TEST_DATA_DIR "/withdompar_private.pkcs8.pem", rng)); std::cout << "Unexpected success: loaded key with unknown OID\n"; } catch (std::exception) { /* OK */ } } catch (std::exception& e) { std::cout << "Exception in test_read_pkcs8 - " << e.what() << "\n"; } } } u32bit do_ecdsa_tests(Botan::RandomNumberGenerator& rng) { std::cout << "Testing ECDSA (InSiTo unit tests): "; test_decode_ecdsa_X509(); test_decode_ver_link_SHA256(); test_decode_ver_link_SHA1(); test_sign_then_ver(rng); test_ec_sign(rng); test_create_pkcs8(rng); test_create_and_verify(rng); test_curve_registry(rng); test_read_pkcs8(rng); std::cout << std::endl; return 0; } #else u32bit do_ecdsa_tests(Botan::RandomNumberGenerator&) { return 0; } #endif