Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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