diff options
-rw-r--r-- | src/build-data/oids.txt | 2 | ||||
-rw-r--r-- | src/lib/asn1/oids.cpp | 4 | ||||
-rw-r--r-- | src/lib/x509/key_constraint.cpp | 60 | ||||
-rw-r--r-- | src/lib/x509/key_constraint.h | 3 | ||||
-rw-r--r-- | src/lib/x509/x509_ca.cpp | 6 | ||||
-rw-r--r-- | src/tests/unit_x509.cpp | 127 |
6 files changed, 127 insertions, 75 deletions
diff --git a/src/build-data/oids.txt b/src/build-data/oids.txt index b59e0a05e..4a42ff9ca 100644 --- a/src/build-data/oids.txt +++ b/src/build-data/oids.txt @@ -143,6 +143,8 @@ 1.2.643.2.2.3 = GOST-34.10/EMSA1(GOST-R-34.11-94) +1.3.6.1.4.1.25258.1.6.1 = GOST-34.10/EMSA1(SHA-256) + # DN [dn] 2.5.4.3 = X520.CommonName diff --git a/src/lib/asn1/oids.cpp b/src/lib/asn1/oids.cpp index 88752bc4d..2f7597981 100644 --- a/src/lib/asn1/oids.cpp +++ b/src/lib/asn1/oids.cpp @@ -1,7 +1,7 @@ /* * OID maps * -* This file was automatically generated by ./src/scripts/oids.py on 2016-11-17 +* This file was automatically generated by ./src/scripts/oids.py on 2016-11-18 * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -99,6 +99,7 @@ std::string lookup(const OID& oid) if(oid_str == "1.3.6.1.4.1.25258.1.3") return "McEliece"; if(oid_str == "1.3.6.1.4.1.25258.1.4") return "Curve25519"; if(oid_str == "1.3.6.1.4.1.25258.1.5") return "XMSS"; + if(oid_str == "1.3.6.1.4.1.25258.1.6.1") return "GOST-34.10/EMSA1(SHA-256)"; if(oid_str == "1.3.6.1.4.1.25258.3.1") return "Serpent/CBC"; if(oid_str == "1.3.6.1.4.1.25258.3.101") return "Serpent/GCM"; if(oid_str == "1.3.6.1.4.1.25258.3.102") return "Twofish/GCM"; @@ -257,6 +258,7 @@ OID lookup(const std::string& name) if(name == "ElGamal") return OID("1.3.6.1.4.1.3029.1.2.1"); if(name == "GOST-34.10") return OID("1.2.643.2.2.19"); if(name == "GOST-34.10/EMSA1(GOST-R-34.11-94)") return OID("1.2.643.2.2.3"); + if(name == "GOST-34.10/EMSA1(SHA-256)") return OID("1.3.6.1.4.1.25258.1.6.1"); if(name == "HMAC(SHA-160)") return OID("1.2.840.113549.2.7"); if(name == "HMAC(SHA-224)") return OID("1.2.840.113549.2.8"); if(name == "HMAC(SHA-256)") return OID("1.2.840.113549.2.9"); diff --git a/src/lib/x509/key_constraint.cpp b/src/lib/x509/key_constraint.cpp index 30d1cb3b8..a39747f9a 100644 --- a/src/lib/x509/key_constraint.cpp +++ b/src/lib/x509/key_constraint.cpp @@ -1,6 +1,6 @@ /* * KeyUsage -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2007,2016 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) @@ -11,6 +11,58 @@ namespace Botan { +std::string key_constraints_to_string(Key_Constraints constraints) + { + std::vector<std::string> str; + + if(constraints == NO_CONSTRAINTS) + return "no_constraints"; + + if(constraints & DIGITAL_SIGNATURE) + str.push_back("digital_signature"); + + if(constraints & NON_REPUDIATION) + str.push_back("non_repudiation"); + + if(constraints & KEY_ENCIPHERMENT) + str.push_back("key_encipherment"); + + if(constraints & DATA_ENCIPHERMENT) + str.push_back("data_encipherment"); + + if(constraints & KEY_AGREEMENT) + str.push_back("key_agreement"); + + if(constraints & KEY_CERT_SIGN) + str.push_back("key_cert_sign"); + + if(constraints & CRL_SIGN) + str.push_back("crl_sign"); + + if(constraints & ENCIPHER_ONLY) + str.push_back("encipher_only"); + + if(constraints & DECIPHER_ONLY) + str.push_back("decipher_only"); + + // Not 0 (checked at start) but nothing matched above! + if(str.empty()) + return "other_unknown_constraints"; + + if(str.size() == 1) + return str[0]; + + std::string out; + for(size_t i = 0; i < str.size() - 1; ++i) + { + out += str[i]; + out += ','; + } + out += str[str.size() - 1]; + + return out; + } + /* * Make sure the given key constraints are permitted for the given key type */ @@ -31,14 +83,14 @@ void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, permitted |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; } - if(name == "RSA" || name == "DSA" || name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA") + if(name == "RSA" || name == "DSA" || name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA" || name == "GOST-34.10") { permitted |= DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_CERT_SIGN | CRL_SIGN; } - if ( ( constraints & permitted ) != constraints ) + if((constraints & permitted) != constraints) { - throw Exception("Constraint not permitted for key type " + name); + throw Exception("Invalid " + name + " constraints " + key_constraints_to_string(constraints)); } } diff --git a/src/lib/x509/key_constraint.h b/src/lib/x509/key_constraint.h index 02c65acec..1158a4772 100644 --- a/src/lib/x509/key_constraint.h +++ b/src/lib/x509/key_constraint.h @@ -10,6 +10,7 @@ #define BOTAN_ENUMS_H__ #include <botan/build.h> +#include <string> namespace Botan { @@ -41,6 +42,8 @@ class Public_Key; BOTAN_DLL void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, Key_Constraints constraints); +std::string BOTAN_DLL key_constraints_to_string(Key_Constraints); + } #endif diff --git a/src/lib/x509/x509_ca.cpp b/src/lib/x509/x509_ca.cpp index f7f5471f4..6aba7311c 100644 --- a/src/lib/x509/x509_ca.cpp +++ b/src/lib/x509/x509_ca.cpp @@ -239,7 +239,11 @@ PK_Signer* choose_sig_format(const Private_Key& key, { padding = "EMSA3"; } - else if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA") + else if(algo_name == "DSA" || + algo_name == "ECDSA" || + algo_name == "ECGDSA" || + algo_name == "ECKCDSA" || + algo_name == "GOST-34.10") { padding = "EMSA1"; } diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp index d08fe96fe..ae860067c 100644 --- a/src/tests/unit_x509.cpp +++ b/src/tests/unit_x509.cpp @@ -16,26 +16,7 @@ #include <botan/x509self.h> #include <botan/x509path.h> #include <botan/x509_ca.h> - -#if defined(BOTAN_HAS_RSA) - #include <botan/rsa.h> -#endif - -#if defined(BOTAN_HAS_DSA) - #include <botan/dsa.h> -#endif - -#if defined(BOTAN_HAS_ECDSA) - #include <botan/ecdsa.h> -#endif - -#if defined(BOTAN_HAS_ECGDSA) - #include <botan/ecgdsa.h> -#endif - -#if defined(BOTAN_HAS_ECKCDSA) - #include <botan/eckcdsa.h> -#endif +#include <botan/pk_algs.h> #endif @@ -103,41 +84,17 @@ Botan::X509_Cert_Options req_opts2() std::unique_ptr<Botan::Private_Key> make_a_private_key(const std::string& algo) { -#if defined(BOTAN_HAS_RSA) + std::string params = ""; // default "" means choose acceptable algo-specific params + + // Here we override defaults as needed if(algo == "RSA") - { - return std::unique_ptr<Botan::Private_Key>(new Botan::RSA_PrivateKey(Test::rng(), 1024)); - } -#endif -#if defined(BOTAN_HAS_DSA) - if(algo == "DSA") - { - Botan::DL_Group grp("dsa/botan/2048"); - return std::unique_ptr<Botan::Private_Key>(new Botan::DSA_PrivateKey(Test::rng(), grp)); - } -#endif -#if defined(BOTAN_HAS_ECDSA) - if(algo == "ECDSA") - { - Botan::EC_Group grp("secp256r1"); - return std::unique_ptr<Botan::Private_Key>(new Botan::ECDSA_PrivateKey(Test::rng(), grp)); - } -#endif -#if defined(BOTAN_HAS_ECGDSA) - if(algo == "ECGDSA") - { - Botan::EC_Group grp("brainpool256r1"); - return std::unique_ptr<Botan::Private_Key>(new Botan::ECGDSA_PrivateKey(Test::rng(), grp)); - } -#endif -#if defined(BOTAN_HAS_ECKCDSA) - if(algo == "ECKCDSA") - { - Botan::EC_Group grp("brainpool256r1"); - return std::unique_ptr<Botan::Private_Key>(new Botan::ECKCDSA_PrivateKey(Test::rng(), grp)); - } -#endif - return std::unique_ptr<Botan::Private_Key>(nullptr); + params = "1024"; + if(algo == "GOST-34.10") + params = "gost_256A"; + if(algo == "ECKCDSA" || algo == "ECGDSA") + params = "brainpool256r1"; + + return Botan::create_private_key(algo, Test::rng(), params); } @@ -302,6 +259,13 @@ Test::Result test_x509_cert(const std::string& sig_algo, const std::string& hash from_date(2008, 01, 01), from_date(2033, 01, 01)); + // user#1 creates a self-signed cert on the side + Botan::X509_Certificate user1_ss_cert = + Botan::X509::create_self_signed_cert(req_opts1(sig_algo), + *user1_key, + hash_fn, + Test::rng()); + result.test_eq("user1 key usage", (user1_cert.constraints() & req_opts1(sig_algo).constraints) == req_opts1(sig_algo).constraints, true); /* Copy, assign and compare */ @@ -329,11 +293,16 @@ Test::Result test_x509_cert(const std::string& sig_algo, const std::string& hash Botan::X509_CRL crl1 = ca.new_crl(Test::rng()); /* Verify the certs */ + Botan::Path_Validation_Restrictions restrictions(false); Botan::Certificate_Store_In_Memory store; - store.add_certificate(ca.ca_certificate()); + // First try with an empty store + Botan::Path_Validation_Result result_no_issuer = Botan::x509_path_validate(user1_cert, restrictions, store); + result.test_eq("user 1 issuer not found", + result_no_issuer.result_string(), + Botan::Path_Validation_Result::status_string(Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND)); - Botan::Path_Validation_Restrictions restrictions(false); + store.add_certificate(ca.ca_certificate()); Botan::Path_Validation_Result result_u1 = Botan::x509_path_validate(user1_cert, restrictions, store); if(!result.confirm("user 1 validates", result_u1.successful_validation())) @@ -347,6 +316,10 @@ Test::Result test_x509_cert(const std::string& sig_algo, const std::string& hash result.test_note("user 2 validation result was " + result_u2.result_string()); } + Botan::Path_Validation_Result result_self_signed = Botan::x509_path_validate(user1_ss_cert, restrictions, store); + result.test_eq("user 1 issuer not found", + result_no_issuer.result_string(), + Botan::Path_Validation_Result::status_string(Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND)); store.add_crl(crl1); std::vector<Botan::CRL_Entry> revoked; @@ -632,12 +605,8 @@ Test::Result test_valid_constraints(const std::string& pk_algo) result.test_throws("cert sign not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key, typical_usage.ca); }); - verify_cert_constraints_valid_for_key_type(*key, typical_usage.non_repudiation); - - result.test_throws("key encipherment not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key, - typical_usage.key_encipherment); }); - result.test_throws("data encipherment not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key, - typical_usage.data_encipherment); }); + verify_cert_constraints_valid_for_key_type(*key, typical_usage.data_encipherment); + verify_cert_constraints_valid_for_key_type(*key, typical_usage.key_encipherment); result.test_throws("key agreement not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key, typical_usage.key_agreement); }); @@ -650,8 +619,7 @@ Test::Result test_valid_constraints(const std::string& pk_algo) result.test_throws("sign, cert sign, crl sign not permitted not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key, typical_usage.sign_everything); }); } - else if(pk_algo == "RW" || pk_algo == "NR" || pk_algo == "DSA" || - pk_algo == "ECDSA" || pk_algo == "ECGDSA" || pk_algo == "ECKCDSA") + else if(pk_algo == "DSA" || pk_algo == "ECDSA" || pk_algo == "ECGDSA" || pk_algo == "ECKCDSA" || pk_algo == "GOST-34.10") { // these are signature algorithms only result.test_throws("all constraints not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key, @@ -686,23 +654,44 @@ class X509_Cert_Unit_Tests : public Test std::vector<Test::Result> run() override { std::vector<Test::Result> results; - const std::vector<std::string> sig_algos { "RSA", "DSA", "ECDSA", "ECGDSA", "ECKCDSA" }; + + const std::vector<std::string> sig_algos { "RSA", "DSA", "ECDSA", "ECGDSA", "ECKCDSA", "GOST-34.10" }; Test::Result cert_result("X509 Unit"); Test::Result usage_result("X509 Usage"); Test::Result self_issued_result("X509 Self Issued"); for(const auto& algo : sig_algos) { - cert_result.merge(test_x509_cert(algo)); - usage_result.merge(test_usage(algo)); - self_issued_result.merge(test_self_issued(algo)); + try { + cert_result.merge(test_x509_cert(algo)); + } + catch(std::exception& e) + { + cert_result.test_failure("test_x509_cert " + algo, e.what()); + } + + try { + usage_result.merge(test_usage(algo)); + } + catch(std::exception& e) + { + usage_result.test_failure("test_usage " + algo, e.what()); + } + + try { + self_issued_result.merge(test_self_issued(algo)); + } + catch(std::exception& e) + { + self_issued_result.test_failure("test_self_issued " + algo, e.what()); + } } results.push_back(cert_result); results.push_back(usage_result); results.push_back(self_issued_result); - const std::vector<std::string> pk_algos { "DH", "ECDH", "RSA", "ElGamal", "RW", "NR", + const std::vector<std::string> pk_algos { "DH", "ECDH", "RSA", "ElGamal", "GOST-34.10", "DSA", "ECDSA", "ECGDSA", "ECKCDSA" }; Test::Result valid_constraints_result("X509 Valid Constraints"); |