diff options
Diffstat (limited to 'src/tests/unit_x509.cpp')
-rw-r--r-- | src/tests/unit_x509.cpp | 333 |
1 files changed, 205 insertions, 128 deletions
diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp index 0d3946012..08ed5b578 100644 --- a/src/tests/unit_x509.cpp +++ b/src/tests/unit_x509.cpp @@ -8,8 +8,6 @@ #if defined(BOTAN_HAS_X509_CERTIFICATES) -#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_DSA) - #include <botan/calendar.h> #include <botan/pkcs8.h> #include <botan/hash.h> @@ -30,34 +28,24 @@ #include <botan/ecdsa.h> #endif -#include <iostream> -#include <memory> +#endif -using namespace Botan; +namespace Botan_Tests { namespace { -X509_Time from_date(const int y, const int m, const int d) - { - auto t = calendar_point(y, m, d, 0, 0, 0); - return X509_Time(t.to_std_timepoint()); - } +#if defined(BOTAN_HAS_X509_CERTIFICATES) -u64bit key_id(const Public_Key* key) +Botan::X509_Time from_date(const int y, const int m, const int d) { - std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-1")); - hash->update(key->algo_name()); - hash->update(key->algorithm_identifier().parameters); - hash->update(key->x509_subject_public_key()); - secure_vector<byte> output = hash->final(); - return load_be<u64bit>(output.data(), 0); + Botan::calendar_point t(y, m, d, 0, 0, 0); + return Botan::X509_Time(t.to_std_timepoint()); } - /* Return some option sets */ -X509_Cert_Options ca_opts() +Botan::X509_Cert_Options ca_opts() { - X509_Cert_Options opts("Test CA/US/Botan Project/Testing"); + Botan::X509_Cert_Options opts("Test CA/US/Botan Project/Testing"); opts.uri = "http://botan.randombit.net"; opts.dns = "botan.randombit.net"; @@ -68,9 +56,9 @@ X509_Cert_Options ca_opts() return opts; } -X509_Cert_Options req_opts1() +Botan::X509_Cert_Options req_opts1() { - X509_Cert_Options opts("Test User 1/US/Botan Project/Testing"); + Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing"); opts.uri = "http://botan.randombit.net"; opts.dns = "botan.randombit.net"; @@ -79,9 +67,9 @@ X509_Cert_Options req_opts1() return opts; } -X509_Cert_Options req_opts2() +Botan::X509_Cert_Options req_opts2() { - X509_Cert_Options opts("Test User 2/US/Botan Project/Testing"); + Botan::X509_Cert_Options opts("Test User 2/US/Botan Project/Testing"); opts.uri = "http://botan.randombit.net"; opts.dns = "botan.randombit.net"; @@ -92,164 +80,253 @@ X509_Cert_Options req_opts2() return opts; } -u32bit check_against_copy(const Private_Key& orig, - RandomNumberGenerator& rng) +std::unique_ptr<Botan::Private_Key> make_a_private_key() { - 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 defined(BOTAN_HAS_DSA) + if(Test::rng().next_byte() < 32) + { + Botan::DL_Group grp("dsa/botan/2048"); + return std::unique_ptr<Botan::Private_Key>(new Botan::DSA_PrivateKey(Test::rng(), grp)); + } +#endif - if(orig_id != pub_id || orig_id != priv_id || orig_id != priv_enc_id) +#if defined(BOTAN_HAS_RSA) + if(Test::rng().next_byte() < 32) { - std::cout << "Failed copy check for " << orig.algo_name() << std::endl; - return 1; + return std::unique_ptr<Botan::Private_Key>(new Botan::RSA_PrivateKey(Test::rng(), 1536)); } - return 0; - } +#endif -} +#if defined(BOTAN_HAS_ECDSA) + Botan::EC_Group grp("secp256r1"); + return std::unique_ptr<Botan::Private_Key>(new Botan::ECDSA_PrivateKey(Test::rng(), grp)); +#endif -size_t test_x509() + throw std::runtime_error("Skipping X.509 cert test due to missing algos"); + } + +class X509_Cert_Unit_Tests : public Test { - auto& rng = test_rng(); - const std::string hash_fn = "SHA-256"; + public: + std::vector<Test::Result> run() override; + + private: + Test::Result test_x509_dates() + { + Test::Result result("X509_Time"); + + Botan::X509_Time time; + result.confirm("unset time not set", !time.time_is_set()); + time = Botan::X509_Time("0802011822Z", Botan::ASN1_Tag::UTC_TIME); + result.confirm("time set after construction", time.time_is_set()); + result.test_eq("time readable_string", time.readable_string(), "2008/02/01 18:22:00 UTC"); + + const std::vector<std::string> valid = { + "0802010000Z", + "0802011724Z", + "0406142334Z", + "9906142334Z", + "0006142334Z", + + "080201000000Z", + "080201172412Z", + "040614233433Z", + "990614233444Z", + "000614233455Z", + }; + + // Dates that are valid per X.500 but rejected as unsupported + const std::vector<std::string> valid_but_unsup = { + "0802010000-0000", + "0802011724+0000", + "0406142334-0500", + "9906142334+0500", + "0006142334-0530", + "0006142334+0530", + + "080201000000-0000", + "080201172412+0000", + "040614233433-0500", + "990614233444+0500", + "000614233455-0530", + "000614233455+0530", + }; + + const std::vector<std::string> invalid = { + "", + " ", + "2008`02-01", + "9999-02-01", + "2000-02-01 17", + "999921", + + // valid length 13 -> range check + "080201000061Z", // seconds too big (61) + "080201000060Z", // seconds too big (60, leap seconds not covered by the standard) + "0802010000-1Z", // seconds too small (-1) + "080201006000Z", // minutes too big (60) + "080201240000Z", // hours too big (24:00) + + // valid length 13 -> invalid numbers + "08020123112 Z", + "08020123112!Z", + "08020123112,Z", + "08020123112\nZ", + "080201232 33Z", + "080201232!33Z", + "080201232,33Z", + "080201232\n33Z", + "0802012 3344Z", + "0802012!3344Z", + "0802012,3344Z", + "08022\n334455Z", + "08022 334455Z", + "08022!334455Z", + "08022,334455Z", + "08022\n334455Z", + "082 33445511Z", + "082!33445511Z", + "082,33445511Z", + "082\n33445511Z", + "2 2211221122Z", + "2!2211221122Z", + "2,2211221122Z", + "2\n2211221122Z", + + // wrong time zone + "0802010000", + "0802010000z" + }; + + for(auto&& v : valid) + { + Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); + } + + for(auto&& v : valid_but_unsup) + { + result.test_throws("valid but unsupported", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); }); + } + + for(auto&& v : invalid) + { + result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); }); + } + + return result; + } + }; + +std::vector<Test::Result> X509_Cert_Unit_Tests::run() + { + std::vector<Test::Result> results; + Test::Result result("X509 Unit"); - size_t fails = 0; + const std::string hash_fn = "SHA-256"; /* Create the CA's key and self-signed cert */ - RSA_PrivateKey ca_key(rng, 2048); + std::unique_ptr<Botan::Private_Key> ca_key(make_a_private_key()); + + Botan::X509_Certificate ca_cert = + Botan::X509::create_self_signed_cert(ca_opts(), + *ca_key, + hash_fn, + Test::rng()); - X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(), - ca_key, - hash_fn, - rng); /* Create user #1's key and cert request */ - DSA_PrivateKey user1_key(rng, DL_Group("dsa/botan/2048")); + std::unique_ptr<Botan::Private_Key> user1_key(make_a_private_key()); - PKCS10_Request user1_req = X509::create_cert_req(req_opts1(), - user1_key, - "SHA-1", - rng); + Botan::PKCS10_Request user1_req = + Botan::X509::create_cert_req(req_opts1(), + *user1_key, + hash_fn, + Test::rng()); /* Create user #2's key and cert request */ -#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::unique_ptr<Botan::Private_Key> user2_key(make_a_private_key()); - PKCS10_Request user2_req = X509::create_cert_req(req_opts2(), - user2_key, - hash_fn, - rng); + Botan::PKCS10_Request user2_req = + Botan::X509::create_cert_req(req_opts2(), + *user2_key, + hash_fn, + Test::rng()); /* Create the CA object */ - X509_CA ca(ca_cert, ca_key, hash_fn); + Botan::X509_CA ca(ca_cert, *ca_key, hash_fn); /* Sign the requests to create the certs */ - X509_Certificate user1_cert = - ca.sign_request(user1_req, rng, - from_date(2008, 01, 01), from_date(2033, 01, 01)); + Botan::X509_Certificate user1_cert = + ca.sign_request(user1_req, Test::rng(), + from_date(2008, 01, 01), + from_date(2033, 01, 01)); - X509_Certificate user2_cert = ca.sign_request(user2_req, rng, + Botan::X509_Certificate user2_cert = ca.sign_request(user2_req, Test::rng(), from_date(2008, 01, 01), from_date(2033, 01, 01)); - X509_CRL crl1 = ca.new_crl(rng); + Botan::X509_CRL crl1 = ca.new_crl(Test::rng()); /* Verify the certs */ - Certificate_Store_In_Memory store; + Botan::Certificate_Store_In_Memory store; store.add_certificate(ca_cert); - Path_Validation_Restrictions restrictions(false); + Botan::Path_Validation_Restrictions restrictions(false); - Path_Validation_Result result_u1 = x509_path_validate(user1_cert, restrictions, store); - if(!result_u1.successful_validation()) + Botan::Path_Validation_Result result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store); + if(!result.confirm("user 1 validates", result_u1.successful_validation())) { - std::cout << "FAILED: User cert #1 did not validate - " - << result_u1.result_string() << std::endl; - ++fails; + result.test_note("user 1 validation result was " + result_u1.result_string()); } - Path_Validation_Result result_u2 = x509_path_validate(user2_cert, restrictions, store); - if(!result_u2.successful_validation()) + Botan::Path_Validation_Result result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store); + if(!result.confirm("user 2 validates", result_u2.successful_validation())) { - std::cout << "FAILED: User cert #2 did not validate - " - << result_u2.result_string() << std::endl; - ++fails; + result.test_note("user 2 validation result was " + result_u2.result_string()); } store.add_crl(crl1); - std::vector<CRL_Entry> revoked; - revoked.push_back(CRL_Entry(user1_cert, CESSATION_OF_OPERATION)); + std::vector<Botan::CRL_Entry> revoked; + revoked.push_back(Botan::CRL_Entry(user1_cert, Botan::CESSATION_OF_OPERATION)); revoked.push_back(user2_cert); - X509_CRL crl2 = ca.update_crl(crl1, revoked, rng); + Botan::X509_CRL crl2 = ca.update_crl(crl1, revoked, Test::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; - ++fails; - } + const std::string revoked_str = + Botan::Path_Validation_Result::status_string(Botan::Certificate_Status_Code::CERT_IS_REVOKED); - 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; - ++fails; - } + result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store); + result.test_eq("user 1 revoked", result_u1.result_string(), revoked_str); + + result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store); + result.test_eq("user 1 revoked", result_u2.result_string(), revoked_str); revoked.clear(); - revoked.push_back(CRL_Entry(user1_cert, REMOVE_FROM_CRL)); - X509_CRL crl3 = ca.update_crl(crl2, revoked, rng); + revoked.push_back(Botan::CRL_Entry(user1_cert, Botan::REMOVE_FROM_CRL)); + Botan::X509_CRL crl3 = ca.update_crl(crl2, revoked, Test::rng()); store.add_crl(crl3); - result_u1 = x509_path_validate(user1_cert, restrictions, store); - if(!result_u1.successful_validation()) + result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store); + if(!result.confirm("user 1 validates", result_u1.successful_validation())) { - std::cout << "FAILED: User cert #1 was not un-revoked - " - << result_u1.result_string() << std::endl; - ++fails; + result.test_note("user 1 validation result was " + result_u1.result_string()); } - check_against_copy(ca_key, rng); - check_against_copy(user1_key, rng); - check_against_copy(user2_key, rng); + result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store); + result.test_eq("user 2 still revoked", result_u2.result_string(), revoked_str); - test_report("X509", 0, fails); - - return fails; + results.push_back(result); + results.push_back(test_x509_dates()); + return results; } -#else - -UNTESTED_WARNING(x509); +BOTAN_REGISTER_TEST("unit_x509", X509_Cert_Unit_Tests); -#endif // BOTAN_HAS_RSA && BOTAN_HAS_DSA - -#else +#endif -SKIP_TEST(x509); +} -#endif // BOTAN_HAS_X509_CERTIFICATES +} |