Botan 3.13.0
Crypto and TLS for C&
Botan::X509_DN Class Referencefinal

#include <pkix_types.h>

Inheritance diagram for Botan::X509_DN:
Botan::ASN1_Object

Public Member Functions

const std::vector< uint8_t > & _canonical_bytes () const
void add_attribute (const OID &oid, const ASN1_String &val)
void add_attribute (const OID &oid, std::string_view val)
void add_attribute (std::string_view key, std::string_view val)
void add_rdn (std::vector< std::pair< OID, ASN1_String > > rdn)
std::vector< uint8_t > BER_encode () const
std::multimap< std::string, std::string > contents () const
size_t count () const
void decode_from (BER_Decoder &from) override
std::vector< uint8_t > DER_encode () const
std::vector< std::pair< OID, ASN1_String > > dn_info () const
bool empty () const
void encode_into (DER_Encoder &to) const override
std::vector< std::string > get_attribute (std::string_view attr) const
std::multimap< OID, std::string > get_attributes () const
const std::vector< uint8_t > & get_bits () const
ASN1_String get_first_attribute (const OID &oid) const
std::string get_first_attribute (std::string_view attr) const
bool has_field (const OID &oid) const
bool has_field (std::string_view attr) const
const std::vector< std::vector< std::pair< OID, ASN1_String > > > & rdns () const
std::string to_string () const
 X509_DN ()=default
 X509_DN (const std::multimap< OID, std::string > &args)
 X509_DN (const std::multimap< std::string, std::string > &args)
 X509_DN (std::initializer_list< std::pair< std::string_view, std::string_view > > args)

Static Public Member Functions

static std::string deref_info_field (std::string_view key)
static size_t lookup_ub (const OID &oid)
static std::optional< X509_DNparse (std::string_view str)

Detailed Description

Distinguished Name

Definition at line 157 of file pkix_types.h.

Constructor & Destructor Documentation

◆ X509_DN() [1/4]

Botan::X509_DN::X509_DN ( )
default

Referenced by parse(), X509_DN(), and X509_DN().

◆ X509_DN() [2/4]

Botan::X509_DN::X509_DN ( std::initializer_list< std::pair< std::string_view, std::string_view > > args)
inline

Definition at line 161 of file pkix_types.h.

161 {
162 for(const auto& i : args) {
163 add_attribute(i.first, i.second);
164 }
165 }
void add_attribute(std::string_view key, std::string_view val)
Definition x509_dn.cpp:137

References add_attribute().

◆ X509_DN() [3/4]

Botan::X509_DN::X509_DN ( const std::multimap< OID, std::string > & args)
inlineexplicit

Since DN matching for Name Constraints requires preserving order and multimaps have sorted keys, this constructor is deprecated.

Definition at line 172 of file pkix_types.h.

172 {
173 for(const auto& i : args) {
174 add_attribute(i.first, i.second);
175 }
176 }

References add_attribute(), and X509_DN().

◆ X509_DN() [4/4]

Botan::X509_DN::X509_DN ( const std::multimap< std::string, std::string > & args)
inlineexplicit

Since DN matching for Name Constraints requires preserving order and multimaps have sorted keys, this constructor is deprecated.

Definition at line 183 of file pkix_types.h.

183 {
184 for(const auto& i : args) {
185 add_attribute(i.first, i.second);
186 }
187 }

References add_attribute(), and X509_DN().

Member Function Documentation

◆ _canonical_bytes()

const std::vector< uint8_t > & Botan::X509_DN::_canonical_bytes ( ) const
inline

Return a canonical byte encoding

Internal interface, not covered by SemVer

Definition at line 274 of file pkix_types.h.

274{ return m_canonical_dn_bits; }

Referenced by Botan::operator<(), Botan::operator==(), and Botan::x509_dn_subtree_match().

◆ add_attribute() [1/3]

void Botan::X509_DN::add_attribute ( const OID & oid,
const ASN1_String & val )

Definition at line 144 of file x509_dn.cpp.

144 {
145 if(str.empty()) {
146 return;
147 }
148
149 // Each programmatic add appends a new single-AVA RDN.
150 m_rdn.push_back({std::make_pair(oid, str)});
151 m_dn_bits.clear();
152 update_canonical_bits();
153}

References Botan::ASN1_String::empty().

◆ add_attribute() [2/3]

void Botan::X509_DN::add_attribute ( const OID & oid,
std::string_view val )
inline

Definition at line 247 of file pkix_types.h.

247{ add_attribute(oid, ASN1_String(val)); }

References add_attribute(), and add_attribute().

Referenced by add_attribute().

◆ add_attribute() [3/3]

void Botan::X509_DN::add_attribute ( std::string_view key,
std::string_view val )

Definition at line 137 of file x509_dn.cpp.

137 {
139}
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:80

References add_attribute(), and Botan::OID::from_string().

Referenced by add_attribute(), add_attribute(), X509_DN(), X509_DN(), and X509_DN().

◆ add_rdn()

void Botan::X509_DN::add_rdn ( std::vector< std::pair< OID, ASN1_String > > rdn)

Append a complete RDN. The provided AVAs become one RelativeDistinguishedName (X.501 SET OF AttributeTypeAndValue). An empty input is ignored.

Definition at line 155 of file x509_dn.cpp.

155 {
156 if(rdn.empty()) {
157 return;
158 }
159 m_rdn.push_back(std::move(rdn));
160 m_dn_bits.clear();
161 update_canonical_bits();
162}

Referenced by Botan::AlternativeName::dn(), and parse().

◆ BER_encode()

std::vector< uint8_t > Botan::ASN1_Object::BER_encode ( ) const
inherited

Return the encoding of this object. This is a convenience method when just one object needs to be serialized. Use DER_Encoder for complicated encodings.

Definition at line 21 of file asn1_obj.cpp.

21 {
22 std::vector<uint8_t> output;
23 DER_Encoder der(output);
24 this->encode_into(der);
25 return output;
26}
virtual void encode_into(DER_Encoder &to) const =0

References encode_into().

Referenced by decode_from(), Botan::PKCS12::export_to(), Botan::Certificate_Store_In_SQL::find_all_certs(), Botan::Certificate_Store_In_SQL::find_cert(), Botan::X509_Certificate::fingerprint(), Botan::Certificate_Store_In_SQL::insert_cert(), Botan::X509_Object::PEM_encode(), and Botan::PSS_Params::PSS_Params().

◆ contents()

std::multimap< std::string, std::string > Botan::X509_DN::contents ( ) const

Definition at line 191 of file x509_dn.cpp.

191 {
192 std::multimap<std::string, std::string> retval;
193
194 for(const auto& rdn : m_rdn) {
195 for(const auto& ava : rdn) {
196 retval.emplace(ava.first.to_formatted_string(), ava.second.value());
197 }
198 }
199 return retval;
200}

◆ count()

size_t Botan::X509_DN::count ( ) const
inline

Number of relative distinguished names (RDNs) in the DN. Note: prior to multi-AVA RDN support this returned the total number of AVAs; the two differ only when the DN contains a multi-valued RDN.

Definition at line 209 of file pkix_types.h.

209{ return m_rdn.size(); }

Referenced by Botan::NameConstraints::is_excluded(), and Botan::NameConstraints::is_permitted().

◆ decode_from()

void Botan::X509_DN::decode_from ( BER_Decoder & from)
overridevirtual

Decode whatever this object is from from

Parameters
fromthe BER_Decoder that will be read from

Implements Botan::ASN1_Object.

Definition at line 408 of file x509_dn.cpp.

408 {
409 std::vector<uint8_t> bits;
410
411 source.start_sequence().raw_bytes(bits).end_cons();
412
413 BER_Decoder sequence(bits, source.limits());
414
415 std::vector<std::vector<std::pair<OID, ASN1_String>>> rdns;
416
417 // Cap AVAs per RDN to bound work for downstream set-based matching.
418 // No legitimate cert has anywhere near this many AVAs in a single RDN.
419 constexpr size_t MAX_AVAS_PER_RDN = 32;
420
421 while(sequence.more_items()) {
422 BER_Decoder rdn_decoder = sequence.start_set();
423
424 std::vector<std::pair<OID, ASN1_String>> rdn;
425 while(rdn_decoder.more_items()) {
426 OID oid;
427 ASN1_String str;
428
429 rdn_decoder.start_sequence()
430 .decode(oid)
431 .decode(str) // TODO support Any
432 .end_cons();
433
434 rdn.emplace_back(std::move(oid), std::move(str));
435
436 if(rdn.size() > MAX_AVAS_PER_RDN) {
437 throw Decoding_Error("X.500 RDN has too many attribute-value assertions");
438 }
439 }
440
441 /*
442 RFC 5280 4.1.2.4:
443 RelativeDistinguishedName ::=
444 SET SIZE (1..MAX) OF AttributeTypeAndValue
445 */
446 if(rdn.empty()) {
447 throw Decoding_Error("X.500 RDN must contain at least one attribute-value assertion");
448 }
449 rdns.push_back(std::move(rdn));
450 }
451
452 auto canonical_bits = canonicalize_dn(rdns);
453
454 m_rdn = std::move(rdns);
455 m_dn_bits = std::move(bits);
456 m_canonical_dn_bits = std::move(canonical_bits);
457}
const std::vector< std::vector< std::pair< OID, ASN1_String > > > & rdns() const
Definition pkix_types.h:229

References Botan::BER_Decoder::decode(), Botan::BER_Decoder::end_cons(), Botan::BER_Decoder::limits(), Botan::BER_Decoder::more_items(), Botan::BER_Decoder::raw_bytes(), rdns(), Botan::BER_Decoder::start_sequence(), and Botan::BER_Decoder::start_set().

Referenced by Botan::Certificate_Store_In_SQL::all_subjects(), and Botan::GeneralName::decode_from().

◆ DER_encode()

std::vector< uint8_t > Botan::X509_DN::DER_encode ( ) const

Definition at line 373 of file x509_dn.cpp.

373 {
374 std::vector<uint8_t> result;
375 DER_Encoder der(result);
376 this->encode_into(der);
377 return result;
378}
void encode_into(DER_Encoder &to) const override
Definition x509_dn.cpp:383

References encode_into().

◆ deref_info_field()

std::string Botan::X509_DN::deref_info_field ( std::string_view key)
static

Definition at line 264 of file x509_dn.cpp.

264 {
265 if(info == "Name" || info == "CommonName" || info == "CN") {
266 return "X520.CommonName";
267 }
268 if(info == "SerialNumber" || info == "SN") {
269 return "X520.SerialNumber";
270 }
271 if(info == "Country" || info == "C") {
272 return "X520.Country";
273 }
274 if(info == "Organization" || info == "O") {
275 return "X520.Organization";
276 }
277 if(info == "Organizational Unit" || info == "OrgUnit" || info == "OU") {
278 return "X520.OrganizationalUnit";
279 }
280 if(info == "Locality" || info == "L") {
281 return "X520.Locality";
282 }
283 if(info == "State" || info == "Province" || info == "ST") {
284 return "X520.State";
285 }
286 if(info == "Email") {
287 return "RFC822";
288 }
289 return std::string(info);
290}

Referenced by get_attribute(), get_first_attribute(), has_field(), and parse().

◆ dn_info()

std::vector< std::pair< OID, ASN1_String > > Botan::X509_DN::dn_info ( ) const

Return the DN attributes as a flat sequence of AVAs in decoded order. RDN structure is not preserved in this view; prefer rdns() to retain it.

Definition at line 164 of file x509_dn.cpp.

164 {
165 std::vector<std::pair<OID, ASN1_String>> flat;
166 for(const auto& rdn : m_rdn) {
167 for(const auto& ava : rdn) {
168 flat.push_back(ava);
169 }
170 }
171 return flat;
172}

◆ empty()

bool Botan::X509_DN::empty ( ) const
inline

Definition at line 202 of file pkix_types.h.

202{ return m_rdn.empty(); }

Referenced by Botan::NameConstraints::is_permitted().

◆ encode_into()

void Botan::X509_DN::encode_into ( DER_Encoder & to) const
overridevirtual

Encode whatever this object is into to

Parameters
tothe DER_Encoder that will be written to

Implements Botan::ASN1_Object.

Definition at line 383 of file x509_dn.cpp.

383 {
384 der.start_sequence();
385
386 if(!m_dn_bits.empty()) {
387 /*
388 If we decoded this from somewhere, encode it back exactly as
389 we received it
390 */
391 der.raw_bytes(m_dn_bits);
392 } else {
393 for(const auto& rdn : m_rdn) {
394 der.start_set();
395 for(const auto& ava : rdn) {
396 der.start_sequence().encode(ava.first).encode(ava.second).end_cons();
397 }
398 der.end_cons();
399 }
400 }
401
402 der.end_cons();
403}

References Botan::DER_Encoder::encode(), Botan::DER_Encoder::end_cons(), Botan::DER_Encoder::raw_bytes(), Botan::DER_Encoder::start_sequence(), and Botan::DER_Encoder::start_set().

Referenced by DER_encode().

◆ get_attribute()

std::vector< std::string > Botan::X509_DN::get_attribute ( std::string_view attr) const

Definition at line 245 of file x509_dn.cpp.

245 {
246 const OID oid = OID::from_string(deref_info_field(attr));
247
248 std::vector<std::string> values;
249
250 for(const auto& rdn : m_rdn) {
251 for(const auto& ava : rdn) {
252 if(ava.first == oid) {
253 values.push_back(ava.second.value());
254 }
255 }
256 }
257
258 return values;
259}
static std::string deref_info_field(std::string_view key)
Definition x509_dn.cpp:264

References deref_info_field(), and Botan::OID::from_string().

Referenced by Botan::NameConstraints::is_excluded(), Botan::NameConstraints::is_permitted(), and Botan::GeneralName::matches().

◆ get_attributes()

std::multimap< OID, std::string > Botan::X509_DN::get_attributes ( ) const

Definition at line 177 of file x509_dn.cpp.

177 {
178 std::multimap<OID, std::string> retval;
179
180 for(const auto& rdn : m_rdn) {
181 for(const auto& ava : rdn) {
182 retval.emplace(ava.first, ava.second.value());
183 }
184 }
185 return retval;
186}

◆ get_bits()

const std::vector< uint8_t > & Botan::X509_DN::get_bits ( ) const
inline

Definition at line 198 of file pkix_types.h.

198{ return m_dn_bits; }

Referenced by botan_x509_crl_view_binary_values().

◆ get_first_attribute() [1/2]

ASN1_String Botan::X509_DN::get_first_attribute ( const OID & oid) const

Definition at line 230 of file x509_dn.cpp.

230 {
231 for(const auto& rdn : m_rdn) {
232 for(const auto& ava : rdn) {
233 if(ava.first == oid) {
234 return ava.second;
235 }
236 }
237 }
238
239 return ASN1_String();
240}

Referenced by get_first_attribute().

◆ get_first_attribute() [2/2]

std::string Botan::X509_DN::get_first_attribute ( std::string_view attr) const

Definition at line 225 of file x509_dn.cpp.

225 {
226 const OID oid = OID::from_string(deref_info_field(attr));
227 return get_first_attribute(oid).value();
228}
const std::string & value() const
Definition asn1_obj.h:590
ASN1_String get_first_attribute(const OID &oid) const
Definition x509_dn.cpp:230

References deref_info_field(), Botan::OID::from_string(), get_first_attribute(), and Botan::ASN1_String::value().

◆ has_field() [1/2]

bool Botan::X509_DN::has_field ( const OID & oid) const

Definition at line 213 of file x509_dn.cpp.

213 {
214 for(const auto& rdn : m_rdn) {
215 for(const auto& ava : rdn) {
216 if(ava.first == oid) {
217 return true;
218 }
219 }
220 }
221
222 return false;
223}

Referenced by has_field().

◆ has_field() [2/2]

bool Botan::X509_DN::has_field ( std::string_view attr) const

Definition at line 202 of file x509_dn.cpp.

202 {
203 try {
204 const OID o = OID::from_string(deref_info_field(attr));
205 if(o.has_value()) {
206 return has_field(o);
207 }
208 } catch(Lookup_Error&) {}
209
210 return false;
211}
bool has_field(const OID &oid) const
Definition x509_dn.cpp:213

References deref_info_field(), Botan::OID::from_string(), has_field(), and Botan::OID::has_value().

◆ lookup_ub()

size_t Botan::X509_DN::lookup_ub ( const OID & oid)
static

Lookup upper bounds in characters for the length of distinguished name fields as given in RFC 5280, Appendix A.

Parameters
oidthe oid of the DN to lookup
Returns
the upper bound, or zero if no ub is known to Botan

Definition at line 16 of file x509_dn_ub.cpp.

16 {
17 /*
18 * See RFC 5280 Appendix A.1 starting with comment "-- Upper Bounds"
19 */
20
21 // NOLINTBEGIN(*-branch-clone)
22 if(auto iso_dn = is_sub_element_of(oid, {2, 5, 4})) {
23 switch(*iso_dn) {
24 case 3:
25 // X520.CommonName
26 return 64;
27 case 4:
28 // X520.Surname
29 return 40;
30 case 5:
31 // X520.SerialNumber
32 return 64;
33 case 6:
34 // X520.Country
35 return 3;
36 case 7:
37 // X520.Locality
38 return 128;
39 case 8:
40 // X520.State
41 return 128;
42 case 9:
43 // X520.StreetAddress
44 return 128;
45 case 10:
46 // X520.Organization
47 return 64;
48 case 11:
49 // X520.OrganizationalUnit
50 return 64;
51 case 12:
52 // X520.Title
53 return 64;
54 case 42:
55 // X520.GivenName
56 return 16;
57 case 43:
58 // X520.Initials
59 return 5;
60 case 44:
61 // X520.GenerationalQualifier
62 return 3;
63 case 46:
64 // X520.DNQualifier
65 return 64;
66 case 65:
67 // X520.Pseudonym
68 return 128;
69 default:
70 return 0;
71 }
72 }
73
74 // NOLINTEND(*-branch-clone)
75
76 return 0;
77}
std::optional< uint32_t > is_sub_element_of(const OID &oid, std::initializer_list< uint32_t > prefix)
Definition x509_utils.h:22

References Botan::is_sub_element_of().

Referenced by Botan::PKIX::check_chain().

◆ parse()

std::optional< X509_DN > Botan::X509_DN::parse ( std::string_view str)
static

Parse the string representation of a distinguished name.

The grammar accepted is a subset of RFC 4514 Section 3, but also accepts quoted-value forms ala RFC 2253. The entire input must be consumed.

Parameters
strthe string to parse
Returns
the parsed DN, or nullopt if str is not a well-formed DN

Definition at line 554 of file x509_dn.cpp.

554 {
555 X509_DN dn;
556
557 // AVAs accumulate here; a trailing '+' keeps the next AVA in the same
558 // RDN, while a ',' (or end of input) flushes them as a single RDN.
559 std::vector<std::pair<OID, ASN1_String>> pending_rdn;
560
561 // Separator that ended the previous AVA. A ',' or '+' still pending after the
562 // loop means the input ended with a separator and no AVA to follow it.
563 char terminator = '\0';
564
565 size_t pos = 0;
566 while(pos < str.size()) {
567 // Whitespace separating an attributeType from the preceding ',' or '+'
568 // is tolerated even though RFC 4514 does not produce it.
569 while(pos < str.size() && is_space(str[pos])) {
570 ++pos;
571 }
572 if(pos == str.size()) {
573 break;
574 }
575
576 // attributeType, terminated by '='
577 const size_t type_start = pos;
578 while(pos < str.size() && str[pos] != '=' && !is_space(str[pos])) {
579 ++pos;
580 }
581 const std::string_view type = str.substr(type_start, pos - type_start);
582 if(type.empty() || pos == str.size() || str[pos] != '=') {
583 return std::nullopt;
584 }
585 ++pos; // consume '='
586
587 /*
588 attributeValue, in RFC 4514 <string> form plus the legacy quoted form.
589 value_len tracks the length up to the last significant octet: leading and
590 trailing unescaped whitespace is not significant unless it was escaped or
591 quoted, so trailing whitespace is dropped by the final resize.
592 */
593 std::string value;
594 size_t value_len = 0;
595
596 // The legacy quoted form wraps the whole value: a quote is only an opening
597 // quote at the start of the value, and nothing but trailing whitespace or a
598 // separator may follow the closing quote.
599 enum class Quote : uint8_t { None, Open, Closed };
600 Quote quote = Quote::None;
601
602 terminator = '\0';
603
604 while(pos < str.size()) {
605 const char c = str[pos];
606
607 if(c == '"') {
608 if(quote == Quote::Open) {
609 quote = Quote::Closed;
610 } else if(quote == Quote::None && value.empty()) {
611 quote = Quote::Open;
612 } else {
613 return std::nullopt; // quote in mid-value or after the closing quote
614 }
615 ++pos;
616 } else if(c == '\\') {
617 if(quote == Quote::Closed) {
618 return std::nullopt; // escape after the closing quote
619 }
620 // pair = ESC ( ESC / special / hexpair )
621 ++pos;
622 if(pos == str.size()) {
623 return std::nullopt;
624 }
625 if(const auto hi = hex_digit_value(str[pos])) {
626 const auto lo = (pos + 1 < str.size()) ? hex_digit_value(str[pos + 1]) : std::nullopt;
627 if(!lo) {
628 return std::nullopt;
629 }
630 value.push_back(static_cast<char>((*hi << 4) | *lo));
631 pos += 2;
632 } else if(is_escapable_char(str[pos])) {
633 value.push_back(str[pos]);
634 ++pos;
635 } else {
636 return std::nullopt; // not ESC / special / hexpair
637 }
638 value_len = value.size(); // an escaped octet is always significant
639 } else if((c == ',' || c == '+') && quote != Quote::Open) {
640 terminator = c;
641 ++pos;
642 break;
643 } else if(quote == Quote::Closed) {
644 if(!is_space(c)) {
645 return std::nullopt; // content after the closing quote
646 }
647 ++pos; // trailing whitespace after the closing quote is insignificant
648 } else if(quote != Quote::Open && is_unescaped_special_value_char(c)) {
649 return std::nullopt;
650 } else {
651 ++pos;
652 if(is_space(c) && quote != Quote::Open) {
653 // Keep interior whitespace only if more content follows; skip it
654 // entirely while leading (value is still empty)
655 if(!value.empty()) {
656 value.push_back(c);
657 }
658 } else {
659 value.push_back(c);
660 value_len = value.size();
661 }
662 }
663 }
664
665 if(quote == Quote::Open) {
666 return std::nullopt; // unterminated quoted value
667 }
668 value.resize(value_len); // strip trailing unescaped whitespace
669
670 try {
671 OID oid = OID::from_string(deref_info_field(type));
672 // ASN1_String rejects values (e.g. a \FF hexpair) that are not valid
673 // for any supported string encoding.
674 pending_rdn.emplace_back(std::move(oid), ASN1_String(value));
675 } catch(const Exception&) {
676 return std::nullopt; // unknown attributeType or invalid attributeValue
677 }
678
679 if(terminator != '+') {
680 dn.add_rdn(std::move(pending_rdn));
681 pending_rdn.clear();
682 }
683 }
684
685 // A trailing ',' or '+' leaves an RDN/AVA with nothing to follow it
686 if(terminator == ',' || terminator == '+') {
687 return std::nullopt;
688 }
689 return dn;
690}
X509_DN()=default

References add_rdn(), deref_info_field(), Botan::OID::from_string(), Botan::None, and X509_DN().

Referenced by Botan::AlternativeName::add_attribute(), and Botan::operator>>().

◆ rdns()

const std::vector< std::vector< std::pair< OID, ASN1_String > > > & Botan::X509_DN::rdns ( ) const
inline

Return the DN as a sequence of RDNs. Each RDN is an X.501 SET OF AttributeTypeAndValue; the inner vector preserves the decoded order but RDN equality is set-based per RFC 5280 7.1.

Definition at line 229 of file pkix_types.h.

229{ return m_rdn; }

Referenced by Botan::PKIX::check_chain(), decode_from(), and Botan::operator<<().

◆ to_string()

std::string Botan::X509_DN::to_string ( ) const

Definition at line 485 of file x509_dn.cpp.

485 {
486 std::ostringstream out;
487 out << *this;
488 return out.str();
489}

Referenced by Botan::Flatfile_Certificate_Store::Flatfile_Certificate_Store().


The documentation for this class was generated from the following files: