From 17952f5ed03bbc0000e486f390d86c6905efd86c Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 29 Nov 2013 19:53:57 +0000 Subject: Move OCSP to x509 subdir as they are quite entangled --- src/cert/ocsp/info.txt | 7 -- src/cert/ocsp/ocsp.cpp | 252 ------------------------------------------- src/cert/ocsp/ocsp.h | 61 ----------- src/cert/ocsp/ocsp_types.cpp | 121 --------------------- src/cert/ocsp/ocsp_types.h | 67 ------------ src/cert/x509/info.txt | 2 +- src/cert/x509/ocsp.cpp | 252 +++++++++++++++++++++++++++++++++++++++++++ src/cert/x509/ocsp.h | 61 +++++++++++ src/cert/x509/ocsp_types.cpp | 121 +++++++++++++++++++++ src/cert/x509/ocsp_types.h | 67 ++++++++++++ 10 files changed, 502 insertions(+), 509 deletions(-) delete mode 100644 src/cert/ocsp/info.txt delete mode 100644 src/cert/ocsp/ocsp.cpp delete mode 100644 src/cert/ocsp/ocsp.h delete mode 100644 src/cert/ocsp/ocsp_types.cpp delete mode 100644 src/cert/ocsp/ocsp_types.h create mode 100644 src/cert/x509/ocsp.cpp create mode 100644 src/cert/x509/ocsp.h create mode 100644 src/cert/x509/ocsp_types.cpp create mode 100644 src/cert/x509/ocsp_types.h diff --git a/src/cert/ocsp/info.txt b/src/cert/ocsp/info.txt deleted file mode 100644 index 914f2b654..000000000 --- a/src/cert/ocsp/info.txt +++ /dev/null @@ -1,7 +0,0 @@ -define OCSP 20131128 - - -x509 -sha1 -http_util - diff --git a/src/cert/ocsp/ocsp.cpp b/src/cert/ocsp/ocsp.cpp deleted file mode 100644 index 2ea413e76..000000000 --- a/src/cert/ocsp/ocsp.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* -* OCSP -* (C) 2012,2013 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -namespace OCSP { - -namespace { - -void decode_optional_list(BER_Decoder& ber, - ASN1_Tag tag, - std::vector& output) - { - BER_Object obj = ber.get_next_object(); - - if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)) - { - ber.push_back(obj); - return; - } - - BER_Decoder list(obj.value); - - while(list.more_items()) - { - BER_Object certbits = list.get_next_object(); - X509_Certificate cert(unlock(certbits.value)); - output.push_back(std::move(cert)); - } - } - -void check_signature(const std::vector& tbs_response, - const AlgorithmIdentifier& sig_algo, - const std::vector& signature, - const X509_Certificate& cert) - { - std::unique_ptr pub_key(cert.subject_public_key()); - - const std::vector sig_info = - split_on(OIDS::lookup(sig_algo.oid), '/'); - - 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; - - PK_Verifier verifier(*pub_key, padding, format); - - if(!verifier.verify_message(ASN1::put_in_sequence(tbs_response), signature)) - throw std::runtime_error("Signature on OCSP response does not verify"); - } - -void check_signature(const std::vector& tbs_response, - const AlgorithmIdentifier& sig_algo, - const std::vector& signature, - const Certificate_Store& trusted_roots, - const std::vector& certs) - { - if(certs.size() < 1) - throw std::invalid_argument("Short cert chain for check_signature"); - - 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 - - if(!certs[0].allowed_usage("PKIX.OCSPSigning")) - throw std::runtime_error("OCSP response cert does not allow OCSP signing"); - - auto 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())) // not needed anymore? - throw std::runtime_error("Certificate chain roots in unknown/untrusted CA"); - - const std::vector& cert_path = result.cert_path(); - - check_signature(tbs_response, sig_algo, signature, cert_path[0]); - } - -} - -std::vector Request::BER_encode() const - { - CertID certid(m_issuer, m_subject); - - return DER_Encoder().start_cons(SEQUENCE) - .start_cons(SEQUENCE) - .start_explicit(0) - .encode(static_cast(0)) // version # - .end_explicit() - .start_cons(SEQUENCE) - .start_cons(SEQUENCE) - .encode(certid) - .end_cons() - .end_cons() - .end_cons() - .end_cons().get_contents_unlocked(); - } - -std::string Request::base64_encode() const - { - return Botan::base64_encode(BER_encode()); - } - -Response::Response(const Certificate_Store& trusted_roots, - const std::vector& response_bits) - { - BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE); - - size_t resp_status = 0; - - response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); - - if(resp_status != 0) - throw std::runtime_error("OCSP response status " + std::to_string(resp_status)); - - if(response_outer.more_items()) - { - BER_Decoder response_bytes = - 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 type in OCSP response"); - - BER_Decoder basicresponse = - BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); - - std::vector tbs_bits; - AlgorithmIdentifier sig_algo; - std::vector signature; - std::vector 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); - - size_t responsedata_version = 0; - X509_DN name; - std::vector key_hash; - X509_Time produced_at; - Extensions extensions; - - BER_Decoder(tbs_bits) - .decode_optional(responsedata_version, ASN1_Tag(0), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - - .decode_optional(name, ASN1_Tag(1), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - - .decode_optional_string(key_hash, ASN1_Tag(2), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) - - .decode(produced_at) - - .decode_list(m_responses) - - .decode_optional(extensions, ASN1_Tag(1), - ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); - - if(certs.empty()) - { - if(auto cert = trusted_roots.find_cert(name, std::vector())) - certs.push_back(*cert); - else - throw std::runtime_error("Could not find certificate that signed OCSP response"); - } - - check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs); - } - - response_outer.end_cons(); - } - -Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, - const X509_Certificate& subject) const - { - for(const auto& response : m_responses) - { - if(response.certid().is_id_for(issuer, subject)) - { - X509_Time current_time(std::chrono::system_clock::now()); - - if(response.this_update() > current_time) - return Certificate_Status_Code::OCSP_NOT_YET_VALID; - - if(response.next_update().time_is_set() && current_time > response.next_update()) - return Certificate_Status_Code::OCSP_EXPIRED; - - if(response.cert_status() == 1) - return Certificate_Status_Code::CERT_IS_REVOKED; - else if(response.cert_status() == 0) - return Certificate_Status_Code::OCSP_RESPONSE_GOOD; - else - return Certificate_Status_Code::OCSP_BAD_STATUS; - } - } - - return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; - } - -Response online_check(const X509_Certificate& issuer, - const X509_Certificate& subject, - const Certificate_Store& trusted_roots) - { - const std::string responder_url = subject.ocsp_responder(); - - if(responder_url == "") - throw std::runtime_error("No OCSP responder specified"); - - OCSP::Request req(issuer, subject); - - auto http = HTTP::POST_sync(responder_url, - "application/ocsp-request", - req.BER_encode()); - - if(http.status_code() != 200) - throw std::runtime_error("HTTP error: " + http.status_message()); - - // Check the MIME type? - - OCSP::Response response(trusted_roots, http.body()); - - return response; - } - -} - -} diff --git a/src/cert/ocsp/ocsp.h b/src/cert/ocsp/ocsp.h deleted file mode 100644 index 0c40bc282..000000000 --- a/src/cert/ocsp/ocsp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -* OCSP -* (C) 2012 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_OCSP_H__ -#define BOTAN_OCSP_H__ - -#include -#include - -namespace Botan { - -class Certificate_Store; - -namespace OCSP { - -class BOTAN_DLL Request - { - public: - Request(const X509_Certificate& issuer_cert, - const X509_Certificate& subject_cert) : - m_issuer(issuer_cert), - m_subject(subject_cert) - {} - - std::vector BER_encode() const; - - std::string base64_encode() const; - - const X509_Certificate& issuer() const { return m_issuer; } - - const X509_Certificate& subject() const { return m_subject; } - private: - X509_Certificate m_issuer, m_subject; - }; - -class BOTAN_DLL Response - { - public: - Response(const Certificate_Store& trusted_roots, - const std::vector& response); - - Certificate_Status_Code status_for(const X509_Certificate& issuer, - const X509_Certificate& subject) const; - - private: - std::vector m_responses; - }; - -BOTAN_DLL Response online_check(const X509_Certificate& issuer, - const X509_Certificate& subject, - const Certificate_Store& trusted_roots); - -} - -} - -#endif diff --git a/src/cert/ocsp/ocsp_types.cpp b/src/cert/ocsp/ocsp_types.cpp deleted file mode 100644 index be41499ee..000000000 --- a/src/cert/ocsp/ocsp_types.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -* OCSP subtypes -* (C) 2012 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -namespace OCSP { - -CertID::CertID(const X509_Certificate& issuer, - const X509_Certificate& subject) - { - /* - In practice it seems some responders, including, notably, - ocsp.verisign.com, will reject anything but SHA-1 here - */ - std::unique_ptr hash(get_hash("SHA-160")); - - m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); - m_issuer_key_hash = unlock(hash->process(extract_key_bitstr(issuer))); - m_issuer_dn_hash = unlock(hash->process(subject.raw_issuer_dn())); - m_subject_serial = BigInt::decode(subject.serial_number()); - } - -std::vector CertID::extract_key_bitstr(const X509_Certificate& cert) const - { - const auto key_bits = cert.subject_public_key_bits(); - - AlgorithmIdentifier public_key_algid; - std::vector public_key_bitstr; - - BER_Decoder(key_bits) - .decode(public_key_algid) - .decode(public_key_bitstr, BIT_STRING); - - return public_key_bitstr; - } - -bool CertID::is_id_for(const X509_Certificate& issuer, - const X509_Certificate& subject) const - { - try - { - if(BigInt::decode(subject.serial_number()) != m_subject_serial) - return false; - - std::unique_ptr hash(get_hash(OIDS::lookup(m_hash_id.oid))); - - if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) - return false; - - if(m_issuer_key_hash != unlock(hash->process(extract_key_bitstr(issuer)))) - return false; - } - catch(...) - { - return false; - } - - return true; - } - -void CertID::encode_into(class DER_Encoder& to) const - { - to.start_cons(SEQUENCE) - .encode(m_hash_id) - .encode(m_issuer_dn_hash, OCTET_STRING) - .encode(m_issuer_key_hash, OCTET_STRING) - .encode(m_subject_serial) - .end_cons(); - } - -void CertID::decode_from(class BER_Decoder& from) - { - from.start_cons(SEQUENCE) - .decode(m_hash_id) - .decode(m_issuer_dn_hash, OCTET_STRING) - .decode(m_issuer_key_hash, OCTET_STRING) - .decode(m_subject_serial) - .end_cons(); - - } - -void SingleResponse::encode_into(class DER_Encoder&) const - { - throw std::runtime_error("Not implemented (SingleResponse::encode_into)"); - } - -void SingleResponse::decode_from(class BER_Decoder& from) - { - BER_Object cert_status; - Extensions extensions; - - from.start_cons(SEQUENCE) - .decode(m_certid) - .get_next(cert_status) - .decode(m_thisupdate) - .decode_optional(m_nextupdate, ASN1_Tag(0), - ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) - .decode_optional(extensions, - ASN1_Tag(1), - ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) - .end_cons(); - - m_cert_status = cert_status.type_tag; - } - -} - -} diff --git a/src/cert/ocsp/ocsp_types.h b/src/cert/ocsp/ocsp_types.h deleted file mode 100644 index f693600ea..000000000 --- a/src/cert/ocsp/ocsp_types.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -* OCSP subtypes -* (C) 2012 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_OCSP_TYPES_H__ -#define BOTAN_OCSP_TYPES_H__ - -#include -#include -#include - -namespace Botan { - -namespace OCSP { - -class BOTAN_DLL CertID : public ASN1_Object - { - public: - CertID() {} - - CertID(const X509_Certificate& issuer, - const X509_Certificate& subject); - - bool is_id_for(const X509_Certificate& issuer, - const X509_Certificate& subject) const; - - void encode_into(class DER_Encoder& to) const override; - - void decode_from(class BER_Decoder& from) override; - private: - std::vector extract_key_bitstr(const X509_Certificate& cert) const; - - AlgorithmIdentifier m_hash_id; - std::vector m_issuer_dn_hash; - std::vector m_issuer_key_hash; - BigInt m_subject_serial; - }; - -class BOTAN_DLL SingleResponse : public ASN1_Object - { - public: - const CertID& certid() const { return m_certid; } - - size_t cert_status() const { return m_cert_status; } - - X509_Time this_update() const { return m_thisupdate; } - - X509_Time next_update() const { return m_thisupdate; } - - void encode_into(class DER_Encoder& to) const override; - - void decode_from(class BER_Decoder& from) override; - private: - CertID m_certid; - size_t m_cert_status = 2; // unknown - X509_Time m_thisupdate; - X509_Time m_nextupdate; - }; - -} - -} - -#endif diff --git a/src/cert/x509/info.txt b/src/cert/x509/info.txt index 1aebd0c81..ef3043e9e 100644 --- a/src/cert/x509/info.txt +++ b/src/cert/x509/info.txt @@ -1,7 +1,7 @@ define X509_CERTIFICATES 20131128 +define OCSP 20131128 datastor http_util -ocsp diff --git a/src/cert/x509/ocsp.cpp b/src/cert/x509/ocsp.cpp new file mode 100644 index 000000000..2ea413e76 --- /dev/null +++ b/src/cert/x509/ocsp.cpp @@ -0,0 +1,252 @@ +/* +* OCSP +* (C) 2012,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +namespace { + +void decode_optional_list(BER_Decoder& ber, + ASN1_Tag tag, + std::vector& output) + { + BER_Object obj = ber.get_next_object(); + + if(obj.type_tag != tag || obj.class_tag != (CONTEXT_SPECIFIC | CONSTRUCTED)) + { + ber.push_back(obj); + return; + } + + BER_Decoder list(obj.value); + + while(list.more_items()) + { + BER_Object certbits = list.get_next_object(); + X509_Certificate cert(unlock(certbits.value)); + output.push_back(std::move(cert)); + } + } + +void check_signature(const std::vector& tbs_response, + const AlgorithmIdentifier& sig_algo, + const std::vector& signature, + const X509_Certificate& cert) + { + std::unique_ptr pub_key(cert.subject_public_key()); + + const std::vector sig_info = + split_on(OIDS::lookup(sig_algo.oid), '/'); + + 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; + + PK_Verifier verifier(*pub_key, padding, format); + + if(!verifier.verify_message(ASN1::put_in_sequence(tbs_response), signature)) + throw std::runtime_error("Signature on OCSP response does not verify"); + } + +void check_signature(const std::vector& tbs_response, + const AlgorithmIdentifier& sig_algo, + const std::vector& signature, + const Certificate_Store& trusted_roots, + const std::vector& certs) + { + if(certs.size() < 1) + throw std::invalid_argument("Short cert chain for check_signature"); + + 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 + + if(!certs[0].allowed_usage("PKIX.OCSPSigning")) + throw std::runtime_error("OCSP response cert does not allow OCSP signing"); + + auto 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())) // not needed anymore? + throw std::runtime_error("Certificate chain roots in unknown/untrusted CA"); + + const std::vector& cert_path = result.cert_path(); + + check_signature(tbs_response, sig_algo, signature, cert_path[0]); + } + +} + +std::vector Request::BER_encode() const + { + CertID certid(m_issuer, m_subject); + + return DER_Encoder().start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .start_explicit(0) + .encode(static_cast(0)) // version # + .end_explicit() + .start_cons(SEQUENCE) + .start_cons(SEQUENCE) + .encode(certid) + .end_cons() + .end_cons() + .end_cons() + .end_cons().get_contents_unlocked(); + } + +std::string Request::base64_encode() const + { + return Botan::base64_encode(BER_encode()); + } + +Response::Response(const Certificate_Store& trusted_roots, + const std::vector& response_bits) + { + BER_Decoder response_outer = BER_Decoder(response_bits).start_cons(SEQUENCE); + + size_t resp_status = 0; + + response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); + + if(resp_status != 0) + throw std::runtime_error("OCSP response status " + std::to_string(resp_status)); + + if(response_outer.more_items()) + { + BER_Decoder response_bytes = + 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 type in OCSP response"); + + BER_Decoder basicresponse = + BER_Decoder(response_bytes.get_next_octet_string()).start_cons(SEQUENCE); + + std::vector tbs_bits; + AlgorithmIdentifier sig_algo; + std::vector signature; + std::vector 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); + + size_t responsedata_version = 0; + X509_DN name; + std::vector key_hash; + X509_Time produced_at; + Extensions extensions; + + BER_Decoder(tbs_bits) + .decode_optional(responsedata_version, ASN1_Tag(0), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional(name, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode_optional_string(key_hash, ASN1_Tag(2), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)) + + .decode(produced_at) + + .decode_list(m_responses) + + .decode_optional(extensions, ASN1_Tag(1), + ASN1_Tag(CONSTRUCTED | CONTEXT_SPECIFIC)); + + if(certs.empty()) + { + if(auto cert = trusted_roots.find_cert(name, std::vector())) + certs.push_back(*cert); + else + throw std::runtime_error("Could not find certificate that signed OCSP response"); + } + + check_signature(tbs_bits, sig_algo, signature, trusted_roots, certs); + } + + response_outer.end_cons(); + } + +Certificate_Status_Code Response::status_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const + { + for(const auto& response : m_responses) + { + if(response.certid().is_id_for(issuer, subject)) + { + X509_Time current_time(std::chrono::system_clock::now()); + + if(response.this_update() > current_time) + return Certificate_Status_Code::OCSP_NOT_YET_VALID; + + if(response.next_update().time_is_set() && current_time > response.next_update()) + return Certificate_Status_Code::OCSP_EXPIRED; + + if(response.cert_status() == 1) + return Certificate_Status_Code::CERT_IS_REVOKED; + else if(response.cert_status() == 0) + return Certificate_Status_Code::OCSP_RESPONSE_GOOD; + else + return Certificate_Status_Code::OCSP_BAD_STATUS; + } + } + + return Certificate_Status_Code::OCSP_CERT_NOT_LISTED; + } + +Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + const Certificate_Store& trusted_roots) + { + const std::string responder_url = subject.ocsp_responder(); + + if(responder_url == "") + throw std::runtime_error("No OCSP responder specified"); + + OCSP::Request req(issuer, subject); + + auto http = HTTP::POST_sync(responder_url, + "application/ocsp-request", + req.BER_encode()); + + if(http.status_code() != 200) + throw std::runtime_error("HTTP error: " + http.status_message()); + + // Check the MIME type? + + OCSP::Response response(trusted_roots, http.body()); + + return response; + } + +} + +} diff --git a/src/cert/x509/ocsp.h b/src/cert/x509/ocsp.h new file mode 100644 index 000000000..0c40bc282 --- /dev/null +++ b/src/cert/x509/ocsp.h @@ -0,0 +1,61 @@ +/* +* OCSP +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OCSP_H__ +#define BOTAN_OCSP_H__ + +#include +#include + +namespace Botan { + +class Certificate_Store; + +namespace OCSP { + +class BOTAN_DLL Request + { + public: + Request(const X509_Certificate& issuer_cert, + const X509_Certificate& subject_cert) : + m_issuer(issuer_cert), + m_subject(subject_cert) + {} + + std::vector BER_encode() const; + + std::string base64_encode() const; + + const X509_Certificate& issuer() const { return m_issuer; } + + const X509_Certificate& subject() const { return m_subject; } + private: + X509_Certificate m_issuer, m_subject; + }; + +class BOTAN_DLL Response + { + public: + Response(const Certificate_Store& trusted_roots, + const std::vector& response); + + Certificate_Status_Code status_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; + + private: + std::vector m_responses; + }; + +BOTAN_DLL Response online_check(const X509_Certificate& issuer, + const X509_Certificate& subject, + const Certificate_Store& trusted_roots); + +} + +} + +#endif diff --git a/src/cert/x509/ocsp_types.cpp b/src/cert/x509/ocsp_types.cpp new file mode 100644 index 000000000..be41499ee --- /dev/null +++ b/src/cert/x509/ocsp_types.cpp @@ -0,0 +1,121 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +CertID::CertID(const X509_Certificate& issuer, + const X509_Certificate& subject) + { + /* + In practice it seems some responders, including, notably, + ocsp.verisign.com, will reject anything but SHA-1 here + */ + std::unique_ptr hash(get_hash("SHA-160")); + + m_hash_id = AlgorithmIdentifier(hash->name(), AlgorithmIdentifier::USE_NULL_PARAM); + m_issuer_key_hash = unlock(hash->process(extract_key_bitstr(issuer))); + m_issuer_dn_hash = unlock(hash->process(subject.raw_issuer_dn())); + m_subject_serial = BigInt::decode(subject.serial_number()); + } + +std::vector CertID::extract_key_bitstr(const X509_Certificate& cert) const + { + const auto key_bits = cert.subject_public_key_bits(); + + AlgorithmIdentifier public_key_algid; + std::vector public_key_bitstr; + + BER_Decoder(key_bits) + .decode(public_key_algid) + .decode(public_key_bitstr, BIT_STRING); + + return public_key_bitstr; + } + +bool CertID::is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const + { + try + { + if(BigInt::decode(subject.serial_number()) != m_subject_serial) + return false; + + std::unique_ptr hash(get_hash(OIDS::lookup(m_hash_id.oid))); + + if(m_issuer_dn_hash != unlock(hash->process(subject.raw_issuer_dn()))) + return false; + + if(m_issuer_key_hash != unlock(hash->process(extract_key_bitstr(issuer)))) + return false; + } + catch(...) + { + return false; + } + + return true; + } + +void CertID::encode_into(class DER_Encoder& to) const + { + to.start_cons(SEQUENCE) + .encode(m_hash_id) + .encode(m_issuer_dn_hash, OCTET_STRING) + .encode(m_issuer_key_hash, OCTET_STRING) + .encode(m_subject_serial) + .end_cons(); + } + +void CertID::decode_from(class BER_Decoder& from) + { + from.start_cons(SEQUENCE) + .decode(m_hash_id) + .decode(m_issuer_dn_hash, OCTET_STRING) + .decode(m_issuer_key_hash, OCTET_STRING) + .decode(m_subject_serial) + .end_cons(); + + } + +void SingleResponse::encode_into(class DER_Encoder&) const + { + throw std::runtime_error("Not implemented (SingleResponse::encode_into)"); + } + +void SingleResponse::decode_from(class BER_Decoder& from) + { + BER_Object cert_status; + Extensions extensions; + + from.start_cons(SEQUENCE) + .decode(m_certid) + .get_next(cert_status) + .decode(m_thisupdate) + .decode_optional(m_nextupdate, ASN1_Tag(0), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .decode_optional(extensions, + ASN1_Tag(1), + ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)) + .end_cons(); + + m_cert_status = cert_status.type_tag; + } + +} + +} diff --git a/src/cert/x509/ocsp_types.h b/src/cert/x509/ocsp_types.h new file mode 100644 index 000000000..f693600ea --- /dev/null +++ b/src/cert/x509/ocsp_types.h @@ -0,0 +1,67 @@ +/* +* OCSP subtypes +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OCSP_TYPES_H__ +#define BOTAN_OCSP_TYPES_H__ + +#include +#include +#include + +namespace Botan { + +namespace OCSP { + +class BOTAN_DLL CertID : public ASN1_Object + { + public: + CertID() {} + + CertID(const X509_Certificate& issuer, + const X509_Certificate& subject); + + bool is_id_for(const X509_Certificate& issuer, + const X509_Certificate& subject) const; + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + private: + std::vector extract_key_bitstr(const X509_Certificate& cert) const; + + AlgorithmIdentifier m_hash_id; + std::vector m_issuer_dn_hash; + std::vector m_issuer_key_hash; + BigInt m_subject_serial; + }; + +class BOTAN_DLL SingleResponse : public ASN1_Object + { + public: + const CertID& certid() const { return m_certid; } + + size_t cert_status() const { return m_cert_status; } + + X509_Time this_update() const { return m_thisupdate; } + + X509_Time next_update() const { return m_thisupdate; } + + void encode_into(class DER_Encoder& to) const override; + + void decode_from(class BER_Decoder& from) override; + private: + CertID m_certid; + size_t m_cert_status = 2; // unknown + X509_Time m_thisupdate; + X509_Time m_nextupdate; + }; + +} + +} + +#endif -- cgit v1.2.3