aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/x509
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-11-14 09:19:50 -0500
committerJack Lloyd <[email protected]>2017-11-14 16:19:44 -0500
commitaf1158dd7707d09bcaf47fa78868d0cedf99c0e1 (patch)
tree088aa218604232611d5c0f9b092a88c507732aba /src/lib/x509
parentdbcdaa424c98ad10ff9657f3574c130a11139228 (diff)
Refactor certificate extension handling
Diffstat (limited to 'src/lib/x509')
-rw-r--r--src/lib/x509/x509_ext.cpp383
-rw-r--r--src/lib/x509/x509_ext.h332
2 files changed, 441 insertions, 274 deletions
diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp
index 6e4c29d42..682cc1cc7 100644
--- a/src/lib/x509/x509_ext.cpp
+++ b/src/lib/x509/x509_ext.cpp
@@ -8,10 +8,11 @@
#include <botan/x509_ext.h>
#include <botan/x509cert.h>
-#include <botan/sha160.h>
+#include <botan/datastor.h>
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/oids.h>
+#include <botan/hash.h>
#include <botan/internal/bit_ops.h>
#include <algorithm>
#include <sstream>
@@ -19,138 +20,177 @@
namespace Botan {
/*
-* List of X.509 Certificate Extensions
+* Create a Certificate_Extension object of some kind to handle
*/
-Certificate_Extension* Extensions::create_extension(const OID& oid, bool critical)
+Certificate_Extension*
+Extensions::create_extn_obj(const OID& oid,
+ bool critical,
+ const std::vector<uint8_t>& body)
{
-#define X509_EXTENSION(NAME, TYPE) \
- if(oid == OIDS::lookup(NAME)) { return new Cert_Extension::TYPE(); }
+ const std::string oid_str = oid.as_string();
- X509_EXTENSION("X509v3.KeyUsage", Key_Usage);
- X509_EXTENSION("X509v3.BasicConstraints", Basic_Constraints);
- X509_EXTENSION("X509v3.SubjectKeyIdentifier", Subject_Key_ID);
- X509_EXTENSION("X509v3.AuthorityKeyIdentifier", Authority_Key_ID);
- X509_EXTENSION("X509v3.ExtendedKeyUsage", Extended_Key_Usage);
- X509_EXTENSION("X509v3.IssuerAlternativeName", Issuer_Alternative_Name);
- X509_EXTENSION("X509v3.SubjectAlternativeName", Subject_Alternative_Name);
- X509_EXTENSION("X509v3.NameConstraints", Name_Constraints);
- X509_EXTENSION("X509v3.CertificatePolicies", Certificate_Policies);
- X509_EXTENSION("X509v3.CRLDistributionPoints", CRL_Distribution_Points);
- X509_EXTENSION("PKIX.AuthorityInformationAccess", Authority_Information_Access);
- X509_EXTENSION("X509v3.CRLNumber", CRL_Number);
- X509_EXTENSION("X509v3.ReasonCode", CRL_ReasonCode);
+ Certificate_Extension* extn = nullptr;
- return critical ? new Cert_Extension::Unknown_Critical_Extension(oid) : nullptr;
+ if(oid == Cert_Extension::Subject_Key_ID::static_oid())
+ {
+ extn = new Cert_Extension::Subject_Key_ID;
+ }
+ else if(oid == Cert_Extension::Key_Usage::static_oid())
+ {
+ extn = new Cert_Extension::Key_Usage;
+ }
+ else if(oid == Cert_Extension::Subject_Alternative_Name::static_oid())
+ {
+ extn = new Cert_Extension::Subject_Alternative_Name;
+ }
+ else if(oid == Cert_Extension::Issuer_Alternative_Name::static_oid())
+ {
+ extn = new Cert_Extension::Issuer_Alternative_Name;
+ }
+ else if(oid == Cert_Extension::Basic_Constraints::static_oid())
+ {
+ extn = new Cert_Extension::Basic_Constraints;
+ }
+ else if(oid == Cert_Extension::CRL_Number::static_oid())
+ {
+ extn = new Cert_Extension::CRL_Number;
+ }
+ else if(oid == Cert_Extension::CRL_ReasonCode::static_oid())
+ {
+ extn = new Cert_Extension::CRL_ReasonCode;
+ }
+ else if(oid == Cert_Extension::Authority_Key_ID::static_oid())
+ {
+ extn = new Cert_Extension::Authority_Key_ID;
+ }
+ else if(oid == Cert_Extension::Name_Constraints::static_oid())
+ {
+ extn = new Cert_Extension::Name_Constraints;
+ }
+ else if(oid == Cert_Extension::CRL_Distribution_Points::static_oid())
+ {
+ extn = new Cert_Extension::CRL_Distribution_Points;
+ }
+ else if(oid == Cert_Extension::Certificate_Policies::static_oid())
+ {
+ extn = new Cert_Extension::Certificate_Policies;
+ }
+ else if(oid == Cert_Extension::Extended_Key_Usage::static_oid())
+ {
+ extn = new Cert_Extension::Extended_Key_Usage;
+ }
+ else if(oid == Cert_Extension::Authority_Information_Access::static_oid())
+ {
+ extn = new Cert_Extension::Authority_Information_Access;
+ }
+ else
+ {
+ // some other unknown extension type
+ extn = new Cert_Extension::Unknown_Extension(oid, critical);
+ }
+
+ try
+ {
+ extn->decode_inner(body);
+ }
+ catch(Decoding_Error& e)
+ {
+ throw Decoding_Error("Decoding X.509 extension " + oid.as_string() + " failed", e.what());
+ }
+ return extn;
}
/*
-* Extensions Copy Constructor
+* Validate the extension (the default implementation is a NOP)
*/
-Extensions::Extensions(const Extensions& extensions) : ASN1_Object()
+void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&,
+ const std::vector<std::shared_ptr<const X509_Certificate>>&,
+ std::vector<std::set<Certificate_Status_Code>>&,
+ size_t)
{
- *this = extensions;
}
/*
-* Extensions Assignment Operator
+* Add a new cert
*/
-Extensions& Extensions::operator=(const Extensions& other)
+void Extensions::add(Certificate_Extension* extn, bool critical)
{
- if(this == &other)
- return *this;
-
- m_extensions.clear();
-
- for(size_t i = 0; i != other.m_extensions.size(); ++i)
- m_extensions.push_back(
- std::make_pair(std::unique_ptr<Certificate_Extension>(other.m_extensions[i].first->copy()),
- other.m_extensions[i].second));
-
- m_extensions_raw = other.m_extensions_raw;
- m_throw_on_unknown_critical = other.m_throw_on_unknown_critical;
+ // sanity check: we don't want to have the same extension more than once
+ if(m_extension_info.count(extn->oid_of()) > 0)
+ throw Invalid_Argument(extn->oid_name() + " extension already present in Extensions::add");
- return (*this);
+ const OID oid = extn->oid_of();
+ Extensions_Info info(critical, extn);
+ m_extension_oids.push_back(oid);
+ m_extension_info.emplace(oid, info);
}
-/*
-* Return the OID of this extension
-*/
-OID Certificate_Extension::oid_of() const
+void Extensions::replace(Certificate_Extension* extn, bool critical)
{
- return OIDS::lookup(oid_name());
+ // Remove it if it existed
+ m_extension_info.erase(extn->oid_of());
+
+ const OID oid = extn->oid_of();
+ Extensions_Info info(critical, extn);
+ m_extension_oids.push_back(oid);
+ m_extension_info.emplace(oid, info);
}
-/*
-* Validate the extension (the default implementation is a NOP)
-*/
-void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&,
- const std::vector<std::shared_ptr<const X509_Certificate>>&,
- std::vector<std::set<Certificate_Status_Code>>&,
- size_t)
+bool Extensions::extension_set(const OID& oid) const
{
+ return (m_extension_info.find(oid) != m_extension_info.end());
}
-void Extensions::add(Certificate_Extension* extn, bool critical)
+bool Extensions::critical_extension_set(const OID& oid) const
{
- // 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));
+ auto i = m_extension_info.find(oid);
+ if(i != m_extension_info.end())
+ return i->second.is_critical();
+ return false;
}
-void Extensions::replace(Certificate_Extension* extn, bool critical)
+const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const
{
- for(auto it = m_extensions.begin(); it != m_extensions.end(); ++it)
- {
- if(it->first->oid_of() == extn->oid_of())
- {
- m_extensions.erase(it);
- break;
- }
- }
+ auto extn = m_extension_info.find(oid);
+ if(extn == m_extension_info.end())
+ return nullptr;
- 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);
+ return &extn->second.obj();
}
std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const
{
- for(auto& ext : m_extensions)
+ if(const Certificate_Extension* ext = this->get_extension_object(oid))
{
- if(ext.first->oid_of() == oid)
- {
- return std::unique_ptr<Certificate_Extension>(ext.first->copy());
- }
+ return std::unique_ptr<Certificate_Extension>(ext->copy());
}
-
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;
- for(auto& ext : m_extensions)
+ for(auto&& ext : m_extension_info)
{
- exts.push_back(std::make_pair(std::unique_ptr<Certificate_Extension>(ext.first->copy()), ext.second));
+ exts.push_back(
+ std::make_pair(
+ std::unique_ptr<Certificate_Extension>(ext.second.obj().copy()),
+ ext.second.is_critical())
+ );
}
return exts;
}
std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw() const
{
- return m_extensions_raw;
+ std::map<OID, std::pair<std::vector<uint8_t>, bool>> out;
+ for(auto&& ext : m_extension_info)
+ {
+ out.emplace(ext.first,
+ std::make_pair(ext.second.bits(),
+ ext.second.is_critical()));
+ }
+ return out;
}
/*
@@ -158,44 +198,20 @@ std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw(
*/
void Extensions::encode_into(DER_Encoder& to_object) const
{
- // encode any known extensions
- for(size_t i = 0; i != m_extensions.size(); ++i)
+ for(auto ext_info : m_extension_info)
{
- const Certificate_Extension* ext = m_extensions[i].first.get();
- const bool is_critical = m_extensions[i].second;
-
- const bool should_encode = ext->should_encode();
+ const OID& oid = ext_info.first;
+ const bool should_encode = ext_info.second.obj().should_encode();
if(should_encode)
{
- to_object.start_cons(SEQUENCE)
- .encode(ext->oid_of())
- .encode_optional(is_critical, false)
- .encode(ext->encode_inner(), OCTET_STRING)
- .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;
- });
+ const bool is_critical = ext_info.second.is_critical();
+ const std::vector<uint8_t>& ext_value = ext_info.second.bits();
- 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)
+ .encode(ext_value, OCTET_STRING)
.end_cons();
}
}
@@ -206,47 +222,29 @@ void Extensions::encode_into(DER_Encoder& to_object) const
*/
void Extensions::decode_from(BER_Decoder& from_source)
{
- m_extensions.clear();
- m_extensions_raw.clear();
+ m_extension_oids.clear();
+ m_extension_info.clear();
BER_Decoder sequence = from_source.start_cons(SEQUENCE);
while(sequence.more_items())
{
OID oid;
- std::vector<uint8_t> value;
bool critical;
+ std::vector<uint8_t> bits;
sequence.start_cons(SEQUENCE)
- .decode(oid)
- .decode_optional(critical, BOOLEAN, UNIVERSAL, false)
- .decode(value, OCTET_STRING)
- .end_cons();
-
- m_extensions_raw.emplace(oid, std::make_pair(value, critical));
-
- std::unique_ptr<Certificate_Extension> ext(create_extension(oid, critical));
+ .decode(oid)
+ .decode_optional(critical, BOOLEAN, UNIVERSAL, false)
+ .decode(bits, OCTET_STRING)
+ .end_cons();
- if(!ext && critical && m_throw_on_unknown_critical)
- throw Decoding_Error("Encountered unknown X.509 extension marked "
- "as critical; OID = " + oid.as_string());
+ Extensions_Info info(critical, bits,
+ create_extn_obj(oid, critical, bits));
- if(ext)
- {
- try
- {
- ext->decode_inner(value);
- }
- catch(std::exception& e)
- {
- throw Decoding_Error("Exception while decoding extension " +
- oid.as_string() + ": " + e.what());
- }
-
- m_extensions.push_back(std::make_pair(std::move(ext), critical));
- }
+ m_extension_oids.push_back(oid);
+ m_extension_info.emplace(oid, info);
}
-
sequence.verify_end();
}
@@ -256,14 +254,14 @@ void Extensions::decode_from(BER_Decoder& from_source)
void Extensions::contents_to(Data_Store& subject_info,
Data_Store& issuer_info) const
{
- for(size_t i = 0; i != m_extensions.size(); ++i)
+ for(auto&& m_extn_info : m_extension_info)
{
- m_extensions[i].first->contents_to(subject_info, issuer_info);
- subject_info.add(m_extensions[i].first->oid_name() + ".is_critical", (m_extensions[i].second ? 1 : 0));
+ m_extn_info.second.obj().contents_to(subject_info, issuer_info);
+ subject_info.add(m_extn_info.second.obj().oid_name() + ".is_critical",
+ m_extn_info.second.is_critical());
}
}
-
namespace Cert_Extension {
/*
@@ -402,8 +400,15 @@ void Subject_Key_ID::contents_to(Data_Store& subject, Data_Store&) const
/*
* Subject_Key_ID Constructor
*/
-Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key) : m_key_id(unlock(SHA_160().process(pub_key)))
- {}
+Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key, const std::string& hash_name)
+ {
+ std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_name));
+
+ m_key_id.resize(hash->output_length());
+
+ hash->update(pub_key);
+ hash->final(m_key_id.data());
+ }
/*
* Encode the extension
@@ -439,61 +444,50 @@ void Authority_Key_ID::contents_to(Data_Store&, Data_Store& issuer) const
/*
* Encode the extension
*/
-std::vector<uint8_t> Alternative_Name::encode_inner() const
+std::vector<uint8_t> Subject_Alternative_Name::encode_inner() const
{
return DER_Encoder().encode(m_alt_name).get_contents_unlocked();
}
/*
-* Decode the extension
+* Encode the extension
*/
-void Alternative_Name::decode_inner(const std::vector<uint8_t>& in)
+std::vector<uint8_t> Issuer_Alternative_Name::encode_inner() const
{
- BER_Decoder(in).decode(m_alt_name);
+ return DER_Encoder().encode(m_alt_name).get_contents_unlocked();
}
/*
-* Return a textual representation
+* Decode the extension
*/
-void Alternative_Name::contents_to(Data_Store& subject_info,
- Data_Store& issuer_info) const
+void Subject_Alternative_Name::decode_inner(const std::vector<uint8_t>& in)
{
- std::multimap<std::string, std::string> contents =
- get_alt_name().contents();
-
- if(m_oid_name_str == "X509v3.SubjectAlternativeName")
- subject_info.add(contents);
- else if(m_oid_name_str == "X509v3.IssuerAlternativeName")
- issuer_info.add(contents);
- else
- throw Internal_Error("In Alternative_Name, unknown type " +
- m_oid_name_str);
+ BER_Decoder(in).decode(m_alt_name);
}
/*
-* Alternative_Name Constructor
+* Decode the extension
*/
-Alternative_Name::Alternative_Name(const AlternativeName& alt_name,
- const std::string& oid_name_str) :
- m_oid_name_str(oid_name_str),
- m_alt_name(alt_name)
- {}
+void Issuer_Alternative_Name::decode_inner(const std::vector<uint8_t>& in)
+ {
+ BER_Decoder(in).decode(m_alt_name);
+ }
/*
-* Subject_Alternative_Name Constructor
+* Return a textual representation
*/
-Subject_Alternative_Name::Subject_Alternative_Name(
- const AlternativeName& name) :
- Alternative_Name(name, "X509v3.SubjectAlternativeName")
+void Subject_Alternative_Name::contents_to(Data_Store& subject_info,
+ Data_Store&) const
{
+ subject_info.add(get_alt_name().contents());
}
/*
-* Issuer_Alternative_Name Constructor
+* Return a textual representation
*/
-Issuer_Alternative_Name::Issuer_Alternative_Name(const AlternativeName& name) :
- Alternative_Name(name, "X509v3.IssuerAlternativeName")
+void Issuer_Alternative_Name::contents_to(Data_Store&, Data_Store& issuer_info) const
{
+ issuer_info.add(get_alt_name().contents());
}
/*
@@ -849,22 +843,26 @@ std::vector<uint8_t> CRL_Distribution_Points::encode_inner() const
void CRL_Distribution_Points::decode_inner(const std::vector<uint8_t>& buf)
{
- BER_Decoder(buf).decode_list(m_distribution_points).verify_end();
- }
+ BER_Decoder(buf)
+ .decode_list(m_distribution_points)
+ .verify_end();
-void CRL_Distribution_Points::contents_to(Data_Store& info, Data_Store&) const
- {
for(size_t i = 0; i != m_distribution_points.size(); ++i)
{
auto point = m_distribution_points[i].point().contents();
auto uris = point.equal_range("URI");
-
for(auto uri = uris.first; uri != uris.second; ++uri)
- info.add("CRL.DistributionPoint", uri->second);
+ m_crl_distribution_urls.push_back(uri->second);
}
}
+void CRL_Distribution_Points::contents_to(Data_Store& subject, Data_Store&) const
+ {
+ for(const std::string& crl_url : m_crl_distribution_urls)
+ subject.add("CRL.DistributionPoint", crl_url);
+ }
+
void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const
{
throw Not_Implemented("CRL_Distribution_Points encoding");
@@ -880,17 +878,20 @@ void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder&
.end_cons().end_cons();
}
-std::vector<uint8_t> Unknown_Critical_Extension::encode_inner() const
+std::vector<uint8_t> Unknown_Extension::encode_inner() const
{
- throw Not_Implemented("Unknown_Critical_Extension encoding");
+ return m_bytes;
}
-void Unknown_Critical_Extension::decode_inner(const std::vector<uint8_t>&)
+void Unknown_Extension::decode_inner(const std::vector<uint8_t>& bytes)
{
+ // Just treat as an opaque blob at this level
+ m_bytes = bytes;
}
-void Unknown_Critical_Extension::contents_to(Data_Store&, Data_Store&) const
+void Unknown_Extension::contents_to(Data_Store&, Data_Store&) const
{
+ // No information store
}
}
diff --git a/src/lib/x509/x509_ext.h b/src/lib/x509/x509_ext.h
index 69647616f..2243d6deb 100644
--- a/src/lib/x509/x509_ext.h
+++ b/src/lib/x509/x509_ext.h
@@ -12,7 +12,6 @@
#include <botan/asn1_oid.h>
#include <botan/asn1_alt_name.h>
#include <botan/cert_status.h>
-#include <botan/datastor.h>
#include <botan/name_constraint.h>
#include <botan/key_constraint.h>
#include <botan/crl_ent.h>
@@ -20,6 +19,7 @@
namespace Botan {
+class Data_Store;
class X509_Certificate;
/**
@@ -31,7 +31,15 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Extension
/**
* @return OID representing this extension
*/
- virtual OID oid_of() const;
+ virtual OID oid_of() const = 0;
+
+ /*
+ * @return specific OID name
+ * If possible OIDS table should match oid_name to OIDS, ie
+ * OIDS::lookup(ext->oid_name()) == ext->oid_of()
+ * Should return empty string if OID is not known
+ */
+ virtual std::string oid_name() const = 0;
/**
* Make a copy of this extension
@@ -49,11 +57,6 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Extension
Data_Store& issuer) const = 0;
/*
- * @return specific OID name
- */
- virtual std::string oid_name() const = 0;
-
- /*
* Callback visited during path validation.
*
* An extension can implement this callback to inspect
@@ -87,13 +90,65 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Extension
class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object
{
public:
+ /**
+ * Look up an object in the extensions, based on OID Returns
+ * nullptr if not set, if the extension was either absent or not
+ * handled. The pointer returned is owned by the Extensions
+ * object.
+ * This would be better with an optional<T> return value
+ */
+ const Certificate_Extension* get_extension_object(const OID& oid) const;
+
+ template<typename T>
+ const T* get_extension_object_as(const OID& oid = T::static_oid()) const
+ {
+ if(const Certificate_Extension* extn = get_extension_object(oid))
+ {
+ if(const T* extn_as_T = dynamic_cast<const T*>(extn))
+ {
+ return extn_as_T;
+ }
+ else
+ {
+ throw Exception("Exception::get_extension_object_as dynamic_cast failed");
+ }
+ }
+
+ return nullptr;
+ }
+
+ /**
+ * Return the set of extensions in the order they appeared in the certificate
+ * (or as they were added, if constructed)
+ */
+ const std::vector<OID>& get_extension_oids() const
+ {
+ return m_extension_oids;
+ }
+
+ /**
+ * Return true if an extension was set
+ */
+ bool extension_set(const OID& oid) const;
+
+ /**
+ * Return true if an extesion was set and marked critical
+ */
+ bool critical_extension_set(const OID& oid) const;
+
+ /**
+ * Return the raw bytes of the extension
+ * Will throw if OID was not set as an extension.
+ */
+ std::vector<uint8_t> get_extension_bits(const OID& oid) const;
+
void encode_into(class DER_Encoder&) const override;
void decode_from(class BER_Decoder&) override;
void contents_to(Data_Store&, Data_Store&) const;
/**
* Adds a new extension to the list.
- * @param extn the certificate extension
+ * @param extn pointer to the certificate extension (Extensions takes ownership)
* @param critical whether this extension should be marked as critical
* @throw Invalid_Argument if the extension is already present in the list
*/
@@ -110,67 +165,103 @@ class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object
* Searches for an extension by OID and returns the result.
* Only the known extensions types declared in this header
* are searched for by this function.
- * @return Pointer to extension with oid, nullptr if not found.
+ * @return Copy of extension with oid, nullptr if not found.
+ * Can avoid creating a copy by using get_extension_object function
*/
std::unique_ptr<Certificate_Extension> get(const OID& oid) const;
/**
- * Searches for an extension by OID and returns the result.
- * Only the unknown extensions, that is, extensions
- * types that are not declared in this header, are searched
- * for by this function.
- * @return Pointer to extension with oid, nullptr if not found.
+ * Searches for an extension by OID and returns the result decoding
+ * it to some arbitrary extension type chosen by the application.
+ *
+ * Only the unknown extensions, that is, extensions types that
+ * are not declared in this header, are searched for by this
+ * function.
+ *
+ * @return Pointer to new extension with oid, nullptr if not found.
*/
template<typename T>
- std::unique_ptr<T> get_raw(const OID& oid)
- {
- try
+ std::unique_ptr<T> get_raw(const OID& oid) const
{
- if(m_extensions_raw.count(oid) > 0)
+ auto extn_info = m_extension_info.find(oid);
+
+ if(extn_info != m_extension_info.end())
{
- std::unique_ptr<T> ext(new T);
- ext->decode_inner(m_extensions_raw[oid].first);
- return std::move(ext);
+ // Unknown_Extension oid_name is empty
+ if(extn_info->second.obj().oid_name() == "")
+ {
+ std::unique_ptr<T> ext(new T);
+ ext->decode_inner(extn_info->second.bits());
+ return std::move(ext);
+ }
}
+ return nullptr;
}
- catch(std::exception& e)
- {
- throw Decoding_Error("Exception while decoding extension " +
- oid.as_string() + ": " + e.what());
- }
- return nullptr;
- }
/**
- * Returns the list of extensions together with the corresponding
- * criticality flag. Only contains the known extensions
- * types declared in this header.
+ * Returns a copy of the list of extensions together with the corresponding
+ * criticality flag. All extensions are encoded as some object, falling back
+ * to Unknown_Extension class which simply allows reading the bytes as well
+ * as the criticality flag.
*/
std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const;
/**
* Returns the list of extensions as raw, encoded bytes
* together with the corresponding criticality flag.
- * Contains all extensions, known as well as unknown extensions.
+ * Contains all extensions, including any extensions encoded as Unknown_Extension
*/
std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const;
- Extensions& operator=(const Extensions&);
+ Extensions() {}
- Extensions(const Extensions&);
+ Extensions(const Extensions&) = default;
+ Extensions& operator=(const Extensions&) = default;
- /**
- * @param st whether to throw an exception when encountering an unknown
- * extension type during decoding
- */
- explicit Extensions(bool st = true) : m_throw_on_unknown_critical(st) {}
+#if !defined(BOTAN_BUILD_COMPILER_IS_MSVC_2013)
+ Extensions(Extensions&&) = default;
+ Extensions& operator=(Extensions&&) = default;
+#endif
private:
- static Certificate_Extension* create_extension(const OID&, bool);
+ static Certificate_Extension* create_extn_obj(const OID& oid,
+ bool critical,
+ const std::vector<uint8_t>& body);
- std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> m_extensions;
- bool m_throw_on_unknown_critical;
- std::map<OID, std::pair<std::vector<uint8_t>, bool>> m_extensions_raw;
+ class Extensions_Info
+ {
+ public:
+ Extensions_Info(bool critical,
+ Certificate_Extension* ext) :
+ m_critical(critical),
+ m_bits(ext->encode_inner()),
+ m_obj(ext)
+ {}
+
+ Extensions_Info(bool critical,
+ const std::vector<uint8_t>& encoding,
+ Certificate_Extension* ext) :
+ m_critical(critical),
+ m_bits(encoding),
+ m_obj(ext)
+ {}
+
+ bool is_critical() const { return m_critical; }
+ const std::vector<uint8_t>& bits() const { return m_bits; }
+ const Certificate_Extension& obj() const
+ {
+ BOTAN_ASSERT_NONNULL(m_obj.get());
+ return *m_obj.get();
+ }
+
+ private:
+ bool m_critical = false;
+ std::vector<uint8_t> m_bits;
+ std::shared_ptr<const Certificate_Extension> m_obj;
+ };
+
+ std::vector<OID> m_extension_oids;
+ std::map<OID, Extensions_Info> m_extension_info;
};
namespace Cert_Extension {
@@ -192,6 +283,9 @@ class BOTAN_PUBLIC_API(2,0) Basic_Constraints final : public Certificate_Extensi
bool get_is_ca() const { return m_is_ca; }
size_t get_path_limit() const;
+ static OID static_oid() { return OID("2.5.29.19"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override
{ return "X509v3.BasicConstraints"; }
@@ -216,6 +310,9 @@ class BOTAN_PUBLIC_API(2,0) Key_Usage final : public Certificate_Extension
Key_Constraints get_constraints() const { return m_constraints; }
+ static OID static_oid() { return OID("2.5.29.15"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override { return "X509v3.KeyUsage"; }
@@ -234,13 +331,21 @@ class BOTAN_PUBLIC_API(2,0) Key_Usage final : public Certificate_Extension
class BOTAN_PUBLIC_API(2,0) Subject_Key_ID final : public Certificate_Extension
{
public:
+ Subject_Key_ID() = default;
+
+ explicit Subject_Key_ID(const std::vector<uint8_t>& k) : m_key_id(k) {}
+
+ Subject_Key_ID(const std::vector<uint8_t>& public_key,
+ const std::string& hash_fn);
+
Subject_Key_ID* copy() const override
{ return new Subject_Key_ID(m_key_id); }
- Subject_Key_ID() = default;
- explicit Subject_Key_ID(const std::vector<uint8_t>&);
+ const std::vector<uint8_t>& get_key_id() const { return m_key_id; }
+
+ static OID static_oid() { return OID("2.5.29.14"); }
+ OID oid_of() const override { return static_oid(); }
- std::vector<uint8_t> get_key_id() const { return m_key_id; }
private:
std::string oid_name() const override
{ return "X509v3.SubjectKeyIdentifier"; }
@@ -265,7 +370,10 @@ class BOTAN_PUBLIC_API(2,0) Authority_Key_ID final : public Certificate_Extensio
Authority_Key_ID() = default;
explicit Authority_Key_ID(const std::vector<uint8_t>& k) : m_key_id(k) {}
- std::vector<uint8_t> get_key_id() const { return m_key_id; }
+ const std::vector<uint8_t>& get_key_id() const { return m_key_id; }
+
+ static OID static_oid() { return OID("2.5.29.35"); }
+ OID oid_of() const override { return static_oid(); }
private:
std::string oid_name() const override
@@ -280,52 +388,59 @@ class BOTAN_PUBLIC_API(2,0) Authority_Key_ID final : public Certificate_Extensio
};
/**
-* Alternative Name Extension Base Class
+* Subject Alternative Name Extension
*/
-class BOTAN_PUBLIC_API(2,0) Alternative_Name : public Certificate_Extension
+class BOTAN_PUBLIC_API(2,4) Subject_Alternative_Name final : public Certificate_Extension
{
public:
- AlternativeName get_alt_name() const { return m_alt_name; }
+ const AlternativeName& get_alt_name() const { return m_alt_name; }
- protected:
- Alternative_Name(const AlternativeName&, const std::string& oid_name);
+ static OID static_oid() { return OID("2.5.29.17"); }
+ OID oid_of() const override { return static_oid(); }
+
+ Subject_Alternative_Name* copy() const override
+ { return new Subject_Alternative_Name(get_alt_name()); }
- Alternative_Name(const std::string&, const std::string&);
+ explicit Subject_Alternative_Name(const AlternativeName& name = AlternativeName()) :
+ m_alt_name(name) {}
private:
- std::string oid_name() const override { return m_oid_name_str; }
+ std::string oid_name() const override { return "X509v3.SubjectAlternativeName"; }
bool should_encode() const override { return m_alt_name.has_items(); }
std::vector<uint8_t> encode_inner() const override;
void decode_inner(const std::vector<uint8_t>&) override;
void contents_to(Data_Store&, Data_Store&) const override;
- std::string m_oid_name_str;
AlternativeName m_alt_name;
};
/**
-* Subject Alternative Name Extension
+* Issuer Alternative Name Extension
*/
-class BOTAN_PUBLIC_API(2,0) Subject_Alternative_Name final : public Alternative_Name
+class BOTAN_PUBLIC_API(2,0) Issuer_Alternative_Name final : public Certificate_Extension
{
public:
- Subject_Alternative_Name* copy() const override
- { return new Subject_Alternative_Name(get_alt_name()); }
+ const AlternativeName& get_alt_name() const { return m_alt_name; }
- explicit Subject_Alternative_Name(const AlternativeName& = AlternativeName());
- };
+ static OID static_oid() { return OID("2.5.29.18"); }
+ OID oid_of() const override { return static_oid(); }
-/**
-* Issuer Alternative Name Extension
-*/
-class BOTAN_PUBLIC_API(2,0) Issuer_Alternative_Name final : public Alternative_Name
- {
- public:
Issuer_Alternative_Name* copy() const override
{ return new Issuer_Alternative_Name(get_alt_name()); }
- explicit Issuer_Alternative_Name(const AlternativeName& = AlternativeName());
+ explicit Issuer_Alternative_Name(const AlternativeName& name = AlternativeName()) :
+ m_alt_name(name) {}
+
+ private:
+ std::string oid_name() const override { return "X509v3.IssuerAlternativeName"; }
+
+ bool should_encode() const override { return m_alt_name.has_items(); }
+ std::vector<uint8_t> encode_inner() const override;
+ void decode_inner(const std::vector<uint8_t>&) override;
+ void contents_to(Data_Store&, Data_Store&) const override;
+
+ AlternativeName m_alt_name;
};
/**
@@ -340,11 +455,13 @@ class BOTAN_PUBLIC_API(2,0) Extended_Key_Usage final : public Certificate_Extens
Extended_Key_Usage() = default;
explicit Extended_Key_Usage(const std::vector<OID>& o) : m_oids(o) {}
- std::vector<OID> get_oids() const { return m_oids; }
+ const std::vector<OID>& get_oids() const { return m_oids; }
+
+ static OID static_oid() { return OID("2.5.29.37"); }
+ OID oid_of() const override { return static_oid(); }
private:
- std::string oid_name() const override
- { return "X509v3.ExtendedKeyUsage"; }
+ std::string oid_name() const override { return "X509v3.ExtendedKeyUsage"; }
bool should_encode() const override { return (m_oids.size() > 0); }
std::vector<uint8_t> encode_inner() const override;
@@ -371,6 +488,11 @@ class BOTAN_PUBLIC_API(2,0) Name_Constraints final : public Certificate_Extensio
std::vector<std::set<Certificate_Status_Code>>& cert_status,
size_t pos) override;
+ const NameConstraints& get_name_constraints() const { return m_name_constraints; }
+
+ static OID static_oid() { return OID("2.5.29.30"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override
{ return "X509v3.NameConstraints"; }
@@ -395,8 +517,14 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Policies final : public Certificate_Exte
Certificate_Policies() = default;
explicit Certificate_Policies(const std::vector<OID>& o) : m_oids(o) {}
+ BOTAN_DEPRECATED("Use get_policy_oids")
std::vector<OID> get_oids() const { return m_oids; }
+ const std::vector<OID>& get_policy_oids() const { return m_oids; }
+
+ static OID static_oid() { return OID("2.5.29.32"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override
{ return "X509v3.CertificatePolicies"; }
@@ -420,6 +548,11 @@ class BOTAN_PUBLIC_API(2,0) Authority_Information_Access final : public Certific
explicit Authority_Information_Access(const std::string& ocsp) :
m_ocsp_responder(ocsp) {}
+ std::string ocsp_responder() const { return m_ocsp_responder; }
+
+ static OID static_oid() { return OID("1.3.6.1.5.5.7.1.1"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override
{ return "PKIX.AuthorityInformationAccess"; }
@@ -447,6 +580,9 @@ class BOTAN_PUBLIC_API(2,0) CRL_Number final : public Certificate_Extension
size_t get_crl_number() const;
+ static OID static_oid() { return OID("2.5.29.20"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override { return "X509v3.CRLNumber"; }
@@ -472,6 +608,9 @@ class BOTAN_PUBLIC_API(2,0) CRL_ReasonCode final : public Certificate_Extension
CRL_Code get_reason() const { return m_reason; }
+ static OID static_oid() { return OID("2.5.29.21"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override { return "X509v3.ReasonCode"; }
@@ -508,9 +647,15 @@ class BOTAN_PUBLIC_API(2,0) CRL_Distribution_Points final : public Certificate_E
explicit CRL_Distribution_Points(const std::vector<Distribution_Point>& points) :
m_distribution_points(points) {}
- std::vector<Distribution_Point> distribution_points() const
+ const std::vector<Distribution_Point>& distribution_points() const
{ return m_distribution_points; }
+ const std::vector<std::string>& crl_distribution_urls() const
+ { return m_crl_distribution_urls; }
+
+ static OID static_oid() { return OID("2.5.29.31"); }
+ OID oid_of() const override { return static_oid(); }
+
private:
std::string oid_name() const override
{ return "X509v3.CRLDistributionPoints"; }
@@ -523,44 +668,65 @@ class BOTAN_PUBLIC_API(2,0) CRL_Distribution_Points final : public Certificate_E
void contents_to(Data_Store&, Data_Store&) const override;
std::vector<Distribution_Point> m_distribution_points;
+ std::vector<std::string> m_crl_distribution_urls;
};
/**
-* An unknown X.509 extension marked as critical
-* Will always add a failure to the path validation result.
+* An unknown X.509 extension
+* Will add a failure to the path validation result, if critical
*/
-class BOTAN_PUBLIC_API(2,0) Unknown_Critical_Extension final : public Certificate_Extension
+class BOTAN_PUBLIC_API(2,4) Unknown_Extension final : public Certificate_Extension
{
public:
- explicit Unknown_Critical_Extension(OID oid) : m_oid(oid) {}
+ Unknown_Extension(const OID& oid, bool critical) :
+ m_oid(oid), m_critical(critical) {}
- Unknown_Critical_Extension* copy() const override
- { return new Unknown_Critical_Extension(m_oid); }
+ Unknown_Extension* copy() const override
+ { return new Unknown_Extension(m_oid, m_critical); }
+ /**
+ * Return the OID of this unknown extension
+ */
OID oid_of() const override
{ return m_oid; }
+ //static_oid not defined for Unknown_Extension
+
+ /**
+ * Return the extension contents
+ */
+ const std::vector<uint8_t>& extension_contents() const { return m_bytes; }
+
+ /**
+ * Return if this extension was marked critical
+ */
+ bool is_critical_extension() const { return m_critical; }
+
void validate(const X509_Certificate&, const X509_Certificate&,
const std::vector<std::shared_ptr<const X509_Certificate>>&,
std::vector<std::set<Certificate_Status_Code>>& cert_status,
size_t pos) override
{
- cert_status.at(pos).insert(Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION);
+ if(m_critical)
+ {
+ cert_status.at(pos).insert(Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION);
+ }
}
private:
- std::string oid_name() const override
- { return "Unknown OID name"; }
+ std::string oid_name() const override { return ""; }
- bool should_encode() const override { return false; }
+ bool should_encode() const override { return true; }
std::vector<uint8_t> encode_inner() const override;
void decode_inner(const std::vector<uint8_t>&) override;
void contents_to(Data_Store&, Data_Store&) const override;
OID m_oid;
+ bool m_critical;
+ std::vector<uint8_t> m_bytes;
};
-}
+ }
}