aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/news.rst4
-rw-r--r--src/build-data/policy/bsi.txt3
-rw-r--r--src/lib/cert/x509/certstor.cpp49
-rw-r--r--src/lib/cert/x509/certstor.h19
-rw-r--r--src/lib/cert/x509/certstor_sql/certstor_sql.cpp302
-rw-r--r--src/lib/cert/x509/certstor_sql/certstor_sql.h93
-rw-r--r--src/lib/cert/x509/certstor_sql/info.txt5
-rw-r--r--src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.cpp18
-rw-r--r--src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.h23
-rw-r--r--src/lib/cert/x509/certstor_sqlite3/info.txt6
-rw-r--r--src/lib/cert/x509/ocsp.cpp4
-rw-r--r--src/lib/cert/x509/x509_crl.cpp9
-rw-r--r--src/lib/cert/x509/x509_crl.h3
-rw-r--r--src/lib/cert/x509/x509_ext.cpp8
-rw-r--r--src/lib/cert/x509/x509_ext.h6
-rw-r--r--src/lib/cert/x509/x509path.cpp76
-rw-r--r--src/lib/cert/x509/x509path.h6
-rw-r--r--src/lib/entropy/entropy_srcs.cpp3
-rw-r--r--src/lib/prov/openssl/openssl_rc4.cpp2
-rw-r--r--src/lib/pubkey/info.txt2
-rw-r--r--src/lib/pubkey/pk_keys.cpp26
-rw-r--r--src/lib/pubkey/pk_keys.h4
-rw-r--r--src/lib/rng/system_rng/system_rng.cpp6
-rw-r--r--src/lib/utils/database.h2
-rw-r--r--src/lib/utils/sqlite3/sqlite3.cpp7
-rw-r--r--src/lib/utils/sqlite3/sqlite3.h1
-rw-r--r--src/tests/data/certstor/cert1.crt17
-rw-r--r--src/tests/data/certstor/cert2.crt17
-rw-r--r--src/tests/data/certstor/cert3.crt17
-rw-r--r--src/tests/data/certstor/cert4.crt17
-rw-r--r--src/tests/data/certstor/cert5a.crt17
-rw-r--r--src/tests/data/certstor/cert5b.crt17
-rw-r--r--src/tests/data/certstor/key01.pem28
-rw-r--r--src/tests/data/certstor/key03.pem28
-rw-r--r--src/tests/data/certstor/key04.pem28
-rw-r--r--src/tests/data/certstor/key05.pem28
-rw-r--r--src/tests/data/certstor/key06.pem28
-rw-r--r--src/tests/test_certstor.cpp257
38 files changed, 1102 insertions, 84 deletions
diff --git a/doc/news.rst b/doc/news.rst
index 892938aff..f8c2fb393 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -6,6 +6,10 @@ Version 1.11.33, Not Yet Released
* Add support for the TLS Supported Point Formats Extension (RFC 4492).
+* Fix entropy source selection bug on Windows, which caused the
+ CryptoAPI entropy source to be not available under its normal name
+ "win32_cryptoapi" but instead "dev_random". GH #644
+
Version 1.11.32, 2016-09-28
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/build-data/policy/bsi.txt b/src/build-data/policy/bsi.txt
index 16671fd13..c2b31e4c6 100644
--- a/src/build-data/policy/bsi.txt
+++ b/src/build-data/policy/bsi.txt
@@ -78,6 +78,7 @@ blowfish
camellia
cascade
cast
+des
gost_28147
idea
idea_sse2
@@ -110,6 +111,7 @@ rc4
salsa20
# kdf
+hkdf
kdf1
kdf2
prf_x942
@@ -149,6 +151,7 @@ siphash
x919_mac
# rng
+hmac_rng
x931_rng
# entropy sources
diff --git a/src/lib/cert/x509/certstor.cpp b/src/lib/cert/x509/certstor.cpp
index 26c9ce117..28b46ef1a 100644
--- a/src/lib/cert/x509/certstor.cpp
+++ b/src/lib/cert/x509/certstor.cpp
@@ -10,57 +10,58 @@
namespace Botan {
-const X509_CRL* Certificate_Store::find_crl_for(const X509_Certificate&) const
+std::shared_ptr<const X509_CRL> Certificate_Store::find_crl_for(const X509_Certificate&) const
{
- return nullptr;
+ return std::shared_ptr<const X509_CRL>();
}
void Certificate_Store_In_Memory::add_certificate(const X509_Certificate& cert)
{
for(size_t i = 0; i != m_certs.size(); ++i)
{
- if(m_certs[i] == cert)
+ if(*m_certs[i] == cert)
return;
}
- m_certs.push_back(cert);
+ m_certs.push_back(std::make_shared<X509_Certificate>(cert));
}
std::vector<X509_DN> Certificate_Store_In_Memory::all_subjects() const
{
std::vector<X509_DN> subjects;
for(size_t i = 0; i != m_certs.size(); ++i)
- subjects.push_back(m_certs[i].subject_dn());
+ subjects.push_back(m_certs[i]->subject_dn());
return subjects;
}
namespace {
-const X509_Certificate*
+template<typename T>
+std::shared_ptr<const X509_Certificate>
cert_search(const X509_DN& subject_dn, const std::vector<byte>& key_id,
- const std::vector<X509_Certificate>& certs)
+ const std::vector<std::shared_ptr<T>>& certs)
{
for(size_t i = 0; i != certs.size(); ++i)
{
// Only compare key ids if set in both call and in the cert
if(key_id.size())
{
- std::vector<byte> skid = certs[i].subject_key_id();
+ std::vector<byte> skid = certs[i]->subject_key_id();
if(skid.size() && skid != key_id) // no match
continue;
}
- if(certs[i].subject_dn() == subject_dn)
- return &certs[i];
+ if(certs[i]->subject_dn() == subject_dn)
+ return certs[i];
}
- return nullptr;
+ return std::shared_ptr<const X509_Certificate>();
}
}
-const X509_Certificate*
+std::shared_ptr<const X509_Certificate>
Certificate_Store_In_Memory::find_cert(const X509_DN& subject_dn,
const std::vector<byte>& key_id) const
{
@@ -74,19 +75,19 @@ void Certificate_Store_In_Memory::add_crl(const X509_CRL& crl)
for(size_t i = 0; i != m_crls.size(); ++i)
{
// Found an update of a previously existing one; replace it
- if(m_crls[i].issuer_dn() == crl_issuer)
+ if(m_crls[i]->issuer_dn() == crl_issuer)
{
- if(m_crls[i].this_update() <= crl.this_update())
- m_crls[i] = crl;
+ if(m_crls[i]->this_update() <= crl.this_update())
+ m_crls[i] = std::make_shared<X509_CRL>(crl);
return;
}
}
// Totally new CRL, add to the list
- m_crls.push_back(crl);
+ m_crls.push_back(std::make_shared<X509_CRL>(crl));
}
-const X509_CRL* Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const
+std::shared_ptr<const X509_CRL> Certificate_Store_In_Memory::find_crl_for(const X509_Certificate& subject) const
{
const std::vector<byte>& key_id = subject.authority_key_id();
@@ -95,17 +96,17 @@ const X509_CRL* Certificate_Store_In_Memory::find_crl_for(const X509_Certificate
// Only compare key ids if set in both call and in the CRL
if(key_id.size())
{
- std::vector<byte> akid = m_crls[i].authority_key_id();
+ std::vector<byte> akid = m_crls[i]->authority_key_id();
if(akid.size() && akid != key_id) // no match
continue;
}
- if(m_crls[i].issuer_dn() == subject.issuer_dn())
- return &m_crls[i];
+ if(m_crls[i]->issuer_dn() == subject.issuer_dn())
+ return m_crls[i];
}
- return nullptr;
+ return std::shared_ptr<const X509_CRL>();
}
Certificate_Store_In_Memory::Certificate_Store_In_Memory(const X509_Certificate& cert)
@@ -123,7 +124,7 @@ Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir)
{
try
{
- m_certs.push_back(X509_Certificate(cert_file));
+ m_certs.push_back(std::make_shared<X509_Certificate>(cert_file));
}
catch(std::exception&)
{
@@ -131,7 +132,7 @@ Certificate_Store_In_Memory::Certificate_Store_In_Memory(const std::string& dir)
}
}
-const X509_Certificate*
+std::shared_ptr<const X509_Certificate>
Certificate_Store_Overlay::find_cert(const X509_DN& subject_dn,
const std::vector<byte>& key_id) const
{
@@ -142,7 +143,7 @@ std::vector<X509_DN> Certificate_Store_Overlay::all_subjects() const
{
std::vector<X509_DN> subjects;
for(size_t i = 0; i != m_certs.size(); ++i)
- subjects.push_back(m_certs[i].subject_dn());
+ subjects.push_back(m_certs[i]->subject_dn());
return subjects;
}
diff --git a/src/lib/cert/x509/certstor.h b/src/lib/cert/x509/certstor.h
index 29948c709..55f6b8c93 100644
--- a/src/lib/cert/x509/certstor.h
+++ b/src/lib/cert/x509/certstor.h
@@ -24,10 +24,10 @@ class BOTAN_DLL Certificate_Store
/**
* Subject DN and (optionally) key identifier
*/
- virtual const X509_Certificate*
+ virtual std::shared_ptr<const X509_Certificate>
find_cert(const X509_DN& subject_dn, const std::vector<byte>& key_id) const = 0;
- virtual const X509_CRL* find_crl_for(const X509_Certificate& subject) const;
+ virtual std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const;
bool certificate_known(const X509_Certificate& cert) const
{
@@ -60,32 +60,31 @@ class BOTAN_DLL Certificate_Store_In_Memory : public Certificate_Store
std::vector<X509_DN> all_subjects() const override;
- const X509_Certificate* find_cert(
+ std::shared_ptr<const X509_Certificate> find_cert(
const X509_DN& subject_dn,
const std::vector<byte>& key_id) const override;
- const X509_CRL* find_crl_for(const X509_Certificate& subject) const override;
+ std::shared_ptr<const X509_CRL> find_crl_for(const X509_Certificate& subject) const override;
private:
// TODO: Add indexing on the DN and key id to avoid linear search
- std::vector<X509_Certificate> m_certs;
- std::vector<X509_CRL> m_crls;
+ std::vector<std::shared_ptr<X509_Certificate>> m_certs;
+ std::vector<std::shared_ptr<X509_CRL>> m_crls;
};
class BOTAN_DLL Certificate_Store_Overlay : public Certificate_Store
{
public:
- explicit Certificate_Store_Overlay(const std::vector<X509_Certificate>& certs) :
+ explicit Certificate_Store_Overlay(const std::vector<std::shared_ptr<const X509_Certificate>>& certs) :
m_certs(certs) {}
std::vector<X509_DN> all_subjects() const override;
- const X509_Certificate* find_cert(
+ std::shared_ptr<const X509_Certificate> find_cert(
const X509_DN& subject_dn,
const std::vector<byte>& key_id) const override;
private:
- const std::vector<X509_Certificate>& m_certs;
+ const std::vector<std::shared_ptr<const X509_Certificate>>& m_certs;
};
}
-
#endif
diff --git a/src/lib/cert/x509/certstor_sql/certstor_sql.cpp b/src/lib/cert/x509/certstor_sql/certstor_sql.cpp
new file mode 100644
index 000000000..b80c063da
--- /dev/null
+++ b/src/lib/cert/x509/certstor_sql/certstor_sql.cpp
@@ -0,0 +1,302 @@
+/*
+* Certificate Store in SQL
+* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/certstor_sql.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/internal/filesystem.h>
+#include <botan/pkcs8.h>
+#include <botan/data_src.h>
+#include <botan/auto_rng.h>
+#include <botan/hash.h>
+#include <botan/hex.h>
+
+namespace Botan {
+
+Certificate_Store_In_SQL::Certificate_Store_In_SQL(std::shared_ptr<SQL_Database> db,
+ const std::string& passwd,
+ const std::string& table_prefix)
+: m_database(db), m_prefix(table_prefix), m_password(passwd)
+ {
+ m_database->create_table("CREATE TABLE IF NOT EXISTS " +
+ m_prefix + "certificates ( \
+ fingerprint BLOB PRIMARY KEY, \
+ subject_dn BLOB, \
+ key_id BLOB, \
+ priv_fingerprint BLOB, \
+ certificate BLOB UNIQUE NOT NULL\
+ )");
+ m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "keys (\
+ fingerprint BLOB PRIMARY KEY, \
+ key BLOB UNIQUE NOT NULL \
+ )");
+ m_database->create_table("CREATE TABLE IF NOT EXISTS " + m_prefix + "revoked (\
+ fingerprint BLOB PRIMARY KEY, \
+ reason BLOB NOT NULL, \
+ time BLOB NOT NULL \
+ )");
+ }
+
+// Certificate handling
+std::shared_ptr<const X509_Certificate>
+Certificate_Store_In_SQL::find_cert(const X509_DN& subject_dn, const std::vector<byte>& key_id) const
+ {
+ DER_Encoder enc;
+ std::shared_ptr<SQL_Database::Statement> stmt;
+
+ subject_dn.encode_into(enc);
+
+ if(key_id.empty())
+ {
+ stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE subject_dn == ?1");
+ stmt->bind(1,enc.get_contents_unlocked());
+ }
+ else
+ {
+ stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE\
+ subject_dn == ?1 AND (key_id == NULL OR key_id == ?2)");
+ stmt->bind(1,enc.get_contents_unlocked());
+ stmt->bind(2,key_id);
+ }
+
+ std::shared_ptr<const X509_Certificate> cert;
+ while(stmt->step())
+ {
+ auto blob = stmt->get_blob(0);
+ cert = std::make_shared<X509_Certificate>(
+ std::vector<byte>(blob.first,blob.first + blob.second));
+
+ }
+
+ return cert;
+ }
+
+std::shared_ptr<const X509_CRL>
+Certificate_Store_In_SQL::find_crl_for(const X509_Certificate& subject) const
+ {
+ auto all_crls = generate_crls();
+
+ for(auto crl: all_crls)
+ {
+ if(!crl.get_revoked().empty() && crl.issuer_dn() == subject.issuer_dn())
+ return std::shared_ptr<X509_CRL>(new X509_CRL(crl));
+ }
+
+ return std::shared_ptr<X509_CRL>();
+ }
+
+std::vector<X509_DN> Certificate_Store_In_SQL::all_subjects() const
+ {
+ std::vector<X509_DN> ret;
+ auto stmt = m_database->new_statement("SELECT subject_dn FROM " + m_prefix + "certificates");
+
+ while(stmt->step())
+ {
+ auto blob = stmt->get_blob(0);
+ BER_Decoder dec(blob.first,blob.second);
+ X509_DN dn;
+
+ dn.decode_from(dec);
+
+ ret.push_back(dn);
+ }
+
+ return ret;
+ }
+
+bool Certificate_Store_In_SQL::insert_cert(const X509_Certificate& cert)
+ {
+ if(find_cert(cert.subject_dn(),cert.subject_key_id()))
+ return false;
+
+ DER_Encoder enc;
+ auto stmt = m_database->new_statement("INSERT OR REPLACE INTO " +
+ m_prefix + "certificates (\
+ fingerprint, \
+ subject_dn, \
+ key_id, \
+ priv_fingerprint, \
+ certificate \
+ ) VALUES ( ?1, ?2, ?3, ?4, ?5 )");
+
+ stmt->bind(1,cert.fingerprint("SHA-256"));
+ cert.subject_dn().encode_into(enc);
+ stmt->bind(2,enc.get_contents_unlocked());
+ stmt->bind(3,cert.subject_key_id());
+ stmt->bind(4,std::vector<byte>());
+ enc = DER_Encoder();
+ cert.encode_into(enc);
+ stmt->bind(5,enc.get_contents_unlocked());
+ stmt->spin();
+
+ return true;
+ }
+
+
+bool Certificate_Store_In_SQL::remove_cert(const X509_Certificate& cert)
+ {
+ if(!find_cert(cert.subject_dn(),cert.subject_key_id()))
+ return false;
+
+ auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "certificates WHERE fingerprint == ?1");
+
+ stmt->bind(1,cert.fingerprint("SHA-256"));
+ stmt->spin();
+
+ return true;
+ }
+
+// Private key handling
+std::shared_ptr<const Private_Key> Certificate_Store_In_SQL::find_key(const X509_Certificate& cert) const
+ {
+ auto stmt = m_database->new_statement("SELECT key FROM " + m_prefix + "keys "
+ "JOIN " + m_prefix + "certificates ON " +
+ m_prefix + "keys.fingerprint == " + m_prefix + "certificates.priv_fingerprint "
+ "WHERE " + m_prefix + "certificates.fingerprint == ?1");
+ stmt->bind(1,cert.fingerprint("SHA-256"));
+
+ std::shared_ptr<const Private_Key> key;
+ while(stmt->step())
+ {
+ auto blob = stmt->get_blob(0);
+ AutoSeeded_RNG rng;
+ DataSource_Memory src(blob.first,blob.second);
+ key.reset(PKCS8::load_key(src,rng,m_password));
+ }
+
+ return key;
+ }
+
+std::vector<std::shared_ptr<const X509_Certificate>>
+Certificate_Store_In_SQL::find_certs_for_key(const Private_Key& key) const
+ {
+ AutoSeeded_RNG rng;
+ auto fpr = key.fingerprint("SHA-256");
+ auto stmt = m_database->new_statement("SELECT certificate FROM " + m_prefix + "certificates WHERE priv_fingerprint == ?1");
+
+ stmt->bind(1,fpr);
+
+ std::vector<std::shared_ptr<const X509_Certificate>> certs;
+ while(stmt->step())
+ {
+ auto blob = stmt->get_blob(0);
+ certs.push_back(std::make_shared<X509_Certificate>(
+ std::vector<byte>(blob.first,blob.first + blob.second)));
+ }
+
+ return certs;
+ }
+
+bool Certificate_Store_In_SQL::insert_key(const X509_Certificate& cert, const Private_Key& key) {
+ insert_cert(cert);
+
+ if(find_key(cert))
+ return false;
+
+ AutoSeeded_RNG rng;
+ auto pkcs8 = PKCS8::BER_encode(key,rng,m_password);
+ auto fpr = key.fingerprint("SHA-256");
+
+ auto stmt1 = m_database->new_statement(
+ "INSERT OR REPLACE INTO " + m_prefix + "keys ( fingerprint, key ) VALUES ( ?1, ?2 )");
+
+ stmt1->bind(1,fpr);
+ stmt1->bind(2,pkcs8.data(),pkcs8.size());
+ stmt1->spin();
+
+ auto stmt2 = m_database->new_statement(
+ "UPDATE " + m_prefix + "certificates SET priv_fingerprint = ?1 WHERE fingerprint == ?2");
+
+ stmt2->bind(1,fpr);
+ stmt2->bind(2,cert.fingerprint("SHA-256"));
+ stmt2->spin();
+
+ return true;
+ }
+
+void Certificate_Store_In_SQL::remove_key(const Private_Key& key)
+ {
+ AutoSeeded_RNG rng;
+ auto fpr = key.fingerprint("SHA-256");
+ auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "keys WHERE fingerprint == ?1");
+
+ stmt->bind(1,fpr);
+ stmt->spin();
+ }
+
+// Revocation
+void Certificate_Store_In_SQL::revoke_cert(const X509_Certificate& cert, CRL_Code code, const X509_Time& time)
+ {
+ insert_cert(cert);
+
+ auto stmt1 = m_database->new_statement(
+ "INSERT OR REPLACE INTO " + m_prefix + "revoked ( fingerprint, reason, time ) VALUES ( ?1, ?2, ?3 )");
+
+ stmt1->bind(1,cert.fingerprint("SHA-256"));
+ stmt1->bind(2,code);
+
+ if(time.time_is_set())
+ {
+ DER_Encoder der;
+ time.encode_into(der);
+ stmt1->bind(3,der.get_contents_unlocked());
+ }
+ else
+ {
+ stmt1->bind(3,-1);
+ }
+
+ stmt1->spin();
+ }
+
+void Certificate_Store_In_SQL::affirm_cert(const X509_Certificate& cert)
+ {
+ auto stmt = m_database->new_statement("DELETE FROM " + m_prefix + "revoked WHERE fingerprint == ?1");
+
+ stmt->bind(1,cert.fingerprint("SHA-256"));
+ stmt->spin();
+ }
+
+std::vector<X509_CRL> Certificate_Store_In_SQL::generate_crls() const
+ {
+ auto stmt = m_database->new_statement(
+ "SELECT certificate,reason,time FROM " + m_prefix + "revoked "
+ "JOIN " + m_prefix + "certificates ON " +
+ m_prefix + "certificates.fingerprint == " + m_prefix + "revoked.fingerprint");
+
+ std::map<X509_DN,std::vector<CRL_Entry>> crls;
+ while(stmt->step())
+ {
+ auto blob = stmt->get_blob(0);
+ auto cert = X509_Certificate(
+ std::vector<byte>(blob.first,blob.first + blob.second));
+ auto code = static_cast<CRL_Code>(stmt->get_size_t(1));
+ auto ent = CRL_Entry(cert,code);
+
+ auto i = crls.find(cert.issuer_dn());
+ if(i == crls.end())
+ {
+ crls.insert(std::make_pair(cert.issuer_dn(),std::vector<CRL_Entry>({ent})));
+ }
+ else
+ {
+ i->second.push_back(ent);
+ }
+ }
+
+ std::vector<X509_CRL> ret;
+ X509_Time t(std::chrono::system_clock::now());
+
+ for(auto p: crls)
+ {
+ ret.push_back(X509_CRL(p.first,t,t,p.second));
+ }
+
+ return ret;
+ }
+
+}
diff --git a/src/lib/cert/x509/certstor_sql/certstor_sql.h b/src/lib/cert/x509/certstor_sql/certstor_sql.h
new file mode 100644
index 000000000..096426b7a
--- /dev/null
+++ b/src/lib/cert/x509/certstor_sql/certstor_sql.h
@@ -0,0 +1,93 @@
+/*
+* Certificate Store in SQL
+* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_CERT_STORE_SQL_H__
+#define BOTAN_CERT_STORE_SQL_H__
+
+#include <botan/certstor.h>
+#include <botan/x509cert.h>
+#include <botan/x509_crl.h>
+#include <botan/database.h>
+
+namespace Botan {
+
+/**
+ * Certificate and private key store backed an SQL database.
+ */
+class BOTAN_DLL Certificate_Store_In_SQL : public Certificate_Store
+ {
+ public:
+ /**
+ * Create/open a certificate store backed by "db".
+ * Inserted private keys are encrypted using "passwd".
+ */
+ explicit Certificate_Store_In_SQL(const std::shared_ptr<SQL_Database> db,
+ const std::string& passwd,
+ const std::string& table_prefix = "");
+
+ /// Returns the first certificate with matching subject DN and optional key ID.
+ virtual std::shared_ptr<const X509_Certificate>
+ find_cert(const X509_DN& subject_dn, const std::vector<byte>& key_id) const override;
+
+ /// Returns all subject DNs known to the store instance,
+ virtual std::vector<X509_DN> all_subjects() const override;
+
+ /**
+ * Inserts "cert" into the store, returns false if the certificate is
+ * already known and true if insertion was successful.
+ */
+ bool insert_cert(const X509_Certificate& cert);
+
+ /**
+ * Removes "cert" from the store. Returns false if the certificate could not
+ * be found and true if removal was successful.
+ */
+ bool remove_cert(const X509_Certificate& cert);
+
+ /// Returns the private key for "cert" or an empty shared_ptr if none was found.
+ std::shared_ptr<const Private_Key> find_key(const X509_Certificate&) const;
+
+ /// Returns all certificates for private key "key".
+ std::vector<std::shared_ptr<const X509_Certificate>>
+ find_certs_for_key(const Private_Key& key) const;
+
+ /**
+ * Inserts "key" for "cert" into the store, returns false if the key is
+ * already known and true if insertion was successful.
+ */
+ bool insert_key(const X509_Certificate& cert, const Private_Key& key);
+
+ /// Removes "key" from the store.
+ void remove_key(const Private_Key& key);
+
+ /// Marks "cert" as revoked starting from "time".
+ void revoke_cert(const X509_Certificate&,CRL_Code,const X509_Time& time = X509_Time());
+
+ /// Reverses the revokation for "cert".
+ void affirm_cert(const X509_Certificate&);
+
+ /**
+ * Generates Certificate Revocation Lists for all certificates marked as revoked.
+ * A CRL is returned for each unique issuer DN.
+ */
+ std::vector<X509_CRL> generate_crls() const;
+
+ /// Generates a CRL for all certificates issued by the given issuer.
+ virtual std::shared_ptr<const X509_CRL>
+ find_crl_for(const X509_Certificate& issuer) const override;
+
+ private:
+ std::string fingerprint_key(const Private_Key&) const;
+
+ std::shared_ptr<SQL_Database> m_database;
+ std::string m_prefix;
+ std::string m_password;
+ std::mutex m_mutex;
+ };
+
+}
+#endif
diff --git a/src/lib/cert/x509/certstor_sql/info.txt b/src/lib/cert/x509/certstor_sql/info.txt
new file mode 100644
index 000000000..cfdd521a2
--- /dev/null
+++ b/src/lib/cert/x509/certstor_sql/info.txt
@@ -0,0 +1,5 @@
+define CERTSTOR_SQL 20160818
+
+<requires>
+datastor
+</requires>
diff --git a/src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.cpp b/src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.cpp
new file mode 100644
index 000000000..89dfb3575
--- /dev/null
+++ b/src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.cpp
@@ -0,0 +1,18 @@
+/*
+* Certificate Store in SQL
+* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/certstor_sqlite.h>
+#include <botan/sqlite3.h>
+
+namespace Botan {
+
+Certificate_Store_In_SQLite::Certificate_Store_In_SQLite(const std::string& db_path,
+ const std::string& passwd,
+ const std::string& table_prefix)
+: Certificate_Store_In_SQL(std::make_shared<Sqlite3_Database>(db_path), passwd, table_prefix)
+ {}
+}
diff --git a/src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.h b/src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.h
new file mode 100644
index 000000000..c7d686d89
--- /dev/null
+++ b/src/lib/cert/x509/certstor_sqlite3/certstor_sqlite.h
@@ -0,0 +1,23 @@
+/*
+* Certificate Store in SQL
+* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_CERT_STORE_SQLITE_H__
+#define BOTAN_CERT_STORE_SQLITE_H__
+
+#include <botan/certstor_sql.h>
+
+namespace Botan {
+
+class BOTAN_DLL Certificate_Store_In_SQLite : public Certificate_Store_In_SQL
+ {
+ public:
+ Certificate_Store_In_SQLite(const std::string& db_path,
+ const std::string& passwd,
+ const std::string& table_prefix = "");
+ };
+}
+#endif
diff --git a/src/lib/cert/x509/certstor_sqlite3/info.txt b/src/lib/cert/x509/certstor_sqlite3/info.txt
new file mode 100644
index 000000000..d5e50fc95
--- /dev/null
+++ b/src/lib/cert/x509/certstor_sqlite3/info.txt
@@ -0,0 +1,6 @@
+define CERTSTOR_SQLITE3 20160818
+
+<requires>
+certstor_sql
+sqlite3
+</requires>
diff --git a/src/lib/cert/x509/ocsp.cpp b/src/lib/cert/x509/ocsp.cpp
index df8df3b39..761c5b436 100644
--- a/src/lib/cert/x509/ocsp.cpp
+++ b/src/lib/cert/x509/ocsp.cpp
@@ -92,9 +92,9 @@ void check_signature(const std::vector<byte>& tbs_response,
if(!trusted_roots.certificate_known(result.trust_root())) // not needed anymore?
throw Exception("Certificate chain roots in unknown/untrusted CA");
- const std::vector<X509_Certificate>& cert_path = result.cert_path();
+ const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = result.cert_path();
- check_signature(tbs_response, sig_algo, signature, cert_path[0]);
+ check_signature(tbs_response, sig_algo, signature, *cert_path[0]);
}
}
diff --git a/src/lib/cert/x509/x509_crl.cpp b/src/lib/cert/x509/x509_crl.cpp
index 64cb1b308..3c75825c1 100644
--- a/src/lib/cert/x509/x509_crl.cpp
+++ b/src/lib/cert/x509/x509_crl.cpp
@@ -39,6 +39,15 @@ X509_CRL::X509_CRL(const std::vector<byte>& in, bool touc) :
do_decode();
}
+X509_CRL::X509_CRL(const X509_DN& issuer, const X509_Time& thisUpdate,
+ const X509_Time& nextUpdate, const std::vector<CRL_Entry>& revoked) :
+ X509_Object(), m_throw_on_unknown_critical(false), m_revoked(revoked)
+ {
+ m_info.add(issuer.contents());
+ m_info.add("X509.CRL.start", thisUpdate.to_string());
+ m_info.add("X509.CRL.end", nextUpdate.to_string());
+ }
+
/**
* Check if this particular certificate is listed in the CRL
*/
diff --git a/src/lib/cert/x509/x509_crl.h b/src/lib/cert/x509/x509_crl.h
index dab4d5153..2e05f98fb 100644
--- a/src/lib/cert/x509/x509_crl.h
+++ b/src/lib/cert/x509/x509_crl.h
@@ -100,6 +100,9 @@ class BOTAN_DLL X509_CRL final : public X509_Object
X509_CRL(const std::vector<byte>& vec,
bool throw_on_unknown_critical = false);
+ X509_CRL(const X509_DN& issuer, const X509_Time& thisUpdate,
+ const X509_Time& nextUpdate, const std::vector<CRL_Entry>& revoked);
+
private:
void force_decode() override;
diff --git a/src/lib/cert/x509/x509_ext.cpp b/src/lib/cert/x509/x509_ext.cpp
index 650c20d53..23340f784 100644
--- a/src/lib/cert/x509/x509_ext.cpp
+++ b/src/lib/cert/x509/x509_ext.cpp
@@ -83,7 +83,7 @@ OID Certificate_Extension::oid_of() const
* Validate the extension (the default implementation is a NOP)
*/
void Certificate_Extension::validate(const X509_Certificate&, const X509_Certificate&,
- const std::vector<X509_Certificate>&,
+ const std::vector<std::shared_ptr<const X509_Certificate>>&,
std::vector<std::set<Certificate_Status_Code>>&,
size_t)
{
@@ -525,7 +525,7 @@ void Name_Constraints::contents_to(Data_Store& subject, Data_Store&) const
}
void Name_Constraints::validate(const X509_Certificate& subject, const X509_Certificate& issuer,
- const std::vector<X509_Certificate>& cert_path,
+ const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
std::vector<std::set<Certificate_Status_Code>>& cert_status,
size_t pos)
{
@@ -547,7 +547,7 @@ void Name_Constraints::validate(const X509_Certificate& subject, const X509_Cert
for(auto c: m_name_constraints.permitted())
{
- switch(c.base().matches(cert_path.at(j)))
+ switch(c.base().matches(*cert_path.at(j)))
{
case GeneralName::MatchResult::NotFound:
case GeneralName::MatchResult::All:
@@ -564,7 +564,7 @@ void Name_Constraints::validate(const X509_Certificate& subject, const X509_Cert
for(auto c: m_name_constraints.excluded())
{
- switch(c.base().matches(cert_path.at(j)))
+ switch(c.base().matches(*cert_path.at(j)))
{
case GeneralName::MatchResult::All:
case GeneralName::MatchResult::Some:
diff --git a/src/lib/cert/x509/x509_ext.h b/src/lib/cert/x509/x509_ext.h
index 8ea2f2da6..b1984fa94 100644
--- a/src/lib/cert/x509/x509_ext.h
+++ b/src/lib/cert/x509/x509_ext.h
@@ -68,7 +68,7 @@ class BOTAN_DLL Certificate_Extension
* @param pos Position of subject certificate in cert_path
*/
virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer,
- const std::vector<X509_Certificate>& cert_path,
+ const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
std::vector<std::set<Certificate_Status_Code>>& cert_status,
size_t pos);
@@ -305,7 +305,7 @@ class BOTAN_DLL Name_Constraints : public Certificate_Extension
Name_Constraints(const NameConstraints &nc) : m_name_constraints(nc) {}
void validate(const X509_Certificate& subject, const X509_Certificate& issuer,
- const std::vector<X509_Certificate>& cert_path,
+ const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
std::vector<std::set<Certificate_Status_Code>>& cert_status,
size_t pos) override;
@@ -479,7 +479,7 @@ class BOTAN_DLL Unknown_Critical_Extension final : public Certificate_Extension
{ return m_oid; };
void validate(const X509_Certificate&, const X509_Certificate&,
- const std::vector<X509_Certificate>&,
+ const std::vector<std::shared_ptr<const X509_Certificate>>&,
std::vector<std::set<Certificate_Status_Code>>& cert_status,
size_t pos) override
{
diff --git a/src/lib/cert/x509/x509path.cpp b/src/lib/cert/x509/x509path.cpp
index c08b11d42..65ab3eac1 100644
--- a/src/lib/cert/x509/x509path.cpp
+++ b/src/lib/cert/x509/x509path.cpp
@@ -20,7 +20,7 @@ namespace Botan {
namespace {
-const X509_Certificate*
+std::shared_ptr<const X509_Certificate>
find_issuing_cert(const X509_Certificate& cert,
Certificate_Store& end_certs,
const std::vector<Certificate_Store*>& certstores)
@@ -28,25 +28,25 @@ find_issuing_cert(const X509_Certificate& cert,
const X509_DN issuer_dn = cert.issuer_dn();
const std::vector<byte> auth_key_id = cert.authority_key_id();
- const X509_Certificate* c = end_certs.find_cert(issuer_dn, auth_key_id);
+ std::shared_ptr<const X509_Certificate> c = end_certs.find_cert(issuer_dn, auth_key_id);
if(c && *c != cert)
return c;
for(size_t i = 0; i != certstores.size(); ++i)
{
- if(const X509_Certificate* c = certstores[i]->find_cert(issuer_dn, auth_key_id))
+ if(std::shared_ptr<const X509_Certificate> c = certstores[i]->find_cert(issuer_dn, auth_key_id))
return c;
}
return nullptr;
}
-const X509_CRL* find_crls_for(const X509_Certificate& cert,
+std::shared_ptr<const X509_CRL> find_crls_for(const X509_Certificate& cert,
const std::vector<Certificate_Store*>& certstores)
{
for(size_t i = 0; i != certstores.size(); ++i)
{
- if(const X509_CRL* crl = certstores[i]->find_crl_for(cert))
+ if(std::shared_ptr<const X509_CRL> crl = certstores[i]->find_crl_for(cert))
return crl;
}
@@ -72,7 +72,7 @@ const X509_CRL* find_crls_for(const X509_Certificate& cert,
}
std::vector<std::set<Certificate_Status_Code>>
-check_chain(const std::vector<X509_Certificate>& cert_path,
+check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
const Path_Validation_Restrictions& restrictions,
const std::vector<Certificate_Store*>& certstores)
{
@@ -92,9 +92,9 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
const bool at_self_signed_root = (i == cert_path.size() - 1);
- const X509_Certificate& subject = cert_path[i];
+ std::shared_ptr<const X509_Certificate> subject = cert_path[i];
- const X509_Certificate& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
+ std::shared_ptr<const X509_Certificate> issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
if(i == 0 || restrictions.ocsp_all_intermediates())
{
@@ -102,25 +102,25 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
if(certstores.size() > 1)
ocsp_responses.push_back(
std::async(std::launch::async,
- OCSP::online_check, issuer, subject, certstores[0]));
+ OCSP::online_check, *issuer, *subject, certstores[0]));
}
// Check all certs for valid time range
- if(current_time < X509_Time(subject.start_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
+ if(current_time < X509_Time(subject->start_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID);
- if(current_time > X509_Time(subject.end_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
+ if(current_time > X509_Time(subject->end_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED);
// Check issuer constraints
- if(!issuer.is_CA_cert() && !self_signed_ee_cert)
+ if(!issuer->is_CA_cert() && !self_signed_ee_cert)
status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER);
- if(issuer.path_limit() < i)
+ if(issuer->path_limit() < i)
status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG);
- std::unique_ptr<Public_Key> issuer_key(issuer.subject_public_key());
+ std::unique_ptr<Public_Key> issuer_key(issuer->subject_public_key());
if(!issuer_key)
{
@@ -128,7 +128,7 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
}
else
{
- if(subject.check_signature(*issuer_key) == false)
+ if(subject->check_signature(*issuer_key) == false)
status.insert(Certificate_Status_Code::SIGNATURE_ERROR);
if(issuer_key->estimated_strength() < restrictions.minimum_key_strength())
@@ -138,15 +138,15 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
// Allow untrusted hashes on self-signed roots
if(!trusted_hashes.empty() && !at_self_signed_root)
{
- if(!trusted_hashes.count(subject.hash_used_for_signature()))
+ if(!trusted_hashes.count(subject->hash_used_for_signature()))
status.insert(Certificate_Status_Code::UNTRUSTED_HASH);
}
// Check cert extensions
- Extensions extensions = subject.v3_extensions();
+ Extensions extensions = subject->v3_extensions();
for(auto& extension : extensions.extensions())
{
- extension.first->validate(subject, issuer, cert_path, cert_status, i);
+ extension.first->validate(*subject, *issuer, cert_path, cert_status, i);
}
}
@@ -154,8 +154,8 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
{
std::set<Certificate_Status_Code>& status = cert_status.at(i);
- const X509_Certificate& subject = cert_path.at(i);
- const X509_Certificate& ca = cert_path.at(i+1);
+ std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
+ std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
if(i < ocsp_responses.size())
{
@@ -163,7 +163,7 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
{
OCSP::Response ocsp = ocsp_responses[i].get();
- auto ocsp_status = ocsp.status_for(ca, subject);
+ auto ocsp_status = ocsp.status_for(*ca, *subject);
status.insert(ocsp_status);
@@ -181,7 +181,7 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
}
}
- const X509_CRL* crl_p = find_crls_for(subject, certstores);
+ std::shared_ptr<const X509_CRL> crl_p = find_crls_for(*subject, certstores);
if(!crl_p)
{
@@ -192,7 +192,7 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
const X509_CRL& crl = *crl_p;
- if(!ca.allowed_usage(CRL_SIGN))
+ if(!ca->allowed_usage(CRL_SIGN))
status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER);
if(current_time < X509_Time(crl.this_update()))
@@ -201,10 +201,10 @@ check_chain(const std::vector<X509_Certificate>& cert_path,
if(current_time > X509_Time(crl.next_update()))
status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED);
- if(crl.check_signature(ca.subject_public_key()) == false)
+ if(crl.check_signature(ca->subject_public_key()) == false)
status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE);
- if(crl.is_revoked(subject))
+ if(crl.is_revoked(*subject))
status.insert(Certificate_Status_Code::CERT_IS_REVOKED);
}
@@ -226,8 +226,12 @@ Path_Validation_Result x509_path_validate(
if(end_certs.empty())
throw Invalid_Argument("x509_path_validate called with no subjects");
- std::vector<X509_Certificate> cert_path;
- cert_path.push_back(end_certs[0]);
+ std::vector<std::shared_ptr<const X509_Certificate>> cert_path;
+ std::vector<std::shared_ptr<const X509_Certificate>> end_certs_sharedptr;
+ cert_path.push_back(std::make_shared<X509_Certificate>(end_certs[0]));
+
+ for(auto c: end_certs)
+ end_certs_sharedptr.push_back(std::make_shared<const X509_Certificate>(c));
/*
* This is an inelegant but functional way of preventing path loops
@@ -236,12 +240,12 @@ Path_Validation_Result x509_path_validate(
*/
std::set<std::string> certs_seen;
- Certificate_Store_Overlay extra(end_certs);
+ Certificate_Store_Overlay extra(end_certs_sharedptr);
// iterate until we reach a root or cannot find the issuer
- while(!cert_path.back().is_self_signed())
+ while(!cert_path.back()->is_self_signed())
{
- const X509_Certificate* cert = find_issuing_cert(cert_path.back(), extra, certstores);
+ std::shared_ptr<const X509_Certificate> cert = find_issuing_cert(*cert_path.back(), extra, certstores);
if(!cert)
return Path_Validation_Result(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND);
@@ -249,15 +253,15 @@ Path_Validation_Result x509_path_validate(
if(certs_seen.count(fprint) > 0)
return Path_Validation_Result(Certificate_Status_Code::CERT_CHAIN_LOOP);
certs_seen.insert(fprint);
- cert_path.push_back(*cert);
+ cert_path.push_back(cert);
}
std::vector<std::set<Certificate_Status_Code>> res = check_chain(cert_path, restrictions, certstores);
- if(!hostname.empty() && !cert_path[0].matches_dns_name(hostname))
+ if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname))
res[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH);
- if(!cert_path[0].allowed_usage(usage))
+ if(!cert_path[0]->allowed_usage(usage))
res[0].insert(Certificate_Status_Code::INVALID_USAGE);
return Path_Validation_Result(res, std::move(cert_path));
@@ -321,7 +325,7 @@ Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev,
}
Path_Validation_Result::Path_Validation_Result(std::vector<std::set<Certificate_Status_Code>> status,
- std::vector<X509_Certificate>&& cert_chain) :
+ std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) :
m_overall(Certificate_Status_Code::VERIFIED),
m_all_status(status),
m_cert_path(cert_chain)
@@ -346,14 +350,14 @@ const X509_Certificate& Path_Validation_Result::trust_root() const
if(result() != Certificate_Status_Code::VERIFIED)
throw Exception("Path_Validation_Result::trust_root meaningless with invalid status");
- return m_cert_path[m_cert_path.size()-1];
+ return *m_cert_path[m_cert_path.size()-1];
}
std::set<std::string> Path_Validation_Result::trusted_hashes() const
{
std::set<std::string> hashes;
for(size_t i = 0; i != m_cert_path.size(); ++i)
- hashes.insert(m_cert_path[i].hash_used_for_signature());
+ hashes.insert(m_cert_path[i]->hash_used_for_signature());
return hashes;
}
diff --git a/src/lib/cert/x509/x509path.h b/src/lib/cert/x509/x509path.h
index b7061685a..60b7fa1a2 100644
--- a/src/lib/cert/x509/x509path.h
+++ b/src/lib/cert/x509/x509path.h
@@ -92,7 +92,7 @@ class BOTAN_DLL Path_Validation_Result
/**
* @return the full path from subject to trust root
*/
- const std::vector<X509_Certificate>& cert_path() const { return m_cert_path; }
+ const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path() const { return m_cert_path; }
/**
* @return true iff the validation was successful
@@ -118,7 +118,7 @@ class BOTAN_DLL Path_Validation_Result
static const char* status_string(Certificate_Status_Code code);
Path_Validation_Result(std::vector<std::set<Certificate_Status_Code>> status,
- std::vector<X509_Certificate>&& cert_chain);
+ std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain);
explicit Path_Validation_Result(Certificate_Status_Code status) : m_overall(status) {}
@@ -130,7 +130,7 @@ class BOTAN_DLL Path_Validation_Result
Certificate_Status_Code m_overall;
std::vector<std::set<Certificate_Status_Code>> m_all_status;
- std::vector<X509_Certificate> m_cert_path;
+ std::vector<std::shared_ptr<const X509_Certificate>> m_cert_path;
};
diff --git a/src/lib/entropy/entropy_srcs.cpp b/src/lib/entropy/entropy_srcs.cpp
index 22d2e5e4b..ad84709a5 100644
--- a/src/lib/entropy/entropy_srcs.cpp
+++ b/src/lib/entropy/entropy_srcs.cpp
@@ -95,11 +95,12 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
{
#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
return std::unique_ptr<Entropy_Source>(new Device_EntropySource(BOTAN_SYSTEM_RNG_POLL_DEVICES));
+#endif
}
if(name == "win32_cryptoapi")
{
-#elif defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
+#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
return std::unique_ptr<Entropy_Source>(new Win32_CAPI_EntropySource);
#endif
}
diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp
index 2e9f8aab7..3db62c32a 100644
--- a/src/lib/prov/openssl/openssl_rc4.cpp
+++ b/src/lib/prov/openssl/openssl_rc4.cpp
@@ -7,7 +7,7 @@
#include <botan/stream_cipher.h>
-#if defined(BOTAN_HAS_OPENSSL)
+#if defined(BOTAN_HAS_OPENSSL) && defined(BOTAN_HAS_RC4)
#include <botan/internal/algo_registry.h>
#include <botan/internal/openssl.h>
diff --git a/src/lib/pubkey/info.txt b/src/lib/pubkey/info.txt
index 77ae820c7..10eb12567 100644
--- a/src/lib/pubkey/info.txt
+++ b/src/lib/pubkey/info.txt
@@ -37,4 +37,6 @@ pem
pk_pad
numbertheory
rng
+hash
+hex
</requires>
diff --git a/src/lib/pubkey/pk_keys.cpp b/src/lib/pubkey/pk_keys.cpp
index ebaa0eb69..9597ed08d 100644
--- a/src/lib/pubkey/pk_keys.cpp
+++ b/src/lib/pubkey/pk_keys.cpp
@@ -8,6 +8,8 @@
#include <botan/pk_keys.h>
#include <botan/der_enc.h>
#include <botan/oids.h>
+#include <botan/hash.h>
+#include <botan/hex.h>
namespace Botan {
@@ -52,4 +54,28 @@ void Private_Key::gen_check(RandomNumberGenerator& rng) const
throw Self_Test_Failure("Private key generation failed");
}
+/*
+* Hash of the PKCS #8 encoding for this key object
+*/
+std::string Private_Key::fingerprint(const std::string& alg) const
+ {
+ secure_vector<byte> buf = pkcs8_private_key();
+ std::unique_ptr<HashFunction> hash(HashFunction::create(alg));
+ hash->update(buf);
+ const auto hex_print = hex_encode(hash->final());
+
+ std::string formatted_print;
+
+ for(size_t i = 0; i != hex_print.size(); i += 2)
+ {
+ formatted_print.push_back(hex_print[i]);
+ formatted_print.push_back(hex_print[i+1]);
+
+ if(i != hex_print.size() - 2)
+ formatted_print.push_back(':');
+ }
+
+ return formatted_print;
+ }
+
}
diff --git a/src/lib/pubkey/pk_keys.h b/src/lib/pubkey/pk_keys.h
index 40b7569af..1a3047a57 100644
--- a/src/lib/pubkey/pk_keys.h
+++ b/src/lib/pubkey/pk_keys.h
@@ -109,6 +109,10 @@ class BOTAN_DLL Private_Key : public virtual Public_Key
virtual AlgorithmIdentifier pkcs8_algorithm_identifier() const
{ return algorithm_identifier(); }
+ /**
+ * @return Hash of the PKCS #8 encoding for this key object
+ */
+ std::string fingerprint(const std::string& alg = "SHA") const;
protected:
/**
* Self-test after loading a key
diff --git a/src/lib/rng/system_rng/system_rng.cpp b/src/lib/rng/system_rng/system_rng.cpp
index 135f4fabd..1ea749327 100644
--- a/src/lib/rng/system_rng/system_rng.cpp
+++ b/src/lib/rng/system_rng/system_rng.cpp
@@ -75,6 +75,12 @@ System_RNG_Impl::System_RNG_Impl()
#endif
m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY);
+
+ // Cannot open in read-write mode. Fall back to read-only
+ // Calls to add_entropy will fail, but randomize will work
+ if(m_fd < 0)
+ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY);
+
if(m_fd < 0)
throw Exception("System_RNG failed to open RNG device");
#endif
diff --git a/src/lib/utils/database.h b/src/lib/utils/database.h
index 4cc0989b1..0cd45dac0 100644
--- a/src/lib/utils/database.h
+++ b/src/lib/utils/database.h
@@ -38,6 +38,8 @@ class BOTAN_DLL SQL_Database
virtual void bind(int column, const std::vector<byte>& blob) = 0;
+ virtual void bind(int column, const byte* data, size_t len) = 0;
+
/* Get output */
virtual std::pair<const byte*, size_t> get_blob(int column) = 0;
diff --git a/src/lib/utils/sqlite3/sqlite3.cpp b/src/lib/utils/sqlite3/sqlite3.cpp
index 77b4c0d10..251cbcdf5 100644
--- a/src/lib/utils/sqlite3/sqlite3.cpp
+++ b/src/lib/utils/sqlite3/sqlite3.cpp
@@ -99,6 +99,13 @@ void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<byt
throw SQL_DB_Error("sqlite3_bind_text failed, code " + std::to_string(rc));
}
+void Sqlite3_Database::Sqlite3_Statement::bind(int column, const byte* p, size_t len)
+ {
+ int rc = ::sqlite3_bind_blob(m_stmt, column, p, len, SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw SQL_DB_Error("sqlite3_bind_text failed, code " + std::to_string(rc));
+ }
+
std::pair<const byte*, size_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column)
{
BOTAN_ASSERT(::sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB,
diff --git a/src/lib/utils/sqlite3/sqlite3.h b/src/lib/utils/sqlite3/sqlite3.h
index 067b94e85..659e1c487 100644
--- a/src/lib/utils/sqlite3/sqlite3.h
+++ b/src/lib/utils/sqlite3/sqlite3.h
@@ -35,6 +35,7 @@ class BOTAN_DLL Sqlite3_Database : public SQL_Database
void bind(int column, size_t val) override;
void bind(int column, std::chrono::system_clock::time_point time) override;
void bind(int column, const std::vector<byte>& val) override;
+ void bind(int column, const byte* data, size_t len) override;
std::pair<const byte*, size_t> get_blob(int column) override;
size_t get_size_t(int column) override;
diff --git a/src/tests/data/certstor/cert1.crt b/src/tests/data/certstor/cert1.crt
new file mode 100644
index 000000000..f94996195
--- /dev/null
+++ b/src/tests/data/certstor/cert1.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaagAwIBAgIBATANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVjZXJ0
+MTAgFw0xNjA4MjUxMzQ2MDBaGA8yMDk2MDgyNTEzNDYwMFowEDEOMAwGA1UEAxMF
+Y2VydDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDc8LorF3s8LuOi
+M6odFrxwz3g5ou53DH7VHmxRUbxfweB+/IqTDtdX+vkodWJs7asqiR4M3jxyjJRV
+HcvIoUiNRF8oIXrshKyWNRtzlgVQnxKcwYu4SGgzx4anUYNMdL5av172CFdzh0lg
+84oXgfx+EdRw9F2CZpWpH26mklx0OqqOQJQOyZzbFe1fJG5hwD6CL+Gcva/KqS6p
+2p0CCJaeRdwhuYxJIGjxkqYj6npChnz3QaWXkytcHR2+4RsSYs6Yh/FEtGeoBCQu
+kzrUgzbiQ/lrmJyW1nxb7lyTHA4J+D1aZ0pjX57N2nqaOY8288O5w/wLR3KMyctJ
+XBiJq0NDAgMBAAGjITAfMB0GA1UdDgQWBBQPl0HKiP7UeJp44xZwTbZHC4BvhzAN
+BgkqhkiG9w0BAQUFAAOCAQEACMl5HRIbx33M15hjQ7tcaXerja6qOMOe8JN3o36a
+6w8V8dqQMqGWuyUBtX4kNLvrleWwC/6soltTT1Y9D0uw2lM37pXTsI3UL4b4bGX+
+WPNVT2Gowdd9eqpn795u9EErGXi2bn7IoIiKAvzHI+eDChFR5OHxulj6b4FTGa9s
+G/V0RNuTx2wvB4v5XQjWhK6Cy1V8giI2X0HiGvbu9I5lo01lj523m6G1lIXU5zmX
++8dNxEfrVqk7RT3Y65QnrrUjhxZlNL6vh3z+JDlQqGi0y/RsDnXVXbH1C4wBawr9
+P7248MakA6ehPikut/4+tZic+1myb0arDKVhEeht4C0KTQ==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/certstor/cert2.crt b/src/tests/data/certstor/cert2.crt
new file mode 100644
index 000000000..d80c024fc
--- /dev/null
+++ b/src/tests/data/certstor/cert2.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaagAwIBAgIBATANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVjZXJ0
+MjAgFw0xNjA4MjUxMzQ3MDBaGA8yMDk2MDgyNTEzNDcwMFowEDEOMAwGA1UEAxMF
+Y2VydDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDc8LorF3s8LuOi
+M6odFrxwz3g5ou53DH7VHmxRUbxfweB+/IqTDtdX+vkodWJs7asqiR4M3jxyjJRV
+HcvIoUiNRF8oIXrshKyWNRtzlgVQnxKcwYu4SGgzx4anUYNMdL5av172CFdzh0lg
+84oXgfx+EdRw9F2CZpWpH26mklx0OqqOQJQOyZzbFe1fJG5hwD6CL+Gcva/KqS6p
+2p0CCJaeRdwhuYxJIGjxkqYj6npChnz3QaWXkytcHR2+4RsSYs6Yh/FEtGeoBCQu
+kzrUgzbiQ/lrmJyW1nxb7lyTHA4J+D1aZ0pjX57N2nqaOY8288O5w/wLR3KMyctJ
+XBiJq0NDAgMBAAGjITAfMB0GA1UdDgQWBBQPl0HKiP7UeJp44xZwTbZHC4BvhzAN
+BgkqhkiG9w0BAQUFAAOCAQEA0Hdd2iHHBuCfJntTMe3M1H6wGKLqjozD/11yIS7k
+Fvu42gke5PE9zI2O3wgDeFeyer7OkA1KI1KK08w33kZBICqKdwXAFH9RYLwM8hUB
+z1zM1nQwVfQlTl8yi2LptD7o5oPZ1dgBetn2eOCKCguC0rAS567JdivD/mxzXorH
+DJTXN8EtZH0yJH6AjFarMobVNGyy6eSwNKCK9nKPrkElTktW5UajkXe9NErMaU7f
+4KmJArN4PsJjj6Qx2Z6/pj2gS3A7IMbbG2jDK2tAlgrQkCEoVLY3+toov5II542k
+ZNej7/z5X9Fcft+/o/+ILufK9H2uAQWHmL4zzHXefjTH6g==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/certstor/cert3.crt b/src/tests/data/certstor/cert3.crt
new file mode 100644
index 000000000..f77834c82
--- /dev/null
+++ b/src/tests/data/certstor/cert3.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaagAwIBAgIBATANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVjZXJ0
+MzAgFw0xNjA4MjUxMzQ3MDBaGA8yMDk2MDgyNTEzNDcwMFowEDEOMAwGA1UEAxMF
+Y2VydDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBvhpDLopDxvrn
+Uo/zN4dEz39wfIepWno0soJBfvV2EuDTp4S89r0Q0dUeThKYlOlyTk3IR5QmcnoG
+7XD9+J+CXvcJI3X2h6uKL+f+2XL9tmSoVmw1u7QXK23cKkhpYIszkh/OK2gY9vfx
+0Tudt0lc8Bxa4iK2lnZwbd6kcQJbWSX4gcF1Hxdfp9mrGg+/f623GW+RAnQVaC50
+HvBLFuWxNaLbcOD0vSkLRutkiI9t9Ng3G7ADJ5xuHY6W68BmEG9DDfKO3Y5kfhIz
+mE/q4X9PcbpBAemzWX0YtNzh6aNqhOw/eKmApC0NbeVurZxYHVnRprO+/X/9WK5D
+i5K3E651AgMBAAGjITAfMB0GA1UdDgQWBBRo9BOhV2RYDu9UhucTMvIkp/ungTAN
+BgkqhkiG9w0BAQUFAAOCAQEAo7AW86pfkFJt9dRn0uF2evp/vaMEt0LjPfxlYlWd
+UgO6OS+s139HPujd+LwmyDN17d99KDb/EjLgdlXm0rnkMMTH9aAaXwoskxNP81vL
+ol+f5bAo/uHGLf00K4WhvJ8pS/94AhZmoo6hzEVqLuZCt7q2ugrQdxPhLxfrnPWm
+IovZxXOmViVYiqU88QVepTbRYF8QByQg2vFiXA9/rGnIKL2UDwci7rBO4mTheGyD
+GotaVth7XAN4t61JVnjHbClxBMgxILR74arkbzTesEYvcLozXfPNriXZfqbHDBTC
+AISmmx4Hh2G3+NC0Q2qqKQPpiKZKSahTMgb0Bja+Kaqb6w==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/certstor/cert4.crt b/src/tests/data/certstor/cert4.crt
new file mode 100644
index 000000000..31a0bc27c
--- /dev/null
+++ b/src/tests/data/certstor/cert4.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaagAwIBAgIBATANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVjZXJ0
+NDAgFw0xNjA4MjUxMzQ4MDBaGA8yMDk2MDgyNTEzNDgwMFowEDEOMAwGA1UEAxMF
+Y2VydDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD72rrxGisXsflB
+yHtIZI4iNHc7Lbgu0CzxsksgzEYzrRNeW/6I8imu47tfZjY1f+XR6sEtROPwZ9vW
+Pqj366SGpYst+FHtmz7k8Wb5JeI0KAsr0JYyIPgMPDSTqpLIRFrMwhsFLo0tR5b6
+/oT8oSNSX+3jQlcwGJWrIQlIkrYzHxvkXiNBcikqTne9+zrAgVobjEvbeedvM+9n
+A9JUgScOQjnJ6YDiGaZ+0n6OzYF7duGHTKTlb/+3bJpbrOlgDrkCgZMMIUaAqDra
+2w8pArUI9sAVex6djUjavI9WzcjX7okjhqbru+TtXEL4FeUF5hAPRi8k02axwuBq
+9jGBRpRhAgMBAAGjITAfMB0GA1UdDgQWBBTW4dmVCqZjKmKS06pvbiAPeCXbdzAN
+BgkqhkiG9w0BAQUFAAOCAQEABcOEZ4gfcNLfYc5l0rRkie1OIOHQas4gIYXLLAxM
+Jh/gV730yR67NLUm1O/99St7GWLzuNpI7EgXhWA5HvaVCUUc92wxmyzrzZl1OmD8
+bAKHVtLUsL5dPgiK0zeJmiN03v2DjME/yLinbN4DtjDtzBFS7+vFCFPnrys2Mw5L
+JtSIfuDKF7f3FWuwsnTSNogG78hYVFQ/DA5YfftI3cPUO4eLLZazRCL3wpKJ6uE6
+2npn2S7e4kgMtstGydLaO19AyuMTG9+TLn+04h5yWdoIrmyAXsJZoFPn76d+8Mc8
+St04VY1xDjwZfxi83Wnywb6BMbW8BEHvfnOvC3K1YmcNww==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/certstor/cert5a.crt b/src/tests/data/certstor/cert5a.crt
new file mode 100644
index 000000000..5a72e123a
--- /dev/null
+++ b/src/tests/data/certstor/cert5a.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaagAwIBAgIBATANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVjZXJ0
+NTAgFw0xNjA4MjUxMzQ4MDBaGA8yMDk2MDgyNTEzNDgwMFowEDEOMAwGA1UEAxMF
+Y2VydDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmAHBoCnzfzQmG
+evf6RDAdAy8Am2xcM70IxPHs2ZJV7kpswz0IH3dQqprHDAKLTnduG4YmeyHXf0JL
+hIIc49mwoXpc+c/brNHDdJBC/B7AF1gb8l9wkLCQEl1FyOJn3CnAuVuXwub/o48f
+zZQNJ10oGFKXwYHWCe9g8CGScDoRbD6p7+4xx7/k6ukD5EY9W8UoiXTuCkqGhi0z
+lbGCxpkHE4lwRMeAKCY1rhXhH3ue0tXe0/RTrR9rYKs4rjt3rBGcFNGELRhWd261
+2/SMN1fCfKK/N2PQZm0O3pnZ7dP/JaQ7phIqVQxts0gDehoA16u7qGgJzwEkJECC
+tFCLxU/PAgMBAAGjITAfMB0GA1UdDgQWBBTkMbO1+qNf/EfUGdkQ8oxq3T99HjAN
+BgkqhkiG9w0BAQUFAAOCAQEAVjOXcX2qbo7YaEYECIL0u35qc8L1qpovA0wpNjFN
+AzF+NbidJJfYAiFCkJgyE1Hl+ycsE2sxfWUky4Hv+ZWQDWb0yEqanbcrsfIHdReP
+40MQCvnJFGZ4N9lBqRUA6y3dc7FY61syamz9uemctq0FVfnXpCKtneje5xIBd0Hq
+fbkSb+yqfheQ/Nlou2iU/7gBC63Lm5D5lGQASS/acJN0jBQQY18mq/TPH9aFyzuj
+9U73anXRLqIJJsbc1OBQmQP3S7ozMKpYy5VIHJ0glE1xPWImIAQDVES64whjr93Y
+Nz8T9lwyby3D+vQtR9oWxA3aIPEKmcVPeFHA9b+fA+D1tw==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/certstor/cert5b.crt b/src/tests/data/certstor/cert5b.crt
new file mode 100644
index 000000000..f766c17b2
--- /dev/null
+++ b/src/tests/data/certstor/cert5b.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICvjCCAaagAwIBAgIBATANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVjZXJ0
+NTAgFw0xNjA4MjUxMzQ5MDBaGA8yMDk2MDgyNTEzNDkwMFowEDEOMAwGA1UEAxMF
+Y2VydDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dh63j9uRBb7m
+Axz65SrG94zowLFFkVm35Bbp+POwTGXWQFuQybXSJm+ltU8gI86UmRn0w30Vo0RF
+GHMfwq4W1tJ/Oxydduk8/QZxBSP91MKFfk7cDjJbPvXhqNEQI7EhRHuBTKk+27Aq
+zugEsSNVxOPReSA7dOOiX37hxV1sDU1fzEDg0U2P/VTGA+T0FQ5dfwI4CMUyCB9b
+WuFTgwPDmutV6eANlmEhvRvIzMUeYxrTTtgjOsKYKkbbZfBis09uMZ3xjLBDfsK/
+Uel5xNSEreh+/vhgURsYWsTFNO8NgJELy7mmRaX9hmz1lNwnNo6PMLF9vWh+Nulq
+2dBkQi3ZAgMBAAGjITAfMB0GA1UdDgQWBBSwyEY1ySgpquTbrMaFPHgbabe0RjAN
+BgkqhkiG9w0BAQUFAAOCAQEAO44gBp8zORkGbm4o+U0AGY8/lHkg4EuAloZp+o1z
+y3J17DSK2nTjzkM3ot4inc84eeQ3EXkcu3lNqii6xblORQGvAIyGC287cueY/e4R
+S7OfPo5GfmFXSsv31doKc53H1BHOXprqoHAp4Vo0V/nRzCWFQ10MoYiCdP5fZeMY
+W83/YTnElGLcnXXFdKIWaCHT13phYXpefYtGIv/NY+dyBzqwxusK5qUPomLbt1Qr
+UGCsGj46oqya+zKq2H+7gIu6xn+PEKqcH5ZYpMONNuoqE68gq7qlpKuRFvkJ0CYx
+LYvsZV9jmFl15ZDqlIXibXRQPI0lwJGQRaUQhYEZ7CG4zQ==
+-----END CERTIFICATE-----
diff --git a/src/tests/data/certstor/key01.pem b/src/tests/data/certstor/key01.pem
new file mode 100644
index 000000000..b77b9f3d9
--- /dev/null
+++ b/src/tests/data/certstor/key01.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDc8LorF3s8LuOi
+M6odFrxwz3g5ou53DH7VHmxRUbxfweB+/IqTDtdX+vkodWJs7asqiR4M3jxyjJRV
+HcvIoUiNRF8oIXrshKyWNRtzlgVQnxKcwYu4SGgzx4anUYNMdL5av172CFdzh0lg
+84oXgfx+EdRw9F2CZpWpH26mklx0OqqOQJQOyZzbFe1fJG5hwD6CL+Gcva/KqS6p
+2p0CCJaeRdwhuYxJIGjxkqYj6npChnz3QaWXkytcHR2+4RsSYs6Yh/FEtGeoBCQu
+kzrUgzbiQ/lrmJyW1nxb7lyTHA4J+D1aZ0pjX57N2nqaOY8288O5w/wLR3KMyctJ
+XBiJq0NDAgMBAAECggEBAKINOy+CIJSq+7Gr3VlKpNrFgbQcqnXNR3X/w4j9v4Io
+zQW3K9jjKNXSMlAXkSK+TC59tfnQQ1vteprXqPG2QmXDQVxI+kVipsfhmgn0fl98
+3YT2fQmkqjFYZo5wvjIk6r3a4cbppWMKVqry1lWZtN2vLDfRNIkBv0H12Q36CjAA
+vpjOCgowhfqtjfI7X+iPGp95Wc2p4AUfgj6W76ZQs0FmsVoXkiZCeQbU9yMLtMNW
+fUiKgCpc5y3s/iQObalsSu8i8O3wBWH1h93w/PqRPGVnucC39iAat12RvFW+cnF6
+zcs0lveidFxxuMvsZX4nzMP2q3pUm4c9GxBo3C71RykCgYEA9xNgckPS/H9Qmd3X
+7V5eRnaeIA4jmnFs5uX8Bri+0BsjY86Sjo/5hKyTh8woSVgombJ4JkwkFzIvo9P4
++EWzPhQEmMEYHEc5JwIrolfpWGfyDjDZw7nlsUrMAWz9IRPeHeq4o420iGawkofo
+xn+mWPHa8NWqQ0tLLqroG0nyRz8CgYEA5OuvmvII7gsGfkFjla65xF9U7hccgsvt
+K7bY5IOJ4KkpBvlnhsD7kNX44eAAOcAkt/iE64jSl2vdKy1c5ci36cziZeoGCLjW
+ZcGwg+fEva8nyADJpKI/RRkVvBWXT8OBvNugWJPz2NFAMXYV9bA9L1OIA05eBzPF
+soPxOCr4pv0CgYEAhrLwpLrnPrLmLUxtmMIW4ZFveYhbzqpBtcvyT3POy0PQUmxf
+KAvD+5neQG2EFSBT2h8bM73U+zRoFofMtwXAx3pAW0sCKwCFXwfm4/XLiF/67dOi
+FPu3BqYBfFF/2tWrBWJe0QPDRY2+e9ROilEzTlBkjWHfFhrpXQLd0WrKBB8CgYBA
+WuGrNY+9G+xfYhKU6eHfis1dgbHKM3ohZ+3hj/ka53NZOpQYFfii5wRou4hUs+ee
+sIbtkDFj0DcFBGOxVZQebjLXY8r+eLgNMz5kVqvAh5UvbMlDNzmCO2MY1RkMm3HF
+nhidzjonIexh+0iBIWKSA3GhPE7Cx5M0dFND7xCoIQKBgHZ4W0HHhYLTAxaUlp3F
+afRTMJhhn4w1N3uzEtNa96VEq3dUwD/Fr/7eLg9Ap/eCrVnJkmR1qHhs+KI397CK
+L+bL9nXEDZZRQV2Ch2EV+6ruU5vV3MvfH9MOg3a9phj25bSAMdQMIXSB0rBee9ss
+aCEgxxyjdAsdN4ESs8q3duJF
+-----END PRIVATE KEY-----
diff --git a/src/tests/data/certstor/key03.pem b/src/tests/data/certstor/key03.pem
new file mode 100644
index 000000000..c7cc94801
--- /dev/null
+++ b/src/tests/data/certstor/key03.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBvhpDLopDxvrn
+Uo/zN4dEz39wfIepWno0soJBfvV2EuDTp4S89r0Q0dUeThKYlOlyTk3IR5QmcnoG
+7XD9+J+CXvcJI3X2h6uKL+f+2XL9tmSoVmw1u7QXK23cKkhpYIszkh/OK2gY9vfx
+0Tudt0lc8Bxa4iK2lnZwbd6kcQJbWSX4gcF1Hxdfp9mrGg+/f623GW+RAnQVaC50
+HvBLFuWxNaLbcOD0vSkLRutkiI9t9Ng3G7ADJ5xuHY6W68BmEG9DDfKO3Y5kfhIz
+mE/q4X9PcbpBAemzWX0YtNzh6aNqhOw/eKmApC0NbeVurZxYHVnRprO+/X/9WK5D
+i5K3E651AgMBAAECggEAdRxzhY6ZV1TtD20xxIQZSTfgQd+UpYMigb4xzGNw/rl0
+m5wUOaEwMf2UxKfOx9qjrku06s6RuBfUuWFHvs1NpiG/VA/SW34w6+v/YWaSAtkA
+yVzMNkLLHoJK+x23/bK1EixO+3Hzj7uhrtOaJMDJINunWCx/bT1QRK+1OFNzaEFS
+txMyWKXmvFpo5dAKAaUw1Nqijcd9PCko/nfo9z2+0dxYyXiQKiH90MNt6FHZ2pS6
+KdkQTnb/WXiGrf3ocLAzLvBMQb1nK14ejRpUkDfVAk0GYcqL+SBuEEgvU6tLw3S9
+AEqs6Eca/OgpLDPU8XGU4cGnLeLzC26RpBJ8/AnpNQKBgQDmFD0dy+vXJ+3uAvzj
+dNpgT8V8L9POYGMcpO4pCBaXBkXEu2NsZQrh3uC2JGTAMBqDvkD/g+riITJKkPMc
+G47njX9f8PjxuGvGDBIOPs1K23TFu1T2rIpbhyEQVQiHPripxw3cWkZcwMSK9U3O
+I/xnO1WK+d+8IYE7rvhNW+cgBwKBgQDXkeArNOEHog3oedG1aJcbuNHYOQhEqPpp
+kynunZPGNug5pN/T/ZXHsfpPkPUrtNgR4cKXRYpuL4ecdi1U7MfTpUaJjnhOXwVU
+EAxMMGjGM12rpIbN8thCz+QF9iAJQFnUnoiIXC1WyMERtRkMyCKwtz60IVmz0S50
+Q0r8AbzmowKBgQCq3jbxTQNuO0IxM9jZl2uigTu52c8kAmM436fbox0btdXUoBHb
+a0LkseAShP6p2E+orX+aAz9KBrtRs0pJApJjlqsU9mH7Kion38j8+Vj/EfIr8s7L
+jyIFjVpZxbzarBL6S1EY55Y/xg1w4XKR+Bm4FNGXr7CgCAXw7CWNVgZUuwKBgQCR
+I8F3tcGxHvYYSTTd3E6pNpXq6/NaLx9yx8faxbPCKCPQ8+ZT2A/phTZQLfw0ci1s
+VMFskkCzEUNQH+1DmaytHkFQymDL+4Qd5jQxdAKHN/xgXYT50wCyc0BGl0FYmUAi
+PJ8WmGFaZg4/+tuj1Hgu3SHVrAK2ZCfP1aL967mg2wKBgDAGXaweI/CSzO9AhuTV
+QhZy5eDgcjm2SJICqNJ2Welt3JyTz7zgxkgShPT0gXTADqfj5WmJ6edbYhSDfC6p
+VAQlfixcogRX1Uxb3GhHCM85r6huOv71L9vX6tVo7ggUGN3rysRPAkf4mk8Cx4F+
+gUid5rlxYk2QhKirTaM1KZH6
+-----END PRIVATE KEY-----
diff --git a/src/tests/data/certstor/key04.pem b/src/tests/data/certstor/key04.pem
new file mode 100644
index 000000000..f148a1d72
--- /dev/null
+++ b/src/tests/data/certstor/key04.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD72rrxGisXsflB
+yHtIZI4iNHc7Lbgu0CzxsksgzEYzrRNeW/6I8imu47tfZjY1f+XR6sEtROPwZ9vW
+Pqj366SGpYst+FHtmz7k8Wb5JeI0KAsr0JYyIPgMPDSTqpLIRFrMwhsFLo0tR5b6
+/oT8oSNSX+3jQlcwGJWrIQlIkrYzHxvkXiNBcikqTne9+zrAgVobjEvbeedvM+9n
+A9JUgScOQjnJ6YDiGaZ+0n6OzYF7duGHTKTlb/+3bJpbrOlgDrkCgZMMIUaAqDra
+2w8pArUI9sAVex6djUjavI9WzcjX7okjhqbru+TtXEL4FeUF5hAPRi8k02axwuBq
+9jGBRpRhAgMBAAECggEASRulSHegKrCu+jmID+uglq1ELxmGbZBge4iV5l9lwXps
+NOffa0FgeDQDIB47fiwyOk065jkpMY/0cKyfv9fXWn6TeDStE5wNFcg9a/VjRGCb
+XYyfDM4lMugHGxZYpWmyMd3mmgp5ULuHSDS5xdvAtRjDpUSMqpl4WMSuPTLZUN0T
+gGpuyOFT5xF+BaQS/9Ech8Jk/FyWHCBn9Z4GE1u/DefEgA20jIcFLGVTGuIpx6J8
+HxuthrH9F4a1fFWO3tFwbES+XmGwNhAuMzSUvDJjUwTy6+g/YoKS2DreZFdYmHQD
+2tah5gHixyD2cmoJ2uJeASloXZKUUK6KAh/44OCfAQKBgQD/T0Hx19kEUJ7Po52R
+6fL6LmD00p2cYy4mzYpAZZqJCotyLrkfqx0u54zFmVgqsgjeng+121IRshZ6RV2K
+8fGCeQRkB+1XKIEHoCSaOVCpiDPU8i6nD4fDfPSHhgMLkdcWEVbLWDbCI+cbujjg
+aRjsWZ20RvRZaJ5grpFXv6vHtQKBgQD8iRSrBC/m8bpafxnv1kkYUz1BFwy0Nv8N
+2OjxFI4X9rQp5XCx0TSjrtCaKsiZnY6v/xgpWxQwo1ITILYihBI+GolQIbL8KJCk
+potJ3UxtLfjhcANTdCiLP+JslwMw5XbhUtpsvQX8jmnGTt220ghx0YxcoTkGWh0I
+4KWCi6ZtfQKBgH/n9DC2I5oezcFWxf0xCLLAA4ED90Q/CAMWnDmw7V/UsZHNyJ8N
++fvis0rXjS0urnThGRvRueb1on81Oyz+EzF7cXCv6/7rYuEwIMZHCps0iksX3bmC
+dVDBzDwNLn9gXDJJE4OiOSTAGetxO0dqP7tBFloX5hjY6eej7VrZwrS1AoGBAJOk
+4XyK2ia/tSArp1Jdiia6o9lmTHsgnEXQR4CLb/f6uKK2DgkoMwpvrm40DUwincWv
+8sRbB5bYJaghO9s6NCAzC4zZ5vceEFLzPARXadN7SUMkZg1ooDupggvSzn7L6ZEb
+C7D/YnyiFp1mhqHYci95QAL4D4rzLH6AOMP2ObtRAoGAJWRKgEX8vo1/chkcWYr7
+l4NNedCOHPceKnWa36Rg9J2ZMMZSVEEsjWluHylpwayMc5E98jEy5thNxm15Bnr8
+IUwMngDhrDreoPeoKXCgH/il0T5EKloOdXwYTARw+3gRM/lIJOYHfegjqQxzwsyI
+mlBDlfWh+LtgbCuIsgqCyEo=
+-----END PRIVATE KEY-----
diff --git a/src/tests/data/certstor/key05.pem b/src/tests/data/certstor/key05.pem
new file mode 100644
index 000000000..75a5b7a0e
--- /dev/null
+++ b/src/tests/data/certstor/key05.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCmAHBoCnzfzQmG
+evf6RDAdAy8Am2xcM70IxPHs2ZJV7kpswz0IH3dQqprHDAKLTnduG4YmeyHXf0JL
+hIIc49mwoXpc+c/brNHDdJBC/B7AF1gb8l9wkLCQEl1FyOJn3CnAuVuXwub/o48f
+zZQNJ10oGFKXwYHWCe9g8CGScDoRbD6p7+4xx7/k6ukD5EY9W8UoiXTuCkqGhi0z
+lbGCxpkHE4lwRMeAKCY1rhXhH3ue0tXe0/RTrR9rYKs4rjt3rBGcFNGELRhWd261
+2/SMN1fCfKK/N2PQZm0O3pnZ7dP/JaQ7phIqVQxts0gDehoA16u7qGgJzwEkJECC
+tFCLxU/PAgMBAAECggEAfwzQ+2AjiOqVwr508q+jn2DjZXSPL9ZNdNu/SYaQEIKr
+paicGo5ytGOOyI8xl0s77yLTvrn5AcUdiUzmhJQC9cPxMh3kb35KoWyiSRJLurtj
+LSiI0U98Qxg7GQER/2mq7x0us+1w/PFCxpWCHbsl+lz7QbjR1W6PLsM6/qg0WUYi
+5cfh9/xIrwY/jZDHMfB01R41NFF5+sD4FsDuWoDP78Cv8E203U5al84SH1xawb/1
+KhbPKivHYQu+Dxp/T2CbD1zdns+ViC8p5ZQXyAbs9+32HpHO0ESTj48XGFL2yFmX
+dz77OlwF/FCpnteQmGOpH7bVcQ7GCypF4ecgOZpGwQKBgQDSR9iXhape110aVrAQ
+pu6MPykDwePdeJKKrOR2CzXo1ndbF3nAUD818cR/XY8dPAvw3X+gCiToAvgpzChB
+33QICE4rDXIGZ0p8RzGF7MJqpQAGolhKN1EZqM8WSSalD1k7fZ+CvAeBmhjF/Of+
+le5F1j1uc8iexOLAegE8TcNELwKBgQDKGAqsGuFukj357+SpxsA8fdXBdQnmReEK
+6jslVGzFUQ0zVAM9edOiy1pYjUyr89E8N9pmHWPO9cgzYgmQOQoDtURtegwR+zzC
+EK9a/PGpkpfWkuGYAf1DKwG0c9L2WYAwvUxxm5j6tv0Ok2iHkRYruLLoHHzeJic8
+Y0F0BA6mYQKBgQDKq36BA85iHJZadWS6l/ng6FsiiPSTF8u9pseHUmTCJjrha+3n
+wjA6UOv/ifAO0Dn+C64fVMefaoU+28uNOc4+k6qragkVTOaIg6Gin7/+Q0uUGVKZ
+LVmYLpBxvU1m1zU81mYv/gQKELiB0rDTOjRt0QBifWvGQqL9ulmIgraJ9wKBgQCL
+MkwHhuxHEIuHn2hMWA0InVOh0E9lQDRlJDhg2emhbtY8yF0C9uqCcrZjz89DkMhJ
+Rd8z/oJEhp3CZoBXyjHPpAbhsPKnX/jVYlClxxtcxQ+4R6sC3DvpC7I87Jod/D+D
+Up9YkOepqGhcpcOVvKUcsDbqENUg3f6gZW0rz6+XgQKBgQCJEWS+y0aSEalRDhVw
+xcIWtEVle9I4wuzuOCKSGzIkWiV0KSzDmLEsfFHQ/F7k09kvBmrIjRQuIm6e3PaK
+vffCp8DG/ctabF4RtQHWhnjFVxkPdm4EZSP7SFodi2aA+MNmUw5f7BnoZR7wCaZp
+25u8dPwvYEfjC3bFY+fdpKPwdg==
+-----END PRIVATE KEY-----
diff --git a/src/tests/data/certstor/key06.pem b/src/tests/data/certstor/key06.pem
new file mode 100644
index 000000000..63006d613
--- /dev/null
+++ b/src/tests/data/certstor/key06.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9dh63j9uRBb7m
+Axz65SrG94zowLFFkVm35Bbp+POwTGXWQFuQybXSJm+ltU8gI86UmRn0w30Vo0RF
+GHMfwq4W1tJ/Oxydduk8/QZxBSP91MKFfk7cDjJbPvXhqNEQI7EhRHuBTKk+27Aq
+zugEsSNVxOPReSA7dOOiX37hxV1sDU1fzEDg0U2P/VTGA+T0FQ5dfwI4CMUyCB9b
+WuFTgwPDmutV6eANlmEhvRvIzMUeYxrTTtgjOsKYKkbbZfBis09uMZ3xjLBDfsK/
+Uel5xNSEreh+/vhgURsYWsTFNO8NgJELy7mmRaX9hmz1lNwnNo6PMLF9vWh+Nulq
+2dBkQi3ZAgMBAAECggEAfDawBtr7MgZZVQXffyK2PAJa0NJcpuaXsreIylcctY4x
+ChnhrniAi0oF0tefC8xOCSCjYtSz8na7MK3J9J23c2PeV+oSZa5rVj/xdDHRmf5e
+lhTscNuh6i7KF+uNPY6Y992lN21iXMK9qiNC/KiCKR5P2qsWFcUZ5P/E+RJjoI2r
+FMjHMSMmi3zDN/A3N9Izmuq3IByDcmwhXf6LOJw3oRYNEwHCfqaz2WjirljBYhu7
+LfCIGTe1+CV8Hkndppc523y4j89++qlAlh25eFC5BEHTFUUz7FCvzpSu3oga9Wr7
+UQTQe7HSLpAu6eHO1jabS/CTwsdGb3+CvaH/A+MLcQKBgQDlQar3TN50tIgsCw4U
+TSE+FG8TqwNxbprTYwyDaNt++G2Xf10B+u1EEtCDPhTL8HyO9RowLbWG4G0cdkFl
+TZs+3I3vqKHOQ/rNVcIVJUC33i7oQyVTWmFXic3RPoTl1BpnSfNk+tG60HOxcwls
+cxD7UyIZu5vuiDyLmVgZze0LVQKBgQDTkAsELc67Mbj7QRRccKFYdk5La5GF45E2
+lGt1czXkIHTpoqN/yLzeEaqfKO6uj7UZRENWJoI9wBJRDux6cdybR7z0YNUz4n+S
+cNjAqY9uJRT+ObEQKG+ik88C9lFpw/jVk2UtIo15OEvFp/gKoxF+UYxpNLQ9c788
+vQZCIzwAdQKBgQCwb1JpUpJdlNa7tqJWQ2nTAhzeMR3MPYgQKUlnFNrgI8cL8ewd
+awUQ/73TU4Lj1Se3SbCm5Xav36Z5YhVAJnLU9R6TE9+7A5xQTLC6X1ooZ2kIPSzL
+smH54ccxQwE6c3sChOo5i8K/GFABf/v/p6qpETjMPxNphxW5hgFEkrPcpQKBgE0x
+zOM8d6dUMEP1biGAs06c9FqOqG2rKGw64a7cV/iiYyZwwqm4rDl3RsOGYvjs1M6g
+WtWPfYxcjhJnmJ/g9fbuySJ+Rq0E4zmi1WQPOpedDjjpAhN8PaebuThCelhWOnBr
+tMowRmDJytQXQulWsOZfiRVGNtIJbukRq7vsMVOVAoGAeEBXbWHKeGc8Qy7NRFVx
+9ZsSiPwk3PSYeRRcvRuHuQxN3PE196oP0AAG2F7k8gJmKHon4K1cEZ4VJjTpFN3P
+RB3SWcwAIKuzeDU89Zs5UTJ8nHQYdxZK/RmUsCWpqcxHK+cpo/c2TrOdgPuF+sbK
+PZ3qHGP8C1j5q/3xWjM2puA=
+-----END PRIVATE KEY-----
diff --git a/src/tests/test_certstor.cpp b/src/tests/test_certstor.cpp
new file mode 100644
index 000000000..59bedf759
--- /dev/null
+++ b/src/tests/test_certstor.cpp
@@ -0,0 +1,257 @@
+/*
+* (C) 2016 Kai Michaelis, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_CERTSTOR_SQLITE3)
+ #include <botan/certstor_sqlite.h>
+ #include <botan/sqlite3.h>
+ #include <botan/internal/filesystem.h>
+ #include <botan/pkcs8.h>
+ #include <botan/auto_rng.h>
+ #include <sstream>
+ extern "C" {
+ #include <unistd.h> // unlink()
+ }
+#endif
+
+
+namespace Botan_Tests {
+
+namespace {
+
+#if defined(BOTAN_HAS_CERTSTOR_SQLITE3)
+
+Test::Result test_certstor_insert_find_remove_test(
+ const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>& certs,
+ Botan::Certificate_Store_In_SQL& store)
+ {
+ Test::Result result("Certificate Store - Insert, Find, Remove");
+
+ for(auto cert_key: certs)
+ {
+ auto cert = cert_key.first;
+ auto key = cert_key.second;
+ auto wo_keyid = store.find_cert(cert.subject_dn(),{});
+ auto w_keyid = store.find_cert(cert.subject_dn(),cert.subject_key_id());
+
+ if(!wo_keyid || !w_keyid)
+ {
+ result.test_failure("Can't retrieve certificate");
+ return result;
+ }
+
+ auto priv = store.find_key(cert);
+ if(!priv && (certs[1] != cert_key && certs[0] != cert_key))
+ {
+ result.test_failure("Can't retrieve private key for " + cert.fingerprint("SHA1"));
+ return result;
+ }
+
+ result.test_eq("Got wrong certificate",cert.fingerprint(),w_keyid->fingerprint());
+
+ if(priv)
+ {
+ result.test_eq("Got wrong private key",key->pkcs8_private_key(),priv->pkcs8_private_key());
+
+ auto rev_certs = store.find_certs_for_key(*priv);
+
+ if(rev_certs.empty())
+ {
+ result.test_failure("No certificate");
+ }
+ else
+ {
+ bool found = std::any_of(rev_certs.begin(),rev_certs.end(),[&](std::shared_ptr<const Botan::X509_Certificate> c)
+ { return c->fingerprint() == cert.fingerprint(); });
+
+ result.test_eq("Got wrong/no certificate",found,true);
+ }
+ }
+
+ if(certs[4] != cert_key && certs[5] != cert_key)
+ {
+ result.test_eq("Got wrong certificate",cert.fingerprint(),wo_keyid->fingerprint());
+ }
+
+ result.test_eq("Can't remove certificate",store.remove_cert(cert),true);
+ result.test_eq("Can't remove certificate",!store.find_cert(cert.subject_dn(),cert.subject_key_id()),true);
+
+ if(priv)
+ {
+ store.remove_key(*key);
+ }
+
+ result.test_eq("Can't remove key",!store.find_key(cert),true);
+ }
+
+ return result;
+ }
+
+Test::Result test_certstor_crl_test(
+ const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>& certs,
+ Botan::Certificate_Store_In_SQL& store)
+ {
+ Test::Result result("Certificate Store - CRL");
+
+ store.revoke_cert(certs[0].first,Botan::CA_COMPROMISE);
+ store.revoke_cert(certs[3].first,Botan::CA_COMPROMISE);
+ store.revoke_cert(certs[3].first,Botan::CA_COMPROMISE);
+
+ {
+ auto crls = store.generate_crls();
+
+ result.test_eq("Can't revoke certificate",crls.size(),2);
+ result.test_eq("Can't revoke certificate",crls[0].is_revoked(certs[0].first) ^ crls[1].is_revoked(certs[0].first),true);
+ result.test_eq("Can't revoke certificate",crls[0].is_revoked(certs[3].first) ^ crls[1].is_revoked(certs[3].first),true);
+ }
+
+ store.affirm_cert(certs[3].first);
+
+ {
+ auto crls = store.generate_crls();
+
+ result.test_eq("Can't revoke certificate, wrong crl size",crls.size(),1);
+ result.test_eq("Can't revoke certificate, cert 0 not revoked",crls[0].is_revoked(certs[0].first),true);
+ }
+
+ auto cert0_crl = store.find_crl_for(certs[0].first);
+
+ result.test_eq("Can't revoke certificate, crl for cert 0",!cert0_crl,false);
+ result.test_eq("Can't revoke certificate, crl for cert 0 size check",cert0_crl->get_revoked().size(),1);
+ result.test_eq("Can't revoke certificate, no crl for cert 0",cert0_crl->is_revoked(certs[0].first),true);
+
+ auto cert3_crl = store.find_crl_for(certs[3].first);
+
+ result.test_eq("Can't revoke certificate, crl for cert 3",!cert3_crl,true);
+
+ return result;
+ }
+
+Test::Result test_certstor_all_subjects_test(
+ const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>& certs,
+ Botan::Certificate_Store_In_SQL& store)
+ {
+ Test::Result result("Certificate Store - All subjects");
+
+ auto subjects = store.all_subjects();
+
+ result.test_eq("Check subject list length",subjects.size(),6);
+
+ for(auto sub: subjects)
+ {
+ std::stringstream ss;
+
+ ss << sub;
+ result.test_eq("Check subject " + ss.str(),
+ certs[0].first.subject_dn() == sub ||
+ certs[1].first.subject_dn() == sub ||
+ certs[2].first.subject_dn() == sub ||
+ certs[3].first.subject_dn() == sub ||
+ certs[4].first.subject_dn() == sub ||
+ certs[5].first.subject_dn() == sub,true);
+
+ }
+ return result;
+ }
+
+class Certstor_Tests : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ const std::string test_dir = Test::data_dir() + "/certstor";
+ const std::vector<std::pair<std::string,std::string>> test_data({
+ std::make_pair("cert1.crt","key01.pem"),
+ std::make_pair("cert2.crt","key01.pem"),
+ std::make_pair("cert3.crt","key03.pem"),
+ std::make_pair("cert4.crt","key04.pem"),
+ std::make_pair("cert5a.crt","key05.pem"),
+ std::make_pair("cert5b.crt","key06.pem")
+ });
+
+ std::vector<Test::Result> results;
+ std::vector<std::pair<std::string,std::function<Test::Result(
+ const std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>>&,
+ Botan::Certificate_Store_In_SQL&)>>>
+ fns({
+ std::make_pair("Certificate Store - Insert, Find, Remove",test_certstor_insert_find_remove_test),
+ std::make_pair("Certificate Store - CRL",test_certstor_crl_test),
+ std::make_pair("Certificate Store - All subjects",test_certstor_all_subjects_test)
+ });
+
+ try
+ {
+ // Do nothing, just test filesystem access
+ Botan::get_files_recursive(test_dir);
+ }
+ catch(Botan::No_Filesystem_Access&)
+ {
+ Test::Result result("Certificate Store");
+ result.test_note("Skipping due to missing filesystem access");
+ return {result};
+ }
+
+ const std::vector<std::string> all_files = Botan::get_files_recursive(test_dir);
+
+ if(all_files.empty())
+ {
+ Test::Result result("Certificate Store");
+ result.test_failure("No test files found in " + test_dir);
+ return {result};
+ }
+
+ for(auto fn: fns)
+ {
+ Test::Result result(fn.first);
+
+ try
+ {
+ unlink((fn.first + ".db").c_str());
+
+ auto& rng = Test::rng();
+ std::string passwd(reinterpret_cast<const char*>(rng.random_vec(8).data()),8);
+ Botan::Certificate_Store_In_SQLite store(fn.first + ".db",passwd);
+ std::vector<std::pair<Botan::X509_Certificate,std::shared_ptr<Botan::Private_Key>>> retrieve;
+
+ for(auto&& cert_key_pair : test_data)
+ {
+ Botan::X509_Certificate cert(test_dir + "/" + cert_key_pair.first);
+ Botan::AutoSeeded_RNG rng;
+ std::shared_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(test_dir + "/" + cert_key_pair.second,rng));
+
+ if(!key)
+ {
+ result.test_failure("Failed to load key from disk");
+ results.push_back(fn.second(retrieve,store));
+ continue;
+ }
+
+
+ store.insert_cert(cert);
+ store.insert_key(cert,*key);
+ retrieve.push_back(std::make_pair(cert,key));
+ }
+
+ results.push_back(fn.second(retrieve,store));
+ }
+ catch(std::exception& e)
+ {
+ results.push_back(Test::Result::Failure("Certstor test '" + fn.first + "'", e.what()));
+ }
+ }
+
+ return results;
+ }
+ };
+
+BOTAN_REGISTER_TEST("certstor", Certstor_Tests);
+
+#endif
+
+}
+
+}