Botan  2.7.0
Crypto and TLS for C++11
x509_dn.cpp
Go to the documentation of this file.
1 /*
2 * X509_DN
3 * (C) 1999-2007,2018 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/x509_dn.h>
9 #include <botan/der_enc.h>
10 #include <botan/ber_dec.h>
11 #include <botan/parsing.h>
12 #include <botan/internal/stl_util.h>
13 #include <botan/oids.h>
14 #include <ostream>
15 #include <cctype>
16 
17 namespace Botan {
18 
19 /*
20 * Add an attribute to a X509_DN
21 */
22 void X509_DN::add_attribute(const std::string& type,
23  const std::string& str)
24  {
26  }
27 
28 /*
29 * Add an attribute to a X509_DN
30 */
31 void X509_DN::add_attribute(const OID& oid, const ASN1_String& str)
32  {
33  if(str.empty())
34  return;
35 
36  m_rdn.push_back(std::make_pair(oid, str));
37  m_dn_bits.clear();
38  }
39 
40 /*
41 * Get the attributes of this X509_DN
42 */
43 std::multimap<OID, std::string> X509_DN::get_attributes() const
44  {
45  std::multimap<OID, std::string> retval;
46 
47  for(auto& i : m_rdn)
48  multimap_insert(retval, i.first, i.second.value());
49  return retval;
50  }
51 
52 /*
53 * Get the contents of this X.500 Name
54 */
55 std::multimap<std::string, std::string> X509_DN::contents() const
56  {
57  std::multimap<std::string, std::string> retval;
58 
59  for(auto& i : m_rdn)
60  {
61  std::string str_value = OIDS::oid2str(i.first);
62 
63  if(str_value.empty())
64  str_value = i.first.as_string();
65  multimap_insert(retval, str_value, i.second.value());
66  }
67  return retval;
68  }
69 
70 bool X509_DN::has_field(const std::string& attr) const
71  {
73  }
74 
75 bool X509_DN::has_field(const OID& oid) const
76  {
77  for(auto& i : m_rdn)
78  {
79  if(i.first == oid)
80  return true;
81  }
82 
83  return false;
84  }
85 
86 std::string X509_DN::get_first_attribute(const std::string& attr) const
87  {
88  const OID oid = OIDS::lookup(deref_info_field(attr));
89  return get_first_attribute(oid).value();
90  }
91 
93  {
94  for(auto& i : m_rdn)
95  {
96  if(i.first == oid)
97  {
98  return i.second;
99  }
100  }
101 
102  return ASN1_String();
103  }
104 
105 /*
106 * Get a single attribute type
107 */
108 std::vector<std::string> X509_DN::get_attribute(const std::string& attr) const
109  {
110  const OID oid = OIDS::lookup(deref_info_field(attr));
111 
112  std::vector<std::string> values;
113 
114  for(auto& i : m_rdn)
115  {
116  if(i.first == oid)
117  {
118  values.push_back(i.second.value());
119  }
120  }
121 
122  return values;
123  }
124 
125 /*
126 * Deref aliases in a subject/issuer info request
127 */
128 std::string X509_DN::deref_info_field(const std::string& info)
129  {
130  if(info == "Name" || info == "CommonName" || info == "CN") return "X520.CommonName";
131  if(info == "SerialNumber" || info == "SN") return "X520.SerialNumber";
132  if(info == "Country" || info == "C") return "X520.Country";
133  if(info == "Organization" || info == "O") return "X520.Organization";
134  if(info == "Organizational Unit" || info == "OrgUnit" || info == "OU")
135  return "X520.OrganizationalUnit";
136  if(info == "Locality" || info == "L") return "X520.Locality";
137  if(info == "State" || info == "Province" || info == "ST") return "X520.State";
138  if(info == "Email") return "RFC822";
139  return info;
140  }
141 
142 /*
143 * Compare two X509_DNs for equality
144 */
145 bool operator==(const X509_DN& dn1, const X509_DN& dn2)
146  {
147  auto attr1 = dn1.get_attributes();
148  auto attr2 = dn2.get_attributes();
149 
150  if(attr1.size() != attr2.size()) return false;
151 
152  auto p1 = attr1.begin();
153  auto p2 = attr2.begin();
154 
155  while(true)
156  {
157  if(p1 == attr1.end() && p2 == attr2.end())
158  break;
159  if(p1 == attr1.end()) return false;
160  if(p2 == attr2.end()) return false;
161  if(p1->first != p2->first) return false;
162  if(!x500_name_cmp(p1->second, p2->second))
163  return false;
164  ++p1;
165  ++p2;
166  }
167  return true;
168  }
169 
170 /*
171 * Compare two X509_DNs for inequality
172 */
173 bool operator!=(const X509_DN& dn1, const X509_DN& dn2)
174  {
175  return !(dn1 == dn2);
176  }
177 
178 /*
179 * Induce an arbitrary ordering on DNs
180 */
181 bool operator<(const X509_DN& dn1, const X509_DN& dn2)
182  {
183  auto attr1 = dn1.get_attributes();
184  auto attr2 = dn2.get_attributes();
185 
186  if(attr1.size() < attr2.size()) return true;
187  if(attr1.size() > attr2.size()) return false;
188 
189  for(auto p1 = attr1.begin(); p1 != attr1.end(); ++p1)
190  {
191  auto p2 = attr2.find(p1->first);
192  if(p2 == attr2.end()) return false;
193  if(p1->second > p2->second) return false;
194  if(p1->second < p2->second) return true;
195  }
196  return false;
197  }
198 
199 /*
200 * DER encode a DistinguishedName
201 */
203  {
204  der.start_cons(SEQUENCE);
205 
206  if(!m_dn_bits.empty())
207  {
208  /*
209  If we decoded this from somewhere, encode it back exactly as
210  we received it
211  */
212  der.raw_bytes(m_dn_bits);
213  }
214  else
215  {
216  for(const auto& dn : m_rdn)
217  {
218  der.start_cons(SET)
220  .encode(dn.first)
221  .encode(dn.second)
222  .end_cons()
223  .end_cons();
224  }
225  }
226 
227  der.end_cons();
228  }
229 
230 /*
231 * Decode a BER encoded DistinguishedName
232 */
234  {
235  std::vector<uint8_t> bits;
236 
237  source.start_cons(SEQUENCE)
238  .raw_bytes(bits)
239  .end_cons();
240 
241  BER_Decoder sequence(bits);
242 
243  while(sequence.more_items())
244  {
245  BER_Decoder rdn = sequence.start_cons(SET);
246 
247  while(rdn.more_items())
248  {
249  OID oid;
250  ASN1_String str;
251 
252  rdn.start_cons(SEQUENCE).decode(oid).decode(str).end_cons();
253 
254  add_attribute(oid, str);
255  }
256  }
257 
258  m_dn_bits = bits;
259  }
260 
261 namespace {
262 
263 std::string to_short_form(const OID& oid)
264  {
265  const std::string long_id = OIDS::oid2str(oid);
266 
267  if(long_id.empty())
268  return oid.to_string();
269 
270  if(long_id == "X520.CommonName")
271  return "CN";
272 
273  if(long_id == "X520.Country")
274  return "C";
275 
276  if(long_id == "X520.Organization")
277  return "O";
278 
279  if(long_id == "X520.OrganizationalUnit")
280  return "OU";
281 
282  return long_id;
283  }
284 
285 }
286 
287 std::ostream& operator<<(std::ostream& out, const X509_DN& dn)
288  {
289  auto info = dn.dn_info();
290 
291  for(size_t i = 0; i != info.size(); ++i)
292  {
293  out << to_short_form(info[i].first) << "=\"";
294  for(char c : info[i].second.value())
295  {
296  if(c == '\\' || c == '\"')
297  {
298  out << "\\";
299  }
300  out << c;
301  }
302  out << "\"";
303 
304  if(i + 1 < info.size())
305  {
306  out << ",";
307  }
308  }
309  return out;
310  }
311 
312 std::istream& operator>>(std::istream& in, X509_DN& dn)
313  {
314  in >> std::noskipws;
315  do
316  {
317  std::string key;
318  std::string val;
319  char c;
320 
321  while(in.good())
322  {
323  in >> c;
324 
325  if(std::isspace(c) && key.empty())
326  continue;
327  else if(!std::isspace(c))
328  {
329  key.push_back(c);
330  break;
331  }
332  else
333  break;
334  }
335 
336  while(in.good())
337  {
338  in >> c;
339 
340  if(!std::isspace(c) && c != '=')
341  key.push_back(c);
342  else if(c == '=')
343  break;
344  else
345  throw Invalid_Argument("Ill-formed X.509 DN");
346  }
347 
348  bool in_quotes = false;
349  while(in.good())
350  {
351  in >> c;
352 
353  if(std::isspace(c))
354  {
355  if(!in_quotes && !val.empty())
356  break;
357  else if(in_quotes)
358  val.push_back(' ');
359  }
360  else if(c == '"')
361  in_quotes = !in_quotes;
362  else if(c == '\\')
363  {
364  if(in.good())
365  in >> c;
366  val.push_back(c);
367  }
368  else if(c == ',' && !in_quotes)
369  break;
370  else
371  val.push_back(c);
372  }
373 
374  if(!key.empty() && !val.empty())
376  else
377  break;
378  }
379  while(in.good());
380  return in;
381  }
382 }
bool operator!=(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition: alg_id.cpp:90
ASN1_String get_first_attribute(const OID &oid) const
Definition: x509_dn.cpp:92
int operator<<(int fd, Pipe &pipe)
Definition: fd_unix.cpp:17
const std::vector< std::pair< OID, ASN1_String > > & dn_info() const
Definition: x509_dn.h:54
static std::string deref_info_field(const std::string &key)
Definition: x509_dn.cpp:128
void add_attribute(const std::string &key, const std::string &val)
Definition: x509_dn.cpp:22
BER_Decoder & raw_bytes(std::vector< uint8_t, Alloc > &out)
Definition: ber_dec.h:156
void encode_into(class DER_Encoder &) const override
Definition: x509_dn.cpp:202
MechanismType type
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
DER_Encoder & raw_bytes(const uint8_t val[], size_t len)
Definition: der_enc.cpp:228
void decode_from(class BER_Decoder &) override
Definition: x509_dn.cpp:233
std::string to_string() const
Definition: asn1_oid.cpp:50
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
bool operator<(const OID &a, const OID &b)
Definition: asn1_oid.cpp:105
std::vector< std::string > get_attribute(const std::string &attr) const
Definition: x509_dn.cpp:108
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
bool x500_name_cmp(const std::string &name1, const std::string &name2)
Definition: parsing.cpp:228
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
Definition: alg_id.cpp:13
const std::string & value() const
Definition: asn1_str.h:27
bool has_field(const OID &oid) const
Definition: x509_dn.cpp:75
std::string oid2str(const OID &oid)
Definition: oids.h:48
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
int operator>>(int fd, Pipe &pipe)
Definition: fd_unix.cpp:40
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition: alg_id.cpp:75
void multimap_insert(std::multimap< K, V > &multimap, const K &key, const V &value)
Definition: stl_util.h:76
std::multimap< OID, std::string > get_attributes() const
Definition: x509_dn.cpp:43
bool more_items() const
Definition: ber_dec.cpp:198
bool empty() const
Definition: asn1_str.h:31
std::string lookup(const OID &oid)
Definition: oids.cpp:113
std::multimap< std::string, std::string > contents() const
Definition: x509_dn.cpp:55