diff options
Diffstat (limited to 'src/tests/test_certstor.cpp')
-rw-r--r-- | src/tests/test_certstor.cpp | 374 |
1 files changed, 226 insertions, 148 deletions
diff --git a/src/tests/test_certstor.cpp b/src/tests/test_certstor.cpp index cacaf8d0e..abe4a4ed0 100644 --- a/src/tests/test_certstor.cpp +++ b/src/tests/test_certstor.cpp @@ -6,178 +6,271 @@ #include "tests.h" -#if defined(BOTAN_HAS_CERTSTOR_SQLITE3) - #include <botan/certstor_sqlite.h> - #include <botan/sqlite3.h> +#if defined(BOTAN_HAS_CERTSTOR_SQL) + #include <botan/certstor.h> #include <botan/internal/filesystem.h> #include <botan/pkcs8.h> #include <sstream> + #if defined(BOTAN_HAS_CERTSTOR_SQLITE3) + #include <botan/certstor_sqlite.h> + #include <botan/sqlite3.h> + #endif #endif - namespace Botan_Tests { namespace { -#if defined(BOTAN_HAS_CERTSTOR_SQLITE3) +#if defined(BOTAN_HAS_CERTSTOR_SQL) +struct CertificateAndKey + { + const Botan::X509_Certificate certificate; + const std::shared_ptr<Botan::Private_Key> private_key; + bool operator!=(const CertificateAndKey& rhs) const + { + return std::tie(certificate, private_key) != std::tie(rhs.certificate, rhs.private_key); + } + }; -Test::Result test_certstor_insert_find_remove_test( - const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>& certs, - Botan::Certificate_Store_In_SQL& store) +#if defined(BOTAN_HAS_CERTSTOR_SQLITE3) +Test::Result test_certstor_sqlite3_insert_find_remove_test(const std::vector<CertificateAndKey>& certsandkeys) { - Test::Result result("Certificate Store - Insert, Find, Remove"); + Test::Result result("Certificate Store SQLITE3 - Insert, Find, Remove"); - for(auto cert_key: certs) + try { - auto cert = cert_key.first; - auto key = cert_key.second; - auto wo_keyid = store.find_cert(cert.subject_dn(),{}); - auto w_keyid = store.find_cert(cert.subject_dn(),cert.subject_key_id()); + auto& rng = Test::rng(); + const std::string passwd(reinterpret_cast<const char*>(rng.random_vec(8).data()), 8); + // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html) + Botan::Certificate_Store_In_SQLite store(":memory:", passwd, rng); - if(!wo_keyid || !w_keyid) - { - result.test_failure("Can't retrieve certificate"); - return result; - } + for(const auto& a : certsandkeys) + store.insert_key(a.certificate, *a.private_key); - auto priv = store.find_key(cert); - if(!priv && (certs[1] != cert_key && certs[0] != cert_key)) + for(const auto certandkey : certsandkeys) { - result.test_failure("Can't retrieve private key for " + cert.fingerprint("SHA1")); - return result; - } + const auto cert = certandkey.certificate; + const auto key = certandkey.private_key; + const auto wo_keyid = store.find_cert(cert.subject_dn(), {}); + const auto w_keyid = store.find_cert(cert.subject_dn(), cert.subject_key_id()); - result.test_eq("Got wrong certificate",cert.fingerprint(),w_keyid->fingerprint()); + if(!wo_keyid || !w_keyid) + { + result.test_failure("Can't retrieve certificate"); + return result; + } - if(priv) - { - result.test_eq("Got wrong private key",key->private_key_bits(),priv->private_key_bits()); + const auto priv = store.find_key(cert); + if(!priv && (certsandkeys[1] != certandkey && certsandkeys[0] != certandkey)) + { + result.test_failure("Can't retrieve private key for " + cert.fingerprint("SHA1")); + return result; + } - auto rev_certs = store.find_certs_for_key(*priv); + result.test_eq("Got wrong certificate", cert.fingerprint(), w_keyid->fingerprint()); - if(rev_certs.empty()) + if(priv) { - result.test_failure("No certificate"); + result.test_eq("Got wrong private key", key->private_key_bits(), priv->private_key_bits()); + + const auto rev_certs = store.find_certs_for_key(*priv); + + if(rev_certs.empty()) + { + result.test_failure("No certificate"); + } + else + { + const bool found = std::any_of(rev_certs.begin(), + rev_certs.end(), [&](std::shared_ptr<const Botan::X509_Certificate> c) { return c->fingerprint() == cert.fingerprint(); }); + + result.test_eq("Got wrong/no certificate", found, true); + } } - else + + if(certsandkeys[4] != certandkey && certsandkeys[5] != certandkey) { - bool found = std::any_of(rev_certs.begin(),rev_certs.end(),[&](std::shared_ptr<const Botan::X509_Certificate> c) - { return c->fingerprint() == cert.fingerprint(); }); + result.test_eq("Got wrong certificate", cert.fingerprint(), wo_keyid->fingerprint()); + } - result.test_eq("Got wrong/no certificate",found,true); + result.test_eq("Can't remove certificate", store.remove_cert(cert), true); + result.test_eq("Can't remove certificate", !store.find_cert(cert.subject_dn(), cert.subject_key_id()), true); + + if(priv) + { + store.remove_key(*key); } + + result.test_eq("Can't remove key", !store.find_key(cert), true); } - if(certs[4] != cert_key && certs[5] != cert_key) + return result; + } + catch(std::exception& e) + { + result.test_failure(e.what()); + return result; + } + } + +Test::Result test_certstor_sqlite3_crl_test(const std::vector<CertificateAndKey>& certsandkeys) + { + Test::Result result("Certificate Store SQLITE3 - CRL"); + try + { + auto& rng = Test::rng(); + const std::string passwd(reinterpret_cast<const char*>(rng.random_vec(8).data()), 8); + // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html) + Botan::Certificate_Store_In_SQLite store(":memory:", passwd, rng); + + for(const auto& a : certsandkeys) + store.insert_cert(a.certificate); + + store.revoke_cert(certsandkeys[0].certificate, Botan::CA_COMPROMISE); + store.revoke_cert(certsandkeys[3].certificate, Botan::CA_COMPROMISE); + store.revoke_cert(certsandkeys[3].certificate, Botan::CA_COMPROMISE); + { - result.test_eq("Got wrong certificate",cert.fingerprint(),wo_keyid->fingerprint()); + const auto crls = store.generate_crls(); + + result.test_eq("Can't revoke certificate", crls.size(), 2); + result.test_eq("Can't revoke certificate", + crls[0].is_revoked(certsandkeys[0].certificate) ^ crls[1].is_revoked(certsandkeys[0].certificate), true); + result.test_eq("Can't revoke certificate", + crls[0].is_revoked(certsandkeys[3].certificate) ^ crls[1].is_revoked(certsandkeys[3].certificate), true); } - - result.test_eq("Can't remove certificate",store.remove_cert(cert),true); - result.test_eq("Can't remove certificate",!store.find_cert(cert.subject_dn(),cert.subject_key_id()),true); - if(priv) + store.affirm_cert(certsandkeys[3].certificate); + { - store.remove_key(*key); + const auto crls = store.generate_crls(); + + result.test_eq("Can't revoke certificate, wrong crl size", crls.size(), 1); + result.test_eq("Can't revoke certificate, cert 0 not revoked", crls[0].is_revoked(certsandkeys[0].certificate), true); } - result.test_eq("Can't remove key",!store.find_key(cert),true); - } + const auto cert0_crl = store.find_crl_for(certsandkeys[0].certificate); - return result; - } + result.test_eq("Can't revoke certificate, crl for cert 0", !cert0_crl, false); + result.test_eq("Can't revoke certificate, crl for cert 0 size check", cert0_crl->get_revoked().size(), 1); + result.test_eq("Can't revoke certificate, no crl for cert 0", cert0_crl->is_revoked(certsandkeys[0].certificate), true); -Test::Result test_certstor_crl_test( - const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>& certs, - Botan::Certificate_Store_In_SQL& store) - { - Test::Result result("Certificate Store - CRL"); + const auto cert3_crl = store.find_crl_for(certsandkeys[3].certificate); + + result.test_eq("Can't revoke certificate, crl for cert 3", !cert3_crl, true); - store.revoke_cert(certs[0].first,Botan::CA_COMPROMISE); - store.revoke_cert(certs[3].first,Botan::CA_COMPROMISE); - store.revoke_cert(certs[3].first,Botan::CA_COMPROMISE); + return result; + } + catch(std::exception& e) + { + result.test_failure(e.what()); + return result; + } + } +Test::Result test_certstor_sqlite3_all_subjects_test(const std::vector<CertificateAndKey>& certsandkeys) { - auto crls = store.generate_crls(); + Test::Result result("Certificate Store SQLITE3 - All subjects"); + try + { + auto& rng = Test::rng(); + const std::string passwd(reinterpret_cast<const char*>(rng.random_vec(8).data()), 8); + // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html) + Botan::Certificate_Store_In_SQLite store(":memory:", passwd, rng); - result.test_eq("Can't revoke certificate",crls.size(),2); - result.test_eq("Can't revoke certificate",crls[0].is_revoked(certs[0].first) ^ crls[1].is_revoked(certs[0].first),true); - result.test_eq("Can't revoke certificate",crls[0].is_revoked(certs[3].first) ^ crls[1].is_revoked(certs[3].first),true); - } + for(const auto& a : certsandkeys) + store.insert_cert(a.certificate); - store.affirm_cert(certs[3].first); + const auto subjects = store.all_subjects(); - { - auto crls = store.generate_crls(); + result.test_eq("Check subject list length", subjects.size(), 6); - result.test_eq("Can't revoke certificate, wrong crl size",crls.size(),1); - result.test_eq("Can't revoke certificate, cert 0 not revoked",crls[0].is_revoked(certs[0].first),true); + for(const auto sub : subjects) + { + std::stringstream ss; + + ss << sub; + result.test_eq("Check subject " + ss.str(), + certsandkeys[0].certificate.subject_dn() == sub || + certsandkeys[1].certificate.subject_dn() == sub || + certsandkeys[2].certificate.subject_dn() == sub || + certsandkeys[3].certificate.subject_dn() == sub || + certsandkeys[4].certificate.subject_dn() == sub || + certsandkeys[5].certificate.subject_dn() == sub, + true); + } + return result; + } + catch(std::exception& e) + { + result.test_failure(e.what()); + return result; + } } - auto cert0_crl = store.find_crl_for(certs[0].first); +#endif - result.test_eq("Can't revoke certificate, crl for cert 0",!cert0_crl,false); - result.test_eq("Can't revoke certificate, crl for cert 0 size check",cert0_crl->get_revoked().size(),1); - result.test_eq("Can't revoke certificate, no crl for cert 0",cert0_crl->is_revoked(certs[0].first),true); +Test::Result test_certstor_find_hash_subject(const std::vector<CertificateAndKey>& certsandkeys) + { + Test::Result result("Certificate Store - Find by subject hash"); - auto cert3_crl = store.find_crl_for(certs[3].first); + try + { + Botan::Certificate_Store_In_Memory store; - result.test_eq("Can't revoke certificate, crl for cert 3",!cert3_crl,true); + for(const auto& a : certsandkeys) + store.add_certificate(a.certificate); - return result; - } + for(const auto certandkey : certsandkeys) + { + const auto cert = certandkey.certificate; + const auto hash = cert.raw_subject_dn_sha256(); -Test::Result test_certstor_all_subjects_test( - const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>& certs, - Botan::Certificate_Store_In_SQL& store) - { - Test::Result result("Certificate Store - All subjects"); + const auto found = store.find_cert_by_raw_subject_dn_sha256(hash); + if(!found) + { + result.test_failure("Can't retrieve certificate " + cert.fingerprint("SHA1")); + return result; + } - auto subjects = store.all_subjects(); - - result.test_eq("Check subject list length",subjects.size(),6); + result.test_eq("Got wrong certificate", hash, found->raw_subject_dn_sha256()); + } - for(auto sub: subjects) + const auto found = store.find_cert_by_raw_subject_dn_sha256(std::vector<uint8_t>(32,0)); + if(found) + { + result.test_failure("Certificate found for dummy hash"); + return result; + } + + return result; + } + catch(std::exception& e) { - std::stringstream ss; - - ss << sub; - result.test_eq("Check subject " + ss.str(), - certs[0].first.subject_dn() == sub || - certs[1].first.subject_dn() == sub || - certs[2].first.subject_dn() == sub || - certs[3].first.subject_dn() == sub || - certs[4].first.subject_dn() == sub || - certs[5].first.subject_dn() == sub,true); - + result.test_failure(e.what()); + return result; } - return result; } class Certstor_Tests : public Test { public: - std::vector<Test::Result> run() override + std::vector<Test::Result> run() override { const std::string test_dir = Test::data_dir() + "/certstor"; - const std::vector<std::pair<std::string,std::string>> test_data({ - std::make_pair("cert1.crt","key01.pem"), - std::make_pair("cert2.crt","key01.pem"), - std::make_pair("cert3.crt","key03.pem"), - std::make_pair("cert4.crt","key04.pem"), - std::make_pair("cert5a.crt","key05.pem"), - std::make_pair("cert5b.crt","key06.pem") - }); - - std::vector<Test::Result> results; - std::vector<std::pair<std::string,std::function<Test::Result( - const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>&, - Botan::Certificate_Store_In_SQL&)>>> - fns({ - std::make_pair("Certificate Store - Insert, Find, Remove",test_certstor_insert_find_remove_test), - std::make_pair("Certificate Store - CRL",test_certstor_crl_test), - std::make_pair("Certificate Store - All subjects",test_certstor_all_subjects_test) - }); + struct CertificateAndKeyFilenames + { + const std::string certificate; + const std::string private_key; + } const certsandkeys_filenames[] + { + {"cert1.crt", "key01.pem"}, + {"cert2.crt", "key01.pem"}, + {"cert3.crt", "key03.pem"}, + {"cert4.crt", "key04.pem"}, + {"cert5a.crt", "key05.pem"}, + {"cert5b.crt", "key06.pem"}, + }; try { @@ -200,53 +293,38 @@ class Certstor_Tests : public Test return {result}; } - for(auto fn: fns) - { - Test::Result result(fn.first); - - try - { - auto& rng = Test::rng(); - std::string passwd(reinterpret_cast<const char*>(rng.random_vec(8).data()),8); - - // Just create a database in memory for testing (https://sqlite.org/inmemorydb.html) - Botan::Certificate_Store_In_SQLite store(":memory:", passwd, rng); - std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>> retrieve; - - for(auto&& cert_key_pair : test_data) - { - Botan::X509_Certificate cert(test_dir + "/" + cert_key_pair.first); - std::shared_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(test_dir + "/" + cert_key_pair.second,rng)); - - if(!key) - { - result.test_failure("Failed to load key from disk"); - results.push_back(fn.second(retrieve,store)); - continue; - } + auto& rng = Test::rng(); + std::vector<CertificateAndKey> certsandkeys; + for(const auto& certandkey_filenames : certsandkeys_filenames) + { + const Botan::X509_Certificate certificate(test_dir + "/" + certandkey_filenames.certificate); + std::shared_ptr<Botan::Private_Key> private_key(Botan::PKCS8::load_key(test_dir + "/" + + certandkey_filenames.private_key, rng)); - store.insert_cert(cert); - store.insert_key(cert,*key); - retrieve.push_back(std::make_pair(cert,key)); - } - - results.push_back(fn.second(retrieve,store)); - } - catch(std::exception& e) + if(!private_key) { - results.push_back(Test::Result::Failure("Certstor test '" + fn.first + "'", e.what())); + Test::Result result("Certificate Store"); + result.test_failure("Failed to load key from disk at path: " + test_dir + "/" + certandkey_filenames.private_key); + return {result}; } + + certsandkeys.push_back({certificate, private_key}); } + std::vector<Test::Result> results; + + results.push_back(test_certstor_find_hash_subject(certsandkeys)); +#if defined(BOTAN_HAS_CERTSTOR_SQLITE3) + results.push_back(test_certstor_sqlite3_insert_find_remove_test(certsandkeys)); + results.push_back(test_certstor_sqlite3_crl_test(certsandkeys)); + results.push_back(test_certstor_sqlite3_all_subjects_test(certsandkeys)); +#endif return results; } }; BOTAN_REGISTER_TEST("certstor", Certstor_Tests); - #endif - } - } |