diff options
author | lloyd <[email protected]> | 2012-05-27 17:35:56 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-05-27 17:35:56 +0000 |
commit | ad4ffbfaf86e58707b7c4c7df92660b46724a9bf (patch) | |
tree | 4a2e062fc5b25a762c07f1cb57eb63b203fe837d | |
parent | a7e3315bcabe81a697f4c2c28e9c72ddb59182c1 (diff) |
Add an X509_Certificate::allowed_usage for extended constraints.
Check that whatever certificate we got is allowed to sign OCSP
responses. Add another helper function BER_Decoder to try to handle
the ASN.1 mess.
-rw-r--r-- | src/asn1/ber_dec.cpp | 7 | ||||
-rw-r--r-- | src/asn1/ber_dec.h | 3 | ||||
-rw-r--r-- | src/cert/ocsp/ocsp.cpp | 83 | ||||
-rw-r--r-- | src/cert/x509/x509cert.cpp | 13 | ||||
-rw-r--r-- | src/cert/x509/x509cert.h | 9 |
5 files changed, 64 insertions, 51 deletions
diff --git a/src/asn1/ber_dec.cpp b/src/asn1/ber_dec.cpp index 51b952e71..497f2615f 100644 --- a/src/asn1/ber_dec.cpp +++ b/src/asn1/ber_dec.cpp @@ -398,6 +398,13 @@ BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) return (*this); } +std::vector<byte> BER_Decoder::get_next_octet_string() + { + std::vector<byte> out_vec; + decode(out_vec, OCTET_STRING); + return out_vec; + } + /* * Decode a BER encoded BOOLEAN */ diff --git a/src/asn1/ber_dec.h b/src/asn1/ber_dec.h index 3aa141550..ee930da21 100644 --- a/src/asn1/ber_dec.h +++ b/src/asn1/ber_dec.h @@ -20,6 +20,9 @@ class BOTAN_DLL BER_Decoder { public: BER_Object get_next_object(); + + std::vector<byte> get_next_octet_string(); + void push_back(const BER_Object& obj); bool more_items() const; diff --git a/src/cert/ocsp/ocsp.cpp b/src/cert/ocsp/ocsp.cpp index 4dfaaad40..8b6d500f5 100644 --- a/src/cert/ocsp/ocsp.cpp +++ b/src/cert/ocsp/ocsp.cpp @@ -43,37 +43,30 @@ void decode_optional_list(BER_Decoder& ber, } } -bool check_signature(const std::vector<byte>& tbs_response, +void check_signature(const std::vector<byte>& tbs_response, const AlgorithmIdentifier& sig_algo, const std::vector<byte>& signature, const X509_Certificate& cert) { - try - { - std::unique_ptr<Public_Key> pub_key(cert.subject_public_key()); + std::unique_ptr<Public_Key> pub_key(cert.subject_public_key()); - const std::vector<std::string> sig_info = - split_on(OIDS::lookup(sig_algo.oid), '/'); + const std::vector<std::string> sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); - if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) - return false; + if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name()) + throw std::runtime_error("Information in OCSP response does not match cert"); - std::string padding = sig_info[1]; - Signature_Format format = - (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; + std::string padding = sig_info[1]; + Signature_Format format = + (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363; - PK_Verifier verifier(*pub_key, padding, format); + PK_Verifier verifier(*pub_key, padding, format); - return verifier.verify_message( - ASN1::put_in_sequence(tbs_response), signature); - } - catch(std::exception& e) - { - return false; - } + if(!verifier.verify_message(ASN1::put_in_sequence(tbs_response), signature)) + throw std::runtime_error("Signature on OCSP response does not verify"); } -bool check_signature(const std::vector<byte>& tbs_response, +void check_signature(const std::vector<byte>& tbs_response, const AlgorithmIdentifier& sig_algo, const std::vector<byte>& signature, const Certificate_Store& trusted_roots, @@ -84,6 +77,9 @@ bool 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")) + throw std::runtime_error("OCSP response cert does not allow OCSP signing"); + Path_Validation_Result result = x509_path_validate(certs, Path_Validation_Restrictions(), @@ -95,7 +91,9 @@ bool check_signature(const std::vector<byte>& tbs_response, if(!trusted_roots.certificate_known(result.trust_root())) throw std::runtime_error("Certificate chain roots in unknown/untrusted CA"); - return check_signature(tbs_response, sig_algo, signature, result.cert_path()[0]); + const std::vector<X509_Certificate>& cert_path = result.cert_path(); + + check_signature(tbs_response, sig_algo, signature, cert_path[0]); } } @@ -126,9 +124,7 @@ std::string Request::base64_encode() const Response::Response(const Certificate_Store& trusted_roots, const std::vector<byte>& response_bits) { - BER_Decoder ber(response_bits); - - BER_Decoder response_outer = ber.start_cons(SEQUENCE); + BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE); size_t resp_status = 0; @@ -142,12 +138,8 @@ Response::Response(const Certificate_Store& trusted_roots, response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), "Unknown response type in OCSP response"); - std::vector<byte> response_vec; - response_bytes.decode(response_vec, OCTET_STRING); - - BER_Decoder basicresponse_x(response_vec); - - BER_Decoder basicresponse = basicresponse_x.start_cons(SEQUENCE); + BER_Decoder basicresponse = + BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); std::vector<byte> tbs_bits; AlgorithmIdentifier sig_algo; @@ -161,31 +153,28 @@ Response::Response(const Certificate_Store& trusted_roots, .decode(signature, BIT_STRING); decode_optional_list(basicresponse, ASN1_Tag(0), certs); - BER_Decoder tbs_response(tbs_bits); - size_t responsedata_version = 0; X509_DN name; std::vector<byte> key_hash; X509_Time produced_at; + Extensions extensions; - // decode_optional_and_check(0, ASN1_Tag(0), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); - tbs_response.decode_optional(responsedata_version, ASN1_Tag(0), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + BER_Decoder(tbs_bits) + .decode_optional(responsedata_version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - // Technically a choice: enforce that? - tbs_response.decode_optional(name, ASN1_Tag(1), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + .decode_optional(name, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - tbs_response.decode_optional_string(key_hash, ASN1_Tag(2), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + .decode_optional_string(key_hash, ASN1_Tag(2), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - tbs_response.decode(produced_at); + .decode(produced_at) - tbs_response.decode_list(m_responses); + .decode_list(m_responses) - Extensions extensions; - tbs_response.decode_optional(extensions, ASN1_Tag(1), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + .decode_optional(extensions, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); if(certs.empty()) { @@ -194,12 +183,10 @@ Response::Response(const Certificate_Store& trusted_roots, throw std::runtime_error("Could not find certificate that signed OCSP response"); } - if(!check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs)) - throw std::runtime_error("Invalid OCSP response"); + check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs); } response_outer.end_cons(); - } bool Response::affirmative_response_for(const X509_Certificate& issuer, diff --git a/src/cert/x509/x509cert.cpp b/src/cert/x509/x509cert.cpp index 176604b63..e1aa2075f 100644 --- a/src/cert/x509/x509cert.cpp +++ b/src/cert/x509/x509cert.cpp @@ -227,11 +227,20 @@ bool X509_Certificate::is_CA_cert() const return allowed_usage(KEY_CERT_SIGN); } -bool X509_Certificate::allowed_usage(Key_Constraints restriction) const +bool X509_Certificate::allowed_usage(Key_Constraints usage) const { if(constraints() == NO_CONSTRAINTS) return true; - return (constraints() & restriction); + return (constraints() & usage); + } + +bool X509_Certificate::allowed_usage(const std::string& usage) const + { + for(auto constraint : ex_constraints()) + if(constraint == usage) + return true; + + return false; } /* diff --git a/src/cert/x509/x509cert.h b/src/cert/x509/x509cert.h index 0accf7113..9df9eba0a 100644 --- a/src/cert/x509/x509cert.h +++ b/src/cert/x509/x509cert.h @@ -127,7 +127,14 @@ class BOTAN_DLL X509_Certificate : public X509_Object */ bool is_CA_cert() const; - bool allowed_usage(Key_Constraints restriction) const; + 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. + */ + bool allowed_usage(const std::string& usage) const; /** * Get the path limit as defined in the BasicConstraints extension of |