diff options
Diffstat (limited to 'src/lib/x509/x509_ext.cpp')
-rw-r--r-- | src/lib/x509/x509_ext.cpp | 71 |
1 files changed, 69 insertions, 2 deletions
diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp index c22e9ebcb..9ef14e88d 100644 --- a/src/lib/x509/x509_ext.cpp +++ b/src/lib/x509/x509_ext.cpp @@ -22,7 +22,7 @@ namespace Botan { /* * List of X.509 Certificate Extensions */ -Certificate_Extension* Extensions::get_extension(const OID& oid, bool critical) +Certificate_Extension* Extensions::create_extension(const OID& oid, bool critical) { #define X509_EXTENSION(NAME, TYPE) \ if(oid == OIDS::lookup(NAME)) { return new Cert_Extension::TYPE(); } @@ -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); + } + +std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const + { + for(auto& ext : m_extensions) + { + if(ext.first->oid_of() == oid) + { + return std::unique_ptr<Certificate_Extension>(ext.first->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; @@ -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(); + } + } } /* @@ -157,7 +224,7 @@ void Extensions::decode_from(BER_Decoder& from_source) m_extensions_raw.emplace(oid, std::make_pair(value, critical)); - std::unique_ptr<Certificate_Extension> ext(get_extension(oid, critical)); + std::unique_ptr<Certificate_Extension> ext(create_extension(oid, critical)); if(!ext && critical && m_throw_on_unknown_critical) throw Decoding_Error("Encountered unknown X.509 extension marked " |