Botan  1.11.30
x509cert.cpp
Go to the documentation of this file.
1 /*
2 * X.509 Certificates
3 * (C) 1999-2010,2015 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/x509cert.h>
9 #include <botan/x509_ext.h>
10 #include <botan/der_enc.h>
11 #include <botan/ber_dec.h>
12 #include <botan/internal/stl_util.h>
13 #include <botan/parsing.h>
14 #include <botan/bigint.h>
15 #include <botan/oids.h>
16 #include <botan/pem.h>
17 #include <botan/hash.h>
18 #include <botan/hex.h>
19 #include <algorithm>
20 #include <iterator>
21 #include <sstream>
22 
23 namespace Botan {
24 
25 namespace {
26 
27 /*
28 * Lookup each OID in the vector
29 */
30 std::vector<std::string> lookup_oids(const std::vector<std::string>& in)
31  {
32  std::vector<std::string> out;
33 
34  for(auto i = in.begin(); i != in.end(); ++i)
35  out.push_back(OIDS::lookup(OID(*i)));
36  return out;
37  }
38 
39 }
40 
41 /*
42 * X509_Certificate Constructor
43 */
44 X509_Certificate::X509_Certificate(DataSource& in) :
45  X509_Object(in, "CERTIFICATE/X509 CERTIFICATE"),
46  m_self_signed(false),
47  m_v3_extensions(false)
48  {
49  do_decode();
50  }
51 
52 /*
53 * X509_Certificate Constructor
54 */
55 X509_Certificate::X509_Certificate(const std::string& in) :
56  X509_Object(in, "CERTIFICATE/X509 CERTIFICATE"),
57  m_self_signed(false),
58  m_v3_extensions(false)
59  {
60  do_decode();
61  }
62 
63 /*
64 * X509_Certificate Constructor
65 */
66 X509_Certificate::X509_Certificate(const std::vector<byte>& in) :
67  X509_Object(in, "CERTIFICATE/X509 CERTIFICATE"),
68  m_self_signed(false),
69  m_v3_extensions(false)
70  {
71  do_decode();
72  }
73 
74 X509_Certificate::X509_Certificate(const X509_Certificate& other) :
75  X509_Object(other)
76  {
77  m_subject = other.m_subject;
78  m_issuer = other.m_issuer;
79  m_self_signed = other.m_self_signed;
80  m_v3_extensions = other.m_v3_extensions;
81  }
82 
84  {
85  if(&other == this)
86  {
87  return *this;
88  }
89  else
90  {
91  m_subject = other.m_subject;
92  m_issuer = other.m_issuer;
93  m_self_signed = other.m_self_signed;
94  m_v3_extensions = other.m_v3_extensions;
95  }
96  return *this;
97  }
98 
99 
100 /*
101 * Decode the TBSCertificate data
102 */
103 void X509_Certificate::force_decode()
104  {
105  size_t version;
106  BigInt serial_bn;
107  AlgorithmIdentifier sig_algo_inner;
108  X509_DN dn_issuer, dn_subject;
109  X509_Time start, end;
110 
111  BER_Decoder tbs_cert(m_tbs_bits);
112 
113  tbs_cert.decode_optional(version, ASN1_Tag(0),
115  .decode(serial_bn)
116  .decode(sig_algo_inner)
117  .decode(dn_issuer)
119  .decode(start)
120  .decode(end)
121  .verify_end()
122  .end_cons()
123  .decode(dn_subject);
124 
125  if(version > 2)
126  throw Decoding_Error("Unknown X.509 cert version " + std::to_string(version));
127  if(m_sig_algo != sig_algo_inner)
128  throw Decoding_Error("Algorithm identifier mismatch");
129 
130  m_self_signed = (dn_subject == dn_issuer);
131 
132  m_subject.add(dn_subject.contents());
133  m_issuer.add(dn_issuer.contents());
134 
135  m_subject.add("X509.Certificate.dn_bits", ASN1::put_in_sequence(dn_subject.get_bits()));
136  m_issuer.add("X509.Certificate.dn_bits", ASN1::put_in_sequence(dn_issuer.get_bits()));
137 
138  BER_Object public_key = tbs_cert.get_next_object();
139  if(public_key.type_tag != SEQUENCE || public_key.class_tag != CONSTRUCTED)
140  throw BER_Bad_Tag("X509_Certificate: Unexpected tag for public key",
141  public_key.type_tag, public_key.class_tag);
142 
143  std::vector<byte> v2_issuer_key_id, v2_subject_key_id;
144 
145  tbs_cert.decode_optional_string(v2_issuer_key_id, BIT_STRING, 1);
146  tbs_cert.decode_optional_string(v2_subject_key_id, BIT_STRING, 2);
147 
148  BER_Object v3_exts_data = tbs_cert.get_next_object();
149  if(v3_exts_data.type_tag == 3 &&
150  v3_exts_data.class_tag == ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC))
151  {
152  BER_Decoder(v3_exts_data.value).decode(m_v3_extensions).verify_end();
153  m_v3_extensions.contents_to(m_subject, m_issuer);
154  }
155  else if(v3_exts_data.type_tag != NO_OBJECT)
156  throw BER_Bad_Tag("Unknown tag in X.509 cert",
157  v3_exts_data.type_tag, v3_exts_data.class_tag);
158 
159  if(tbs_cert.more_items())
160  throw Decoding_Error("TBSCertificate has more items that expected");
161 
162  m_subject.add("X509.Certificate.version", static_cast<u32bit>(version));
163  m_subject.add("X509.Certificate.serial", BigInt::encode(serial_bn));
164  m_subject.add("X509.Certificate.start", start.to_string());
165  m_subject.add("X509.Certificate.end", end.to_string());
166 
167  m_issuer.add("X509.Certificate.v2.key_id", v2_issuer_key_id);
168  m_subject.add("X509.Certificate.v2.key_id", v2_subject_key_id);
169 
170  m_subject.add("X509.Certificate.public_key",
171  hex_encode(public_key.value));
172 
173  if(m_self_signed && version == 0)
174  {
175  m_subject.add("X509v3.BasicConstraints.is_ca", 1);
176  m_subject.add("X509v3.BasicConstraints.path_constraint", Cert_Extension::NO_CERT_PATH_LIMIT);
177  }
178 
179  if(is_CA_cert() &&
180  !m_subject.has_value("X509v3.BasicConstraints.path_constraint"))
181  {
182  const size_t limit = (x509_version() < 3) ?
183  Cert_Extension::NO_CERT_PATH_LIMIT : 0;
184 
185  m_subject.add("X509v3.BasicConstraints.path_constraint", static_cast<u32bit>(limit));
186  }
187  }
188 
189 /*
190 * Return the X.509 version in use
191 */
193  {
194  return (m_subject.get1_u32bit("X509.Certificate.version") + 1);
195  }
196 
197 /*
198 * Return the time this cert becomes valid
199 */
200 std::string X509_Certificate::start_time() const
201  {
202  return m_subject.get1("X509.Certificate.start");
203  }
204 
205 /*
206 * Return the time this cert becomes invalid
207 */
208 std::string X509_Certificate::end_time() const
209  {
210  return m_subject.get1("X509.Certificate.end");
211  }
212 
213 /*
214 * Return information about the subject
215 */
216 std::vector<std::string>
217 X509_Certificate::subject_info(const std::string& what) const
218  {
219  return m_subject.get(X509_DN::deref_info_field(what));
220  }
221 
222 /*
223 * Return information about the issuer
224 */
225 std::vector<std::string>
226 X509_Certificate::issuer_info(const std::string& what) const
227  {
228  return m_issuer.get(X509_DN::deref_info_field(what));
229  }
230 
231 /*
232 * Return the public key in this certificate
233 */
235  {
236  return X509::load_key(
238  }
239 
241  {
242  return hex_decode(m_subject.get1("X509.Certificate.public_key"));
243  }
244 
245 /*
246 * Check if the certificate is for a CA
247 */
249  {
250  if(!m_subject.get1_u32bit("X509v3.BasicConstraints.is_ca"))
251  return false;
252 
254  }
255 
257  {
258  if(constraints() == NO_CONSTRAINTS)
259  return true;
260  return ((constraints() & usage) != 0);
261  }
262 
263 bool X509_Certificate::allowed_usage(const std::string& usage) const
264  {
265  const std::vector<std::string> ex = ex_constraints();
266 
267  if(ex.empty())
268  return true;
269 
270  if(std::find(ex.begin(), ex.end(), usage) != ex.end())
271  return true;
272 
273  return false;
274  }
275 
277  {
278  switch(usage)
279  {
281  return true;
282 
285 
288 
291 
293  return is_CA_cert();
294  }
295 
296  return false;
297  }
298 
299 /*
300 * Return the path length constraint
301 */
303  {
304  return m_subject.get1_u32bit("X509v3.BasicConstraints.path_constraint", 0);
305  }
306 
307 /*
308 * Return if a certificate extension is marked critical
309 */
310 bool X509_Certificate::is_critical(const std::string& ex_name) const
311  {
312  return !!m_subject.get1_u32bit(ex_name + ".is_critical",0);
313  }
314 
315 /*
316 * Return the key usage constraints
317 */
319  {
320  return Key_Constraints(m_subject.get1_u32bit("X509v3.KeyUsage",
321  NO_CONSTRAINTS));
322  }
323 
324 /*
325 * Return the list of extended key usage OIDs
326 */
327 std::vector<std::string> X509_Certificate::ex_constraints() const
328  {
329  return lookup_oids(m_subject.get("X509v3.ExtendedKeyUsage"));
330  }
331 
332 /*
333 * Return the name constraints
334 */
336  {
337  std::vector<GeneralSubtree> permit, exclude;
338 
339  for(const std::string& v: m_subject.get("X509v3.NameConstraints.permitted"))
340  {
341  permit.push_back(GeneralSubtree(v));
342  }
343 
344  for(const std::string& v: m_subject.get("X509v3.NameConstraints.excluded"))
345  {
346  exclude.push_back(GeneralSubtree(v));
347  }
348 
349  return NameConstraints(std::move(permit),std::move(exclude));
350  }
351 
352 /*
353 * Return the list of certificate policies
354 */
355 std::vector<std::string> X509_Certificate::policies() const
356  {
357  return lookup_oids(m_subject.get("X509v3.CertificatePolicies"));
358  }
359 
361  {
362  return m_v3_extensions;
363  }
364 
366  {
367  return m_subject.get1("OCSP.responder", "");
368  }
369 
371  {
372  return m_subject.get1("CRL.DistributionPoint", "");
373  }
374 
375 /*
376 * Return the authority key id
377 */
378 std::vector<byte> X509_Certificate::authority_key_id() const
379  {
380  return m_issuer.get1_memvec("X509v3.AuthorityKeyIdentifier");
381  }
382 
383 /*
384 * Return the subject key id
385 */
386 std::vector<byte> X509_Certificate::subject_key_id() const
387  {
388  return m_subject.get1_memvec("X509v3.SubjectKeyIdentifier");
389  }
390 
391 /*
392 * Return the certificate serial number
393 */
394 std::vector<byte> X509_Certificate::serial_number() const
395  {
396  return m_subject.get1_memvec("X509.Certificate.serial");
397  }
398 
400  {
401  return create_dn(m_issuer);
402  }
403 
404 std::vector<byte> X509_Certificate::raw_issuer_dn() const
405  {
406  return m_issuer.get1_memvec("X509.Certificate.dn_bits");
407  }
408 
410  {
411  return create_dn(m_subject);
412  }
413 
414 std::vector<byte> X509_Certificate::raw_subject_dn() const
415  {
416  return m_subject.get1_memvec("X509.Certificate.dn_bits");
417  }
418 
419 std::string X509_Certificate::fingerprint(const std::string& hash_name) const
420  {
421  std::unique_ptr<HashFunction> hash(HashFunction::create(hash_name));
422  hash->update(this->BER_encode());
423  const auto hex_print = hex_encode(hash->final());
424 
425  std::string formatted_print;
426 
427  for(size_t i = 0; i != hex_print.size(); i += 2)
428  {
429  formatted_print.push_back(hex_print[i]);
430  formatted_print.push_back(hex_print[i+1]);
431 
432  if(i != hex_print.size() - 2)
433  formatted_print.push_back(':');
434  }
435 
436  return formatted_print;
437  }
438 
439 bool X509_Certificate::matches_dns_name(const std::string& name) const
440  {
441  if(name.empty())
442  return false;
443 
444  std::vector<std::string> issued_names = subject_info("DNS");
445 
446  // Fall back to CN only if no DNS names are set (RFC 6125 sec 6.4.4)
447  if(issued_names.empty())
448  issued_names = subject_info("Name");
449 
450  for(size_t i = 0; i != issued_names.size(); ++i)
451  {
452  if(host_wildcard_match(issued_names[i], name))
453  return true;
454  }
455 
456  return false;
457  }
458 
459 /*
460 * Compare two certificates for equality
461 */
463  {
464  return (m_sig == other.m_sig &&
465  m_sig_algo == other.m_sig_algo &&
466  m_self_signed == other.m_self_signed &&
467  m_issuer == other.m_issuer &&
468  m_subject == other.m_subject);
469  }
470 
472  {
473  /* If signature values are not equal, sort by lexicographic ordering of that */
474  if(m_sig != other.m_sig)
475  {
476  if(m_sig < other.m_sig)
477  return true;
478  return false;
479  }
480 
481  // Then compare the signed contents
482  return m_tbs_bits < other.m_tbs_bits;
483  }
484 
485 /*
486 * X.509 Certificate Comparison
487 */
488 bool operator!=(const X509_Certificate& cert1, const X509_Certificate& cert2)
489  {
490  return !(cert1 == cert2);
491  }
492 
493 std::string X509_Certificate::to_string() const
494  {
495  const std::vector<std::string> dn_fields{
496  "Name",
497  "Email",
498  "Organization",
499  "Organizational Unit",
500  "Locality",
501  "State",
502  "Country",
503  "IP",
504  "DNS",
505  "URI",
506  "PKIX.XMPPAddr"
507  };
508 
509  std::ostringstream out;
510 
511  for(auto&& field : dn_fields)
512  {
513  for(auto&& val : subject_info(field))
514  {
515  out << "Subject " << field << ": " << val << "\n";
516  }
517  }
518 
519  for(auto&& field : dn_fields)
520  {
521  for(auto&& val : issuer_info(field))
522  {
523  out << "Issuer " << field << ": " << val << "\n";
524  }
525  }
526 
527  out << "Version: " << this->x509_version() << "\n";
528 
529  out << "Not valid before: " << this->start_time() << "\n";
530  out << "Not valid after: " << this->end_time() << "\n";
531 
532  out << "Constraints:\n";
534  if(constraints == NO_CONSTRAINTS)
535  out << " None\n";
536  else
537  {
538  if(constraints & DIGITAL_SIGNATURE)
539  out << " Digital Signature\n";
540  if(constraints & NON_REPUDIATION)
541  out << " Non-Repuidation\n";
542  if(constraints & KEY_ENCIPHERMENT)
543  out << " Key Encipherment\n";
544  if(constraints & DATA_ENCIPHERMENT)
545  out << " Data Encipherment\n";
546  if(constraints & KEY_AGREEMENT)
547  out << " Key Agreement\n";
548  if(constraints & KEY_CERT_SIGN)
549  out << " Cert Sign\n";
550  if(constraints & CRL_SIGN)
551  out << " CRL Sign\n";
552  }
553 
554  std::vector<std::string> policies = this->policies();
555  if(!policies.empty())
556  {
557  out << "Policies: " << "\n";
558  for(size_t i = 0; i != policies.size(); i++)
559  out << " " << policies[i] << "\n";
560  }
561 
562  std::vector<std::string> ex_constraints = this->ex_constraints();
563  if(!ex_constraints.empty())
564  {
565  out << "Extended Constraints:\n";
566  for(size_t i = 0; i != ex_constraints.size(); i++)
567  out << " " << ex_constraints[i] << "\n";
568  }
569 
571  if(!name_constraints.permitted().empty() ||
572  !name_constraints.excluded().empty())
573  {
574  out << "Name Constraints:\n";
575 
576  if(!name_constraints.permitted().empty())
577  {
578  out << " Permit";
579  for(auto st: name_constraints.permitted())
580  {
581  out << " " << st.base();
582  }
583  out << "\n";
584  }
585 
586  if(!name_constraints.excluded().empty())
587  {
588  out << " Exclude";
589  for(auto st: name_constraints.excluded())
590  {
591  out << " " << st.base();
592  }
593  out << "\n";
594  }
595  }
596 
597  if(!ocsp_responder().empty())
598  out << "OCSP responder " << ocsp_responder() << "\n";
599  if(!crl_distribution_point().empty())
600  out << "CRL " << crl_distribution_point() << "\n";
601 
602  out << "Signature algorithm: " <<
603  OIDS::lookup(this->signature_algorithm().oid) << "\n";
604 
605  out << "Serial number: " << hex_encode(this->serial_number()) << "\n";
606 
607  if(this->authority_key_id().size())
608  out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n";
609 
610  if(this->subject_key_id().size())
611  out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n";
612 
613  std::unique_ptr<X509_PublicKey> pubkey(this->subject_public_key());
614  out << "Public Key:\n" << X509::PEM_encode(*pubkey);
615 
616  return out.str();
617  }
618 
619 /*
620 * Create and populate a X509_DN
621 */
623  {
624  auto names = info.search_for(
625  [](const std::string& key, const std::string&)
626  {
627  return (key.find("X520.") != std::string::npos);
628  });
629 
630  X509_DN dn;
631 
632  for(auto i = names.begin(); i != names.end(); ++i)
633  dn.add_attribute(i->first, i->second);
634 
635  return dn;
636  }
637 
638 /*
639 * Create and populate an AlternativeName
640 */
642  {
643  auto names = info.search_for(
644  [](const std::string& key, const std::string&)
645  {
646  return (key == "RFC822" ||
647  key == "DNS" ||
648  key == "URI" ||
649  key == "IP");
650  });
651 
652  AlternativeName alt_name;
653 
654  for(auto i = names.begin(); i != names.end(); ++i)
655  alt_name.add_attribute(i->first, i->second);
656 
657  return alt_name;
658  }
659 
660 }
AlgorithmIdentifier m_sig_algo
Definition: x509_obj.h:96
void add_attribute(const std::string &, const std::string &)
std::vector< byte > get_bits() const
Definition: x509_dn.cpp:111
friend class BER_Decoder
Definition: x509cert.h:262
bool operator==(const X509_Certificate &other) const
Definition: x509cert.cpp:462
static std::vector< byte > encode(const BigInt &n, Base base=Binary)
Definition: big_code.cpp:54
size_t hex_decode(byte output[], const char input[], size_t input_length, size_t &input_consumed, bool ignore_ws)
Definition: hex.cpp:49
std::multimap< std::string, std::string > search_for(std::function< bool(std::string, std::string)> predicate) const
Definition: datastor.cpp:35
bool operator!=(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition: alg_id.cpp:82
bool matches_dns_name(const std::string &name) const
Definition: x509cert.cpp:439
Public_Key * load_key(DataSource &source)
Definition: x509_key.cpp:41
bool is_CA_cert() const
Definition: x509cert.cpp:248
std::string ocsp_responder() const
Definition: x509cert.cpp:365
Key_Constraints constraints() const
Definition: x509cert.cpp:318
const std::vector< GeneralSubtree > & permitted() const
Permitted names.
X509_Certificate & operator=(const X509_Certificate &other)
Definition: x509cert.cpp:83
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:373
void add_attribute(const std::string &, const std::string &)
Definition: x509_dn.cpp:47
std::uint32_t u32bit
Definition: types.h:33
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
bool allowed_usage(Key_Constraints usage) const
Definition: x509cert.cpp:256
std::string crl_distribution_point() const
Definition: x509cert.cpp:370
void contents_to(Data_Store &, Data_Store &) const
Definition: x509_ext.cpp:188
std::vector< byte > raw_subject_dn() const
Definition: x509cert.cpp:414
secure_vector< byte > value
Definition: asn1_obj.h:91
std::string get1(const std::string &key) const
Definition: datastor.cpp:62
u32bit path_limit() const
Definition: x509cert.cpp:302
NameConstraints name_constraints() const
Definition: x509cert.cpp:335
std::vector< byte > serial_number() const
Definition: x509cert.cpp:394
BER_Decoder & decode_optional(T &out, ASN1_Tag type_tag, ASN1_Tag class_tag, const T &default_value=T())
Definition: ber_dec.h:181
const std::vector< GeneralSubtree > & excluded() const
Excluded names.
Extensions v3_extensions() const
Definition: x509cert.cpp:360
BER_Decoder & end_cons()
Definition: ber_dec.cpp:269
X509_DN create_dn(const Data_Store &info)
Definition: x509cert.cpp:622
bool more_items() const
Definition: ber_dec.cpp:155
std::string end_time() const
Definition: x509cert.cpp:208
AlternativeName create_alt_name(const Data_Store &info)
Definition: x509cert.cpp:641
std::vector< byte > get1_memvec(const std::string &) const
Definition: datastor.cpp:92
std::string to_string() const
Definition: x509cert.cpp:493
std::vector< byte > BER_encode() const
Definition: x509_obj.cpp:113
std::string lookup(const OID &oid)
Definition: oids.cpp:155
ASN1_Tag
Definition: asn1_obj.h:22
std::string fingerprint(const std::string &="SHA-1") const
Definition: x509cert.cpp:419
std::vector< byte > subject_public_key_bits() const
Definition: x509cert.cpp:240
std::vector< byte > m_tbs_bits
Definition: x509_obj.h:97
static std::unique_ptr< HashFunction > create(const std::string &algo_spec, const std::string &provider="")
Definition: hash.cpp:98
std::vector< byte > m_sig
Definition: x509_obj.h:97
std::string start_time() const
Definition: x509cert.cpp:200
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:255
std::string PEM_encode(const Public_Key &key)
Definition: x509_key.cpp:32
Definition: alg_id.cpp:13
bool operator<(const X509_Certificate &other) const
Definition: x509cert.cpp:471
std::vector< byte > raw_issuer_dn() const
Definition: x509cert.cpp:404
A single Name Constraints.
std::vector< byte > subject_key_id() const
Definition: x509cert.cpp:386
std::vector< std::string > policies() const
Definition: x509cert.cpp:355
BER_Object get_next_object()
Definition: ber_dec.cpp:207
std::string to_string() const
Return an internal string representation of the time.
Definition: asn1_time.cpp:60
ASN1_Tag class_tag
Definition: asn1_obj.h:88
u32bit get1_u32bit(const std::string &, u32bit=0) const
Definition: datastor.cpp:109
bool has_value(const std::string &) const
Definition: datastor.cpp:27
ASN1_Tag type_tag
Definition: asn1_obj.h:88
BER_Decoder & verify_end()
Definition: ber_dec.cpp:165
X509_DN issuer_dn() const
Definition: x509cert.cpp:399
std::vector< std::string > subject_info(const std::string &name) const
Definition: x509cert.cpp:217
bool is_critical(const std::string &ex_name) const
Definition: x509cert.cpp:310
std::vector< std::string > ex_constraints() const
Definition: x509cert.cpp:327
static std::string deref_info_field(const std::string &)
Definition: x509_dn.cpp:119
std::vector< std::string > issuer_info(const std::string &name) const
Definition: x509cert.cpp:226
std::vector< byte > authority_key_id() const
Definition: x509cert.cpp:378
BER_Decoder & decode_optional_string(std::vector< byte, Alloc > &out, ASN1_Tag real_type, u16bit type_no, ASN1_Tag class_tag=CONTEXT_SPECIFIC)
Definition: ber_dec.h:130
Public_Key * subject_public_key() const
Definition: x509cert.cpp:234
std::multimap< std::string, std::string > contents() const
Definition: x509_dn.cpp:85
bool host_wildcard_match(const std::string &issued, const std::string &host)
Definition: parsing.cpp:335
X509_DN subject_dn() const
Definition: x509cert.cpp:409
u32bit x509_version() const
Definition: x509cert.cpp:192
std::vector< byte > put_in_sequence(const std::vector< byte > &contents)
Definition: asn1_obj.cpp:35
std::vector< std::string > get(const std::string &) const
Definition: datastor.cpp:50
AlgorithmIdentifier signature_algorithm() const
Definition: x509_obj.cpp:147
Usage_Type
Definition: x509cert.h:24
void add(const std::multimap< std::string, std::string > &)
Definition: datastor.cpp:155
Name Constraints.
void hex_encode(char output[], const byte input[], size_t input_length, bool uppercase)
Definition: hex.cpp:14