diff options
author | René Korthaus <[email protected]> | 2016-09-05 11:01:42 +0200 |
---|---|---|
committer | René Korthaus <[email protected]> | 2016-12-02 11:01:59 +0100 |
commit | e8b3e26f4167524216718204c6b5a14ed0e7942d (patch) | |
tree | 12e4469750d81a565185212766c0d51a7312ea4d /src/tests | |
parent | 5c49dbac212e53be821b0771d3df46f78801efbe (diff) |
Allow custom extensions in X509_Cert_Options
Allow custom extensions in CA-signed cert requests
Add templated getter for extensions
Diffstat (limited to 'src/tests')
-rw-r--r-- | src/tests/unit_x509.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp index 7a22033a8..ceed26c75 100644 --- a/src/tests/unit_x509.cpp +++ b/src/tests/unit_x509.cpp @@ -17,6 +17,8 @@ #include <botan/x509path.h> #include <botan/x509_ca.h> #include <botan/pk_algs.h> +#include <botan/ber_dec.h> +#include <botan/der_enc.h> #endif @@ -710,6 +712,117 @@ Test::Result test_valid_constraints(const std::string& pk_algo) return result; } +/** + * @brief X.509v3 extension that encodes a given string + */ +class String_Extension : public Botan::Certificate_Extension + { + public: + String_Extension(const Botan::OID& oid, const std::string& val) : m_oid(oid), m_contents(val) {} + + std::string value() const { return m_contents; } + + String_Extension* copy() const override { return new String_Extension(m_oid, m_contents); } + + Botan::OID oid_of() const override { return m_oid; } + std::string oid_name() const override { return "String Extension"; } + + void contents_to(Botan::Data_Store&, Botan::Data_Store&) const override {} + + std::vector<byte> encode_inner() const override + { + return Botan::DER_Encoder().encode(Botan::ASN1_String(m_contents, Botan::UTF8_STRING)).get_contents_unlocked(); + } + + void decode_inner(const std::vector<byte>& in) override + { + Botan::ASN1_String str; + Botan::BER_Decoder(in).decode(str, Botan::UTF8_STRING).verify_end(); + m_contents = str.value(); + } + + private: + Botan::OID m_oid; + std::string m_contents; + }; + +Test::Result test_x509_extensions(const std::string& sig_algo, const std::string& hash_fn = "SHA-256") + { + using Botan::Key_Constraints; + + Test::Result result("X509 Extensions"); + + /* Create the CA's key and self-signed cert */ + std::unique_ptr<Botan::Private_Key> ca_key(make_a_private_key(sig_algo)); + + if(!ca_key) + { + // Failure because X.509 enabled but requested signature algorithm is not present + result.test_note("Skipping due to missing signature algorithm: " + sig_algo); + return result; + } + + /* Create the self-signed cert */ + Botan::X509_Certificate ca_cert = + Botan::X509::create_self_signed_cert(ca_opts(), + *ca_key, + hash_fn, + Test::rng()); + + /* Create the CA object */ + Botan::X509_CA ca(ca_cert, *ca_key, hash_fn); + + std::unique_ptr<Botan::Private_Key> user_key(make_a_private_key(sig_algo)); + + Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing"); + opts.constraints = Key_Constraints::DIGITAL_SIGNATURE; + + // include a custom extension in the request + Botan::Extensions req_extensions; + Botan::OID oid("1.2.3.4.5.6.7.8.9.1"); + req_extensions.add(new String_Extension(oid, "1Test"), false); + opts.extensions = req_extensions; + + /* Create a self-signed certificate */ + Botan::X509_Certificate self_signed_cert = Botan::X509::create_self_signed_cert(opts, *user_key, hash_fn, Test::rng()); + + // check if custom extension is present in cert + // it would be nice if we could use v3_extensions().extensions() instead + auto ext_raw = self_signed_cert.v3_extensions().extensions_raw(); + if(result.confirm("Custom extension present in self-signed certificate", ext_raw.count(oid) > 0)) + { + std::vector<byte> in = ext_raw.at(oid).first; + String_Extension ext(oid, ""); + ext.decode_inner(in); + + result.confirm("Custom extension value matches in self-signed certificate", ext.value() == "1Test"); + } + + + Botan::PKCS10_Request user_req = + Botan::X509::create_cert_req(opts, + *user_key, + hash_fn, + Test::rng()); + + /* Create a CA-signed certificate */ + Botan::X509_Certificate user_cert = + ca.sign_request(user_req, Test::rng(), + from_date(2008, 01, 01), + from_date(2033, 01, 01)); + + ext_raw = user_cert.v3_extensions().extensions_raw(); + if(result.confirm("Custom extension present in user certificate", ext_raw.count(oid) > 0)) + { + std::vector<byte> in = ext_raw.at(oid).first; + String_Extension ext(oid, ""); + ext.decode_inner(in); + + result.confirm("Custom extension value matches in user certificate", ext.value() == "1Test"); + } + + return result; + } class X509_Cert_Unit_Tests : public Test { @@ -722,6 +835,7 @@ class X509_Cert_Unit_Tests : public Test Test::Result cert_result("X509 Unit"); Test::Result usage_result("X509 Usage"); Test::Result self_issued_result("X509 Self Issued"); + Test::Result extensions_result("X509 Extensions"); for(const auto& algo : sig_algos) { @@ -748,11 +862,20 @@ class X509_Cert_Unit_Tests : public Test { self_issued_result.test_failure("test_self_issued " + algo, e.what()); } + + try { + extensions_result.merge(test_x509_extensions(algo)); + } + catch(std::exception& e) + { + extensions_result.test_failure("test_extensions " + algo, e.what()); + } } results.push_back(cert_result); results.push_back(usage_result); results.push_back(self_issued_result); + results.push_back(extensions_result); const std::vector<std::string> pk_algos { "DH", "ECDH", "RSA", "ElGamal", "GOST-34.10", "DSA", "ECDSA", "ECGDSA", "ECKCDSA" }; |