aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/build-data/os/linux.txt2
-rw-r--r--src/lib/x509/certstor_system_linux/certstor_linux.cpp18
-rw-r--r--src/lib/x509/certstor_system_linux/certstor_linux.h27
-rw-r--r--src/lib/x509/certstor_system_linux/info.txt16
-rw-r--r--src/tests/test_certstor_linux.cpp249
-rw-r--r--src/tests/test_certstor_macos.cpp54
-rw-r--r--src/tests/test_certstor_utils.h72
7 files changed, 385 insertions, 53 deletions
diff --git a/src/build-data/os/linux.txt b/src/build-data/os/linux.txt
index 208e13b9b..dfda7ce9f 100644
--- a/src/build-data/os/linux.txt
+++ b/src/build-data/os/linux.txt
@@ -10,6 +10,8 @@ proc_fs
clock_gettime
getauxval
+linux_certstore
+
# not enabled by default as only available in newer kernel/glibc
#getrandom
diff --git a/src/lib/x509/certstor_system_linux/certstor_linux.cpp b/src/lib/x509/certstor_system_linux/certstor_linux.cpp
new file mode 100644
index 000000000..dcd325933
--- /dev/null
+++ b/src/lib/x509/certstor_system_linux/certstor_linux.cpp
@@ -0,0 +1,18 @@
+/*
+* Certificate Store
+* (C) 1999-2019 Jack Lloyd
+* (C) 2019 Patrick Schmidt
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/build.h>
+
+#include <botan/certstor_linux.h>
+
+namespace Botan {
+Certificate_Store_Linux::Certificate_Store_Linux() :
+ Flatfile_Certificate_Store(BOTAN_LINUX_CERTSTORE_DEFAULT_FILE)
+ {
+ }
+}
diff --git a/src/lib/x509/certstor_system_linux/certstor_linux.h b/src/lib/x509/certstor_system_linux/certstor_linux.h
new file mode 100644
index 000000000..d92364da9
--- /dev/null
+++ b/src/lib/x509/certstor_system_linux/certstor_linux.h
@@ -0,0 +1,27 @@
+/*
+* Certificate Store
+* (C) 1999-2019 Jack Lloyd
+* (C) 2019 Patrick Schmidt
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_CERT_STORE_SYSTEM_LINUX_H_
+#define BOTAN_CERT_STORE_SYSTEM_LINUX_H_
+
+#include <botan/certstor_flatfile.h>
+
+namespace Botan {
+
+/**
+* Certificate Store that is backed by a file of PEMs of trusted CAs located at
+* BOTAN_LINUX_CERTSTORE_DEFAULT_FILE.
+*/
+class BOTAN_PUBLIC_API(2, 11) Certificate_Store_Linux final : public Flatfile_Certificate_Store
+ {
+ public:
+ Certificate_Store_Linux();
+ };
+}
+
+#endif
diff --git a/src/lib/x509/certstor_system_linux/info.txt b/src/lib/x509/certstor_system_linux/info.txt
new file mode 100644
index 000000000..53a82dbb6
--- /dev/null
+++ b/src/lib/x509/certstor_system_linux/info.txt
@@ -0,0 +1,16 @@
+<defines>
+CERTSTOR_LINUX -> 20190402
+</defines>
+
+<os_features>
+linux_certstore
+</os_features>
+
+<requires>
+certstor_flatfile
+</requires>
+
+<header:public>
+certstor_linux.h
+</header:public>
+
diff --git a/src/tests/test_certstor_linux.cpp b/src/tests/test_certstor_linux.cpp
new file mode 100644
index 000000000..5cd991a44
--- /dev/null
+++ b/src/tests/test_certstor_linux.cpp
@@ -0,0 +1,249 @@
+/*
+* (C) 1999-2019 Jack Lloyd
+* (C) 2019 René Meusel
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_CERTSTOR_LINUX)
+
+#include "test_certstor_utils.h"
+#include <botan/certstor_linux.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/hex.h>
+
+namespace Botan_Tests {
+
+namespace {
+
+Test::Result open_certificate_store()
+ {
+ Test::Result result("linux Certificate Store - Open Store");
+
+ try
+ {
+ result.start_timer();
+ Botan::Certificate_Store_Linux unused;
+ result.end_timer();
+ result.test_gt("found some certificates", unused.all_subjects().size(), 0);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ result.test_success();
+
+ return result;
+ }
+
+Test::Result find_certificate_by_pubkey_sha1()
+ {
+ Test::Result result("linux Certificate Store - Find Certificate by SHA1(pubkey)");
+
+ try
+ {
+ result.start_timer();
+ Botan::Certificate_Store_Linux certstore;
+ auto cert = certstore.find_cert_by_pubkey_sha1(get_key_id());
+ result.end_timer();
+
+ if(result.test_not_null("found certificate", cert.get()))
+ {
+ auto cns = cert->subject_dn().get_attribute("CN");
+ result.test_is_eq("exactly one CN", cns.size(), 1ul);
+ result.test_eq("CN", cns.front(), "DST Root CA X3");
+ }
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ result.test_throws("on invalid SHA1 hash data", [&]
+ {
+ Botan::Certificate_Store_Linux certstore;
+ certstore.find_cert_by_pubkey_sha1({});
+ });
+
+ return result;
+ }
+
+Test::Result find_cert_by_subject_dn()
+ {
+ Test::Result result("linux Certificate Store - Find Certificate by subject DN");
+
+ try
+ {
+ auto dn = get_dn();
+
+ result.start_timer();
+ Botan::Certificate_Store_Linux certstore;
+ auto cert = certstore.find_cert(dn, std::vector<uint8_t>());
+ result.end_timer();
+
+ if(result.test_not_null("found certificate", cert.get()))
+ {
+ auto cns = cert->subject_dn().get_attribute("CN");
+ result.test_is_eq("exactly one CN", cns.size(), 1ul);
+ result.test_eq("CN", cns.front(), "DST Root CA X3");
+ }
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ return result;
+ }
+
+Test::Result find_cert_by_subject_dn_and_key_id()
+ {
+ Test::Result result("linux Certificate Store - Find Certificate by subject DN and key ID");
+
+ try
+ {
+ auto dn = get_dn();
+
+ result.start_timer();
+ Botan::Certificate_Store_Linux certstore;
+ auto cert = certstore.find_cert(dn, get_key_id());
+ result.end_timer();
+
+ if(result.test_not_null("found certificate", cert.get()))
+ {
+ auto cns = cert->subject_dn().get_attribute("CN");
+ result.test_is_eq("exactly one CN", cns.size(), 1ul);
+ result.test_eq("CN", cns.front(), "DST Root CA X3");
+ }
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ return result;
+ }
+
+Test::Result find_certs_by_subject_dn_and_key_id()
+ {
+ Test::Result result("linux Certificate Store - Find Certificates by subject DN and key ID");
+
+ try
+ {
+ auto dn = get_dn();
+
+ result.start_timer();
+ Botan::Certificate_Store_Linux certstore;
+ auto certs = certstore.find_all_certs(dn, get_key_id());
+ result.end_timer();
+
+ if(result.confirm("result not empty", !certs.empty()) &&
+ result.test_eq("exactly one certificate", certs.size(), 1))
+ {
+ auto cns = certs.front()->subject_dn().get_attribute("CN");
+ result.test_is_eq("exactly one CN", cns.size(), 1ul);
+ result.test_eq("CN", cns.front(), "DST Root CA X3");
+ }
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ return result;
+ }
+
+Test::Result find_all_subjects()
+ {
+ Test::Result result("linux Certificate Store - Find all Certificate Subjects");
+
+ try
+ {
+ result.start_timer();
+ Botan::Certificate_Store_Linux certstore;
+ auto subjects = certstore.all_subjects();
+ result.end_timer();
+
+ if(result.confirm("result not empty", !subjects.empty()))
+ {
+ auto dn = get_dn();
+ auto needle = std::find_if(subjects.cbegin(),
+ subjects.cend(),
+ [=](const Botan::X509_DN &subject)
+ {
+ return subject == dn;
+ });
+
+ if(result.confirm("found expected certificate", needle != subjects.end()))
+ {
+ result.confirm("expected certificate", *needle == dn);
+ }
+ }
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ return result;
+ }
+
+Test::Result no_certificate_matches()
+ {
+ Test::Result result("linux Certificate Store - can deal with no matches (regression test)");
+
+ try
+ {
+ auto dn = get_unknown_dn();
+ auto kid = get_unknown_key_id();
+
+ result.start_timer();
+ Botan::Certificate_Store_Linux certstore;
+
+ auto certs = certstore.find_all_certs(dn, kid);
+ auto cert = certstore.find_cert(dn, kid);
+ auto pubk_cert = certstore.find_cert_by_pubkey_sha1(kid);
+ result.end_timer();
+
+ result.confirm("find_all_certs did not find the dummy", certs.empty());
+ result.confirm("find_cert did not find the dummy", !cert);
+ result.confirm("find_cert_by_pubkey_sha1 did not find the dummy", !pubk_cert);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+
+ return result;
+ }
+
+class Certstor_Linux_Tests final : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<Test::Result> results;
+
+ results.push_back(open_certificate_store());
+ results.push_back(find_certificate_by_pubkey_sha1());
+ results.push_back(find_cert_by_subject_dn());
+ results.push_back(find_cert_by_subject_dn_and_key_id());
+ results.push_back(find_certs_by_subject_dn_and_key_id());
+ results.push_back(find_all_subjects());
+ results.push_back(no_certificate_matches());
+
+ return results;
+ }
+ };
+
+BOTAN_REGISTER_TEST("certstor_linux", Certstor_Linux_Tests);
+
+}
+
+}
+
+#endif
diff --git a/src/tests/test_certstor_macos.cpp b/src/tests/test_certstor_macos.cpp
index 243a150da..a21fd2a32 100644
--- a/src/tests/test_certstor_macos.cpp
+++ b/src/tests/test_certstor_macos.cpp
@@ -9,6 +9,7 @@
#if defined(BOTAN_HAS_CERTSTOR_MACOS)
+#include "test_certstor_utils.h"
#include <botan/certstor_macos.h>
#include <botan/ber_dec.h>
#include <botan/der_enc.h>
@@ -18,59 +19,6 @@ namespace Botan_Tests {
namespace {
-Botan::X509_DN read_dn(const std::string hex)
- {
- Botan::X509_DN dn;
- Botan::BER_Decoder decoder(Botan::hex_decode(hex));
- dn.decode_from(decoder);
- return dn;
- }
-
-Botan::X509_DN get_dn()
- {
- // Public key fingerprint of "DST Root CA X3"
- // This certificate is in the standard "System Roots" of any macOS setup,
- // serves as the trust root of botan.randombit.net and expires on
- // Thursday, 30. September 2021 at 16:01:15 Central European Summer Time
- return read_dn("303f31243022060355040a131b4469676974616c205369676e6174757265"
- "20547275737420436f2e311730150603550403130e44535420526f6f7420"
- "4341205833");
- }
-
-std::vector<uint8_t> get_key_id()
- {
- // this is the same as the public key SHA1
- return Botan::hex_decode("c4a7b1a47b2c71fadbe14b9075ffc41560858910");
- }
-
-Botan::X509_DN get_unknown_dn()
- {
- // thats a D-Trust "Test Certificate". It should be fairly likely that
- // _nobody_ will _ever_ have that in their system keychain
- // CN: D-TRUST Limited Basic Test PU CA 1-4 2016
- return read_dn("305b310b300906035504061302444531153013060355040a0c0c442d5472"
- "75737420476d62483135303306035504030c2c442d5452555354204c696d"
- "6974656420426173696320526f6f74205465737420505520434120312032"
- "303135");
- }
-
-Botan::X509_DN get_skewed_dn()
- {
- // This DN contains ASN.1 PrintableString fields that are not 'normalized'
- // according to Apple's idea of a normalized PrintableString field:
- // (1) It has leading and trailing white space
- // (2) It contains multiple spaces between 'words'
- return read_dn("304b312a3028060355040a132120204469676974616c2020205369676e61"
- "7475726520547275737420436f2e2020311d301b06035504031314202044"
- "5354202020526f6f742043412058332020");
- }
-
-std::vector<uint8_t> get_unknown_key_id()
- {
- // this is the same as the public key SHA1
- return Botan::hex_decode("785c0b67b536eeacbb2b27cf9123301abe7ab09a");
- }
-
Test::Result open_certificate_store()
{
Test::Result result("macOS Certificate Store - Open Keychain");
diff --git a/src/tests/test_certstor_utils.h b/src/tests/test_certstor_utils.h
new file mode 100644
index 000000000..66119519a
--- /dev/null
+++ b/src/tests/test_certstor_utils.h
@@ -0,0 +1,72 @@
+/*
+* (C) 1999-2019 Jack Lloyd
+* (C) 2019 René Meusel
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_TEST_CERT_STORE_UTILS_H_
+#define BOTAN_TEST_CERT_STORE_UTILS_H_
+
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/hex.h>
+#include <botan/x509_dn.h>
+
+namespace Botan_Tests {
+
+Botan::X509_DN read_dn(const std::string hex)
+ {
+ Botan::X509_DN dn;
+ Botan::BER_Decoder decoder(Botan::hex_decode(hex));
+ dn.decode_from(decoder);
+ return dn;
+ }
+
+Botan::X509_DN get_dn()
+ {
+ // Public key fingerprint of "DST Root CA X3"
+ // This certificate is in the standard "System Roots" of any macOS setup,
+ // serves as the trust root of botan.randombit.net and expires on
+ // Thursday, 30. September 2021 at 16:01:15 Central European Summer Time
+ return read_dn("303f31243022060355040a131b4469676974616c205369676e6174757265"
+ "20547275737420436f2e311730150603550403130e44535420526f6f7420"
+ "4341205833");
+ }
+
+std::vector<uint8_t> get_key_id()
+ {
+ // this is the same as the public key SHA1
+ return Botan::hex_decode("c4a7b1a47b2c71fadbe14b9075ffc41560858910");
+ }
+
+Botan::X509_DN get_unknown_dn()
+ {
+ // thats a D-Trust "Test Certificate". It should be fairly likely that
+ // _nobody_ will _ever_ have that in their system keychain
+ // CN: D-TRUST Limited Basic Test PU CA 1-4 2016
+ return read_dn("305b310b300906035504061302444531153013060355040a0c0c442d5472"
+ "75737420476d62483135303306035504030c2c442d5452555354204c696d"
+ "6974656420426173696320526f6f74205465737420505520434120312032"
+ "303135");
+ }
+
+Botan::X509_DN get_skewed_dn()
+ {
+ // This DN contains ASN.1 PrintableString fields that are not 'normalized'
+ // according to Apple's idea of a normalized PrintableString field:
+ // (1) It has leading and trailing white space
+ // (2) It contains multiple spaces between 'words'
+ return read_dn("304b312a3028060355040a132120204469676974616c2020205369676e61"
+ "7475726520547275737420436f2e2020311d301b06035504031314202044"
+ "5354202020526f6f742043412058332020");
+ }
+
+std::vector<uint8_t> get_unknown_key_id()
+ {
+ // this is the same as the public key SHA1
+ return Botan::hex_decode("785c0b67b536eeacbb2b27cf9123301abe7ab09a");
+ }
+}
+#endif
+