/* * (C) 2009 Jack Lloyd * * Distributed under the terms of the Botan license */ #include #if defined(BOTAN_HAS_RSA) #include #endif #if defined(BOTAN_HAS_DSA) #include #endif #if defined(BOTAN_HAS_ECDSA) #include #endif #if defined(BOTAN_HAS_X509_CERTIFICATES) #include #include #include #include #endif using namespace Botan; #include #include #include "validate.h" #include "common.h" #if defined(BOTAN_HAS_X509_CERTIFICATES) && \ defined(BOTAN_HAS_RSA) && \ defined(BOTAN_HAS_DSA) namespace { u64bit key_id(const Public_Key* key) { Pipe pipe(new Hash_Filter("SHA-1", 8)); pipe.start_msg(); pipe.write(key->algo_name()); pipe.write(key->algorithm_identifier().parameters); pipe.write(key->x509_subject_public_key()); pipe.end_msg(); secure_vector output = pipe.read_all(); if(output.size() != 8) throw Internal_Error("Public_Key::key_id: Incorrect output size"); u64bit id = 0; for(u32bit j = 0; j != 8; ++j) id = (id << 8) | output[j]; return id; } /* Return some option sets */ X509_Cert_Options ca_opts() { X509_Cert_Options opts("Test CA/US/Botan Project/Testing"); opts.uri = "http://botan.randombit.net"; opts.dns = "botan.randombit.net"; opts.email = "testing@randombit.net"; opts.CA_key(1); return opts; } X509_Cert_Options req_opts1() { X509_Cert_Options opts("Test User 1/US/Botan Project/Testing"); opts.uri = "http://botan.randombit.net"; opts.dns = "botan.randombit.net"; opts.email = "testing@randombit.net"; return opts; } X509_Cert_Options req_opts2() { X509_Cert_Options opts("Test User 2/US/Botan Project/Testing"); opts.uri = "http://botan.randombit.net"; opts.dns = "botan.randombit.net"; opts.email = "testing@randombit.net"; opts.add_ex_constraint("PKIX.EmailProtection"); return opts; } u32bit check_against_copy(const Private_Key& orig, RandomNumberGenerator& rng) { Private_Key* copy_priv = PKCS8::copy_key(orig, rng); Public_Key* copy_pub = X509::copy_key(orig); const std::string passphrase= "I need work! -Mr. T"; DataSource_Memory enc_source(PKCS8::PEM_encode(orig, rng, passphrase)); Private_Key* copy_priv_enc = PKCS8::load_key(enc_source, rng, passphrase); u64bit orig_id = key_id(&orig); u64bit pub_id = key_id(copy_pub); u64bit priv_id = key_id(copy_priv); u64bit priv_enc_id = key_id(copy_priv_enc); delete copy_pub; delete copy_priv; delete copy_priv_enc; if(orig_id != pub_id || orig_id != priv_id || orig_id != priv_enc_id) { std::cout << "Failed copy check for " << orig.algo_name() << "\n"; return 1; } return 0; } } void do_x509_tests(RandomNumberGenerator& rng) { std::cout << "Testing X.509 CA/CRL/cert/cert request: " << std::flush; std::string hash_fn = "SHA-256"; /* Create the CA's key and self-signed cert */ std::cout << '.' << std::flush; RSA_PrivateKey ca_key(rng, 2048); std::cout << '.' << std::flush; X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(), ca_key, hash_fn, rng); std::cout << '.' << std::flush; /* Create user #1's key and cert request */ DSA_PrivateKey user1_key(rng, DL_Group("dsa/botan/2048")); std::cout << '.' << std::flush; PKCS10_Request user1_req = X509::create_cert_req(req_opts1(), user1_key, "SHA-1", rng); /* Create user #2's key and cert request */ std::cout << '.' << std::flush; #if defined(BOTAN_HAS_ECDSA) EC_Group ecc_domain(OID("1.2.840.10045.3.1.7")); ECDSA_PrivateKey user2_key(rng, ecc_domain); #else RSA_PrivateKey user2_key(rng, 1536); #endif std::cout << '.' << std::flush; PKCS10_Request user2_req = X509::create_cert_req(req_opts2(), user2_key, hash_fn, rng); /* Create the CA object */ std::cout << '.' << std::flush; X509_CA ca(ca_cert, ca_key, hash_fn); std::cout << '.' << std::flush; /* Sign the requests to create the certs */ std::cout << '.' << std::flush; X509_Certificate user1_cert = ca.sign_request(user1_req, rng, X509_Time("2008-01-01"), X509_Time("2100-01-01")); std::cout << '.' << std::flush; X509_Certificate user2_cert = ca.sign_request(user2_req, rng, X509_Time("2008-01-01"), X509_Time("2100-01-01")); std::cout << '.' << std::flush; X509_CRL crl1 = ca.new_crl(rng); /* Verify the certs */ Certificate_Store_In_Memory store; store.add_certificate(ca_cert); std::cout << '.' << std::flush; Path_Validation_Restrictions restrictions; Path_Validation_Result result_u1 = x509_path_validate(user1_cert, restrictions, store); if(!result_u1.successful_validation()) std::cout << "FAILED: User cert #1 did not validate - " << result_u1.result_string() << std::endl; Path_Validation_Result result_u2 = x509_path_validate(user2_cert, restrictions, store); if(!result_u2.successful_validation()) std::cout << "FAILED: User cert #2 did not validate - " << result_u2.result_string() << std::endl; store.add_crl(crl1); std::vector revoked; revoked.push_back(CRL_Entry(user1_cert, CESSATION_OF_OPERATION)); revoked.push_back(user2_cert); X509_CRL crl2 = ca.update_crl(crl1, revoked, rng); store.add_crl(crl2); result_u1 = x509_path_validate(user1_cert, restrictions, store); if(result_u1.result() != Certificate_Status_Code::CERT_IS_REVOKED) std::cout << "FAILED: User cert #1 was not revoked - " << result_u1.result_string() << std::endl; result_u2 = x509_path_validate(user2_cert, restrictions, store); if(result_u2.result() != Certificate_Status_Code::CERT_IS_REVOKED) std::cout << "FAILED: User cert #2 was not revoked - " << result_u2.result_string() << std::endl; revoked.clear(); revoked.push_back(CRL_Entry(user1_cert, REMOVE_FROM_CRL)); X509_CRL crl3 = ca.update_crl(crl2, revoked, rng); store.add_crl(crl3); result_u1 = x509_path_validate(user1_cert, restrictions, store); if(!result_u1.successful_validation()) std::cout << "FAILED: User cert #1 was not un-revoked - " << result_u1.result_string() << std::endl; check_against_copy(ca_key, rng); check_against_copy(user1_key, rng); check_against_copy(user2_key, rng); std::cout << std::endl; } #else void do_x509_tests(RandomNumberGenerator&) { std::cout << "Skipping Botan X.509 tests (disabled in build)\n"; } #endif