summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/cli/x509.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/cli/x509.cpp')
-rw-r--r--comm/third_party/botan/src/cli/x509.cpp417
1 files changed, 417 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/cli/x509.cpp b/comm/third_party/botan/src/cli/x509.cpp
new file mode 100644
index 0000000000..a92ec1309e
--- /dev/null
+++ b/comm/third_party/botan/src/cli/x509.cpp
@@ -0,0 +1,417 @@
+/*
+* (C) 2010,2014,2015,2018 Jack Lloyd
+* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+
+#include <botan/certstor.h>
+#include <botan/pk_keys.h>
+#include <botan/pkcs8.h>
+#include <botan/x509_ca.h>
+#include <botan/x509cert.h>
+#include <botan/x509path.h>
+#include <botan/x509self.h>
+#include <botan/data_src.h>
+#include <botan/parsing.h>
+
+#if defined(BOTAN_HAS_OCSP)
+ #include <botan/ocsp.h>
+#endif
+
+#if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
+ #include <botan/certstor_system.h>
+#endif
+
+namespace Botan_CLI {
+
+#if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
+
+class Trust_Root_Info final : public Command
+ {
+ public:
+ Trust_Root_Info() : Command("trust_roots --dn --dn-only --display") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "List certs in the system trust store";
+ }
+
+ void go() override
+ {
+ Botan::System_Certificate_Store trust_roots;
+
+ const auto dn_list = trust_roots.all_subjects();
+
+ if(flag_set("dn-only"))
+ {
+ for(auto dn : dn_list)
+ output() << dn << "\n";
+ }
+ else
+ {
+ for(auto dn : dn_list)
+ {
+ // Some certstores have more than one cert with a particular DN
+ for(auto cert : trust_roots.find_all_certs(dn, std::vector<uint8_t>()))
+ {
+ if(flag_set("dn"))
+ output() << "# " << dn << "\n";
+
+ if(flag_set("display"))
+ output() << cert->to_string() << "\n";
+
+ output() << cert->PEM_encode() << "\n";
+ }
+ }
+
+ }
+ }
+
+ };
+
+BOTAN_REGISTER_COMMAND("trust_roots", Trust_Root_Info);
+
+#endif
+
+class Sign_Cert final : public Command
+ {
+ public:
+ Sign_Cert()
+ : Command("sign_cert --ca-key-pass= --hash=SHA-256 "
+ "--duration=365 --emsa= ca_cert ca_key pkcs10_req") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "Create a CA-signed X.509 certificate from a PKCS #10 CSR";
+ }
+
+ void go() override
+ {
+ Botan::X509_Certificate ca_cert(get_arg("ca_cert"));
+
+ const std::string key_file = get_arg("ca_key");
+ const std::string pass = get_passphrase_arg("Password for " + key_file, "ca-key-pass");
+ const std::string emsa = get_arg("emsa");
+ const std::string hash = get_arg("hash");
+
+ std::unique_ptr<Botan::Private_Key> key;
+ if(!pass.empty())
+ {
+ key.reset(Botan::PKCS8::load_key(key_file, rng(), pass));
+ }
+ else
+ {
+ key.reset(Botan::PKCS8::load_key(key_file, rng()));
+ }
+
+ if(!key)
+ {
+ throw CLI_Error("Failed to load key from " + key_file);
+ }
+
+ std::map<std::string, std::string> options;
+ if(emsa.empty() == false)
+ options["padding"] = emsa;
+
+ Botan::X509_CA ca(ca_cert, *key, options, hash, rng());
+
+ Botan::PKCS10_Request req(get_arg("pkcs10_req"));
+
+ auto now = std::chrono::system_clock::now();
+
+ Botan::X509_Time start_time(now);
+
+ typedef std::chrono::duration<int, std::ratio<86400>> days;
+
+ Botan::X509_Time end_time(now + days(get_arg_sz("duration")));
+
+ Botan::X509_Certificate new_cert = ca.sign_request(req, rng(), start_time, end_time);
+
+ output() << new_cert.PEM_encode();
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("sign_cert", Sign_Cert);
+
+class Cert_Info final : public Command
+ {
+ public:
+ Cert_Info() : Command("cert_info --fingerprint file") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "Parse X.509 certificate and display data fields";
+ }
+
+ void go() override
+ {
+ const std::string arg_file = get_arg("file");
+
+ std::vector<uint8_t> data = slurp_file(get_arg("file"));
+
+ Botan::DataSource_Memory in(data);
+
+ while(!in.end_of_data())
+ {
+ try
+ {
+ Botan::X509_Certificate cert(in);
+
+ try
+ {
+ output() << cert.to_string() << std::endl;
+ }
+ catch(Botan::Exception& e)
+ {
+ // to_string failed - report the exception and continue
+ output() << "X509_Certificate::to_string failed: " << e.what() << "\n";
+ }
+
+ if(flag_set("fingerprint"))
+ output() << "Fingerprint: " << cert.fingerprint("SHA-256") << std::endl;
+ }
+ catch(Botan::Exception& e)
+ {
+ if(!in.end_of_data())
+ {
+ output() << "X509_Certificate parsing failed " << e.what() << "\n";
+ }
+ }
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("cert_info", Cert_Info);
+
+#if defined(BOTAN_HAS_OCSP) && defined(BOTAN_HAS_HTTP_UTIL)
+
+class OCSP_Check final : public Command
+ {
+ public:
+ OCSP_Check() : Command("ocsp_check --timeout=3000 subject issuer") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "Verify an X.509 certificate against the issuers OCSP responder";
+ }
+
+ void go() override
+ {
+ Botan::X509_Certificate subject(get_arg("subject"));
+ Botan::X509_Certificate issuer(get_arg("issuer"));
+ std::chrono::milliseconds timeout(get_arg_sz("timeout"));
+
+ Botan::Certificate_Store_In_Memory cas;
+ cas.add_certificate(issuer);
+ Botan::OCSP::Response resp = Botan::OCSP::online_check(issuer, subject, &cas, timeout);
+
+ auto status = resp.status_for(issuer, subject, std::chrono::system_clock::now());
+
+ if(status == Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD)
+ {
+ output() << "OCSP check OK\n";
+ }
+ else
+ {
+ output() << "OCSP check failed " << Botan::Path_Validation_Result::status_string(status) << "\n";
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("ocsp_check", OCSP_Check);
+
+#endif // OCSP && HTTP
+
+class Cert_Verify final : public Command
+ {
+ public:
+ Cert_Verify() : Command("cert_verify subject *ca_certs") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "Verify if the passed X.509 certificate passes path validation";
+ }
+
+ void go() override
+ {
+ Botan::X509_Certificate subject_cert(get_arg("subject"));
+ Botan::Certificate_Store_In_Memory trusted;
+
+ for(auto const& certfile : get_arg_list("ca_certs"))
+ {
+ trusted.add_certificate(Botan::X509_Certificate(certfile));
+ }
+
+ Botan::Path_Validation_Restrictions restrictions;
+
+ Botan::Path_Validation_Result result =
+ Botan::x509_path_validate(subject_cert,
+ restrictions,
+ trusted);
+
+ if(result.successful_validation())
+ {
+ output() << "Certificate passes validation checks\n";
+ }
+ else
+ {
+ output() << "Certificate did not validate - " << result.result_string() << "\n";
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("cert_verify", Cert_Verify);
+
+class Gen_Self_Signed final : public Command
+ {
+ public:
+ Gen_Self_Signed()
+ : Command("gen_self_signed key CN --country= --dns= "
+ "--organization= --email= --path-limit=1 --days=365 --key-pass= --ca --hash=SHA-256 --emsa= --der") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "Generate a self signed X.509 certificate";
+ }
+
+ void go() override
+ {
+ const std::string key_file = get_arg("key");
+ const std::string passphrase = get_passphrase_arg("Passphrase for " + key_file, "key-pass");
+ std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(key_file, rng(), passphrase));
+
+ if(!key)
+ {
+ throw CLI_Error("Failed to load key from " + get_arg("key"));
+ }
+
+ const uint32_t lifetime = static_cast<uint32_t>(get_arg_sz("days") * 24 * 60 * 60);
+
+ Botan::X509_Cert_Options opts("", lifetime);
+
+ opts.common_name = get_arg("CN");
+ opts.country = get_arg("country");
+ opts.organization = get_arg("organization");
+ opts.email = get_arg("email");
+ opts.more_dns = Botan::split_on(get_arg("dns"), ',');
+ const bool der_format = flag_set("der");
+
+ std::string emsa = get_arg("emsa");
+
+ if(emsa.empty() == false)
+ opts.set_padding_scheme(emsa);
+
+ if(flag_set("ca"))
+ {
+ opts.CA_key(get_arg_sz("path-limit"));
+ }
+
+ Botan::X509_Certificate cert = Botan::X509::create_self_signed_cert(opts, *key, get_arg("hash"), rng());
+
+ if(der_format)
+ {
+ auto der = cert.BER_encode();
+ output().write(reinterpret_cast<const char*>(der.data()), der.size());
+ }
+ else
+ output() << cert.PEM_encode();
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("gen_self_signed", Gen_Self_Signed);
+
+class Generate_PKCS10 final : public Command
+ {
+ public:
+ Generate_PKCS10()
+ : Command("gen_pkcs10 key CN --country= --organization= "
+ "--ca --path-limit=1 --email= --dns= --ext-ku= --key-pass= --hash=SHA-256 --emsa=") {}
+
+ std::string group() const override
+ {
+ return "x509";
+ }
+
+ std::string description() const override
+ {
+ return "Generate a PKCS #10 certificate signing request (CSR)";
+ }
+
+ void go() override
+ {
+ std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(get_arg("key"), rng(), get_arg("key-pass")));
+
+ if(!key)
+ {
+ throw CLI_Error("Failed to load key from " + get_arg("key"));
+ }
+
+ Botan::X509_Cert_Options opts;
+
+ opts.common_name = get_arg("CN");
+ opts.country = get_arg("country");
+ opts.organization = get_arg("organization");
+ opts.email = get_arg("email");
+ opts.more_dns = Botan::split_on(get_arg("dns"), ',');
+
+ if(flag_set("ca"))
+ {
+ opts.CA_key(get_arg_sz("path-limit"));
+ }
+
+ for(std::string ext_ku : Botan::split_on(get_arg("ext-ku"), ','))
+ {
+ opts.add_ex_constraint(ext_ku);
+ }
+
+ std::string emsa = get_arg("emsa");
+
+ if(emsa.empty() == false)
+ opts.set_padding_scheme(emsa);
+
+ Botan::PKCS10_Request req = Botan::X509::create_cert_req(opts, *key, get_arg("hash"), rng());
+
+ output() << req.PEM_encode();
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("gen_pkcs10", Generate_PKCS10);
+
+}
+
+#endif