aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorRené Korthaus <[email protected]>2016-09-05 11:01:42 +0200
committerRené Korthaus <[email protected]>2016-12-02 11:01:59 +0100
commite8b3e26f4167524216718204c6b5a14ed0e7942d (patch)
tree12e4469750d81a565185212766c0d51a7312ea4d /src/lib
parent5c49dbac212e53be821b0771d3df46f78801efbe (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.cpp53
-rw-r--r--src/lib/x509/pkcs10.h11
-rw-r--r--src/lib/x509/x509_ca.cpp14
-rw-r--r--src/lib/x509/x509_ext.cpp67
-rw-r--r--src/lib/x509/x509_ext.h23
-rw-r--r--src/lib/x509/x509self.cpp4
-rw-r--r--src/lib/x509/x509self.h6
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.
*/