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/lib | |
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/lib')
-rw-r--r-- | src/lib/x509/pkcs10.cpp | 53 | ||||
-rw-r--r-- | src/lib/x509/pkcs10.h | 11 | ||||
-rw-r--r-- | src/lib/x509/x509_ca.cpp | 14 | ||||
-rw-r--r-- | src/lib/x509/x509_ext.cpp | 67 | ||||
-rw-r--r-- | src/lib/x509/x509_ext.h | 23 | ||||
-rw-r--r-- | src/lib/x509/x509self.cpp | 4 | ||||
-rw-r--r-- | src/lib/x509/x509self.h | 6 |
7 files changed, 153 insertions, 25 deletions
diff --git a/src/lib/x509/pkcs10.cpp b/src/lib/x509/pkcs10.cpp index ccd22454b..bac220277 100644 --- a/src/lib/x509/pkcs10.cpp +++ b/src/lib/x509/pkcs10.cpp @@ -46,7 +46,7 @@ PKCS10_Request::PKCS10_Request(const std::vector<byte>& in) : } /* -* Deocde the CertificateRequestInfo +* Decode the CertificateRequestInfo */ void PKCS10_Request::force_decode() { @@ -120,11 +120,7 @@ void PKCS10_Request::handle_attribute(const Attribute& attr) } else if(attr.oid == OIDS::lookup("PKCS9.ExtensionRequest")) { - Extensions extensions; - value.decode(extensions).verify_end(); - - Data_Store issuer_info; - extensions.contents_to(m_info, issuer_info); + value.decode(m_extensions).verify_end(); } } @@ -175,7 +171,12 @@ AlternativeName PKCS10_Request::subject_alt_name() const */ Key_Constraints PKCS10_Request::constraints() const { - return Key_Constraints(m_info.get1_u32bit("X509v3.KeyUsage", NO_CONSTRAINTS)); + if(Certificate_Extension* ext = m_extensions.get(OIDS::lookup("X509v3.KeyUsage"))) + { + return dynamic_cast<Cert_Extension::Key_Usage&>(*ext).get_constraints(); + } + + return NO_CONSTRAINTS; } /* @@ -183,12 +184,12 @@ Key_Constraints PKCS10_Request::constraints() const */ std::vector<OID> PKCS10_Request::ex_constraints() const { - std::vector<std::string> oids = m_info.get("X509v3.ExtendedKeyUsage"); + if(Certificate_Extension* ext = m_extensions.get(OIDS::lookup("X509v3.ExtendedKeyUsage"))) + { + return dynamic_cast<Cert_Extension::Extended_Key_Usage&>(*ext).get_oids(); + } - std::vector<OID> result; - for(size_t i = 0; i != oids.size(); ++i) - result.push_back(OID(oids[i])); - return result; + return {}; } /* @@ -196,15 +197,37 @@ std::vector<OID> PKCS10_Request::ex_constraints() const */ bool PKCS10_Request::is_CA() const { - return (m_info.get1_u32bit("X509v3.BasicConstraints.is_ca") > 0); + if(Certificate_Extension* ext = m_extensions.get(OIDS::lookup("X509v3.BasicConstraints"))) + { + return dynamic_cast<Cert_Extension::Basic_Constraints&>(*ext).get_is_ca(); + } + + return false; } /* * Return the desired path limit (if any) */ -u32bit PKCS10_Request::path_limit() const +size_t PKCS10_Request::path_limit() const + { + if(Certificate_Extension* ext = m_extensions.get(OIDS::lookup("X509v3.BasicConstraints"))) + { + Cert_Extension::Basic_Constraints& basic_constraints = dynamic_cast<Cert_Extension::Basic_Constraints&>(*ext); + if(basic_constraints.get_is_ca()) + { + return basic_constraints.get_path_limit(); + } + } + + return 0; + } + +/* +* Return the X509v3 extensions +*/ +Extensions PKCS10_Request::extensions() const { - return m_info.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0); + return m_extensions; } } diff --git a/src/lib/x509/pkcs10.h b/src/lib/x509/pkcs10.h index c7a9ec300..2202b92a4 100644 --- a/src/lib/x509/pkcs10.h +++ b/src/lib/x509/pkcs10.h @@ -1,6 +1,7 @@ /* * PKCS #10 * (C) 1999-2007 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -10,6 +11,7 @@ #include <botan/x509_obj.h> #include <botan/x509_dn.h> +#include <botan/x509_ext.h> #include <botan/datastor.h> #include <botan/key_constraint.h> #include <botan/asn1_attribute.h> @@ -72,7 +74,7 @@ class BOTAN_DLL PKCS10_Request final : public X509_Object * in the BasicConstraints extension. * @return path limit */ - u32bit path_limit() const; + size_t path_limit() const; /** * Get the challenge password for this request @@ -81,6 +83,12 @@ class BOTAN_DLL PKCS10_Request final : public X509_Object std::string challenge_password() const; /** + * Get the X509v3 extensions. + * @return X509v3 extensions + */ + Extensions extensions() const; + + /** * Create a PKCS#10 Request from a data source. * @param source the data source providing the DER encoded request */ @@ -105,6 +113,7 @@ class BOTAN_DLL PKCS10_Request final : public X509_Object void handle_attribute(const Attribute&); Data_Store m_info; + Extensions m_extensions; }; } diff --git a/src/lib/x509/x509_ca.cpp b/src/lib/x509/x509_ca.cpp index 6aba7311c..ec56abc92 100644 --- a/src/lib/x509/x509_ca.cpp +++ b/src/lib/x509/x509_ca.cpp @@ -63,24 +63,24 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, constraints = req.constraints(); } - Extensions extensions; + Extensions extensions = req.extensions(); - extensions.add( + extensions.replace( new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()), true); if(constraints != NO_CONSTRAINTS) { - extensions.add(new Cert_Extension::Key_Usage(constraints), true); + extensions.replace(new Cert_Extension::Key_Usage(constraints), true); } - extensions.add(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id())); - extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key())); + extensions.replace(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id())); + extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key())); - extensions.add( + extensions.replace( new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); - extensions.add( + extensions.replace( new Cert_Extension::Extended_Key_Usage(req.ex_constraints())); return make_cert(m_signer, rng, m_ca_sig_algo, diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp index c22e9ebcb..f475c50c2 100644 --- a/src/lib/x509/x509_ext.cpp +++ b/src/lib/x509/x509_ext.cpp @@ -90,10 +90,52 @@ void Certificate_Extension::validate(const X509_Certificate&, const X509_Certifi void Extensions::add(Certificate_Extension* extn, bool critical) { + // sanity check: we don't want to have the same extension more than once + for(const auto& ext : m_extensions) + { + if(ext.first->oid_of() == extn->oid_of()) + { + throw Invalid_Argument(extn->oid_name() + " extension already present"); + } + } + + if(m_extensions_raw.count(extn->oid_of()) > 0) + { + throw Invalid_Argument(extn->oid_name() + " extension already present"); + } + m_extensions.push_back(std::make_pair(std::unique_ptr<Certificate_Extension>(extn), critical)); m_extensions_raw.emplace(extn->oid_of(), std::make_pair(extn->encode_inner(), critical)); } +void Extensions::replace(Certificate_Extension* extn, bool critical) + { + for(auto it = m_extensions.begin(); it != m_extensions.end(); ++it) + { + if(it->first->oid_of() == extn->oid_of()) + { + m_extensions.erase(it); + break; + } + } + + m_extensions.push_back(std::make_pair(std::unique_ptr<Certificate_Extension>(extn), critical)); + m_extensions_raw[extn->oid_of()] = std::make_pair(extn->encode_inner(), critical); + } + +Certificate_Extension* Extensions::get(const OID& oid) const + { + for(auto& ext : m_extensions) + { + if(ext.first->oid_of() == oid) + { + return ext.first.get(); + } + } + + return nullptr; + } + std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const { std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts; @@ -114,6 +156,7 @@ std::map<OID, std::pair<std::vector<byte>, bool>> Extensions::extensions_raw() c */ void Extensions::encode_into(DER_Encoder& to_object) const { + // encode any known extensions for(size_t i = 0; i != m_extensions.size(); ++i) { const Certificate_Extension* ext = m_extensions[i].first.get(); @@ -130,6 +173,30 @@ void Extensions::encode_into(DER_Encoder& to_object) const .end_cons(); } } + + // encode any unknown extensions + for(const auto& ext_raw : m_extensions_raw) + { + const bool is_critical = ext_raw.second.second; + const OID oid = ext_raw.first; + const std::vector<uint8_t> value = ext_raw.second.first; + + auto pos = std::find_if(std::begin(m_extensions), std::end(m_extensions), + [&oid](const std::pair<std::unique_ptr<Certificate_Extension>, bool>& ext) -> bool + { + return ext.first->oid_of() == oid; + }); + + if(pos == std::end(m_extensions)) + { + // not found in m_extensions, must be unknown + to_object.start_cons(SEQUENCE) + .encode(oid) + .encode_optional(is_critical, false) + .encode(value, OCTET_STRING) + .end_cons(); + } + } } /* diff --git a/src/lib/x509/x509_ext.h b/src/lib/x509/x509_ext.h index b1984fa94..ee7589ea5 100644 --- a/src/lib/x509/x509_ext.h +++ b/src/lib/x509/x509_ext.h @@ -92,6 +92,29 @@ class BOTAN_DLL Extensions : public ASN1_Object void contents_to(Data_Store&, Data_Store&) const; void add(Certificate_Extension* extn, bool critical = false); + void replace(Certificate_Extension* extn, bool critical = false); + + Certificate_Extension* get(const OID& oid) const; + + template<typename T> + std::unique_ptr<T> get_extension(const OID& oid) + { + try + { + if(m_extensions_raw.count(oid) > 0) + { + std::unique_ptr<T> ext(new T); + ext->decode_inner(m_extensions_raw[oid].first); + return std::move(ext); + } + } + catch(std::exception& e) + { + throw Decoding_Error("Exception while decoding extension " + + oid.as_string() + ": " + e.what()); + } + return nullptr; + } std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; diff --git a/src/lib/x509/x509self.cpp b/src/lib/x509/x509self.cpp index b59b45f6a..fe0336014 100644 --- a/src/lib/x509/x509self.cpp +++ b/src/lib/x509/x509self.cpp @@ -65,7 +65,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, constraints = opts.constraints; } - Extensions extensions; + Extensions extensions = opts.extensions; extensions.add( new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit), @@ -119,7 +119,7 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, constraints = opts.constraints; } - Extensions extensions; + Extensions extensions = opts.extensions; extensions.add( new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit)); diff --git a/src/lib/x509/x509self.h b/src/lib/x509/x509self.h index 401b2eb2f..008eece51 100644 --- a/src/lib/x509/x509self.h +++ b/src/lib/x509/x509self.h @@ -9,6 +9,7 @@ #define BOTAN_X509_SELF_H__ #include <botan/x509cert.h> +#include <botan/x509_ext.h> #include <botan/pkcs10.h> #include <botan/asn1_time.h> @@ -115,6 +116,11 @@ class BOTAN_DLL X509_Cert_Options std::vector<OID> ex_constraints; /** + * Additional X.509 extensions + */ + Extensions extensions; + + /** * Mark the certificate as a CA certificate and set the path limit. * @param limit the path limit to be set in the BasicConstraints extension. */ |