diff options
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp')
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp b/src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp new file mode 100644 index 0000000000..9eb509daba --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/x509/x509_dn.cpp @@ -0,0 +1,382 @@ +/* +* X509_DN +* (C) 1999-2007,2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/x509_dn.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/parsing.h> +#include <botan/internal/stl_util.h> +#include <botan/oids.h> +#include <ostream> +#include <cctype> + +namespace Botan { + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const std::string& type, + const std::string& str) + { + add_attribute(OIDS::lookup(type), str); + } + +/* +* Add an attribute to a X509_DN +*/ +void X509_DN::add_attribute(const OID& oid, const ASN1_String& str) + { + if(str.empty()) + return; + + m_rdn.push_back(std::make_pair(oid, str)); + m_dn_bits.clear(); + } + +/* +* Get the attributes of this X509_DN +*/ +std::multimap<OID, std::string> X509_DN::get_attributes() const + { + std::multimap<OID, std::string> retval; + + for(auto& i : m_rdn) + multimap_insert(retval, i.first, i.second.value()); + return retval; + } + +/* +* Get the contents of this X.500 Name +*/ +std::multimap<std::string, std::string> X509_DN::contents() const + { + std::multimap<std::string, std::string> retval; + + for(auto& i : m_rdn) + { + std::string str_value = OIDS::oid2str(i.first); + + if(str_value.empty()) + str_value = i.first.as_string(); + multimap_insert(retval, str_value, i.second.value()); + } + return retval; + } + +bool X509_DN::has_field(const std::string& attr) const + { + return has_field(OIDS::lookup(deref_info_field(attr))); + } + +bool X509_DN::has_field(const OID& oid) const + { + for(auto& i : m_rdn) + { + if(i.first == oid) + return true; + } + + return false; + } + +std::string X509_DN::get_first_attribute(const std::string& attr) const + { + const OID oid = OIDS::lookup(deref_info_field(attr)); + return get_first_attribute(oid).value(); + } + +ASN1_String X509_DN::get_first_attribute(const OID& oid) const + { + for(auto& i : m_rdn) + { + if(i.first == oid) + { + return i.second; + } + } + + return ASN1_String(); + } + +/* +* Get a single attribute type +*/ +std::vector<std::string> X509_DN::get_attribute(const std::string& attr) const + { + const OID oid = OIDS::lookup(deref_info_field(attr)); + + std::vector<std::string> values; + + for(auto& i : m_rdn) + { + if(i.first == oid) + { + values.push_back(i.second.value()); + } + } + + return values; + } + +/* +* Deref aliases in a subject/issuer info request +*/ +std::string X509_DN::deref_info_field(const std::string& info) + { + if(info == "Name" || info == "CommonName" || info == "CN") return "X520.CommonName"; + if(info == "SerialNumber" || info == "SN") return "X520.SerialNumber"; + if(info == "Country" || info == "C") return "X520.Country"; + if(info == "Organization" || info == "O") return "X520.Organization"; + if(info == "Organizational Unit" || info == "OrgUnit" || info == "OU") + return "X520.OrganizationalUnit"; + if(info == "Locality" || info == "L") return "X520.Locality"; + if(info == "State" || info == "Province" || info == "ST") return "X520.State"; + if(info == "Email") return "RFC822"; + return info; + } + +/* +* Compare two X509_DNs for equality +*/ +bool operator==(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() != attr2.size()) return false; + + auto p1 = attr1.begin(); + auto p2 = attr2.begin(); + + while(true) + { + if(p1 == attr1.end() && p2 == attr2.end()) + break; + if(p1 == attr1.end()) return false; + if(p2 == attr2.end()) return false; + if(p1->first != p2->first) return false; + if(!x500_name_cmp(p1->second, p2->second)) + return false; + ++p1; + ++p2; + } + return true; + } + +/* +* Compare two X509_DNs for inequality +*/ +bool operator!=(const X509_DN& dn1, const X509_DN& dn2) + { + return !(dn1 == dn2); + } + +/* +* Induce an arbitrary ordering on DNs +*/ +bool operator<(const X509_DN& dn1, const X509_DN& dn2) + { + auto attr1 = dn1.get_attributes(); + auto attr2 = dn2.get_attributes(); + + if(attr1.size() < attr2.size()) return true; + if(attr1.size() > attr2.size()) return false; + + for(auto p1 = attr1.begin(); p1 != attr1.end(); ++p1) + { + auto p2 = attr2.find(p1->first); + if(p2 == attr2.end()) return false; + if(p1->second > p2->second) return false; + if(p1->second < p2->second) return true; + } + return false; + } + +/* +* DER encode a DistinguishedName +*/ +void X509_DN::encode_into(DER_Encoder& der) const + { + der.start_cons(SEQUENCE); + + if(!m_dn_bits.empty()) + { + /* + If we decoded this from somewhere, encode it back exactly as + we received it + */ + der.raw_bytes(m_dn_bits); + } + else + { + for(const auto& dn : m_rdn) + { + der.start_cons(SET) + .start_cons(SEQUENCE) + .encode(dn.first) + .encode(dn.second) + .end_cons() + .end_cons(); + } + } + + der.end_cons(); + } + +/* +* Decode a BER encoded DistinguishedName +*/ +void X509_DN::decode_from(BER_Decoder& source) + { + std::vector<uint8_t> bits; + + source.start_cons(SEQUENCE) + .raw_bytes(bits) + .end_cons(); + + BER_Decoder sequence(bits); + + while(sequence.more_items()) + { + BER_Decoder rdn = sequence.start_cons(SET); + + while(rdn.more_items()) + { + OID oid; + ASN1_String str; + + rdn.start_cons(SEQUENCE).decode(oid).decode(str).end_cons(); + + add_attribute(oid, str); + } + } + + m_dn_bits = bits; + } + +namespace { + +std::string to_short_form(const OID& oid) + { + const std::string long_id = OIDS::oid2str(oid); + + if(long_id.empty()) + return oid.to_string(); + + if(long_id == "X520.CommonName") + return "CN"; + + if(long_id == "X520.Country") + return "C"; + + if(long_id == "X520.Organization") + return "O"; + + if(long_id == "X520.OrganizationalUnit") + return "OU"; + + return long_id; + } + +} + +std::ostream& operator<<(std::ostream& out, const X509_DN& dn) + { + auto info = dn.dn_info(); + + for(size_t i = 0; i != info.size(); ++i) + { + out << to_short_form(info[i].first) << "=\""; + for(char c : info[i].second.value()) + { + if(c == '\\' || c == '\"') + { + out << "\\"; + } + out << c; + } + out << "\""; + + if(i + 1 < info.size()) + { + out << ","; + } + } + return out; + } + +std::istream& operator>>(std::istream& in, X509_DN& dn) + { + in >> std::noskipws; + do + { + std::string key; + std::string val; + char c; + + while(in.good()) + { + in >> c; + + if(std::isspace(c) && key.empty()) + continue; + else if(!std::isspace(c)) + { + key.push_back(c); + break; + } + else + break; + } + + while(in.good()) + { + in >> c; + + if(!std::isspace(c) && c != '=') + key.push_back(c); + else if(c == '=') + break; + else + throw Invalid_Argument("Ill-formed X.509 DN"); + } + + bool in_quotes = false; + while(in.good()) + { + in >> c; + + if(std::isspace(c)) + { + if(!in_quotes && !val.empty()) + break; + else if(in_quotes) + val.push_back(' '); + } + else if(c == '"') + in_quotes = !in_quotes; + else if(c == '\\') + { + if(in.good()) + in >> c; + val.push_back(c); + } + else if(c == ',' && !in_quotes) + break; + else + val.push_back(c); + } + + if(!key.empty() && !val.empty()) + dn.add_attribute(X509_DN::deref_info_field(key),val); + else + break; + } + while(in.good()); + return in; + } +} |