diff options
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 + +} + +} |