diff options
-rw-r--r-- | doc/log.txt | 2 | ||||
-rw-r--r-- | src/cert/ocsp/info.txt | 2 | ||||
-rw-r--r-- | src/cert/ocsp/ocsp.cpp | 96 | ||||
-rw-r--r-- | src/cert/ocsp/ocsp.h | 7 | ||||
-rw-r--r-- | src/cert/ocsp/ocsp_types.cpp | 2 |
5 files changed, 91 insertions, 18 deletions
diff --git a/doc/log.txt b/doc/log.txt index 9db96396b..701497220 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -29,6 +29,8 @@ Version 1.11.0, Not Yet Released handles path validation and Certificate_Store handles storage of certificates and CRLs. +* Add support for OCSP + * TLS v1.2 is now supported * TLS now supports session resumption. Session information can be diff --git a/src/cert/ocsp/info.txt b/src/cert/ocsp/info.txt index 5f2eb2ca5..0db22f687 100644 --- a/src/cert/ocsp/info.txt +++ b/src/cert/ocsp/info.txt @@ -1,7 +1,5 @@ define OCSP -load_on never - <requires> x509 sha1 diff --git a/src/cert/ocsp/ocsp.cpp b/src/cert/ocsp/ocsp.cpp index c08f09efb..4dfaaad40 100644 --- a/src/cert/ocsp/ocsp.cpp +++ b/src/cert/ocsp/ocsp.cpp @@ -9,10 +9,11 @@ #include <botan/der_enc.h> #include <botan/ber_dec.h> #include <botan/x509_ext.h> +#include <botan/oids.h> #include <botan/base64.h> - -#include <iostream> -#include <botan/hex.h> +#include <botan/pubkey.h> +#include <botan/x509path.h> +#include <memory> namespace Botan { @@ -42,6 +43,61 @@ void decode_optional_list(BER_Decoder& ber, } } +bool 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()); + + 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; + + 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); + + return verifier.verify_message( + ASN1::put_in_sequence(tbs_response), signature); + } + catch(std::exception& e) + { + return false; + } + } + +bool check_signature(const std::vector<byte>& tbs_response, + const AlgorithmIdentifier& sig_algo, + const std::vector<byte>& signature, + const Certificate_Store& trusted_roots, + const std::vector<X509_Certificate>& certs) + { + if(trusted_roots.certificate_known(certs[0])) + return check_signature(tbs_response, sig_algo, signature, certs[0]); + + // Otherwise attempt to chain the signing cert to a trust root + + Path_Validation_Result result = + x509_path_validate(certs, + Path_Validation_Restrictions(), + trusted_roots); + + if(!result.successful_validation()) + throw std::runtime_error("Certificate validation failure: " + result.result_string()); + + 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]); + } + } std::vector<byte> Request::BER_encode() const @@ -67,7 +123,8 @@ std::string Request::base64_encode() const return Botan::base64_encode(BER_encode()); } -Response::Response(const std::vector<byte>& response_bits) +Response::Response(const Certificate_Store& trusted_roots, + const std::vector<byte>& response_bits) { BER_Decoder ber(response_bits); @@ -83,7 +140,7 @@ Response::Response(const std::vector<byte>& response_bits) response_outer.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).start_cons(SEQUENCE); response_bytes.decode_and_check(OID("1.3.6.1.5.5.7.48.1.1"), - "Unknown response OID in OCSP response"); + "Unknown response type in OCSP response"); std::vector<byte> response_vec; response_bytes.decode(response_vec, OCTET_STRING); @@ -91,17 +148,21 @@ Response::Response(const std::vector<byte>& response_bits) BER_Decoder basicresponse_x(response_vec); BER_Decoder basicresponse = basicresponse_x.start_cons(SEQUENCE); - BER_Decoder tbs_response = basicresponse.start_cons(SEQUENCE); + std::vector<byte> tbs_bits; AlgorithmIdentifier sig_algo; std::vector<byte> signature; - - basicresponse.decode(sig_algo); - basicresponse.decode(signature, BIT_STRING); - std::vector<X509_Certificate> certs; + + basicresponse.start_cons(SEQUENCE) + .raw_bytes(tbs_bits) + .end_cons() + .decode(sig_algo) + .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; @@ -125,16 +186,27 @@ Response::Response(const std::vector<byte>& response_bits) Extensions extensions; tbs_response.decode_optional(extensions, ASN1_Tag(1), ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + + if(certs.empty()) + { + certs = trusted_roots.find_cert_by_subject_and_key_id(name, std::vector<byte>()); + if(certs.empty()) + 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"); } response_outer.end_cons(); } -bool Response::affirmative_response_for(const Request& req) +bool Response::affirmative_response_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const { for(auto response : m_responses) - if(response.affirmative_response_for(req.issuer(), req.subject())) + if(response.affirmative_response_for(issuer, subject)) return true; return false; diff --git a/src/cert/ocsp/ocsp.h b/src/cert/ocsp/ocsp.h index f576ba41e..ad2d2cf81 100644 --- a/src/cert/ocsp/ocsp.h +++ b/src/cert/ocsp/ocsp.h @@ -9,6 +9,7 @@ #define BOTAN_OCSP_H__ #include <botan/ocsp_types.h> +#include <botan/certstor.h> namespace Botan { @@ -37,9 +38,11 @@ class BOTAN_DLL Request class BOTAN_DLL Response { public: - Response(const std::vector<byte>& response); + Response(const Certificate_Store& trusted_roots, + const std::vector<byte>& response); - bool affirmative_response_for(const Request&); + bool affirmative_response_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; private: std::vector<SingleResponse> m_responses; diff --git a/src/cert/ocsp/ocsp_types.cpp b/src/cert/ocsp/ocsp_types.cpp index bead099ab..14e3f393f 100644 --- a/src/cert/ocsp/ocsp_types.cpp +++ b/src/cert/ocsp/ocsp_types.cpp @@ -9,11 +9,9 @@ #include <botan/der_enc.h> #include <botan/ber_dec.h> #include <botan/x509_ext.h> - #include <botan/lookup.h> #include <botan/hash.h> #include <botan/oids.h> - #include <memory> namespace Botan { |