Botan  1.11.15
src/lib/asn1/x509_dn.cpp
Go to the documentation of this file.
00001 /*
00002 * X509_DN
00003 * (C) 1999-2007 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/x509_dn.h>
00009 #include <botan/der_enc.h>
00010 #include <botan/ber_dec.h>
00011 #include <botan/parsing.h>
00012 #include <botan/internal/stl_util.h>
00013 #include <botan/oids.h>
00014 #include <ostream>
00015 
00016 namespace Botan {
00017 
00018 /*
00019 * Create an empty X509_DN
00020 */
00021 X509_DN::X509_DN()
00022    {
00023    }
00024 
00025 /*
00026 * Create an X509_DN
00027 */
00028 X509_DN::X509_DN(const std::multimap<OID, std::string>& args)
00029    {
00030    for(auto i = args.begin(); i != args.end(); ++i)
00031       add_attribute(i->first, i->second);
00032    }
00033 
00034 /*
00035 * Create an X509_DN
00036 */
00037 X509_DN::X509_DN(const std::multimap<std::string, std::string>& args)
00038    {
00039    for(auto i = args.begin(); i != args.end(); ++i)
00040       add_attribute(OIDS::lookup(i->first), i->second);
00041    }
00042 
00043 /*
00044 * Add an attribute to a X509_DN
00045 */
00046 void X509_DN::add_attribute(const std::string& type,
00047                             const std::string& str)
00048    {
00049    OID oid = OIDS::lookup(type);
00050    add_attribute(oid, str);
00051    }
00052 
00053 /*
00054 * Add an attribute to a X509_DN
00055 */
00056 void X509_DN::add_attribute(const OID& oid, const std::string& str)
00057    {
00058    if(str == "")
00059       return;
00060 
00061    auto range = dn_info.equal_range(oid);
00062    for(auto i = range.first; i != range.second; ++i)
00063       if(i->second.value() == str)
00064          return;
00065 
00066    multimap_insert(dn_info, oid, ASN1_String(str));
00067    dn_bits.clear();
00068    }
00069 
00070 /*
00071 * Get the attributes of this X509_DN
00072 */
00073 std::multimap<OID, std::string> X509_DN::get_attributes() const
00074    {
00075    std::multimap<OID, std::string> retval;
00076    for(auto i = dn_info.begin(); i != dn_info.end(); ++i)
00077       multimap_insert(retval, i->first, i->second.value());
00078    return retval;
00079    }
00080 
00081 /*
00082 * Get the contents of this X.500 Name
00083 */
00084 std::multimap<std::string, std::string> X509_DN::contents() const
00085    {
00086    std::multimap<std::string, std::string> retval;
00087    for(auto i = dn_info.begin(); i != dn_info.end(); ++i)
00088       multimap_insert(retval, OIDS::lookup(i->first), i->second.value());
00089    return retval;
00090    }
00091 
00092 /*
00093 * Get a single attribute type
00094 */
00095 std::vector<std::string> X509_DN::get_attribute(const std::string& attr) const
00096    {
00097    const OID oid = OIDS::lookup(deref_info_field(attr));
00098 
00099    auto range = dn_info.equal_range(oid);
00100 
00101    std::vector<std::string> values;
00102    for(auto i = range.first; i != range.second; ++i)
00103       values.push_back(i->second.value());
00104    return values;
00105    }
00106 
00107 /*
00108 * Return the BER encoded data, if any
00109 */
00110 std::vector<byte> X509_DN::get_bits() const
00111    {
00112    return dn_bits;
00113    }
00114 
00115 /*
00116 * Deref aliases in a subject/issuer info request
00117 */
00118 std::string X509_DN::deref_info_field(const std::string& info)
00119    {
00120    if(info == "Name" || info == "CommonName") return "X520.CommonName";
00121    if(info == "SerialNumber")                 return "X520.SerialNumber";
00122    if(info == "Country")                      return "X520.Country";
00123    if(info == "Organization")                 return "X520.Organization";
00124    if(info == "Organizational Unit" || info == "OrgUnit")
00125       return "X520.OrganizationalUnit";
00126    if(info == "Locality")                     return "X520.Locality";
00127    if(info == "State" || info == "Province")  return "X520.State";
00128    if(info == "Email")                        return "RFC822";
00129    return info;
00130    }
00131 
00132 /*
00133 * Compare two X509_DNs for equality
00134 */
00135 bool operator==(const X509_DN& dn1, const X509_DN& dn2)
00136    {
00137    auto attr1 = dn1.get_attributes();
00138    auto attr2 = dn2.get_attributes();
00139 
00140    if(attr1.size() != attr2.size()) return false;
00141 
00142    auto p1 = attr1.begin();
00143    auto p2 = attr2.begin();
00144 
00145    while(true)
00146       {
00147       if(p1 == attr1.end() && p2 == attr2.end())
00148          break;
00149       if(p1 == attr1.end())      return false;
00150       if(p2 == attr2.end())      return false;
00151       if(p1->first != p2->first) return false;
00152       if(!x500_name_cmp(p1->second, p2->second))
00153          return false;
00154       ++p1;
00155       ++p2;
00156       }
00157    return true;
00158    }
00159 
00160 /*
00161 * Compare two X509_DNs for inequality
00162 */
00163 bool operator!=(const X509_DN& dn1, const X509_DN& dn2)
00164    {
00165    return !(dn1 == dn2);
00166    }
00167 
00168 /*
00169 * Induce an arbitrary ordering on DNs
00170 */
00171 bool operator<(const X509_DN& dn1, const X509_DN& dn2)
00172    {
00173    auto attr1 = dn1.get_attributes();
00174    auto attr2 = dn2.get_attributes();
00175 
00176    if(attr1.size() < attr2.size()) return true;
00177    if(attr1.size() > attr2.size()) return false;
00178 
00179    for(auto p1 = attr1.begin(); p1 != attr1.end(); ++p1)
00180       {
00181       auto p2 = attr2.find(p1->first);
00182       if(p2 == attr2.end())       return false;
00183       if(p1->second > p2->second) return false;
00184       if(p1->second < p2->second) return true;
00185       }
00186    return false;
00187    }
00188 
00189 namespace {
00190 
00191 /*
00192 * DER encode a RelativeDistinguishedName
00193 */
00194 void do_ava(DER_Encoder& encoder,
00195             const std::multimap<OID, std::string>& dn_info,
00196             ASN1_Tag string_type, const std::string& oid_str,
00197             bool must_exist = false)
00198    {
00199    const OID oid = OIDS::lookup(oid_str);
00200    const bool exists = (dn_info.find(oid) != dn_info.end());
00201 
00202    if(!exists && must_exist)
00203       throw Encoding_Error("X509_DN: No entry for " + oid_str);
00204    if(!exists) return;
00205 
00206    auto range = dn_info.equal_range(oid);
00207 
00208    for(auto i = range.first; i != range.second; ++i)
00209       {
00210       encoder.start_cons(SET)
00211          .start_cons(SEQUENCE)
00212             .encode(oid)
00213             .encode(ASN1_String(i->second, string_type))
00214          .end_cons()
00215       .end_cons();
00216       }
00217    }
00218 
00219 }
00220 
00221 /*
00222 * DER encode a DistinguishedName
00223 */
00224 void X509_DN::encode_into(DER_Encoder& der) const
00225    {
00226    auto dn_info = get_attributes();
00227 
00228    der.start_cons(SEQUENCE);
00229 
00230    if(!dn_bits.empty())
00231       der.raw_bytes(dn_bits);
00232    else
00233       {
00234       do_ava(der, dn_info, PRINTABLE_STRING, "X520.Country");
00235       do_ava(der, dn_info, DIRECTORY_STRING, "X520.State");
00236       do_ava(der, dn_info, DIRECTORY_STRING, "X520.Locality");
00237       do_ava(der, dn_info, DIRECTORY_STRING, "X520.Organization");
00238       do_ava(der, dn_info, DIRECTORY_STRING, "X520.OrganizationalUnit");
00239       do_ava(der, dn_info, DIRECTORY_STRING, "X520.CommonName");
00240       do_ava(der, dn_info, PRINTABLE_STRING, "X520.SerialNumber");
00241       }
00242 
00243    der.end_cons();
00244    }
00245 
00246 /*
00247 * Decode a BER encoded DistinguishedName
00248 */
00249 void X509_DN::decode_from(BER_Decoder& source)
00250    {
00251    std::vector<byte> bits;
00252 
00253    source.start_cons(SEQUENCE)
00254       .raw_bytes(bits)
00255    .end_cons();
00256 
00257    BER_Decoder sequence(bits);
00258 
00259    while(sequence.more_items())
00260       {
00261       BER_Decoder rdn = sequence.start_cons(SET);
00262 
00263       while(rdn.more_items())
00264          {
00265          OID oid;
00266          ASN1_String str;
00267 
00268          rdn.start_cons(SEQUENCE)
00269             .decode(oid)
00270             .decode(str)
00271             .verify_end()
00272         .end_cons();
00273 
00274          add_attribute(oid, str.value());
00275          }
00276       }
00277 
00278    dn_bits = bits;
00279    }
00280 
00281 namespace {
00282 
00283 std::string to_short_form(const std::string& long_id)
00284    {
00285    if(long_id == "X520.CommonName")
00286       return "CN";
00287 
00288    if(long_id == "X520.Organization")
00289       return "O";
00290 
00291    if(long_id == "X520.OrganizationalUnit")
00292       return "OU";
00293 
00294    return long_id;
00295    }
00296 
00297 }
00298 
00299 std::ostream& operator<<(std::ostream& out, const X509_DN& dn)
00300    {
00301    std::multimap<std::string, std::string> contents = dn.contents();
00302 
00303    for(std::multimap<std::string, std::string>::const_iterator i = contents.begin();
00304        i != contents.end(); ++i)
00305       {
00306       out << to_short_form(i->first) << "=" << i->second << ' ';
00307       }
00308    return out;
00309    }
00310 
00311 }