diff options
Diffstat (limited to 'src/lib/cert/x509')
-rw-r--r-- | src/lib/cert/x509/key_constraint.cpp | 63 | ||||
-rw-r--r-- | src/lib/cert/x509/key_constraint.h | 28 | ||||
-rw-r--r-- | src/lib/cert/x509/name_constraint.cpp | 4 | ||||
-rw-r--r-- | src/lib/cert/x509/ocsp.cpp | 2 | ||||
-rw-r--r-- | src/lib/cert/x509/ocsp_types.cpp | 2 | ||||
-rw-r--r-- | src/lib/cert/x509/x509_ca.cpp | 20 | ||||
-rw-r--r-- | src/lib/cert/x509/x509_ca.h | 1 | ||||
-rw-r--r-- | src/lib/cert/x509/x509_ext.cpp | 18 | ||||
-rw-r--r-- | src/lib/cert/x509/x509cert.cpp | 46 | ||||
-rw-r--r-- | src/lib/cert/x509/x509cert.h | 32 | ||||
-rw-r--r-- | src/lib/cert/x509/x509opt.cpp | 13 | ||||
-rw-r--r-- | src/lib/cert/x509/x509self.cpp | 39 | ||||
-rw-r--r-- | src/lib/cert/x509/x509self.h | 5 |
13 files changed, 151 insertions, 122 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/name_constraint.cpp b/src/lib/cert/x509/name_constraint.cpp index a1ed19856..83f6386ba 100644 --- a/src/lib/cert/x509/name_constraint.cpp +++ b/src/lib/cert/x509/name_constraint.cpp @@ -33,7 +33,7 @@ GeneralName::GeneralName(const std::string& v) : GeneralName() void GeneralName::encode_into(class DER_Encoder&) const { - throw Exception("General Name encoding not implemented"); + throw Not_Implemented("GeneralName encoding"); } void GeneralName::decode_from(class BER_Decoder& ber) @@ -249,7 +249,7 @@ GeneralSubtree::GeneralSubtree(const std::string& v) : GeneralSubtree() void GeneralSubtree::encode_into(class DER_Encoder&) const { - throw std::runtime_error("General Subtree encoding not implemented"); + throw Not_Implemented("General Subtree encoding"); } void GeneralSubtree::decode_from(class BER_Decoder& ber) diff --git a/src/lib/cert/x509/ocsp.cpp b/src/lib/cert/x509/ocsp.cpp index 4f4a3aece..df8df3b39 100644 --- a/src/lib/cert/x509/ocsp.cpp +++ b/src/lib/cert/x509/ocsp.cpp @@ -81,7 +81,7 @@ void check_signature(const std::vector<byte>& tbs_response, // Otherwise attempt to chain the signing cert to a trust root - if(!certs[0].allowed_usage("PKIX.OCSPSigning")) + if(!certs[0].allowed_extended_usage("PKIX.OCSPSigning")) throw Exception("OCSP response cert does not allow OCSP signing"); auto result = x509_path_validate(certs, Path_Validation_Restrictions(), trusted_roots); diff --git a/src/lib/cert/x509/ocsp_types.cpp b/src/lib/cert/x509/ocsp_types.cpp index ba5b825f7..d470c2fa1 100644 --- a/src/lib/cert/x509/ocsp_types.cpp +++ b/src/lib/cert/x509/ocsp_types.cpp @@ -92,7 +92,7 @@ void CertID::decode_from(class BER_Decoder& from) void SingleResponse::encode_into(class DER_Encoder&) const { - throw Exception("Not implemented (SingleResponse::encode_into)"); + throw Not_Implemented("SingleResponse::encode_into"); } void SingleResponse::decode_from(class BER_Decoder& from) diff --git a/src/lib/cert/x509/x509_ca.cpp b/src/lib/cert/x509/x509_ca.cpp index 46c8c65f2..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,13 +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") + } + else if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA") + { padding = "EMSA1"; - else if(algo_name == "ECDSA") - padding = "EMSA1_BSI"; + } 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_ca.h b/src/lib/cert/x509/x509_ca.h index 6ea51cd06..ba3724f5e 100644 --- a/src/lib/cert/x509/x509_ca.h +++ b/src/lib/cert/x509/x509_ca.h @@ -22,7 +22,6 @@ namespace Botan { class BOTAN_DLL X509_CA { public: - /** * Sign a PKCS#10 Request. * @param req the request to sign diff --git a/src/lib/cert/x509/x509_ext.cpp b/src/lib/cert/x509/x509_ext.cpp index 85d40bf21..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); } @@ -461,7 +464,7 @@ void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const */ std::vector<byte> Name_Constraints::encode_inner() const { - throw std::runtime_error("Name_Constraints encoding not implemented"); + throw Not_Implemented("Name_Constraints encoding"); } @@ -777,7 +780,7 @@ void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const std::vector<byte> CRL_Distribution_Points::encode_inner() const { - throw Exception("CRL_Distribution_Points encoding not implemented"); + throw Not_Implemented("CRL_Distribution_Points encoding"); } void CRL_Distribution_Points::decode_inner(const std::vector<byte>& buf) @@ -800,7 +803,7 @@ void CRL_Distribution_Points::contents_to(Data_Store& info, Data_Store&) const void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const { - throw Exception("CRL_Distribution_Points encoding not implemented"); + throw Not_Implemented("CRL_Distribution_Points encoding"); } void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber) @@ -815,16 +818,15 @@ void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& std::vector<byte> Unknown_Critical_Extension::encode_inner() const { - throw Exception("Unknown_Critical_Extension encoding not implemented"); + 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 d7da00af0..ffedf43f0 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,10 +258,10 @@ 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_usage(const std::string& usage) const +bool X509_Certificate::allowed_extended_usage(const std::string& usage) const { const std::vector<std::string> ex = ex_constraints(); @@ -275,19 +276,21 @@ bool X509_Certificate::allowed_usage(const std::string& usage) const bool X509_Certificate::allowed_usage(Usage_Type usage) const { + // These follow suggestions in RFC 5280 4.2.1.12 + switch(usage) { case Usage_Type::UNSPECIFIED: return true; case Usage_Type::TLS_SERVER_AUTH: - return allowed_usage(Key_Constraints(DATA_ENCIPHERMENT | KEY_ENCIPHERMENT | DIGITAL_SIGNATURE)) && allowed_usage("PKIX.ServerAuth"); + return (allowed_usage(KEY_AGREEMENT) || allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DIGITAL_SIGNATURE)) && allowed_extended_usage("PKIX.ServerAuth"); case Usage_Type::TLS_CLIENT_AUTH: - return allowed_usage(Key_Constraints(DIGITAL_SIGNATURE | NON_REPUDIATION)) && allowed_usage("PKIX.ClientAuth"); + return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(KEY_AGREEMENT)) && allowed_extended_usage("PKIX.ClientAuth"); case Usage_Type::OCSP_RESPONDER: - return allowed_usage(Key_Constraints(DIGITAL_SIGNATURE | NON_REPUDIATION)) && allowed_usage("PKIX.OCSPSigning"); + return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(NON_REPUDIATION)) && allowed_extended_usage("PKIX.OCSPSigning"); case Usage_Type::CERTIFICATE_AUTHORITY: return is_CA_cert(); @@ -296,6 +299,33 @@ bool X509_Certificate::allowed_usage(Usage_Type usage) const return false; } +bool X509_Certificate::has_constraints(Key_Constraints constraints) const + { + if(this->constraints() == NO_CONSTRAINTS) + { + return false; + } + + return ((this->constraints() & constraints) != 0); + } + +bool X509_Certificate::has_ex_constraint(const std::string& ex_constraint) const + { + const std::vector<std::string> ex = ex_constraints(); + + if(ex.empty()) + { + return false; + } + + if(std::find(ex.begin(), ex.end(), ex_constraint) != ex.end()) + { + return true; + } + + return false; + } + /* * Return the path length constraint */ @@ -538,7 +568,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) @@ -549,6 +579,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/x509cert.h b/src/lib/cert/x509/x509cert.h index c521cf7ca..eb98f9c3d 100644 --- a/src/lib/cert/x509/x509cert.h +++ b/src/lib/cert/x509/x509cert.h @@ -33,7 +33,7 @@ enum class Usage_Type /** * This class represents X.509 Certificate */ -class BOTAN_DLL X509_Certificate final : public X509_Object +class BOTAN_DLL X509_Certificate : public X509_Object { public: /** @@ -140,17 +140,39 @@ class BOTAN_DLL X509_Certificate final : public X509_Object */ bool is_CA_cert() const; + /** + * Returns true if the specified @param usage is set in the key usage extension + * or if no key usage constraints are set at all. + * To check if a certain key constraint is set in the certificate + * use @see X509_Certificate#has_constraints. + */ bool allowed_usage(Key_Constraints usage) const; /** - * Returns true if and only if name (referring to an extended key - * constraint, eg "PKIX.ServerAuth") is included in the extended - * key extension. + * Returns true if the specified @param usage is set in the extended key usage extension + * or if no extended key usage constraints are set at all. + * To check if a certain extended key constraint is set in the certificate + * use @see X509_Certificate#has_ex_constraint. */ - bool allowed_usage(const std::string& usage) const; + bool allowed_extended_usage(const std::string& usage) const; + /** + * Returns true if the required key and extended key constraints are set in the certificate + * for the specified @param usage or if no key constraints are set in both the key usage + * and extended key usage extension. + */ bool allowed_usage(Usage_Type usage) const; + /// Returns true if the specified @param constraints are included in the key usage extension. + bool has_constraints(Key_Constraints constraints) const; + + /** + * Returns true if and only if @param ex_constraint (referring to an extended key + * constraint, eg "PKIX.ServerAuth") is included in the extended + * key extension. + */ + bool has_ex_constraint(const std::string& ex_constraint) const; + /** * Get the path limit as defined in the BasicConstraints extension of * this certificate. diff --git a/src/lib/cert/x509/x509opt.cpp b/src/lib/cert/x509/x509opt.cpp index 158f4c779..2dd2098fe 100644 --- a/src/lib/cert/x509/x509opt.cpp +++ b/src/lib/cert/x509/x509opt.cpp @@ -62,19 +62,6 @@ void X509_Cert_Options::CA_key(size_t limit) } /* -* Do basic sanity checks -*/ -void X509_Cert_Options::sanity_check() const - { - if(common_name.empty() || country.empty()) - throw Encoding_Error("X.509 certificate: name and country MUST be set"); - if(country.size() != 2) - throw Encoding_Error("Invalid ISO country code: " + country); - if(start >= end) - throw Encoding_Error("X509_Cert_Options: invalid time constraints"); - } - -/* * Initialize the certificate options */ X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts, diff --git a/src/lib/cert/x509/x509self.cpp b/src/lib/cert/x509/x509self.cpp index 7d1c01c37..102e24f77 100644 --- a/src/lib/cert/x509/x509self.cpp +++ b/src/lib/cert/x509/x509self.cpp @@ -49,17 +49,20 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, X509_DN subject_dn; AlternativeName subject_alt; - opts.sanity_check(); - std::vector<byte> pub_key = X509::BER_encode(key); std::unique_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo)); load_info(opts, subject_dn, subject_alt); 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; @@ -67,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)); @@ -95,24 +101,33 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, X509_DN subject_dn; AlternativeName subject_alt; - opts.sanity_check(); - std::vector<byte> pub_key = X509::BER_encode(key); std::unique_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo)); load_info(opts, subject_dn, subject_alt); 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/cert/x509/x509self.h b/src/lib/cert/x509/x509self.h index a4bbad214..401b2eb2f 100644 --- a/src/lib/cert/x509/x509self.h +++ b/src/lib/cert/x509/x509self.h @@ -115,11 +115,6 @@ class BOTAN_DLL X509_Cert_Options std::vector<OID> ex_constraints; /** - * Check the options set in this object for validity. - */ - void sanity_check() const; - - /** * Mark the certificate as a CA certificate and set the path limit. * @param limit the path limit to be set in the BasicConstraints extension. */ |