1 /*
2 * (C) 2009,2019 Jack Lloyd
3 * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include "tests.h"
9 
10 #if defined(BOTAN_HAS_X509_CERTIFICATES)
11    #include <botan/calendar.h>
12    #include <botan/pkcs10.h>
13    #include <botan/pkcs8.h>
14    #include <botan/x509self.h>
15    #include <botan/x509path.h>
16    #include <botan/x509_ca.h>
17    #include <botan/x509_ext.h>
18    #include <botan/pk_algs.h>
19    #include <botan/ber_dec.h>
20    #include <botan/der_enc.h>
21    #include <botan/oids.h>
22    #include <botan/internal/padding.h>
23 #endif
24 
25 namespace Botan_Tests {
26 
27 namespace {
28 
29 #if defined(BOTAN_HAS_X509_CERTIFICATES)
30 
from_date(const int y,const int m,const int d)31 Botan::X509_Time from_date(const int y, const int m, const int d)
32    {
33    const size_t this_year = Botan::calendar_value(std::chrono::system_clock::now()).get_year();
34 
35    Botan::calendar_point t(static_cast<uint32_t>(this_year + y), m, d, 0, 0, 0);
36    return Botan::X509_Time(t.to_std_timepoint());
37    }
38 
39 /* Return some option sets */
ca_opts(const std::string & sig_padding="")40 Botan::X509_Cert_Options ca_opts(const std::string& sig_padding = "")
41    {
42    Botan::X509_Cert_Options opts("Test CA/US/Botan Project/Testing");
43 
44    opts.uri = "https://botan.randombit.net";
45    opts.dns = "botan.randombit.net";
46    opts.email = "testing@randombit.net";
47    opts.set_padding_scheme(sig_padding);
48 
49    opts.CA_key(1);
50 
51    return opts;
52    }
53 
req_opts1(const std::string & algo,const std::string & sig_padding="")54 Botan::X509_Cert_Options req_opts1(const std::string& algo, const std::string& sig_padding = "")
55    {
56    Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");
57 
58    opts.uri = "https://botan.randombit.net";
59    opts.dns = "botan.randombit.net";
60    opts.email = "testing@randombit.net";
61    opts.set_padding_scheme(sig_padding);
62 
63    opts.not_before("160101200000Z");
64    opts.not_after("300101200000Z");
65 
66    opts.challenge = "zoom";
67 
68    if(algo == "RSA")
69       {
70       opts.constraints = Botan::Key_Constraints(Botan::KEY_ENCIPHERMENT);
71       }
72    else if(algo == "DSA" || algo == "ECDSA" || algo == "ECGDSA" || algo == "ECKCDSA")
73       {
74       opts.constraints = Botan::Key_Constraints(Botan::DIGITAL_SIGNATURE);
75       }
76 
77    return opts;
78    }
79 
req_opts2(const std::string & sig_padding="")80 Botan::X509_Cert_Options req_opts2(const std::string& sig_padding = "")
81    {
82    Botan::X509_Cert_Options opts("Test User 2/US/Botan Project/Testing");
83 
84    opts.uri = "https://botan.randombit.net";
85    opts.dns = "botan.randombit.net";
86    opts.email = "testing@randombit.net";
87    opts.set_padding_scheme(sig_padding);
88 
89    opts.add_ex_constraint("PKIX.EmailProtection");
90 
91    return opts;
92    }
93 
req_opts3(const std::string & sig_padding="")94 Botan::X509_Cert_Options req_opts3(const std::string& sig_padding = "")
95    {
96    Botan::X509_Cert_Options opts("Test User 2/US/Botan Project/Testing");
97 
98    opts.uri = "https://botan.randombit.net";
99    opts.dns = "botan.randombit.net";
100    opts.email = "testing@randombit.net";
101    opts.set_padding_scheme(sig_padding);
102 
103    opts.more_org_units.push_back("IT");
104    opts.more_org_units.push_back("Security");
105    opts.more_dns.push_back("www.botan.randombit.net");
106 
107    return opts;
108    }
109 
make_a_private_key(const std::string & algo)110 std::unique_ptr<Botan::Private_Key> make_a_private_key(const std::string& algo)
111    {
112    const std::string params = [&]
113       {
114       // Here we override defaults as needed
115       if(algo == "RSA")
116          {
117          return "1024";
118          }
119       if(algo == "GOST-34.10")
120          {
121          return "gost_256A";
122          }
123       if(algo == "ECKCDSA" || algo == "ECGDSA")
124          {
125          return "brainpool256r1";
126          }
127       return ""; // default "" means choose acceptable algo-specific params
128       }();
129 
130    return Botan::create_private_key(algo, Test::rng(), params);
131    }
132 
test_cert_status_strings()133 Test::Result test_cert_status_strings()
134    {
135    Test::Result result("Certificate_Status_Code to_string");
136 
137    std::set<std::string> seen;
138 
139    result.test_eq("Same string",
140                   Botan::to_string(Botan::Certificate_Status_Code::OK),
141                   Botan::to_string(Botan::Certificate_Status_Code::VERIFIED));
142 
143    const Botan::Certificate_Status_Code codes[]
144       {
145       Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD,
146       Botan::Certificate_Status_Code::OCSP_SIGNATURE_OK,
147       Botan::Certificate_Status_Code::VALID_CRL_CHECKED,
148       Botan::Certificate_Status_Code::OCSP_NO_HTTP,
149 
150       Botan::Certificate_Status_Code::CERT_SERIAL_NEGATIVE,
151       Botan::Certificate_Status_Code::DN_TOO_LONG,
152 
153       Botan::Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK,
154       Botan::Certificate_Status_Code::NO_MATCHING_CRLDP,
155       Botan::Certificate_Status_Code::UNTRUSTED_HASH,
156       Botan::Certificate_Status_Code::NO_REVOCATION_DATA,
157       Botan::Certificate_Status_Code::CERT_NOT_YET_VALID,
158       Botan::Certificate_Status_Code::CERT_HAS_EXPIRED,
159       Botan::Certificate_Status_Code::OCSP_NOT_YET_VALID,
160       Botan::Certificate_Status_Code::OCSP_HAS_EXPIRED,
161       Botan::Certificate_Status_Code::CRL_NOT_YET_VALID,
162       Botan::Certificate_Status_Code::CRL_HAS_EXPIRED,
163       Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND,
164       Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST,
165       Botan::Certificate_Status_Code::CERT_CHAIN_LOOP,
166       Botan::Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT,
167       Botan::Certificate_Status_Code::CHAIN_NAME_MISMATCH,
168       Botan::Certificate_Status_Code::POLICY_ERROR,
169       Botan::Certificate_Status_Code::DUPLICATE_CERT_POLICY,
170       Botan::Certificate_Status_Code::INVALID_USAGE,
171       Botan::Certificate_Status_Code::CERT_CHAIN_TOO_LONG,
172       Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER,
173       Botan::Certificate_Status_Code::NAME_CONSTRAINT_ERROR,
174       Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER,
175       Botan::Certificate_Status_Code::OCSP_CERT_NOT_LISTED,
176       Botan::Certificate_Status_Code::OCSP_BAD_STATUS,
177       Botan::Certificate_Status_Code::CERT_NAME_NOMATCH,
178       Botan::Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION,
179       Botan::Certificate_Status_Code::DUPLICATE_CERT_EXTENSION,
180       Botan::Certificate_Status_Code::EXT_IN_V1_V2_CERT,
181       Botan::Certificate_Status_Code::OCSP_SIGNATURE_ERROR,
182       Botan::Certificate_Status_Code::OCSP_ISSUER_NOT_FOUND,
183       Botan::Certificate_Status_Code::OCSP_RESPONSE_MISSING_KEYUSAGE,
184       Botan::Certificate_Status_Code::OCSP_RESPONSE_INVALID,
185       Botan::Certificate_Status_Code::CERT_IS_REVOKED,
186       Botan::Certificate_Status_Code::CRL_BAD_SIGNATURE,
187       Botan::Certificate_Status_Code::SIGNATURE_ERROR,
188       Botan::Certificate_Status_Code::CERT_PUBKEY_INVALID,
189       Botan::Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN,
190       Botan::Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS,
191       };
192 
193    for(const auto code : codes)
194       {
195       const std::string s = Botan::to_string(code);
196       result.confirm("String is long enough to be informative", s.size() > 12);
197       result.test_eq("No duplicates", seen.count(s), 0);
198       seen.insert(s);
199       }
200 
201    return result;
202 
203    }
204 
test_x509_extension()205 Test::Result test_x509_extension()
206    {
207    Test::Result result("X509 Extensions API");
208 
209    Botan::Extensions extn;
210 
211    const auto oid_bc = Botan::OID::from_string("X509v3.BasicConstraints");
212    const auto oid_skid = Botan::OID::from_string("X509v3.SubjectKeyIdentifier");
213 
214    extn.add(new Botan::Cert_Extension::Basic_Constraints(true), true);
215 
216    result.confirm("Basic constraints is set", extn.extension_set(oid_bc));
217    result.confirm("Basic constraints is critical", extn.critical_extension_set(oid_bc));
218    result.confirm("SKID is not set", !extn.extension_set(oid_skid));
219    result.confirm("SKID is not critical", !extn.critical_extension_set(oid_skid));
220 
221    result.test_eq("Extension::get_extension_bits",
222                   extn.get_extension_bits(oid_bc), "30060101FF020100");
223 
224    result.test_throws("Extension::get_extension_bits throws if not set",
225                       [&]() { extn.get_extension_bits(oid_skid); });
226 
227    result.test_throws("Extension::add throws on second add",
228                       [&]() { extn.add(new Botan::Cert_Extension::Basic_Constraints(false), false); });
229 
230    result.test_eq("Extension::get_extension_bits",
231                   extn.get_extension_bits(oid_bc), "30060101FF020100");
232 
233    result.confirm("Returns false since extension already existed",
234                   !extn.add_new(new Botan::Cert_Extension::Basic_Constraints(false), false));
235 
236    result.confirm("Basic constraints is still critical", extn.critical_extension_set(oid_bc));
237 
238    extn.replace(new Botan::Cert_Extension::Basic_Constraints(false), false);
239    result.confirm("Replaced basic constraints is not critical", !extn.critical_extension_set(oid_bc));
240    result.test_eq("Extension::get_extension_bits", extn.get_extension_bits(oid_bc), "3000");
241 
242    result.confirm("Delete returns false if extn not set", !extn.remove(oid_skid));
243    result.confirm("Delete returns true if extn was set", extn.remove(oid_bc));
244    result.confirm("Basic constraints is not set", !extn.extension_set(oid_bc));
245    result.confirm("Basic constraints is not critical", !extn.critical_extension_set(oid_bc));
246 
247    return result;
248    }
249 
test_x509_dates()250 Test::Result test_x509_dates()
251    {
252    Test::Result result("X509 Time");
253 
254    Botan::X509_Time time;
255    result.confirm("unset time not set", !time.time_is_set());
256    time = Botan::X509_Time("080201182200Z", Botan::ASN1_Tag::UTC_TIME);
257    result.confirm("time set after construction", time.time_is_set());
258    result.test_eq("time readable_string", time.readable_string(), "2008/02/01 18:22:00 UTC");
259 
260    time = Botan::X509_Time("200305100350Z", Botan::ASN1_Tag::UTC_TIME);
261    result.test_eq("UTC_TIME readable_string", time.readable_string(), "2020/03/05 10:03:50 UTC");
262 
263    time = Botan::X509_Time("200305100350Z", Botan::ASN1_Tag::UTC_OR_GENERALIZED_TIME);
264    result.test_eq("UTC_OR_GENERALIZED_TIME from UTC_TIME readable_string", time.readable_string(),
265                   "2020/03/05 10:03:50 UTC");
266 
267    time = Botan::X509_Time("20200305100350Z", Botan::ASN1_Tag::UTC_OR_GENERALIZED_TIME);
268    result.test_eq("UTC_OR_GENERALIZED_TIME from GENERALIZED_TIME readable_string", time.readable_string(),
269                   "2020/03/05 10:03:50 UTC");
270 
271    time = Botan::X509_Time("20200305100350Z", Botan::ASN1_Tag::GENERALIZED_TIME);
272    result.test_eq("GENERALIZED_TIME readable_string", time.readable_string(), "2020/03/05 10:03:50 UTC");
273 
274    // Dates that are valid per X.500 but rejected as unsupported
275    const std::string valid_but_unsup[]
276       {
277       "0802010000-0000",
278       "0802011724+0000",
279       "0406142334-0500",
280       "9906142334+0500",
281       "0006142334-0530",
282       "0006142334+0530",
283 
284       "080201000000-0000",
285       "080201172412+0000",
286       "040614233433-0500",
287       "990614233444+0500",
288       "000614233455-0530",
289       "000614233455+0530",
290       };
291 
292    // valid length 13
293    const std::string valid_utc[]
294       {
295       "080201000000Z",
296       "080201172412Z",
297       "040614233433Z",
298       "990614233444Z",
299       "000614233455Z",
300       };
301 
302    const std::string invalid_utc[]
303       {
304       "",
305       " ",
306       "2008`02-01",
307       "9999-02-01",
308       "2000-02-01 17",
309       "999921",
310 
311       // No seconds
312       "0802010000Z",
313       "0802011724Z",
314       "0406142334Z",
315       "9906142334Z",
316       "0006142334Z",
317 
318       // valid length 13 -> range check
319       "080201000061Z", // seconds too big (61)
320       "080201000060Z", // seconds too big (60, leap seconds not covered by the standard)
321       "0802010000-1Z", // seconds too small (-1)
322       "080201006000Z", // minutes too big (60)
323       "080201240000Z", // hours too big (24:00)
324 
325       // valid length 13 -> invalid numbers
326       "08020123112 Z",
327       "08020123112!Z",
328       "08020123112,Z",
329       "08020123112\nZ",
330       "080201232 33Z",
331       "080201232!33Z",
332       "080201232,33Z",
333       "080201232\n33Z",
334       "0802012 3344Z",
335       "0802012!3344Z",
336       "0802012,3344Z",
337       "08022\n334455Z",
338       "08022 334455Z",
339       "08022!334455Z",
340       "08022,334455Z",
341       "08022\n334455Z",
342       "082 33445511Z",
343       "082!33445511Z",
344       "082,33445511Z",
345       "082\n33445511Z",
346       "2 2211221122Z",
347       "2!2211221122Z",
348       "2,2211221122Z",
349       "2\n2211221122Z",
350 
351       // wrong time zone
352       "080201000000",
353       "080201000000z",
354 
355       // Fractional seconds
356       "170217180154.001Z",
357 
358       // Timezone offset
359       "170217180154+0100",
360 
361       // Extra digits
362       "17021718015400Z",
363 
364       // Non-digits
365       "17021718015aZ",
366 
367       // Trailing garbage
368       "170217180154Zlongtrailinggarbage",
369 
370       // Swapped type
371       "20170217180154Z",
372       };
373 
374    // valid length 15
375    const std::string valid_generalized_time[]
376       {
377       "20000305100350Z",
378       };
379 
380    const std::string invalid_generalized[]
381       {
382       // No trailing Z
383       "20000305100350",
384 
385       // No seconds
386       "200003051003Z",
387 
388       // Fractional seconds
389       "20000305100350.001Z",
390 
391       // Timezone offset
392       "20170217180154+0100",
393 
394       // Extra digits
395       "2017021718015400Z",
396 
397       // Non-digits
398       "2017021718015aZ",
399 
400       // Trailing garbage
401       "20170217180154Zlongtrailinggarbage",
402 
403       // Swapped type
404       "170217180154Z",
405       };
406 
407    for(const auto& v : valid_but_unsup)
408       {
409       result.test_throws("valid but unsupported", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
410       }
411 
412    for(const auto& v : valid_utc)
413       {
414       Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME);
415       }
416 
417    for(const auto& v : valid_generalized_time)
418       {
419       Botan::X509_Time t(v, Botan::ASN1_Tag::GENERALIZED_TIME);
420       }
421 
422    for(const auto& v : invalid_utc)
423       {
424       result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
425       }
426 
427    for(const auto& v : invalid_generalized)
428       {
429       result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::GENERALIZED_TIME); });
430       }
431 
432    return result;
433    }
434 
435 #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
436 
test_crl_dn_name()437 Test::Result test_crl_dn_name()
438    {
439    Test::Result result("CRL DN name");
440 
441    // See GH #1252
442 
443 #if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EMSA_PKCS1)
444    const Botan::OID dc_oid("0.9.2342.19200300.100.1.25");
445 
446    Botan::X509_Certificate cert(Test::data_file("x509/misc/opcuactt_ca.der"));
447 
448    Botan::DataSource_Stream key_input(Test::data_file("x509/misc/opcuactt_ca.pem"));
449    std::unique_ptr<Botan::Private_Key> key = Botan::PKCS8::load_key(key_input);
450    Botan::X509_CA ca(cert, *key, "SHA-256", Test::rng());
451 
452    Botan::X509_CRL crl = ca.new_crl(Test::rng());
453 
454    result.confirm("matches issuer cert", crl.issuer_dn() == cert.subject_dn());
455 
456    result.confirm("contains DC component",
457                   crl.issuer_dn().get_attributes().count(dc_oid) == 1);
458 #endif
459 
460    return result;
461    }
462 
test_rdn_multielement_set_name()463 Test::Result test_rdn_multielement_set_name()
464    {
465    Test::Result result("DN with multiple elements in RDN");
466 
467    // GH #2611
468 
469    Botan::X509_Certificate cert(Test::data_file("x509/misc/rdn_set.crt"));
470 
471    result.confirm("contains expected name components",
472                   cert.issuer_dn().get_attributes().size() == 4);
473 
474    return result;
475    }
476 
test_rsa_oaep()477 Test::Result test_rsa_oaep()
478    {
479    Test::Result result("RSA OAEP decoding");
480 
481 #if defined(BOTAN_HAS_RSA)
482    Botan::X509_Certificate cert(Test::data_file("x509/misc/rsa_oaep.pem"));
483 
484    auto public_key = cert.load_subject_public_key();
485    result.test_not_null("Decoding RSA-OAEP worked", public_key.get());
486    auto pk_info = cert.subject_public_key_algo();
487 
488    result.test_eq("RSA-OAEP OID", pk_info.get_oid().to_string(), Botan::OID::from_string("RSA/OAEP").to_string());
489 #endif
490 
491    return result;
492    }
493 
test_x509_decode_list()494 Test::Result test_x509_decode_list()
495    {
496    Test::Result result("X509_Certificate list decode");
497 
498    Botan::DataSource_Stream input(Test::data_file("x509/misc/cert_seq.der"), true);
499 
500    Botan::BER_Decoder dec(input);
501    std::vector<Botan::X509_Certificate> certs;
502    dec.decode_list(certs);
503 
504    result.test_eq("Expected number of certs in list", certs.size(), 2);
505 
506    result.test_eq("Expected cert 1 CN", certs[0].subject_dn().get_first_attribute("CN"), "CA1-PP.01.02");
507    result.test_eq("Expected cert 2 CN", certs[1].subject_dn().get_first_attribute("CN"), "User1-PP.01.02");
508 
509    return result;
510    }
511 
test_x509_utf8()512 Test::Result test_x509_utf8()
513    {
514    Test::Result result("X509 with UTF-8 encoded fields");
515 
516    try
517       {
518       Botan::X509_Certificate utf8_cert(Test::data_file("x509/misc/contains_utf8string.pem"));
519 
520       // UTF-8 encoded fields of test certificate (contains cyrillic letters)
521       const std::string organization =
522          "\xD0\x9C\xD0\xBE\xD1\x8F\x20\xD0\xBA\xD0\xBE\xD0"
523          "\xBC\xD0\xBF\xD0\xB0\xD0\xBD\xD0\xB8\xD1\x8F";
524       const std::string organization_unit =
525          "\xD0\x9C\xD0\xBE\xD1\x91\x20\xD0\xBF\xD0\xBE\xD0\xB4\xD1\x80\xD0\xB0"
526          "\xD0\xB7\xD0\xB4\xD0\xB5\xD0\xBB\xD0\xB5\xD0\xBD\xD0\xB8\xD0\xB5";
527       const std::string common_name =
528          "\xD0\x9E\xD0\xBF\xD0\xB8\xD1\x81\xD0\xB0\xD0\xBD\xD0\xB8"
529          "\xD0\xB5\x20\xD1\x81\xD0\xB0\xD0\xB9\xD1\x82\xD0\xB0";
530       const std::string location =
531          "\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0";
532 
533       const Botan::X509_DN& issuer_dn = utf8_cert.issuer_dn();
534 
535       result.test_eq("O",  issuer_dn.get_first_attribute("O"),  organization);
536       result.test_eq("OU", issuer_dn.get_first_attribute("OU"), organization_unit);
537       result.test_eq("CN", issuer_dn.get_first_attribute("CN"), common_name);
538       result.test_eq("L",  issuer_dn.get_first_attribute("L"),  location);
539       }
540    catch (const Botan::Decoding_Error &ex)
541       {
542       result.test_failure(ex.what());
543       }
544 
545    return result;
546    }
547 
test_x509_bmpstring()548 Test::Result test_x509_bmpstring()
549    {
550    Test::Result result("X509 with UCS-2 (BMPString) encoded fields");
551 
552    try
553       {
554       Botan::X509_Certificate ucs2_cert(Test::data_file("x509/misc/contains_bmpstring.pem"));
555 
556       // UTF-8 encoded fields of test certificate (contains cyrillic and greek letters)
557       const std::string organization =
558          "\x6E\x65\xCF\x87\xCF\xB5\x6E\x69\xCF\x89";
559       const std::string common_name =
560          "\xC3\xA8\x6E\xC7\x9D\xD0\xAF\x20\xD0\x9C\xC7\x9D\xD0\xB9\xD0\xB7\xD1\x8D\xD0\xBB";
561 
562       // UTF-8 encoded fields of test certificate (contains only ASCII characters)
563       const std::string location = "Berlin";
564 
565       const Botan::X509_DN& issuer_dn = ucs2_cert.issuer_dn();
566 
567       result.test_eq("O",  issuer_dn.get_first_attribute("O"),  organization);
568       result.test_eq("CN", issuer_dn.get_first_attribute("CN"), common_name);
569       result.test_eq("L",  issuer_dn.get_first_attribute("L"),  location);
570       }
571    catch (const Botan::Decoding_Error &ex)
572       {
573       result.test_failure(ex.what());
574       }
575 
576    return result;
577    }
578 
test_x509_authority_info_access_extension()579 Test::Result test_x509_authority_info_access_extension()
580    {
581    Test::Result result("X509 with PKIX.AuthorityInformationAccess extension");
582 
583    // contains no AIA extension
584    Botan::X509_Certificate no_aia_cert(Test::data_file("x509/misc/contains_utf8string.pem"));
585 
586    result.test_eq("number of ca_issuers URLs", no_aia_cert.ca_issuers().size(), 0);
587    result.test_eq("CA issuer URL matches", no_aia_cert.ocsp_responder(), "");
588 
589    // contains AIA extension with 1 CA issuer URL and 1 OCSP responder
590    Botan::X509_Certificate aia_cert(Test::data_file("x509/misc/contains_authority_info_access.pem"));
591 
592    const auto ca_issuers = aia_cert.ca_issuers();
593 
594    result.test_eq("number of ca_issuers URLs", ca_issuers.size(), 1);
595    if (result.tests_failed())
596       return result;
597 
598    result.test_eq("CA issuer URL matches", ca_issuers[0], "http://gp.symcb.com/gp.crt");
599    result.test_eq("OCSP responder URL matches", aia_cert.ocsp_responder(), "http://gp.symcd.com");
600 
601    // contains AIA extension with 2 CA issuer URL and 1 OCSP responder
602    Botan::X509_Certificate aia_cert_2ca(Test::data_file("x509/misc/contains_authority_info_access_with_two_ca_issuers.pem"));
603 
604    const auto ca_issuers2 = aia_cert_2ca.ca_issuers();
605 
606    result.test_eq("number of ca_issuers URLs", ca_issuers2.size(), 2);
607    if (result.tests_failed())
608       return result;
609 
610    result.test_eq("CA issuer URL matches", ca_issuers2[0], "http://www.d-trust.net/cgi-bin/Bdrive_Test_CA_1-2_2017.crt");
611    result.test_eq("CA issuer URL matches", ca_issuers2[1], "ldap://directory.d-trust.net/CN=Bdrive%20Test%20CA%201-2%202017,O=Bundesdruckerei%20GmbH,C=DE?cACertificate?base?");
612    result.test_eq("OCSP responder URL matches", aia_cert_2ca.ocsp_responder(), "http://staging.ocsp.d-trust.net");
613 
614    return result;
615    }
616 
test_verify_gost2012_cert()617 Test::Result test_verify_gost2012_cert()
618    {
619    Test::Result result("X509 GOST-2012 certificates");
620 
621 #if defined(BOTAN_HAS_GOST_34_10_2012) && defined(BOTAN_HAS_STREEBOG) && defined(BOTAN_HAS_EMSA1)
622    try
623       {
624       Botan::X509_Certificate root_cert(Test::data_file("x509/gost/gost_root.pem"));
625       Botan::X509_Certificate root_int(Test::data_file("x509/gost/gost_int.pem"));
626 
627       Botan::Certificate_Store_In_Memory trusted;
628       trusted.add_certificate(root_cert);
629 
630       const Botan::Path_Validation_Restrictions restrictions(false, 128, false, {"Streebog-256"});
631       const Botan::Path_Validation_Result validation_result = Botan::x509_path_validate(root_int, restrictions, trusted);
632 
633       result.confirm("GOST certificate validates", validation_result.successful_validation());
634       }
635    catch(const Botan::Decoding_Error& e)
636       {
637       result.test_failure(e.what());
638       }
639 #endif
640 
641    return result;
642    }
643 
644 /*
645  * @brief checks the configurability of the EMSA4(RSA-PSS) signature scheme
646  *
647  * For the other algorithms than RSA, only one padding is supported right now.
648  */
649 #if defined(BOTAN_HAS_EMSA_PKCS1) && defined(BOTAN_HAS_EMSA_PSSR) && defined(BOTAN_HAS_RSA)
test_padding_config()650  Test::Result test_padding_config() {
651    // Throughout the test, some synonyms for EMSA4 are used, e.g. PSSR, EMSA-PSS
652    Test::Result test_result("X509 Padding Config");
653 
654    std::unique_ptr<Botan::Private_Key> sk(Botan::PKCS8::load_key(
655       Test::data_file("x509/misc/rsa_key.pem"), Test::rng()));
656 
657    // Create X509 CA certificate; EMSA3 is used for signing by default
658    Botan::X509_Cert_Options opt("TESTCA");
659    opt.CA_key();
660 
661    Botan::X509_Certificate ca_cert_def = Botan::X509::create_self_signed_cert(opt, (*sk), "SHA-512", Test::rng());
662    test_result.test_eq("CA certificate signature algorithm (default)",
663       Botan::OIDS::oid2str_or_throw(ca_cert_def.signature_algorithm().get_oid()),"RSA/EMSA3(SHA-512)");
664 
665    // Create X509 CA certificate; RSA-PSS is explicitly set
666    opt.set_padding_scheme("PSSR");
667    Botan::X509_Certificate ca_cert_exp = Botan::X509::create_self_signed_cert(opt, (*sk), "SHA-512", Test::rng());
668    test_result.test_eq("CA certificate signature algorithm (explicit)",
669       Botan::OIDS::oid2str_or_throw(ca_cert_exp.signature_algorithm().get_oid()),"RSA/EMSA4");
670 
671 #if defined(BOTAN_HAS_EMSA1)
672 
673    // Try to set a padding scheme that is not supported for signing with the given key type
674    opt.set_padding_scheme("EMSA1");
675    try
676       {
677       Botan::X509_Certificate ca_cert_wrong = Botan::X509::create_self_signed_cert(opt, (*sk), "SHA-512", Test::rng());
678       test_result.test_failure("Could build CA cert with invalid encoding scheme EMSA1 for key type " + sk->algo_name());
679       }
680    catch (const Botan::Invalid_Argument& e)
681       {
682       test_result.test_eq("Build CA certitiface with invalid encoding scheme EMSA1 for key type " +
683          sk->algo_name(), e.what(),
684          "Encoding scheme with canonical name EMSA1 not supported for signature algorithm RSA");
685       }
686 #endif
687 
688    test_result.test_eq("CA certificate signature algorithm (explicit)",
689       Botan::OIDS::oid2str_or_throw(ca_cert_exp.signature_algorithm().get_oid()),"RSA/EMSA4");
690 
691    const Botan::X509_Time not_before = from_date(-1, 1, 1);
692    const Botan::X509_Time not_after = from_date(2, 1, 2);
693 
694    // Prepare a signing request for the end certificate
695    Botan::X509_Cert_Options req_opt("endpoint");
696    req_opt.set_padding_scheme("EMSA4(SHA-512,MGF1,64)");
697    Botan::PKCS10_Request end_req = Botan::X509::create_cert_req(req_opt, (*sk), "SHA-512", Test::rng());
698    test_result.test_eq("Certificate request signature algorithm", Botan::OIDS::oid2str_or_throw(end_req.signature_algorithm().get_oid()),"RSA/EMSA4");
699 
700    // Create X509 CA object: will fail as the chosen hash functions differ
701    try
702       {
703       Botan::X509_CA ca_fail(ca_cert_exp, (*sk), {{"padding","EMSA4(SHA-256)"}},"SHA-512", Test::rng());
704       test_result.test_failure("Configured conflicting hash functions for CA");
705       }
706    catch(const Botan::Invalid_Argument& e)
707       {
708       test_result.test_eq("Configured conflicting hash functions for CA",
709             e.what(),
710             "Hash function from opts and hash_fn argument need to be identical");
711       }
712 
713    // Create X509 CA object: its signer will use the padding scheme from the CA certificate, i.e. EMSA3
714    Botan::X509_CA ca_def(ca_cert_def, (*sk), "SHA-512", Test::rng());
715    Botan::X509_Certificate end_cert_emsa3 = ca_def.sign_request(end_req, Test::rng(), not_before, not_after);
716    test_result.test_eq("End certificate signature algorithm", Botan::OIDS::oid2str_or_throw(end_cert_emsa3.signature_algorithm().get_oid()), "RSA/EMSA3(SHA-512)");
717 
718    // Create X509 CA object: its signer will use the explicitly configured padding scheme, which is different from the CA certificate's scheme
719    Botan::X509_CA ca_diff(ca_cert_def, (*sk), {{"padding","EMSA-PSS"}}, "SHA-512", Test::rng());
720    Botan::X509_Certificate end_cert_diff_emsa4 = ca_diff.sign_request(end_req, Test::rng(), not_before, not_after);
721    test_result.test_eq("End certificate signature algorithm", Botan::OIDS::oid2str_or_throw(end_cert_diff_emsa4.signature_algorithm().get_oid()), "RSA/EMSA4");
722 
723    // Create X509 CA object: its signer will use the explicitly configured padding scheme, which is identical to the CA certificate's scheme
724    Botan::X509_CA ca_exp(ca_cert_exp, (*sk), {{"padding","EMSA4(SHA-512,MGF1,64)"}},"SHA-512", Test::rng());
725    Botan::X509_Certificate end_cert_emsa4= ca_exp.sign_request(end_req, Test::rng(), not_before, not_after);
726    test_result.test_eq("End certificate signature algorithm", Botan::OIDS::oid2str_or_throw(end_cert_emsa4.signature_algorithm().get_oid()), "RSA/EMSA4");
727 
728    // Check CRL signature algorithm
729    Botan::X509_CRL crl = ca_exp.new_crl(Test::rng());
730    test_result.test_eq("CRL signature algorithm", Botan::OIDS::oid2str_or_throw(crl.signature_algorithm().get_oid()), "RSA/EMSA4");
731 
732    // sanity check for verification, the heavy lifting is done in the other unit tests
733    const Botan::Certificate_Store_In_Memory trusted(ca_exp.ca_certificate());
734    const Botan::Path_Validation_Restrictions restrictions(false, 80);
735    const Botan::Path_Validation_Result validation_result = Botan::x509_path_validate(
736             end_cert_emsa4, restrictions, trusted);
737    test_result.confirm("EMSA4-signed certificate validates", validation_result.successful_validation());
738 
739    return test_result;
740 }
741 #endif
742 
743 #endif
744 
test_pkcs10_ext(const Botan::Private_Key & key,const std::string & sig_padding,const std::string & hash_fn="SHA-256")745 Test::Result test_pkcs10_ext(const Botan::Private_Key& key,
746                              const std::string& sig_padding,
747                              const std::string& hash_fn = "SHA-256")
748    {
749    Test::Result result("PKCS10 extensions");
750 
751    Botan::X509_Cert_Options opts;
752 
753    opts.padding_scheme = sig_padding;
754 
755    Botan::AlternativeName alt_name;
756    alt_name.add_attribute("DNS", "example.org");
757    alt_name.add_attribute("DNS", "example.com");
758    alt_name.add_attribute("DNS", "example.net");
759 
760    opts.extensions.add(new Botan::Cert_Extension::Subject_Alternative_Name(alt_name));
761 
762    Botan::PKCS10_Request req = Botan::X509::create_cert_req(opts, key, hash_fn, Test::rng());
763 
764    std::vector<std::string> alt_dns_names = req.subject_alt_name().get_attribute("DNS");
765 
766    result.test_eq("Expected number of DNS names", alt_dns_names.size(), 3);
767 
768    // The order is not guaranteed so sort before comparing
769    std::sort(alt_dns_names.begin(), alt_dns_names.end());
770 
771    result.test_eq("Expected DNS name 1", alt_dns_names.at(0), "example.com");
772    result.test_eq("Expected DNS name 2", alt_dns_names.at(1), "example.net");
773    result.test_eq("Expected DNS name 3", alt_dns_names.at(2), "example.org");
774 
775    return result;
776    }
777 
test_x509_cert(const Botan::Private_Key & ca_key,const std::string & sig_algo,const std::string & sig_padding="",const std::string & hash_fn="SHA-256")778 Test::Result test_x509_cert(const Botan::Private_Key& ca_key,
779                             const std::string& sig_algo,
780                             const std::string& sig_padding = "",
781                             const std::string& hash_fn = "SHA-256")
782    {
783    Test::Result result("X509 Unit");
784 
785    /* Create the self-signed cert */
786    const auto ca_cert = Botan::X509::create_self_signed_cert(ca_opts(sig_padding), ca_key, hash_fn, Test::rng());
787 
788       {
789       const auto constraints = Botan::Key_Constraints(Botan::KEY_CERT_SIGN | Botan::CRL_SIGN);
790       result.test_eq("ca key usage", (ca_cert.constraints() & constraints) == constraints, true);
791       }
792 
793    /* Create user #1's key and cert request */
794    std::unique_ptr<Botan::Private_Key> user1_key(make_a_private_key(sig_algo));
795 
796    Botan::PKCS10_Request user1_req =
797       Botan::X509::create_cert_req(req_opts1(sig_algo, sig_padding),
798                                    *user1_key,
799                                    hash_fn,
800                                    Test::rng());
801 
802    result.test_eq("PKCS10 challenge password parsed",
803                   user1_req.challenge_password(), "zoom");
804 
805    /* Create user #2's key and cert request */
806    std::unique_ptr<Botan::Private_Key> user2_key(make_a_private_key(sig_algo));
807 
808    Botan::PKCS10_Request user2_req =
809       Botan::X509::create_cert_req(req_opts2(sig_padding),
810                                    *user2_key,
811                                    hash_fn,
812                                    Test::rng());
813 
814    // /* Create user #3's key and cert request */
815    std::unique_ptr<Botan::Private_Key> user3_key(make_a_private_key(sig_algo));
816 
817    Botan::PKCS10_Request user3_req =
818       Botan::X509::create_cert_req(req_opts3(sig_padding),
819                                    *user3_key,
820                                    hash_fn,
821                                    Test::rng());
822 
823    /* Create the CA object */
824    Botan::X509_CA ca(ca_cert, ca_key, {{"padding",sig_padding}}, hash_fn, Test::rng());
825 
826    const BigInt user1_serial = 99;
827 
828    /* Sign the requests to create the certs */
829    Botan::X509_Certificate user1_cert =
830       ca.sign_request(user1_req, Test::rng(), user1_serial,
831                       from_date(-1, 01, 01),
832                       from_date(2, 01, 01));
833 
834    result.test_eq("User1 serial size matches expected", user1_cert.serial_number().size(), 1);
835    result.test_eq("User1 serial matches expected", user1_cert.serial_number().at(0), size_t(99));
836 
837    Botan::X509_Certificate user2_cert =
838       ca.sign_request(user2_req, Test::rng(),
839                       from_date(-1, 01, 01),
840                       from_date(2, 01, 01));
841 
842    Botan::X509_Certificate user3_cert =
843       ca.sign_request(user3_req, Test::rng(),
844                       from_date(-1, 01, 01),
845                       from_date(2, 01, 01));
846 
847    // user#1 creates a self-signed cert on the side
848    const auto user1_ss_cert =
849       Botan::X509::create_self_signed_cert(req_opts1(sig_algo, sig_padding), *user1_key, hash_fn, Test::rng());
850 
851       {
852       auto constrains = req_opts1(sig_algo).constraints;
853       result.test_eq("user1 key usage", (user1_cert.constraints() & constrains) == constrains, true);
854       }
855 
856    /* Copy, assign and compare */
857    Botan::X509_Certificate user1_cert_copy(user1_cert);
858    result.test_eq("certificate copy", user1_cert == user1_cert_copy, true);
859 
860    user1_cert_copy = user2_cert;
861    result.test_eq("certificate assignment", user2_cert == user1_cert_copy, true);
862 
863    Botan::X509_Certificate user1_cert_differ =
864       ca.sign_request(user1_req, Test::rng(),
865                       from_date(-1, 01, 01),
866                       from_date(2, 01, 01));
867 
868    result.test_eq("certificate differs", user1_cert == user1_cert_differ, false);
869 
870    /* Get cert data */
871    result.test_eq("x509 version", user1_cert.x509_version(), size_t(3));
872 
873    const Botan::X509_DN& user1_issuer_dn = user1_cert.issuer_dn();
874    result.test_eq("issuer info CN", user1_issuer_dn.get_first_attribute("CN"), ca_opts().common_name);
875    result.test_eq("issuer info Country", user1_issuer_dn.get_first_attribute("C"), ca_opts().country);
876    result.test_eq("issuer info Orga", user1_issuer_dn.get_first_attribute("O"), ca_opts().organization);
877    result.test_eq("issuer info OrgaUnit", user1_issuer_dn.get_first_attribute("OU"), ca_opts().org_unit);
878 
879    const Botan::X509_DN& user3_subject_dn = user3_cert.subject_dn();
880    result.test_eq("subject OrgaUnit count", user3_subject_dn.get_attribute("OU").size(), req_opts3(sig_algo).more_org_units.size() + 1);
881    result.test_eq("subject OrgaUnit #2", user3_subject_dn.get_attribute("OU").at(1), req_opts3(sig_algo).more_org_units.at(0));
882 
883    const Botan::AlternativeName& user1_altname = user1_cert.subject_alt_name();
884    result.test_eq("subject alt email", user1_altname.get_first_attribute("RFC822"), "testing@randombit.net");
885    result.test_eq("subject alt dns", user1_altname.get_first_attribute("DNS"), "botan.randombit.net");
886    result.test_eq("subject alt uri", user1_altname.get_first_attribute("URI"), "https://botan.randombit.net");
887 
888    const Botan::AlternativeName& user3_altname = user3_cert.subject_alt_name();
889    result.test_eq("subject alt dns count", user3_altname.get_attribute("DNS").size(), req_opts3(sig_algo).more_dns.size() + 1);
890    result.test_eq("subject alt dns #2", user3_altname.get_attribute("DNS").at(1), req_opts3(sig_algo).more_dns.at(0));
891 
892    const Botan::X509_CRL crl1 = ca.new_crl(Test::rng());
893 
894    /* Verify the certs */
895    Botan::Path_Validation_Restrictions restrictions(false, 80);
896    Botan::Certificate_Store_In_Memory store;
897 
898    // First try with an empty store
899    Botan::Path_Validation_Result result_no_issuer = Botan::x509_path_validate(user1_cert, restrictions, store);
900    result.test_eq("user 1 issuer not found",
901                   result_no_issuer.result_string(),
902                   Botan::Path_Validation_Result::status_string(Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND));
903 
904    store.add_certificate(ca.ca_certificate());
905 
906    Botan::Path_Validation_Result result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store);
907    if(!result.confirm("user 1 validates", result_u1.successful_validation()))
908       {
909       result.test_note("user 1 validation result was " + result_u1.result_string());
910       }
911    else
912       {
913       const std::set<std::string> u1_hashes = result_u1.trusted_hashes();
914 
915       if(result.test_eq("Single trusted hash", u1_hashes.size(), 1))
916          {
917          result.test_eq("Hash matches test", *u1_hashes.begin(), hash_fn);
918          }
919       }
920 
921    Botan::Path_Validation_Result result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store);
922    if(!result.confirm("user 2 validates", result_u2.successful_validation()))
923       {
924       result.test_note("user 2 validation result was " + result_u2.result_string());
925       }
926 
927    Botan::Path_Validation_Result result_self_signed = Botan::x509_path_validate(user1_ss_cert, restrictions, store);
928    result.test_eq("user 1 issuer not found",
929                   result_no_issuer.result_string(),
930                   Botan::Path_Validation_Result::status_string(Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND));
931    store.add_crl(crl1);
932 
933    std::vector<Botan::CRL_Entry> revoked;
934    revoked.push_back(Botan::CRL_Entry(user1_cert, Botan::CESSATION_OF_OPERATION));
935    revoked.push_back(user2_cert);
936 
937    const Botan::X509_CRL crl2 = ca.update_crl(crl1, revoked, Test::rng());
938 
939    store.add_crl(crl2);
940 
941    const std::string revoked_str =
942       Botan::Path_Validation_Result::status_string(Botan::Certificate_Status_Code::CERT_IS_REVOKED);
943 
944    result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store);
945    result.test_eq("user 1 revoked", result_u1.result_string(), revoked_str);
946 
947    result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store);
948    result.test_eq("user 1 revoked", result_u2.result_string(), revoked_str);
949 
950    revoked.clear();
951    revoked.push_back(Botan::CRL_Entry(user1_cert, Botan::REMOVE_FROM_CRL));
952    Botan::X509_CRL crl3 = ca.update_crl(crl2, revoked, Test::rng());
953 
954    store.add_crl(crl3);
955 
956    result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store);
957    if(!result.confirm("user 1 validates", result_u1.successful_validation()))
958       {
959       result.test_note("user 1 validation result was " + result_u1.result_string());
960       }
961 
962    result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store);
963    result.test_eq("user 2 still revoked", result_u2.result_string(), revoked_str);
964 
965    return result;
966    }
967 
test_usage(const Botan::Private_Key & ca_key,const std::string & sig_algo,const std::string & hash_fn="SHA-256")968 Test::Result test_usage(const Botan::Private_Key& ca_key,
969                         const std::string& sig_algo,
970                         const std::string& hash_fn = "SHA-256")
971    {
972    using Botan::Key_Constraints;
973    using Botan::Usage_Type;
974 
975    Test::Result result("X509 Usage");
976 
977    /* Create the self-signed cert */
978    const Botan::X509_Certificate ca_cert = Botan::X509::create_self_signed_cert(
979          ca_opts(),
980          ca_key,
981          hash_fn,
982          Test::rng());
983 
984    /* Create the CA object */
985    const Botan::X509_CA ca(ca_cert, ca_key, hash_fn, Test::rng());
986 
987    std::unique_ptr<Botan::Private_Key> user1_key(make_a_private_key(sig_algo));
988 
989    Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");
990    opts.constraints = Key_Constraints::DIGITAL_SIGNATURE;
991 
992    const Botan::PKCS10_Request user1_req = Botan::X509::create_cert_req(
993          opts,
994          *user1_key,
995          hash_fn,
996          Test::rng());
997 
998    const Botan::X509_Certificate user1_cert = ca.sign_request(
999             user1_req,
1000             Test::rng(),
1001             from_date(-1, 01, 01),
1002             from_date(2, 01, 01));
1003 
1004    // cert only allows digitalSignature, but we check for both digitalSignature and cRLSign
1005    result.test_eq("key usage cRLSign not allowed",
1006                   user1_cert.allowed_usage(
1007                      Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::CRL_SIGN)), false);
1008    result.test_eq("encryption is not allowed",
1009                   user1_cert.allowed_usage(Usage_Type::ENCRYPTION), false);
1010 
1011    // cert only allows digitalSignature, so checking for only that should be ok
1012    result.confirm("key usage digitalSignature allowed", user1_cert.allowed_usage(Key_Constraints::DIGITAL_SIGNATURE));
1013 
1014    opts.constraints = Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::CRL_SIGN);
1015 
1016    const Botan::PKCS10_Request mult_usage_req = Botan::X509::create_cert_req(
1017             opts,
1018             *user1_key,
1019             hash_fn,
1020             Test::rng());
1021 
1022    const Botan::X509_Certificate mult_usage_cert = ca.sign_request(
1023             mult_usage_req,
1024             Test::rng(),
1025             from_date(-1, 01, 01),
1026             from_date(2, 01, 01));
1027 
1028    // cert allows multiple usages, so each one of them as well as both together should be allowed
1029    result.confirm("key usage multiple digitalSignature allowed",
1030                   mult_usage_cert.allowed_usage(Key_Constraints::DIGITAL_SIGNATURE));
1031    result.confirm("key usage multiple cRLSign allowed", mult_usage_cert.allowed_usage(Key_Constraints::CRL_SIGN));
1032    result.confirm("key usage multiple digitalSignature and cRLSign allowed", mult_usage_cert.allowed_usage(
1033                      Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::CRL_SIGN)));
1034    result.test_eq("encryption is not allowed",
1035                   mult_usage_cert.allowed_usage(Usage_Type::ENCRYPTION), false);
1036 
1037 
1038    opts.constraints = Key_Constraints::NO_CONSTRAINTS;
1039 
1040    const Botan::PKCS10_Request no_usage_req = Botan::X509::create_cert_req(opts, *user1_key, hash_fn, Test::rng());
1041 
1042    const Botan::X509_Certificate no_usage_cert =
1043       ca.sign_request(no_usage_req, Test::rng(),
1044                       from_date(-1, 01, 01),
1045                       from_date(2, 01, 01));
1046 
1047    // cert allows every usage
1048    result.confirm("key usage digitalSignature allowed", no_usage_cert.allowed_usage(Key_Constraints::DIGITAL_SIGNATURE));
1049    result.confirm("key usage cRLSign allowed", no_usage_cert.allowed_usage(Key_Constraints::CRL_SIGN));
1050    result.confirm("key usage encryption allowed", no_usage_cert.allowed_usage(Usage_Type::ENCRYPTION));
1051 
1052    if (sig_algo == "RSA")
1053       {
1054       // cert allows data encryption
1055        opts.constraints = Key_Constraints(Key_Constraints::KEY_ENCIPHERMENT | Key_Constraints::DATA_ENCIPHERMENT);
1056 
1057       const Botan::PKCS10_Request enc_req = Botan::X509::create_cert_req(
1058                opts,
1059                *user1_key,
1060                hash_fn,
1061                Test::rng());
1062 
1063       const Botan::X509_Certificate enc_cert = ca.sign_request(
1064                enc_req,
1065                Test::rng(),
1066                from_date(-1, 01, 01),
1067                from_date(2, 01, 01));
1068 
1069       result.confirm("cert allows encryption", enc_cert.allowed_usage(Usage_Type::ENCRYPTION));
1070       result.confirm("cert does not allow TLS client auth", !enc_cert.allowed_usage(Usage_Type::TLS_CLIENT_AUTH));
1071       }
1072 
1073    return result;
1074    }
1075 
test_self_issued(const Botan::Private_Key & ca_key,const std::string & sig_algo,const std::string & sig_padding="",const std::string & hash_fn="SHA-256")1076 Test::Result test_self_issued(const Botan::Private_Key& ca_key,
1077                               const std::string& sig_algo,
1078                               const std::string& sig_padding = "",
1079                               const std::string& hash_fn = "SHA-256")
1080    {
1081    using Botan::Key_Constraints;
1082 
1083    Test::Result result("X509 Self Issued");
1084 
1085    // create the self-signed cert
1086    const Botan::X509_Certificate ca_cert = Botan::X509::create_self_signed_cert(
1087          ca_opts(sig_padding), ca_key, hash_fn, Test::rng());
1088 
1089    /* Create the CA object */
1090    const Botan::X509_CA ca(ca_cert, ca_key, {{"padding",sig_padding}}, hash_fn, Test::rng());
1091 
1092    std::unique_ptr<Botan::Private_Key> user_key(make_a_private_key(sig_algo));
1093 
1094    // create a self-issued certificate, that is, a certificate with subject dn == issuer dn,
1095    // but signed by a CA, not signed by it's own private key
1096    Botan::X509_Cert_Options opts = ca_opts();
1097    opts.constraints = Key_Constraints::DIGITAL_SIGNATURE;
1098    opts.set_padding_scheme(sig_padding);
1099 
1100    const Botan::PKCS10_Request self_issued_req = Botan::X509::create_cert_req(opts, *user_key, hash_fn, Test::rng());
1101 
1102    const Botan::X509_Certificate self_issued_cert = ca.sign_request(
1103             self_issued_req, Test::rng(), from_date(-1, 01, 01), from_date(2, 01, 01));
1104 
1105    // check that this chain can can be verified successfully
1106    const Botan::Certificate_Store_In_Memory trusted(ca.ca_certificate());
1107 
1108    const Botan::Path_Validation_Restrictions restrictions(false, 80);
1109 
1110    const Botan::Path_Validation_Result validation_result = Botan::x509_path_validate(
1111             self_issued_cert, restrictions, trusted);
1112 
1113    result.confirm("chain with self-issued cert validates", validation_result.successful_validation());
1114 
1115    return result;
1116    }
1117 
test_x509_uninit()1118 Test::Result test_x509_uninit()
1119    {
1120    Test::Result result("X509 object uninitialized access");
1121 
1122    Botan::X509_Certificate cert;
1123    result.test_throws("uninitialized cert access causes exception",
1124                       "X509_Certificate uninitialized",
1125                       [&cert]() { cert.x509_version(); });
1126 
1127    Botan::X509_CRL crl;
1128    result.test_throws("uninitialized crl access causes exception",
1129                       "X509_CRL uninitialized",
1130                       [&crl]() { crl.crl_number(); });
1131 
1132    return result;
1133    }
1134 
1135 
1136 using Botan::Key_Constraints;
1137 
1138 /**
1139 * @brief Some typical key usage scenarios (taken from RFC 5280, sec. 4.2.1.3)
1140 */
1141 struct typical_usage_constraints
1142    {
1143    // ALL constraints are not typical at all, but we use them for a negative test
1144    Key_Constraints all = Key_Constraints(
1145                             Key_Constraints::DIGITAL_SIGNATURE |
1146                             Key_Constraints::NON_REPUDIATION |
1147                             Key_Constraints::KEY_ENCIPHERMENT |
1148                             Key_Constraints::DATA_ENCIPHERMENT |
1149                             Key_Constraints::KEY_AGREEMENT |
1150                             Key_Constraints::KEY_CERT_SIGN |
1151                             Key_Constraints::CRL_SIGN |
1152                             Key_Constraints::ENCIPHER_ONLY |
1153                             Key_Constraints::DECIPHER_ONLY);
1154 
1155    Key_Constraints ca = Key_Constraints(Key_Constraints::KEY_CERT_SIGN);
1156    Key_Constraints sign_data = Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE);
1157    Key_Constraints non_repudiation = Key_Constraints(
1158                                         Key_Constraints::NON_REPUDIATION |
1159                                         Key_Constraints::DIGITAL_SIGNATURE);
1160    Key_Constraints key_encipherment = Key_Constraints(Key_Constraints::KEY_ENCIPHERMENT);
1161    Key_Constraints data_encipherment = Key_Constraints(Key_Constraints::DATA_ENCIPHERMENT);
1162    Key_Constraints key_agreement = Key_Constraints(Key_Constraints::KEY_AGREEMENT);
1163    Key_Constraints key_agreement_encipher_only = Key_Constraints(
1164             Key_Constraints::KEY_AGREEMENT |
1165             Key_Constraints::ENCIPHER_ONLY);
1166    Key_Constraints key_agreement_decipher_only = Key_Constraints(
1167             Key_Constraints::KEY_AGREEMENT |
1168             Key_Constraints::DECIPHER_ONLY);
1169    Key_Constraints crl_sign = Key_Constraints::CRL_SIGN;
1170    Key_Constraints sign_everything = Key_Constraints(
1171                                         Key_Constraints::DIGITAL_SIGNATURE |
1172                                         Key_Constraints::KEY_CERT_SIGN |
1173                                         Key_Constraints::CRL_SIGN);
1174    };
1175 
1176 
test_valid_constraints(const Botan::Private_Key & key,const std::string & pk_algo)1177 Test::Result test_valid_constraints(const Botan::Private_Key& key,
1178                                     const std::string& pk_algo)
1179    {
1180    Test::Result result("X509 Valid Constraints");
1181 
1182    // should not throw on empty constraints
1183    verify_cert_constraints_valid_for_key_type(key, Key_Constraints(Key_Constraints::NO_CONSTRAINTS));
1184 
1185    // now check some typical usage scenarios for the given key type
1186    typical_usage_constraints typical_usage;
1187 
1188    if(pk_algo == "DH" || pk_algo == "ECDH")
1189       {
1190       // DH and ECDH only for key agreement
1191       result.test_throws("all constraints not permitted", [&key, &typical_usage]()
1192          {
1193          verify_cert_constraints_valid_for_key_type(key, typical_usage.all);
1194          });
1195       result.test_throws("cert sign not permitted", [&key, &typical_usage]()
1196          {
1197          verify_cert_constraints_valid_for_key_type(key, typical_usage.ca);
1198          });
1199       result.test_throws("signature not permitted", [&key, &typical_usage]()
1200          {
1201          verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_data);
1202          });
1203       result.test_throws("non repudiation not permitted", [&key, &typical_usage]()
1204          {
1205          verify_cert_constraints_valid_for_key_type(key, typical_usage.non_repudiation);
1206          });
1207       result.test_throws("key encipherment not permitted", [&key, &typical_usage]()
1208          {
1209          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_encipherment);
1210          });
1211       result.test_throws("data encipherment not permitted", [&key, &typical_usage]()
1212          {
1213          verify_cert_constraints_valid_for_key_type(key, typical_usage.data_encipherment);
1214          });
1215 
1216       verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement);
1217       verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_encipher_only);
1218       verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_decipher_only);
1219 
1220       result.test_throws("crl sign not permitted", [&key, &typical_usage]()
1221          {
1222          verify_cert_constraints_valid_for_key_type(key, typical_usage.crl_sign);
1223          });
1224       result.test_throws("sign, cert sign, crl sign not permitted", [&key, &typical_usage]()
1225          {
1226          verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_everything);
1227          });
1228       }
1229    else if(pk_algo == "RSA")
1230       {
1231       // RSA can do everything except key agreement
1232       result.test_throws("all constraints not permitted", [&key, &typical_usage]()
1233          {
1234          verify_cert_constraints_valid_for_key_type(key, typical_usage.all);
1235          });
1236 
1237       verify_cert_constraints_valid_for_key_type(key, typical_usage.ca);
1238       verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_data);
1239       verify_cert_constraints_valid_for_key_type(key, typical_usage.non_repudiation);
1240       verify_cert_constraints_valid_for_key_type(key, typical_usage.key_encipherment);
1241       verify_cert_constraints_valid_for_key_type(key, typical_usage.data_encipherment);
1242 
1243       result.test_throws("key agreement not permitted", [&key, &typical_usage]()
1244          {
1245          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement);
1246          });
1247       result.test_throws("key agreement, encipher only not permitted", [&key, &typical_usage]()
1248          {
1249          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_encipher_only);
1250          });
1251       result.test_throws("key agreement, decipher only not permitted", [&key, &typical_usage]()
1252          {
1253          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_decipher_only);
1254          });
1255 
1256       verify_cert_constraints_valid_for_key_type(key, typical_usage.crl_sign);
1257       verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_everything);
1258       }
1259    else if(pk_algo == "ElGamal")
1260       {
1261       // only ElGamal encryption is currently implemented
1262       result.test_throws("all constraints not permitted", [&key, &typical_usage]()
1263          {
1264          verify_cert_constraints_valid_for_key_type(key, typical_usage.all);
1265          });
1266       result.test_throws("cert sign not permitted", [&key, &typical_usage]()
1267          {
1268          verify_cert_constraints_valid_for_key_type(key, typical_usage.ca);
1269          });
1270 
1271       verify_cert_constraints_valid_for_key_type(key, typical_usage.data_encipherment);
1272       verify_cert_constraints_valid_for_key_type(key, typical_usage.key_encipherment);
1273 
1274       result.test_throws("key agreement not permitted", [&key, &typical_usage]()
1275          {
1276          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement);
1277          });
1278       result.test_throws("key agreement, encipher only not permitted", [&key, &typical_usage]()
1279          {
1280          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_encipher_only);
1281          });
1282       result.test_throws("key agreement, decipher only not permitted", [&key, &typical_usage]()
1283          {
1284          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_decipher_only);
1285          });
1286       result.test_throws("crl sign not permitted", [&key, &typical_usage]()
1287          {
1288          verify_cert_constraints_valid_for_key_type(key, typical_usage.crl_sign);
1289          });
1290       result.test_throws("sign, cert sign, crl sign not permitted not permitted", [&key, &typical_usage]()
1291          {
1292          verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_everything);
1293          });
1294       }
1295    else if(pk_algo == "DSA" || pk_algo == "ECDSA" || pk_algo == "ECGDSA" || pk_algo == "ECKCDSA" ||
1296            pk_algo == "GOST-34.10")
1297       {
1298       // these are signature algorithms only
1299       result.test_throws("all constraints not permitted", [&key, &typical_usage]()
1300          {
1301          verify_cert_constraints_valid_for_key_type(key, typical_usage.all);
1302          });
1303 
1304       verify_cert_constraints_valid_for_key_type(key, typical_usage.ca);
1305       verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_data);
1306       verify_cert_constraints_valid_for_key_type(key, typical_usage.non_repudiation);
1307 
1308       result.test_throws("key encipherment not permitted", [&key, &typical_usage]()
1309          {
1310          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_encipherment);
1311          });
1312       result.test_throws("data encipherment not permitted", [&key, &typical_usage]()
1313          {
1314          verify_cert_constraints_valid_for_key_type(key, typical_usage.data_encipherment);
1315          });
1316       result.test_throws("key agreement not permitted", [&key, &typical_usage]()
1317          {
1318          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement);
1319          });
1320       result.test_throws("key agreement, encipher only not permitted", [&key, &typical_usage]()
1321          {
1322          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_encipher_only);
1323          });
1324       result.test_throws("key agreement, decipher only not permitted", [&key, &typical_usage]()
1325          {
1326          verify_cert_constraints_valid_for_key_type(key, typical_usage.key_agreement_decipher_only);
1327          });
1328 
1329       verify_cert_constraints_valid_for_key_type(key, typical_usage.crl_sign);
1330       verify_cert_constraints_valid_for_key_type(key, typical_usage.sign_everything);
1331       }
1332 
1333    return result;
1334    }
1335 
1336 /**
1337  * @brief X.509v3 extension that encodes a given string
1338  */
1339 class String_Extension final : public Botan::Certificate_Extension
1340    {
1341    public:
1342       String_Extension() = default;
String_Extension(const std::string & val)1343       String_Extension(const std::string& val) : m_contents(val) {}
1344 
value() const1345       std::string value() const
1346          {
1347          return m_contents;
1348          }
1349 
copy() const1350       String_Extension* copy() const override
1351          {
1352          return new String_Extension(m_contents);
1353          }
1354 
oid_of() const1355       Botan::OID oid_of() const override
1356          {
1357          return Botan::OID("1.2.3.4.5.6.7.8.9.1");
1358          }
1359 
should_encode() const1360       bool should_encode() const override
1361          {
1362          return true;
1363          }
1364 
oid_name() const1365       std::string oid_name() const override
1366          {
1367          return "String Extension";
1368          }
1369 
contents_to(Botan::Data_Store &,Botan::Data_Store &) const1370       void contents_to(Botan::Data_Store&, Botan::Data_Store&) const override {}
1371 
encode_inner() const1372       std::vector<uint8_t> encode_inner() const override
1373          {
1374          std::vector<uint8_t> bits;
1375          Botan::DER_Encoder(bits).encode(Botan::ASN1_String(m_contents, Botan::UTF8_STRING));
1376          return bits;
1377          }
1378 
decode_inner(const std::vector<uint8_t> & in)1379       void decode_inner(const std::vector<uint8_t>& in) override
1380          {
1381          Botan::ASN1_String str;
1382          Botan::BER_Decoder(in).decode(str, Botan::UTF8_STRING).verify_end();
1383          m_contents = str.value();
1384          }
1385 
1386    private:
1387       std::string m_contents;
1388    };
1389 
test_custom_dn_attr(const Botan::Private_Key & ca_key,const std::string & sig_algo,const std::string & sig_padding="",const std::string & hash_fn="SHA-256")1390 Test::Result test_custom_dn_attr(const Botan::Private_Key& ca_key,
1391                                   const std::string& sig_algo,
1392                                   const std::string& sig_padding = "",
1393                                   const std::string& hash_fn = "SHA-256")
1394    {
1395    Test::Result result("X509 Custom DN");
1396 
1397    /* Create the self-signed cert */
1398    Botan::X509_Certificate ca_cert =
1399       Botan::X509::create_self_signed_cert(ca_opts(sig_padding), ca_key, hash_fn, Test::rng());
1400 
1401    /* Create the CA object */
1402    Botan::X509_CA ca(ca_cert, ca_key, {{"padding",sig_padding}}, hash_fn, Test::rng());
1403 
1404    std::unique_ptr<Botan::Private_Key> user_key(make_a_private_key(sig_algo));
1405 
1406    Botan::X509_DN subject_dn;
1407 
1408    const Botan::OID attr1(Botan::OID("1.3.6.1.4.1.25258.9.1.1"));
1409    const Botan::OID attr2(Botan::OID("1.3.6.1.4.1.25258.9.1.2"));
1410    const Botan::ASN1_String val1("Custom Attr 1", Botan::PRINTABLE_STRING);
1411    const Botan::ASN1_String val2("12345", Botan::UTF8_STRING);
1412 
1413    subject_dn.add_attribute(attr1, val1);
1414    subject_dn.add_attribute(attr2, val2);
1415 
1416    Botan::Extensions extensions;
1417 
1418    Botan::PKCS10_Request req =
1419       Botan::PKCS10_Request::create(*user_key,
1420                                     subject_dn,
1421                                     extensions,
1422                                     hash_fn,
1423                                     Test::rng(),
1424                                     sig_padding);
1425 
1426    Botan::X509_DN req_dn = req.subject_dn();
1427 
1428    result.test_eq("Expected number of DN entries", req_dn.dn_info().size(), 2);
1429 
1430    Botan::ASN1_String req_val1 = req_dn.get_first_attribute(attr1);
1431    Botan::ASN1_String req_val2 = req_dn.get_first_attribute(attr2);
1432    result.confirm("Attr1 matches encoded", req_val1 == val1);
1433    result.confirm("Attr2 matches encoded", req_val2 == val2);
1434    result.confirm("Attr1 tag matches encoded", req_val1.tagging() == val1.tagging());
1435    result.confirm("Attr2 tag matches encoded", req_val2.tagging() == val2.tagging());
1436 
1437    Botan::X509_Time not_before("100301123001Z", Botan::UTC_TIME);
1438    Botan::X509_Time not_after("300301123001Z", Botan::UTC_TIME);
1439 
1440    auto cert = ca.sign_request(req, Test::rng(), not_before, not_after);
1441 
1442    Botan::X509_DN cert_dn = cert.subject_dn();
1443 
1444    result.test_eq("Expected number of DN entries", cert_dn.dn_info().size(), 2);
1445 
1446    Botan::ASN1_String cert_val1 = cert_dn.get_first_attribute(attr1);
1447    Botan::ASN1_String cert_val2 = cert_dn.get_first_attribute(attr2);
1448    result.confirm("Attr1 matches encoded", cert_val1 == val1);
1449    result.confirm("Attr2 matches encoded", cert_val2 == val2);
1450    result.confirm("Attr1 tag matches encoded", cert_val1.tagging() == val1.tagging());
1451    result.confirm("Attr2 tag matches encoded", cert_val2.tagging() == val2.tagging());
1452 
1453    return result;
1454    }
1455 
1456 
test_x509_extensions(const Botan::Private_Key & ca_key,const std::string & sig_algo,const std::string & sig_padding="",const std::string & hash_fn="SHA-256")1457 Test::Result test_x509_extensions(const Botan::Private_Key& ca_key,
1458                                   const std::string& sig_algo,
1459                                   const std::string& sig_padding = "",
1460                                   const std::string& hash_fn = "SHA-256")
1461    {
1462    using Botan::Key_Constraints;
1463 
1464    Test::Result result("X509 Extensions");
1465 
1466    /* Create the self-signed cert */
1467    Botan::X509_Certificate ca_cert =
1468       Botan::X509::create_self_signed_cert(ca_opts(sig_padding), ca_key, hash_fn, Test::rng());
1469 
1470    /* Create the CA object */
1471    Botan::X509_CA ca(ca_cert, ca_key, {{"padding",sig_padding}}, hash_fn, Test::rng());
1472 
1473    std::unique_ptr<Botan::Private_Key> user_key(make_a_private_key(sig_algo));
1474 
1475    Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");
1476    opts.constraints = Key_Constraints::DIGITAL_SIGNATURE;
1477 
1478    // include a custom extension in the request
1479    Botan::Extensions req_extensions;
1480    const Botan::OID oid("1.2.3.4.5.6.7.8.9.1");
1481    const Botan::OID ku_oid = Botan::OID::from_string("X509v3.KeyUsage");
1482    req_extensions.add(new String_Extension("AAAAAAAAAAAAAABCDEF"), false);
1483    opts.extensions = req_extensions;
1484    opts.set_padding_scheme(sig_padding);
1485 
1486    /* Create a self-signed certificate */
1487    const Botan::X509_Certificate self_signed_cert = Botan::X509::create_self_signed_cert(
1488             opts, *user_key, hash_fn, Test::rng());
1489 
1490    result.confirm("Extensions::extension_set true for Key_Usage", self_signed_cert.v3_extensions().extension_set(ku_oid));
1491 
1492    // check if known Key_Usage extension is present in self-signed cert
1493    auto key_usage_ext = self_signed_cert.v3_extensions().get(ku_oid);
1494    if(result.confirm("Key_Usage extension present in self-signed certificate", key_usage_ext != nullptr))
1495       {
1496       result.confirm("Key_Usage extension value matches in self-signed certificate",
1497                      dynamic_cast<Botan::Cert_Extension::Key_Usage&>(*key_usage_ext).get_constraints() == opts.constraints);
1498       }
1499 
1500    // check if custom extension is present in self-signed cert
1501    auto string_ext = self_signed_cert.v3_extensions().get_raw<String_Extension>(oid);
1502    if(result.confirm("Custom extension present in self-signed certificate", string_ext != nullptr))
1503       {
1504       result.test_eq("Custom extension value matches in self-signed certificate", string_ext->value(), "AAAAAAAAAAAAAABCDEF");
1505       }
1506 
1507 
1508    const Botan::PKCS10_Request user_req = Botan::X509::create_cert_req(opts, *user_key, hash_fn, Test::rng());
1509 
1510    /* Create a CA-signed certificate */
1511    const Botan::X509_Certificate ca_signed_cert =
1512       ca.sign_request(user_req, Test::rng(),
1513                       from_date(-1, 01, 01),
1514                       from_date(2, 01, 01));
1515 
1516    // check if known Key_Usage extension is present in CA-signed cert
1517    result.confirm("Extensions::extension_set true for Key_Usage", ca_signed_cert.v3_extensions().extension_set(ku_oid));
1518 
1519    key_usage_ext = ca_signed_cert.v3_extensions().get(ku_oid);
1520    if(result.confirm("Key_Usage extension present in CA-signed certificate", key_usage_ext != nullptr))
1521       {
1522       result.confirm("Key_Usage extension value matches in user certificate",
1523                      dynamic_cast<Botan::Cert_Extension::Key_Usage&>(*key_usage_ext).get_constraints() == Botan::DIGITAL_SIGNATURE);
1524       }
1525 
1526    // check if custom extension is present in CA-signed cert
1527    result.confirm("Extensions::extension_set true for String_Extension", ca_signed_cert.v3_extensions().extension_set(oid));
1528    string_ext = ca_signed_cert.v3_extensions().get_raw<String_Extension>(oid);
1529    if(result.confirm("Custom extension present in CA-signed certificate", string_ext != nullptr))
1530       {
1531       result.test_eq("Custom extension value matches in CA-signed certificate", string_ext->value(), "AAAAAAAAAAAAAABCDEF");
1532       }
1533 
1534    return result;
1535    }
1536 
test_hashes(const Botan::Private_Key & key,const std::string & hash_fn="SHA-256")1537 Test::Result test_hashes(const Botan::Private_Key& key,
1538                          const std::string& hash_fn = "SHA-256")
1539    {
1540    Test::Result result("X509 Hashes");
1541 
1542    struct TestData
1543       {
1544       const std::string issuer, subject, issuer_hash, subject_hash;
1545       } const cases[]
1546       {
1547          {
1548          "",
1549          "",
1550          "E4F60D0AA6D7F3D3B6A6494B1C861B99F649C6F9EC51ABAF201B20F297327C95",
1551          "E4F60D0AA6D7F3D3B6A6494B1C861B99F649C6F9EC51ABAF201B20F297327C95"
1552          },
1553          {
1554          "a",
1555          "b",
1556          "BC2E013472F39AC579964880E422737C82BA812CB8BC2FD17E013060D71E6E19",
1557          "5E31CFAA3FAFB1A5BA296A0D2BAB9CA44D7936E9BF0BBC54637D0C53DBC4A432"
1558          },
1559          {
1560          "A",
1561          "B",
1562          "4B3206201C4BC9B6CD6C36532A97687DF9238155D99ADB60C66BF2B2220643D8",
1563          "FFF635A52A16618B4A0E9CD26B5E5A2FA573D343C051E6DE8B0811B1ACC89B86"
1564          },
1565          {
1566          "Test Issuer/US/Botan Project/Testing",
1567          "Test Subject/US/Botan Project/Testing",
1568          "ACB4F373004A56A983A23EB8F60FA4706312B5DB90FD978574FE7ACC84E093A5",
1569          "87039231C2205B74B6F1F3830A66272C0B41F71894B03AC3150221766D95267B",
1570          },
1571          {
1572          "Test Subject/US/Botan Project/Testing",
1573          "Test Issuer/US/Botan Project/Testing",
1574          "87039231C2205B74B6F1F3830A66272C0B41F71894B03AC3150221766D95267B",
1575          "ACB4F373004A56A983A23EB8F60FA4706312B5DB90FD978574FE7ACC84E093A5",
1576          }
1577       };
1578 
1579    for(const auto& a : cases)
1580       {
1581       Botan::X509_Cert_Options opts{a.issuer};
1582       opts.CA_key();
1583 
1584       const Botan::X509_Certificate issuer_cert =
1585          Botan::X509::create_self_signed_cert(opts, key, hash_fn, Test::rng());
1586 
1587       result.test_eq(a.issuer, Botan::hex_encode(issuer_cert.raw_issuer_dn_sha256()), a.issuer_hash);
1588       result.test_eq(a.issuer, Botan::hex_encode(issuer_cert.raw_subject_dn_sha256()), a.issuer_hash);
1589 
1590       const Botan::X509_CA ca(issuer_cert, key, hash_fn, Test::rng());
1591       const Botan::PKCS10_Request req =
1592          Botan::X509::create_cert_req(a.subject, key, hash_fn, Test::rng());
1593       const Botan::X509_Certificate subject_cert =
1594          ca.sign_request(req, Test::rng(), from_date(-1, 01, 01), from_date(2, 01, 01));
1595 
1596       result.test_eq(a.subject, Botan::hex_encode(subject_cert.raw_issuer_dn_sha256()), a.issuer_hash);
1597       result.test_eq(a.subject, Botan::hex_encode(subject_cert.raw_subject_dn_sha256()), a.subject_hash);
1598       }
1599    return result;
1600    }
1601 
1602 class X509_Cert_Unit_Tests final : public Test
1603    {
1604    public:
run()1605       std::vector<Test::Result> run() override
1606          {
1607          std::vector<Test::Result> results;
1608 
1609          const std::string sig_algos[] { "RSA", "DSA", "ECDSA", "ECGDSA", "ECKCDSA", "GOST-34.10", "Ed25519" };
1610 
1611          for(const std::string& algo : sig_algos)
1612             {
1613 #if !defined(BOTAN_HAS_EMSA_PKCS1)
1614             if(algo == "RSA")
1615                continue;
1616 #endif
1617 
1618 #if !defined(BOTAN_HAS_EMSA1)
1619             if(algo != "RSA" && algo != "Ed25519")
1620                continue;
1621 #endif
1622 
1623             std::unique_ptr<Botan::Private_Key> key = make_a_private_key(algo);
1624 
1625             if(key == nullptr)
1626                continue;
1627 
1628             results.push_back(test_hashes(*key));
1629             results.push_back(test_valid_constraints(*key, algo));
1630 
1631             Test::Result usage_result("X509 Usage");
1632             try
1633                {
1634                usage_result.merge(test_usage(*key, algo));
1635                }
1636             catch(std::exception& e)
1637                {
1638                usage_result.test_failure("test_usage " + algo, e.what());
1639                }
1640             results.push_back(usage_result);
1641 
1642             for(auto padding_scheme : Botan::get_sig_paddings(algo))
1643                {
1644                Test::Result cert_result("X509 Unit");
1645                try
1646                   {
1647                   cert_result.merge(test_x509_cert(*key, algo, padding_scheme));
1648                   }
1649                catch(std::exception& e)
1650                   {
1651                   cert_result.test_failure("test_x509_cert " + algo, e.what());
1652                   }
1653                results.push_back(cert_result);
1654 
1655                Test::Result pkcs10_result("PKCS10 extensions");
1656                try
1657                   {
1658                   pkcs10_result.merge(test_pkcs10_ext(*key, padding_scheme));
1659                   }
1660                catch(std::exception& e)
1661                   {
1662                   pkcs10_result.test_failure("test_pkcs10_ext " + algo, e.what());
1663                   }
1664                results.push_back(pkcs10_result);
1665 
1666                Test::Result self_issued_result("X509 Self Issued");
1667                try
1668                   {
1669                   self_issued_result.merge(test_self_issued(*key, algo, padding_scheme));
1670                   }
1671                catch(std::exception& e)
1672                   {
1673                   self_issued_result.test_failure("test_self_issued " + algo, e.what());
1674                   }
1675                results.push_back(self_issued_result);
1676 
1677                Test::Result extensions_result("X509 Extensions");
1678                try
1679                   {
1680                   extensions_result.merge(test_x509_extensions(*key, algo, padding_scheme));
1681                   }
1682                catch(std::exception& e)
1683                   {
1684                   extensions_result.test_failure("test_extensions " + algo, e.what());
1685                   }
1686                results.push_back(extensions_result);
1687 
1688                Test::Result custom_dn_result("X509 Custom DN");
1689                try
1690                   {
1691                   custom_dn_result.merge(test_custom_dn_attr(*key, algo, padding_scheme));
1692                   }
1693                catch(std::exception& e)
1694                   {
1695                   custom_dn_result.test_failure("test_custom_dn_attr " + algo, e.what());
1696                   }
1697                results.push_back(custom_dn_result);
1698                }
1699 
1700             }
1701 
1702          /*
1703          These are algos which cannot sign but can be included in certs
1704          */
1705          const std::vector<std::string> enc_algos = { "DH", "ECDH", "ElGamal" };
1706 
1707          for(std::string algo : enc_algos)
1708             {
1709             std::unique_ptr<Botan::Private_Key> key = make_a_private_key(algo);
1710 
1711             if(key)
1712                {
1713                results.push_back(test_valid_constraints(*key, algo));
1714                }
1715             }
1716 
1717 
1718 #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM) && defined(BOTAN_HAS_EMSA_PKCS1) && defined(BOTAN_HAS_EMSA_PSSR) && defined(BOTAN_HAS_RSA)
1719          Test::Result pad_config_result("X509 Padding Config");
1720          try
1721             {
1722             pad_config_result.merge(test_padding_config());
1723             }
1724          catch(const std::exception& e)
1725             {
1726             pad_config_result.test_failure("test_padding_config", e.what());
1727             }
1728          results.push_back(pad_config_result);
1729 #endif
1730 
1731 #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1732          results.push_back(test_x509_utf8());
1733          results.push_back(test_x509_bmpstring());
1734          results.push_back(test_crl_dn_name());
1735          results.push_back(test_rdn_multielement_set_name());
1736          results.push_back(test_x509_decode_list());
1737          results.push_back(test_rsa_oaep());
1738          results.push_back(test_x509_authority_info_access_extension());
1739          results.push_back(test_verify_gost2012_cert());
1740 #endif
1741 
1742          results.push_back(test_x509_extension());
1743          results.push_back(test_x509_dates());
1744          results.push_back(test_cert_status_strings());
1745          results.push_back(test_x509_uninit());
1746 
1747          return results;
1748          }
1749    };
1750 
1751 BOTAN_REGISTER_TEST("x509", "x509_unit", X509_Cert_Unit_Tests);
1752 
1753 #endif
1754 
1755 }
1756 
1757 }
1758