aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-08-19 16:03:40 -0400
committerJack Lloyd <[email protected]>2016-08-19 16:03:40 -0400
commit165a21393f0061a6f3c68b9244a20b41c16c2a78 (patch)
treeff78cfd1907d0a208c0bb42b73622b0310172633
parentf26dfb3572aaab003e0c80002615d190488fb613 (diff)
parent6cbff45093199d821dee7ee74380474300f49948 (diff)
Merge GH #591
Change behavior of default key usage encoding, default now omits the key usage unless the user set a value. Fix allowed_usage which could produce incorrect results. More X.509 tests
-rw-r--r--src/lib/cert/x509/key_constraint.cpp63
-rw-r--r--src/lib/cert/x509/key_constraint.h28
-rw-r--r--src/lib/cert/x509/x509_ca.cpp18
-rw-r--r--src/lib/cert/x509/x509_ext.cpp10
-rw-r--r--src/lib/cert/x509/x509cert.cpp9
-rw-r--r--src/lib/cert/x509/x509self.cpp35
-rw-r--r--src/lib/math/bigint/big_code.cpp11
-rw-r--r--src/lib/math/bigint/bigint.h9
-rw-r--r--src/lib/pubkey/dsa/dsa.cpp5
-rw-r--r--src/lib/pubkey/ecdsa/ecdsa.cpp5
-rw-r--r--src/lib/pubkey/ecgdsa/ecgdsa.cpp5
-rw-r--r--src/lib/pubkey/eckcdsa/eckcdsa.cpp7
-rw-r--r--src/tests/test_bigint.cpp27
-rw-r--r--src/tests/unit_x509.cpp606
14 files changed, 606 insertions, 232 deletions
diff --git a/src/lib/cert/x509/key_constraint.cpp b/src/lib/cert/x509/key_constraint.cpp
index 24791b34a..a90af013c 100644
--- a/src/lib/cert/x509/key_constraint.cpp
+++ b/src/lib/cert/x509/key_constraint.cpp
@@ -1,69 +1,46 @@
/*
* KeyUsage
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/key_constraint.h>
#include <botan/x509_key.h>
-#include <botan/ber_dec.h>
namespace Botan {
-namespace BER {
-
-/*
-* Decode a BER encoded KeyUsage
-*/
-void decode(BER_Decoder& source, Key_Constraints& key_usage)
- {
- BER_Object obj = source.get_next_object();
-
- if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL)
- throw BER_Bad_Tag("Bad tag for usage constraint",
- obj.type_tag, obj.class_tag);
- if(obj.value.size() != 2 && obj.value.size() != 3)
- throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");
- if(obj.value[0] >= 8)
- throw BER_Decoding_Error("Invalid unused bits in usage constraint");
-
- const byte mask = (0xFF << obj.value[0]);
- obj.value[obj.value.size()-1] &= mask;
-
- u16bit usage = 0;
- for(size_t j = 1; j != obj.value.size(); ++j)
- usage = (obj.value[j] << 8) | usage;
-
- key_usage = Key_Constraints(usage);
- }
-
-}
-
/*
-* Find the allowable key constraints
+* Make sure the given key constraints are permitted for the given key type
*/
-Key_Constraints find_constraints(const Public_Key& pub_key,
- Key_Constraints limits)
+void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key,
+ Key_Constraints constraints)
{
const std::string name = pub_key.algo_name();
- size_t constraints = 0;
+ size_t permitted = 0;
if(name == "DH" || name == "ECDH")
- constraints |= KEY_AGREEMENT;
+ {
+ permitted |= KEY_AGREEMENT | ENCIPHER_ONLY | DECIPHER_ONLY;
+ }
if(name == "RSA" || name == "ElGamal")
- constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT;
+ {
+ permitted |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT;
+ }
if(name == "RSA" || name == "RW" || name == "NR" ||
- name == "DSA" || name == "ECDSA")
- constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION;
-
- if(limits)
- constraints &= limits;
-
- return Key_Constraints(constraints);
+ name == "DSA" || name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA")
+ {
+ permitted |= DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_CERT_SIGN | CRL_SIGN;
+ }
+
+ if ( ( constraints & permitted ) != constraints )
+ {
+ throw Exception("Constraint not permitted for key type " + name);
+ }
}
}
diff --git a/src/lib/cert/x509/key_constraint.h b/src/lib/cert/x509/key_constraint.h
index 179e413b5..b67eb7010 100644
--- a/src/lib/cert/x509/key_constraint.h
+++ b/src/lib/cert/x509/key_constraint.h
@@ -1,6 +1,7 @@
/*
* Enumerations
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,7 +9,7 @@
#ifndef BOTAN_ENUMS_H__
#define BOTAN_ENUMS_H__
-#include <botan/ber_dec.h>
+#include <botan/build.h>
namespace Botan {
@@ -32,26 +33,13 @@ enum Key_Constraints {
class Public_Key;
/**
-* Create the key constraints for a specific public key.
-* @param pub_key the public key from which the basic set of
-* constraints to be placed in the return value is derived
-* @param limits additional limits that will be incorporated into the
-* return value
-* @return combination of key type specific constraints and
-* additional limits
+* Check that key constraints are permitted for a specific public key.
+* @param pub_key the public key on which the constraints shall be enforced on
+* @param constrains the constraints that shall be enforced on the key
+* @throw Exception if the given constraints are not permitted for this key
*/
-
-BOTAN_DLL Key_Constraints find_constraints(const Public_Key& pub_key,
- Key_Constraints limits);
-
-/**
-* BER Decoding Function for key constraints
-*/
-namespace BER {
-
-void BOTAN_DLL decode(BER_Decoder&, Key_Constraints&);
-
-}
+BOTAN_DLL void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key,
+ Key_Constraints constraints);
}
diff --git a/src/lib/cert/x509/x509_ca.cpp b/src/lib/cert/x509/x509_ca.cpp
index 147fdd6ad..58c6676f4 100644
--- a/src/lib/cert/x509/x509_ca.cpp
+++ b/src/lib/cert/x509/x509_ca.cpp
@@ -52,11 +52,14 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
{
Key_Constraints constraints;
if(req.is_CA())
+ {
constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
else
{
std::unique_ptr<Public_Key> key(req.subject_public_key());
- constraints = find_constraints(*key, req.constraints());
+ verify_cert_constraints_valid_for_key_type(*key, req.constraints());
+ constraints = req.constraints();
}
Extensions extensions;
@@ -65,7 +68,10 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
true);
- extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ }
extensions.add(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id()));
extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));
@@ -233,11 +239,17 @@ PK_Signer* choose_sig_format(const Private_Key& key,
std::string padding;
if(algo_name == "RSA")
+ {
padding = "EMSA3";
- else if(algo_name == "DSA" || algo_name == "ECDSA" )
+ }
+ else if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA")
+ {
padding = "EMSA1";
+ }
else
+ {
throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
+ }
const Signature_Format format = (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
diff --git a/src/lib/cert/x509/x509_ext.cpp b/src/lib/cert/x509/x509_ext.cpp
index 986254bc9..650c20d53 100644
--- a/src/lib/cert/x509/x509_ext.cpp
+++ b/src/lib/cert/x509/x509_ext.cpp
@@ -1,6 +1,7 @@
/*
* X.509 Certificate Extensions
* (C) 1999-2010,2012 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -293,7 +294,9 @@ void Key_Usage::decode_inner(const std::vector<byte>& in)
u16bit usage = 0;
for(size_t i = 1; i != obj.value.size(); ++i)
- usage = (obj.value[i] << 8) | usage;
+ {
+ usage = (obj.value[i] << 8*(sizeof(usage)-i)) | usage;
+ }
m_constraints = Key_Constraints(usage);
}
@@ -818,13 +821,12 @@ std::vector<byte> Unknown_Critical_Extension::encode_inner() const
throw Not_Implemented("Unknown_Critical_Extension encoding");
}
-void Unknown_Critical_Extension::decode_inner(const std::vector<byte>& buf)
+void Unknown_Critical_Extension::decode_inner(const std::vector<byte>&)
{
}
-void Unknown_Critical_Extension::contents_to(Data_Store& info, Data_Store&) const
+void Unknown_Critical_Extension::contents_to(Data_Store&, Data_Store&) const
{
- // TODO: textual representation?
}
}
diff --git a/src/lib/cert/x509/x509cert.cpp b/src/lib/cert/x509/x509cert.cpp
index bd3aff6d5..20a4bca25 100644
--- a/src/lib/cert/x509/x509cert.cpp
+++ b/src/lib/cert/x509/x509cert.cpp
@@ -1,6 +1,7 @@
/*
* X.509 Certificates
* (C) 1999-2010,2015 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -257,7 +258,7 @@ bool X509_Certificate::allowed_usage(Key_Constraints usage) const
{
if(constraints() == NO_CONSTRAINTS)
return true;
- return ((constraints() & usage) != 0);
+ return ((constraints() & usage) == usage);
}
bool X509_Certificate::allowed_extended_usage(const std::string& usage) const
@@ -565,7 +566,7 @@ std::string X509_Certificate::to_string() const
if(constraints & DIGITAL_SIGNATURE)
out << " Digital Signature\n";
if(constraints & NON_REPUDIATION)
- out << " Non-Repuidation\n";
+ out << " Non-Repudiation\n";
if(constraints & KEY_ENCIPHERMENT)
out << " Key Encipherment\n";
if(constraints & DATA_ENCIPHERMENT)
@@ -576,6 +577,10 @@ std::string X509_Certificate::to_string() const
out << " Cert Sign\n";
if(constraints & CRL_SIGN)
out << " CRL Sign\n";
+ if(constraints & ENCIPHER_ONLY)
+ out << " Encipher Only\n";
+ if(constraints & DECIPHER_ONLY)
+ out << " Decipher Only\n";
}
std::vector<std::string> policies = this->policies();
diff --git a/src/lib/cert/x509/x509self.cpp b/src/lib/cert/x509/x509self.cpp
index 8b9aeda09..102e24f77 100644
--- a/src/lib/cert/x509/x509self.cpp
+++ b/src/lib/cert/x509/x509self.cpp
@@ -55,9 +55,14 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts,
Key_Constraints constraints;
if(opts.is_CA)
+ {
constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
else
- constraints = find_constraints(key, opts.constraints);
+ {
+ verify_cert_constraints_valid_for_key_type(key, opts.constraints);
+ constraints = opts.constraints;
+ }
Extensions extensions;
@@ -65,7 +70,10 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts,
new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit),
true);
- extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ }
extensions.add(new Cert_Extension::Subject_Key_ID(pub_key));
@@ -99,16 +107,27 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts,
const size_t PKCS10_VERSION = 0;
+ Key_Constraints constraints;
+ if(opts.is_CA)
+ {
+ constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
+ else
+ {
+ verify_cert_constraints_valid_for_key_type(key, opts.constraints);
+ constraints = opts.constraints;
+ }
+
Extensions extensions;
extensions.add(
new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit));
- extensions.add(
- new Cert_Extension::Key_Usage(
- opts.is_CA ? Key_Constraints(KEY_CERT_SIGN | CRL_SIGN) :
- find_constraints(key, opts.constraints)
- )
- );
+
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(
+ new Cert_Extension::Key_Usage(constraints));
+ }
extensions.add(
new Cert_Extension::Extended_Key_Usage(opts.ex_constraints));
extensions.add(
diff --git a/src/lib/math/bigint/big_code.cpp b/src/lib/math/bigint/big_code.cpp
index 299fdc246..c8687715d 100644
--- a/src/lib/math/bigint/big_code.cpp
+++ b/src/lib/math/bigint/big_code.cpp
@@ -98,6 +98,17 @@ void BigInt::encode_1363(byte output[], size_t bytes, const BigInt& n)
}
/*
+* Encode two BigInt, with leading 0s if needed, and concatenate
+*/
+secure_vector<byte> BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes)
+ {
+ secure_vector<byte> output(2 * bytes);
+ BigInt::encode_1363(output.data(), bytes, n1);
+ BigInt::encode_1363(output.data() + bytes, bytes, n2);
+ return output;
+ }
+
+/*
* Decode a BigInt
*/
BigInt BigInt::decode(const byte buf[], size_t length, Base base)
diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h
index 2963ba35d..a61bee39c 100644
--- a/src/lib/math/bigint/bigint.h
+++ b/src/lib/math/bigint/bigint.h
@@ -566,6 +566,15 @@ class BOTAN_DLL BigInt
static void encode_1363(byte out[], size_t bytes, const BigInt& n);
+ /**
+ * Encode two BigInt to a byte array according to IEEE 1363
+ * @param n1 the first BigInt to encode
+ * @param n2 the second BigInt to encode
+ * @param bytes the length of the encoding of each single BigInt
+ * @result a secure_vector<byte> containing the concatenation of the two encoded BigInt
+ */
+ static secure_vector<byte> encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes);
+
private:
secure_vector<word> m_reg;
Sign m_signedness = Positive;
diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp
index 6effb81dd..399756b1a 100644
--- a/src/lib/pubkey/dsa/dsa.cpp
+++ b/src/lib/pubkey/dsa/dsa.cpp
@@ -133,10 +133,7 @@ DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_q.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_q.bytes());
}
/**
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index 6fe7ce319..264a36963 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -86,10 +86,7 @@ ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_order.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
}
/**
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
index 3e14aa8f4..30ea32817 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.cpp
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
@@ -73,10 +73,7 @@ ECGDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_order.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
}
/**
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.cpp b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
index 83439332e..5ca89675c 100644
--- a/src/lib/pubkey/eckcdsa/eckcdsa.cpp
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
@@ -100,10 +100,9 @@ ECKCDSA_Signature_Operation::raw_sign(const byte msg[], size_t,
const BigInt s = m_mod_order.multiply(m_x, k - w);
BOTAN_ASSERT(s != 0, "invalid s");
- secure_vector<byte> signature(r.bytes() + s.bytes());
- r.binary_encode(signature.data());
- s.binary_encode(&signature[r.bytes()]);
- return signature;
+ secure_vector<byte> output = BigInt::encode_1363(r, c.size());
+ output += BigInt::encode_1363(s, m_mod_order.get_modulus().bytes());
+ return output;
}
/**
diff --git a/src/tests/test_bigint.cpp b/src/tests/test_bigint.cpp
index 6f3d603db..cee7b5b8b 100644
--- a/src/tests/test_bigint.cpp
+++ b/src/tests/test_bigint.cpp
@@ -30,6 +30,7 @@ class BigInt_Unit_Tests : public Test
results.push_back(test_bigint_sizes());
results.push_back(test_random_integer());
+ results.push_back(test_encode());
return results;
}
@@ -143,6 +144,32 @@ class BigInt_Unit_Tests : public Test
return result;
}
+
+ Test::Result test_encode()
+ {
+ Test::Result result("BigInt encoding functions");
+
+ const BigInt n1(0xffff);
+ const BigInt n2(1023);
+
+ Botan::secure_vector<byte> encoded_n1 = BigInt::encode_1363(n1, 256);
+ Botan::secure_vector<byte> encoded_n2 = BigInt::encode_1363(n2, 256);
+ Botan::secure_vector<byte> expected = encoded_n1;
+ expected += encoded_n2;
+
+ Botan::secure_vector<byte> encoded_n1_n2 = BigInt::encode_fixed_length_int_pair(n1, n2, 256);
+ result.test_eq("encode_fixed_length_int_pair", encoded_n1_n2, expected);
+
+ for (size_t i = 0; i < 256 - n1.bytes(); ++i)
+ {
+ if ( encoded_n1[i] != 0 )
+ {
+ result.test_failure("encode_1363", "no zero byte");
+ }
+ }
+
+ return result;
+ }
};
BOTAN_REGISTER_TEST("bigint_unit", BigInt_Unit_Tests);
diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp
index 93e26eee2..4d3c63a1b 100644
--- a/src/tests/unit_x509.cpp
+++ b/src/tests/unit_x509.cpp
@@ -1,5 +1,6 @@
/*
* (C) 2009 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -28,6 +29,14 @@
#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
+
#endif
namespace Botan_Tests {
@@ -56,7 +65,7 @@ Botan::X509_Cert_Options ca_opts()
return opts;
}
-Botan::X509_Cert_Options req_opts1()
+Botan::X509_Cert_Options req_opts1(const std::string& algo)
{
Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");
@@ -64,6 +73,18 @@ Botan::X509_Cert_Options req_opts1()
opts.dns = "botan.randombit.net";
opts.email = "[email protected]";
+ opts.not_before("1601012000Z");
+ opts.not_after("3001012000Z");
+
+ if(algo == "RSA")
+ {
+ opts.constraints = Botan::Key_Constraints(Botan::KEY_ENCIPHERMENT);
+ }
+ else if(algo == "DSA" || algo == "ECDSA" || algo == "ECGDSA" || algo == "ECKCDSA")
+ {
+ opts.constraints = Botan::Key_Constraints(Botan::DIGITAL_SIGNATURE);
+ }
+
return opts;
}
@@ -80,168 +101,186 @@ Botan::X509_Cert_Options req_opts2()
return opts;
}
-std::unique_ptr<Botan::Private_Key> make_a_private_key()
+std::unique_ptr<Botan::Private_Key> make_a_private_key(const std::string& algo)
{
+#if defined(BOTAN_HAS_RSA)
+ 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)
- Botan::EC_Group grp("secp256r1");
- return std::unique_ptr<Botan::Private_Key>(new Botan::ECDSA_PrivateKey(Test::rng(), grp));
-#elif defined(BOTAN_HAS_RSA)
- return std::unique_ptr<Botan::Private_Key>(new Botan::RSA_PrivateKey(Test::rng(), 1024));
-#elif defined(BOTAN_HAS_DSA)
- Botan::DL_Group grp("dsa/botan/2048");
- return std::unique_ptr<Botan::Private_Key>(new Botan::DSA_PrivateKey(Test::rng(), grp));
-#else
- return std::unique_ptr<Botan::Private_Key>(nullptr);
+ 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);
}
-class X509_Cert_Unit_Tests : public Test
+
+Test::Result test_x509_dates()
{
- public:
- std::vector<Test::Result> run() override;
+ Test::Result result("X509_Time");
+
+ Botan::X509_Time time;
+ result.confirm("unset time not set", !time.time_is_set());
+ time = Botan::X509_Time("0802011822Z", Botan::ASN1_Tag::UTC_TIME);
+ result.confirm("time set after construction", time.time_is_set());
+ result.test_eq("time readable_string", time.readable_string(), "2008/02/01 18:22:00 UTC");
+
+ const std::vector<std::string> valid = {
+ "0802010000Z",
+ "0802011724Z",
+ "0406142334Z",
+ "9906142334Z",
+ "0006142334Z",
+
+ "080201000000Z",
+ "080201172412Z",
+ "040614233433Z",
+ "990614233444Z",
+ "000614233455Z",
+ };
- private:
- Test::Result test_x509_dates()
- {
- Test::Result result("X509_Time");
-
- Botan::X509_Time time;
- result.confirm("unset time not set", !time.time_is_set());
- time = Botan::X509_Time("0802011822Z", Botan::ASN1_Tag::UTC_TIME);
- result.confirm("time set after construction", time.time_is_set());
- result.test_eq("time readable_string", time.readable_string(), "2008/02/01 18:22:00 UTC");
-
- const std::vector<std::string> valid = {
- "0802010000Z",
- "0802011724Z",
- "0406142334Z",
- "9906142334Z",
- "0006142334Z",
-
- "080201000000Z",
- "080201172412Z",
- "040614233433Z",
- "990614233444Z",
- "000614233455Z",
- };
-
- // Dates that are valid per X.500 but rejected as unsupported
- const std::vector<std::string> valid_but_unsup = {
- "0802010000-0000",
- "0802011724+0000",
- "0406142334-0500",
- "9906142334+0500",
- "0006142334-0530",
- "0006142334+0530",
-
- "080201000000-0000",
- "080201172412+0000",
- "040614233433-0500",
- "990614233444+0500",
- "000614233455-0530",
- "000614233455+0530",
- };
-
- const std::vector<std::string> invalid = {
- "",
- " ",
- "2008`02-01",
- "9999-02-01",
- "2000-02-01 17",
- "999921",
-
- // valid length 13 -> range check
- "080201000061Z", // seconds too big (61)
- "080201000060Z", // seconds too big (60, leap seconds not covered by the standard)
- "0802010000-1Z", // seconds too small (-1)
- "080201006000Z", // minutes too big (60)
- "080201240000Z", // hours too big (24:00)
-
- // valid length 13 -> invalid numbers
- "08020123112 Z",
- "08020123112!Z",
- "08020123112,Z",
- "08020123112\nZ",
- "080201232 33Z",
- "080201232!33Z",
- "080201232,33Z",
- "080201232\n33Z",
- "0802012 3344Z",
- "0802012!3344Z",
- "0802012,3344Z",
- "08022\n334455Z",
- "08022 334455Z",
- "08022!334455Z",
- "08022,334455Z",
- "08022\n334455Z",
- "082 33445511Z",
- "082!33445511Z",
- "082,33445511Z",
- "082\n33445511Z",
- "2 2211221122Z",
- "2!2211221122Z",
- "2,2211221122Z",
- "2\n2211221122Z",
-
- // wrong time zone
- "0802010000",
- "0802010000z"
- };
-
- for(auto&& v : valid)
- {
- Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME);
- }
+ // Dates that are valid per X.500 but rejected as unsupported
+ const std::vector<std::string> valid_but_unsup = {
+ "0802010000-0000",
+ "0802011724+0000",
+ "0406142334-0500",
+ "9906142334+0500",
+ "0006142334-0530",
+ "0006142334+0530",
+
+ "080201000000-0000",
+ "080201172412+0000",
+ "040614233433-0500",
+ "990614233444+0500",
+ "000614233455-0530",
+ "000614233455+0530",
+ };
- for(auto&& v : valid_but_unsup)
- {
- result.test_throws("valid but unsupported", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
- }
+ const std::vector<std::string> invalid = {
+ "",
+ " ",
+ "2008`02-01",
+ "9999-02-01",
+ "2000-02-01 17",
+ "999921",
+
+ // valid length 13 -> range check
+ "080201000061Z", // seconds too big (61)
+ "080201000060Z", // seconds too big (60, leap seconds not covered by the standard)
+ "0802010000-1Z", // seconds too small (-1)
+ "080201006000Z", // minutes too big (60)
+ "080201240000Z", // hours too big (24:00)
+
+ // valid length 13 -> invalid numbers
+ "08020123112 Z",
+ "08020123112!Z",
+ "08020123112,Z",
+ "08020123112\nZ",
+ "080201232 33Z",
+ "080201232!33Z",
+ "080201232,33Z",
+ "080201232\n33Z",
+ "0802012 3344Z",
+ "0802012!3344Z",
+ "0802012,3344Z",
+ "08022\n334455Z",
+ "08022 334455Z",
+ "08022!334455Z",
+ "08022,334455Z",
+ "08022\n334455Z",
+ "082 33445511Z",
+ "082!33445511Z",
+ "082,33445511Z",
+ "082\n33445511Z",
+ "2 2211221122Z",
+ "2!2211221122Z",
+ "2,2211221122Z",
+ "2\n2211221122Z",
+
+ // wrong time zone
+ "0802010000",
+ "0802010000z"
+ };
- for(auto&& v : invalid)
- {
- result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
- }
+ for(auto&& v : valid)
+ {
+ Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME);
+ }
- return result;
- }
- };
+ for(auto&& v : valid_but_unsup)
+ {
+ result.test_throws("valid but unsupported", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
+ }
-std::vector<Test::Result> X509_Cert_Unit_Tests::run()
+ for(auto&& v : invalid)
+ {
+ result.test_throws("invalid", [v]() { Botan::X509_Time t(v, Botan::ASN1_Tag::UTC_TIME); });
+ }
+
+ return result;
+ }
+
+Test::Result test_x509_cert(const std::string& sig_algo, const std::string& hash_fn = "SHA-256")
{
- std::vector<Test::Result> results;
Test::Result result("X509 Unit");
- const std::string hash_fn = "SHA-256";
-
/* Create the CA's key and self-signed cert */
- std::unique_ptr<Botan::Private_Key> ca_key(make_a_private_key());
+ std::unique_ptr<Botan::Private_Key> ca_key(make_a_private_key(sig_algo));
if(!ca_key)
{
- // Failure because X.509 enabled but no RSA or ECDSA seems off
- result.test_failure("Skipping due to no enabled signature algorithms");
- results.push_back(result);
- return results;
+ // Failure because X.509 enabled but requested signature algorithm is not present
+ result.test_note("Skipping due to missing signature algorithm: " + sig_algo);
+ return result;
}
+ /* Create the self-signed cert */
Botan::X509_Certificate ca_cert =
Botan::X509::create_self_signed_cert(ca_opts(),
*ca_key,
hash_fn,
Test::rng());
+ result.test_eq("ca key usage", (ca_cert.constraints() & Botan::Key_Constraints(Botan::KEY_CERT_SIGN | Botan::CRL_SIGN)) ==
+ Botan::Key_Constraints(Botan::KEY_CERT_SIGN | Botan::CRL_SIGN), true);
+
/* Create user #1's key and cert request */
- std::unique_ptr<Botan::Private_Key> user1_key(make_a_private_key());
+ std::unique_ptr<Botan::Private_Key> user1_key(make_a_private_key(sig_algo));
Botan::PKCS10_Request user1_req =
- Botan::X509::create_cert_req(req_opts1(),
+ Botan::X509::create_cert_req(req_opts1(sig_algo),
*user1_key,
hash_fn,
Test::rng());
/* Create user #2's key and cert request */
- std::unique_ptr<Botan::Private_Key> user2_key(make_a_private_key());
+ std::unique_ptr<Botan::Private_Key> user2_key(make_a_private_key(sig_algo));
Botan::PKCS10_Request user2_req =
Botan::X509::create_cert_req(req_opts2(),
@@ -258,15 +297,41 @@ std::vector<Test::Result> X509_Cert_Unit_Tests::run()
from_date(2008, 01, 01),
from_date(2033, 01, 01));
- Botan::X509_Certificate user2_cert = ca.sign_request(user2_req, Test::rng(),
- from_date(2008, 01, 01),
- from_date(2033, 01, 01));
+ Botan::X509_Certificate user2_cert =
+ ca.sign_request(user2_req, Test::rng(),
+ from_date(2008, 01, 01),
+ from_date(2033, 01, 01));
+
+ result.test_eq("user1 key usage", (user1_cert.constraints() & req_opts1(sig_algo).constraints) == req_opts1(sig_algo).constraints, true);
+
+ /* Copy, assign and compare */
+ Botan::X509_Certificate user1_cert_copy(user1_cert);
+ result.test_eq("certificate copy", user1_cert == user1_cert_copy, true);
+
+ user1_cert_copy = user1_cert;
+ result.test_eq("certificate assignment", user1_cert == user1_cert_copy, true);
+
+ Botan::X509_Certificate user1_cert_differ =
+ ca.sign_request(user1_req, Test::rng(),
+ from_date(2008, 01, 01),
+ from_date(2032, 01, 01));
+
+ result.test_eq("certificate differs", user1_cert == user1_cert_differ, false);
+
+ /* Get cert data */
+ result.test_eq("x509 version", user1_cert.x509_version(), size_t(3));
+
+ result.test_eq("issuer info CN", user1_cert.issuer_info("CN").at(0), ca_opts().common_name);
+ result.test_eq("issuer info Country", user1_cert.issuer_info("C").at(0), ca_opts().country);
+ result.test_eq("issuer info Orga", user1_cert.issuer_info("O").at(0), ca_opts().organization);
+ result.test_eq("issuer info OrgaUnit", user1_cert.issuer_info("OU").at(0), ca_opts().org_unit);
+
Botan::X509_CRL crl1 = ca.new_crl(Test::rng());
/* Verify the certs */
Botan::Certificate_Store_In_Memory store;
- store.add_certificate(ca_cert);
+ store.add_certificate(ca.ca_certificate());
Botan::Path_Validation_Restrictions restrictions(false);
@@ -316,11 +381,280 @@ std::vector<Test::Result> X509_Cert_Unit_Tests::run()
result_u2 = Botan::x509_path_validate(user2_cert, restrictions, store);
result.test_eq("user 2 still revoked", result_u2.result_string(), revoked_str);
- results.push_back(result);
- results.push_back(test_x509_dates());
- return results;
+ return result;
+ }
+
+Test::Result test_usage(const std::string& sig_algo, const std::string& hash_fn = "SHA-256")
+ {
+ using Botan::Key_Constraints;
+
+ Test::Result result("X509 Usage");
+
+ /* Create the CA's key and self-signed cert */
+ std::unique_ptr<Botan::Private_Key> ca_key(make_a_private_key(sig_algo));
+
+ if(!ca_key)
+ {
+ // Failure because X.509 enabled but requested signature algorithm is not present
+ result.test_note("Skipping due to missing signature algorithm: " + sig_algo);
+ return result;
+ }
+
+ /* Create the self-signed cert */
+ Botan::X509_Certificate ca_cert =
+ Botan::X509::create_self_signed_cert(ca_opts(),
+ *ca_key,
+ hash_fn,
+ Test::rng());
+
+ /* Create the CA object */
+ Botan::X509_CA ca(ca_cert, *ca_key, hash_fn);
+
+ std::unique_ptr<Botan::Private_Key> user1_key(make_a_private_key(sig_algo));
+
+ Botan::X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");
+ opts.constraints = Key_Constraints::DIGITAL_SIGNATURE;
+
+ Botan::PKCS10_Request user1_req =
+ Botan::X509::create_cert_req(opts,
+ *user1_key,
+ hash_fn,
+ Test::rng());
+
+ Botan::X509_Certificate user1_cert =
+ ca.sign_request(user1_req, Test::rng(),
+ from_date(2008, 01, 01),
+ from_date(2033, 01, 01));
+
+ // cert only allows digitalSignature, but we check for both digitalSignature and cRLSign
+ result.test_eq("key usage cRLSign not allowed", user1_cert.allowed_usage(Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE |
+ Key_Constraints::CRL_SIGN)), false);
+
+ // cert only allows digitalSignature, so checking for only that should be ok
+ result.confirm("key usage digitalSignature allowed", user1_cert.allowed_usage(Key_Constraints::DIGITAL_SIGNATURE));
+
+ opts.constraints = Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::CRL_SIGN);
+
+ Botan::PKCS10_Request mult_usage_req =
+ Botan::X509::create_cert_req(opts,
+ *user1_key,
+ hash_fn,
+ Test::rng());
+
+ Botan::X509_Certificate mult_usage_cert =
+ ca.sign_request(mult_usage_req, Test::rng(),
+ from_date(2008, 01, 01),
+ from_date(2033, 01, 01));
+
+ // cert allows multiple usages, so each one of them as well as both together should be allowed
+ result.confirm("key usage multiple digitalSignature allowed", mult_usage_cert.allowed_usage(Key_Constraints::DIGITAL_SIGNATURE));
+ result.confirm("key usage multiple cRLSign allowed", mult_usage_cert.allowed_usage(Key_Constraints::CRL_SIGN));
+ result.confirm("key usage multiple digitalSignature and cRLSign allowed", mult_usage_cert.allowed_usage(
+ Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::CRL_SIGN)));
+
+ opts.constraints = Key_Constraints::NO_CONSTRAINTS;
+
+ Botan::PKCS10_Request no_usage_req =
+ Botan::X509::create_cert_req(opts,
+ *user1_key,
+ hash_fn,
+ Test::rng());
+
+ Botan::X509_Certificate no_usage_cert =
+ ca.sign_request(no_usage_req, Test::rng(),
+ from_date(2008, 01, 01),
+ from_date(2033, 01, 01));
+
+ // cert allows every usage
+ result.confirm("key usage digitalSignature allowed", no_usage_cert.allowed_usage(Key_Constraints::DIGITAL_SIGNATURE));
+ result.confirm("key usage cRLSign allowed", no_usage_cert.allowed_usage(Key_Constraints::CRL_SIGN));
+
+ return result;
+ }
+
+using Botan::Key_Constraints;
+
+/**
+* @brief Some typical key usage scenarios (taken from RFC 5280, sec. 4.2.1.3)
+*/
+struct typical_usage_constraints
+ {
+ // ALL constraints are not typical at all, but we use them for a negative test
+ Key_Constraints all = Key_Constraints(
+ Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::NON_REPUDIATION | Key_Constraints::KEY_ENCIPHERMENT |
+ Key_Constraints::DATA_ENCIPHERMENT | Key_Constraints::KEY_AGREEMENT | Key_Constraints::KEY_CERT_SIGN |
+ Key_Constraints::CRL_SIGN | Key_Constraints::ENCIPHER_ONLY | Key_Constraints::DECIPHER_ONLY);
+
+ Key_Constraints ca = Key_Constraints(Key_Constraints::KEY_CERT_SIGN);
+ Key_Constraints sign_data = Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE);
+ Key_Constraints non_repudiation = Key_Constraints(Key_Constraints::NON_REPUDIATION | Key_Constraints::DIGITAL_SIGNATURE);
+ Key_Constraints key_encipherment = Key_Constraints(Key_Constraints::KEY_ENCIPHERMENT);
+ Key_Constraints data_encipherment = Key_Constraints(Key_Constraints::DATA_ENCIPHERMENT);
+ Key_Constraints key_agreement = Key_Constraints(Key_Constraints::KEY_AGREEMENT);
+ Key_Constraints key_agreement_encipher_only = Key_Constraints(Key_Constraints::KEY_AGREEMENT | Key_Constraints::ENCIPHER_ONLY);
+ Key_Constraints key_agreement_decipher_only = Key_Constraints(Key_Constraints::KEY_AGREEMENT | Key_Constraints::DECIPHER_ONLY);
+ Key_Constraints crl_sign = Key_Constraints(Key_Constraints::CRL_SIGN);
+ Key_Constraints sign_everything = Key_Constraints(Key_Constraints::DIGITAL_SIGNATURE | Key_Constraints::KEY_CERT_SIGN | Key_Constraints::CRL_SIGN);
+ };
+
+
+Test::Result test_valid_constraints(const std::string& pk_algo)
+ {
+ Test::Result result("X509 Valid Constraints");
+
+ std::unique_ptr<Botan::Private_Key> key(make_a_private_key(pk_algo));
+
+ if(!key)
+ {
+ // Failure because X.509 enabled but requested algorithm is not present
+ result.test_note("Skipping due to missing signature algorithm: " + pk_algo);
+ return result;
+ }
+
+ // should not throw on empty constraints
+ verify_cert_constraints_valid_for_key_type(*key, Key_Constraints(Key_Constraints::NO_CONSTRAINTS));
+
+ // now check some typical usage scenarios for the given key type
+ typical_usage_constraints typical_usage;
+
+ if(pk_algo == "DH" || pk_algo == "ECDH")
+ {
+ // DH and ECDH only for key agreement
+ result.test_throws("all constraints not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.all); });
+ result.test_throws("cert sign not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.ca); });
+ result.test_throws("signature not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.sign_data); });
+ result.test_throws("non repudiation not permitted", [&key, &typical_usage]() { 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.key_agreement);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.key_agreement_encipher_only);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.key_agreement_decipher_only);
+
+ result.test_throws("crl sign not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.crl_sign); });
+ result.test_throws("sign, cert sign, crl sign not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.sign_everything); });
+ }
+ else if(pk_algo == "RSA")
+ {
+ // RSA can do everything except key agreement
+ result.test_throws("all constraints not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.all); });
+
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.ca);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.sign_data);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.non_repudiation);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.key_encipherment);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.data_encipherment);
+
+ result.test_throws("key agreement not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement); });
+ result.test_throws("key agreement, encipher only not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement_encipher_only); });
+ result.test_throws("key agreement, decipher only not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement_decipher_only); });
+
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.crl_sign);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.sign_everything);
+ }
+ else if(pk_algo == "ElGamal")
+ {
+ // only ElGamal encryption is currently implemented
+ result.test_throws("all constraints not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.all); });
+ 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); });
+
+ result.test_throws("key agreement not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement); });
+ result.test_throws("key agreement, encipher only not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement_encipher_only); });
+ result.test_throws("key agreement, decipher only not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement_decipher_only); });
+ result.test_throws("crl sign not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.crl_sign); });
+ 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")
+ {
+ // these are signature algorithms only
+ result.test_throws("all constraints not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.all); });
+
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.ca);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.sign_data);
+ 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); });
+ result.test_throws("key agreement not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement); });
+ result.test_throws("key agreement, encipher only not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement_encipher_only); });
+ result.test_throws("key agreement, decipher only not permitted", [&key, &typical_usage]() { verify_cert_constraints_valid_for_key_type(*key,
+ typical_usage.key_agreement_decipher_only); });
+
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.crl_sign);
+ verify_cert_constraints_valid_for_key_type(*key, typical_usage.sign_everything);
+ }
+
+ return result;
}
+
+class X509_Cert_Unit_Tests : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<Test::Result> results;
+ const std::vector<std::string> sig_algos { "RSA", "DSA", "ECDSA", "ECGDSA", "ECKCDSA" };
+ Test::Result cert_result("X509 Unit");
+ Test::Result usage_result("X509 Usage");
+
+ for(const auto& algo : sig_algos)
+ {
+ cert_result.merge(test_x509_cert(algo));
+ usage_result.merge(test_usage(algo));
+ }
+
+ results.push_back(cert_result);
+ results.push_back(usage_result);
+
+ const std::vector<std::string> pk_algos { "DH", "ECDH", "RSA", "ElGamal", "RW", "NR",
+ "DSA", "ECDSA", "ECGDSA", "ECKCDSA" };
+ Test::Result valid_constraints_result("X509 Valid Constraints");
+
+ for(const auto& algo : pk_algos)
+ {
+ valid_constraints_result.merge(test_valid_constraints(algo));
+ }
+
+ results.push_back(valid_constraints_result);
+ results.push_back(test_x509_dates());
+
+ return results;
+ }
+ };
+
BOTAN_REGISTER_TEST("unit_x509", X509_Cert_Unit_Tests);
#endif