mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
618 lines
20 KiB
C++
618 lines
20 KiB
C++
|
|
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "zeek/file_analysis/analyzer/x509/OCSP.h"
|
|
|
|
#include <openssl/asn1.h>
|
|
#include <openssl/opensslconf.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/x509v3.h>
|
|
#include <string>
|
|
|
|
#include "zeek/Event.h"
|
|
#include "zeek/Reporter.h"
|
|
#include "zeek/file_analysis/File.h"
|
|
#include "zeek/file_analysis/Manager.h"
|
|
#include "zeek/file_analysis/analyzer/x509/X509.h"
|
|
#include "zeek/file_analysis/analyzer/x509/ocsp_events.bif.h"
|
|
|
|
// helper function of sk_X509_value to avoid namespace problem
|
|
// sk_X509_value(X,Y) = > SKM_sk_value(X509,X,Y)
|
|
// X509 => file_analysis::X509
|
|
X509* helper_sk_X509_value(const STACK_OF(X509) * certs, int i) { return sk_X509_value(certs, i); }
|
|
|
|
namespace zeek::file_analysis::detail {
|
|
|
|
#define OCSP_STRING_BUF_SIZE 2048
|
|
|
|
static bool OCSP_RESPID_bio(OCSP_BASICRESP* basic_resp, BIO* bio) {
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
ASN1_OCTET_STRING* key = nullptr;
|
|
X509_NAME* name = nullptr;
|
|
|
|
if ( ! basic_resp->tbsResponseData )
|
|
return false;
|
|
|
|
auto resp_id = basic_resp->tbsResponseData->responderId;
|
|
|
|
if ( resp_id->type == V_OCSP_RESPID_NAME )
|
|
name = resp_id->value.byName;
|
|
else if ( resp_id->type == V_OCSP_RESPID_KEY )
|
|
key = resp_id->value.byKey;
|
|
else
|
|
return false;
|
|
#else
|
|
const ASN1_OCTET_STRING* key = nullptr;
|
|
const X509_NAME* name = nullptr;
|
|
|
|
if ( ! OCSP_resp_get0_id(basic_resp, &key, &name) )
|
|
return false;
|
|
#endif
|
|
|
|
if ( name )
|
|
X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE);
|
|
else
|
|
i2a_ASN1_STRING(bio, key, V_ASN1_OCTET_STRING);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ocsp_add_cert_id(const OCSP_CERTID* cert_id, zeek::Args* vl, BIO* bio) {
|
|
ASN1_OBJECT* hash_alg = nullptr;
|
|
ASN1_OCTET_STRING* issuer_name_hash = nullptr;
|
|
ASN1_OCTET_STRING* issuer_key_hash = nullptr;
|
|
ASN1_INTEGER* serial_number = nullptr;
|
|
|
|
auto res = OCSP_id_get0_info(&issuer_name_hash, &hash_alg, &issuer_key_hash, &serial_number,
|
|
const_cast<OCSP_CERTID*>(cert_id));
|
|
|
|
if ( ! res ) {
|
|
reporter->Weird("OpenSSL failed to get OCSP_CERTID info");
|
|
vl->emplace_back(val_mgr->EmptyString());
|
|
vl->emplace_back(val_mgr->EmptyString());
|
|
vl->emplace_back(val_mgr->EmptyString());
|
|
vl->emplace_back(val_mgr->EmptyString());
|
|
return false;
|
|
}
|
|
|
|
char buf[OCSP_STRING_BUF_SIZE];
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
i2a_ASN1_OBJECT(bio, hash_alg);
|
|
int len = BIO_read(bio, buf, sizeof(buf));
|
|
vl->emplace_back(make_intrusive<StringVal>(len, buf));
|
|
BIO_reset(bio);
|
|
|
|
i2a_ASN1_STRING(bio, issuer_name_hash, V_ASN1_OCTET_STRING);
|
|
len = BIO_read(bio, buf, sizeof(buf));
|
|
vl->emplace_back(make_intrusive<StringVal>(len, buf));
|
|
BIO_reset(bio);
|
|
|
|
i2a_ASN1_STRING(bio, issuer_key_hash, V_ASN1_OCTET_STRING);
|
|
len = BIO_read(bio, buf, sizeof(buf));
|
|
vl->emplace_back(make_intrusive<StringVal>(len, buf));
|
|
BIO_reset(bio);
|
|
|
|
i2a_ASN1_INTEGER(bio, serial_number);
|
|
len = BIO_read(bio, buf, sizeof(buf));
|
|
vl->emplace_back(make_intrusive<StringVal>(len, buf));
|
|
BIO_reset(bio);
|
|
|
|
return true;
|
|
}
|
|
|
|
file_analysis::Analyzer* OCSP::InstantiateRequest(RecordValPtr args, file_analysis::File* file) {
|
|
return new OCSP(std::move(args), file, true);
|
|
}
|
|
|
|
file_analysis::Analyzer* OCSP::InstantiateReply(RecordValPtr args, file_analysis::File* file) {
|
|
return new OCSP(std::move(args), file, false);
|
|
}
|
|
|
|
OCSP::OCSP(RecordValPtr args, file_analysis::File* file, bool arg_request)
|
|
: X509Common::X509Common(file_mgr->GetComponentTag("OCSP"), std::move(args), file), request(arg_request) {}
|
|
|
|
bool OCSP::DeliverStream(const u_char* data, uint64_t len) {
|
|
ocsp_data.append(reinterpret_cast<const char*>(data), len);
|
|
return true;
|
|
}
|
|
|
|
bool OCSP::Undelivered(uint64_t offset, uint64_t len) { return false; }
|
|
|
|
// we parse the entire OCSP response in EOF, because we just pass it on
|
|
// to OpenSSL.
|
|
bool OCSP::EndOfFile() {
|
|
const unsigned char* ocsp_char = reinterpret_cast<const unsigned char*>(ocsp_data.data());
|
|
|
|
if ( request ) {
|
|
OCSP_REQUEST* req = d2i_OCSP_REQUEST(NULL, &ocsp_char, ocsp_data.size());
|
|
|
|
if ( ! req ) {
|
|
reporter->Weird(GetFile(), "openssl_ocsp_request_parse_error");
|
|
return false;
|
|
}
|
|
|
|
ParseRequest(req);
|
|
OCSP_REQUEST_free(req);
|
|
}
|
|
else {
|
|
OCSP_RESPONSE* resp = d2i_OCSP_RESPONSE(NULL, &ocsp_char, ocsp_data.size());
|
|
|
|
if ( ! resp ) {
|
|
reporter->Weird(GetFile(), "openssl_ocsp_response_parse_error");
|
|
return false;
|
|
}
|
|
|
|
ParseResponse(resp);
|
|
OCSP_RESPONSE_free(resp);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER >= 0x10100000L )
|
|
|
|
struct ASN1Seq {
|
|
ASN1Seq(const unsigned char** der_in, long length) { decoded = d2i_ASN1_SEQUENCE_ANY(nullptr, der_in, length); }
|
|
|
|
~ASN1Seq() { sk_ASN1_TYPE_pop_free(decoded, ASN1_TYPE_free); }
|
|
|
|
explicit operator bool() const { return decoded; }
|
|
|
|
operator ASN1_SEQUENCE_ANY*() const { return decoded; }
|
|
|
|
ASN1_SEQUENCE_ANY* decoded;
|
|
};
|
|
|
|
// Re-encode and then parse out ASN1 structures to get at what we need...
|
|
/*- BasicOCSPResponse ::= SEQUENCE {
|
|
* tbsResponseData ResponseData,
|
|
* signatureAlgorithm AlgorithmIdentifier,
|
|
* signature BIT STRING,
|
|
* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
|
|
typedef struct ocsp_basic_response_st {
|
|
OCSP_RESPDATA *tbsResponseData;
|
|
X509_ALGOR *signatureAlgorithm;
|
|
ASN1_BIT_STRING *signature;
|
|
STACK_OF(X509) *certs;
|
|
} OCSP_BASICRESP;
|
|
*/
|
|
static StringValPtr parse_basic_resp_sig_alg(OCSP_BASICRESP* basic_resp, BIO* bio, char* buf, size_t buf_len) {
|
|
int der_basic_resp_len = 0;
|
|
unsigned char* der_basic_resp_dat = nullptr;
|
|
|
|
der_basic_resp_len = i2d_OCSP_BASICRESP(basic_resp, &der_basic_resp_dat);
|
|
|
|
if ( der_basic_resp_len <= 0 )
|
|
return val_mgr->EmptyString();
|
|
|
|
const unsigned char* const_der_basic_resp_dat = der_basic_resp_dat;
|
|
|
|
ASN1Seq bseq{&const_der_basic_resp_dat, der_basic_resp_len};
|
|
|
|
if ( ! bseq ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
if ( sk_ASN1_TYPE_num(bseq) < 3 ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
auto constexpr sig_alg_idx = 1u;
|
|
auto aseq_type = sk_ASN1_TYPE_value(bseq, sig_alg_idx);
|
|
|
|
if ( ASN1_TYPE_get(aseq_type) != V_ASN1_SEQUENCE ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
auto aseq_str = aseq_type->value.asn1_string;
|
|
auto aseq_len = ASN1_STRING_length(aseq_str);
|
|
auto aseq_dat = ASN1_STRING_get0_data(aseq_str);
|
|
|
|
ASN1Seq aseq{&aseq_dat, aseq_len};
|
|
|
|
if ( ! aseq ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
if ( sk_ASN1_TYPE_num(aseq) < 1 ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
auto constexpr alg_obj_idx = 0u;
|
|
auto alg_obj_type = sk_ASN1_TYPE_value(aseq, alg_obj_idx);
|
|
|
|
if ( ASN1_TYPE_get(alg_obj_type) != V_ASN1_OBJECT ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
auto alg_obj = alg_obj_type->value.object;
|
|
i2a_ASN1_OBJECT(bio, alg_obj);
|
|
auto alg_len = BIO_read(bio, buf, buf_len);
|
|
auto rval = make_intrusive<StringVal>(alg_len, buf);
|
|
BIO_reset(bio);
|
|
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return rval;
|
|
}
|
|
|
|
static ValPtr parse_basic_resp_data_version(OCSP_BASICRESP* basic_resp) {
|
|
int der_basic_resp_len = 0;
|
|
unsigned char* der_basic_resp_dat = nullptr;
|
|
|
|
der_basic_resp_len = i2d_OCSP_BASICRESP(basic_resp, &der_basic_resp_dat);
|
|
|
|
if ( der_basic_resp_len <= 0 )
|
|
return val_mgr->Count(-1);
|
|
|
|
const unsigned char* const_der_basic_resp_dat = der_basic_resp_dat;
|
|
|
|
ASN1Seq bseq{&const_der_basic_resp_dat, der_basic_resp_len};
|
|
|
|
if ( ! bseq ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->Count(-1);
|
|
}
|
|
|
|
if ( sk_ASN1_TYPE_num(bseq) < 3 ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->Count(-1);
|
|
}
|
|
|
|
auto constexpr resp_data_idx = 0u;
|
|
auto dseq_type = sk_ASN1_TYPE_value(bseq, resp_data_idx);
|
|
|
|
if ( ASN1_TYPE_get(dseq_type) != V_ASN1_SEQUENCE ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->Count(-1);
|
|
}
|
|
|
|
auto dseq_str = dseq_type->value.asn1_string;
|
|
auto dseq_len = ASN1_STRING_length(dseq_str);
|
|
auto dseq_dat = ASN1_STRING_get0_data(dseq_str);
|
|
|
|
ASN1Seq dseq{&dseq_dat, dseq_len};
|
|
|
|
if ( ! dseq ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->Count(-1);
|
|
}
|
|
|
|
if ( sk_ASN1_TYPE_num(dseq) < 1 ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->Count(-1);
|
|
}
|
|
|
|
/*- ResponseData ::= SEQUENCE {
|
|
* version [0] EXPLICIT Version DEFAULT v1,
|
|
* responderID ResponderID,
|
|
* producedAt GeneralizedTime,
|
|
* responses SEQUENCE OF SingleResponse,
|
|
* responseExtensions [1] EXPLICIT Extensions OPTIONAL }
|
|
*/
|
|
|
|
auto constexpr version_idx = 0u;
|
|
auto version_type = sk_ASN1_TYPE_value(dseq, version_idx);
|
|
|
|
if ( ASN1_TYPE_get(version_type) != V_ASN1_INTEGER ) {
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
// Not present, use default value.
|
|
return val_mgr->Count(0);
|
|
}
|
|
|
|
uint64_t asn1_int = ASN1_INTEGER_get(version_type->value.integer);
|
|
OPENSSL_free(der_basic_resp_dat);
|
|
return val_mgr->Count(asn1_int);
|
|
}
|
|
|
|
static uint64_t parse_request_version(OCSP_REQUEST* req) {
|
|
int der_req_len = 0;
|
|
unsigned char* der_req_dat = nullptr;
|
|
der_req_len = i2d_OCSP_REQUEST(req, &der_req_dat);
|
|
const unsigned char* const_der_req_dat = der_req_dat;
|
|
|
|
if ( ! der_req_dat )
|
|
return -1;
|
|
|
|
ASN1Seq rseq{&const_der_req_dat, der_req_len};
|
|
|
|
if ( ! rseq ) {
|
|
OPENSSL_free(der_req_dat);
|
|
return -1;
|
|
}
|
|
|
|
if ( sk_ASN1_TYPE_num(rseq) < 1 ) {
|
|
OPENSSL_free(der_req_dat);
|
|
return -1;
|
|
}
|
|
|
|
auto constexpr version_idx = 0u;
|
|
auto version_type = sk_ASN1_TYPE_value(rseq, version_idx);
|
|
|
|
if ( ASN1_TYPE_get(version_type) != V_ASN1_INTEGER ) {
|
|
OPENSSL_free(der_req_dat);
|
|
// Not present, use default value.
|
|
return 0;
|
|
}
|
|
|
|
uint64_t asn1_int = ASN1_INTEGER_get(version_type->value.integer);
|
|
OPENSSL_free(der_req_dat);
|
|
return asn1_int;
|
|
}
|
|
#endif
|
|
|
|
void OCSP::ParseRequest(OCSP_REQUEST* req) {
|
|
char buf[OCSP_STRING_BUF_SIZE]; // we need a buffer for some of the openssl functions
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
uint64_t version = 0;
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
if ( req->tbsRequest->version )
|
|
version = (uint64_t)ASN1_INTEGER_get(req->tbsRequest->version);
|
|
#else
|
|
version = parse_request_version(req);
|
|
// TODO: try to parse out general name ?
|
|
#endif
|
|
|
|
if ( ocsp_request )
|
|
event_mgr.Enqueue(ocsp_request, GetFile()->ToVal(), val_mgr->Count(version));
|
|
|
|
BIO* bio = BIO_new(BIO_s_mem());
|
|
|
|
int req_count = OCSP_request_onereq_count(req);
|
|
for ( int i = 0; i < req_count; i++ ) {
|
|
zeek::Args rvl;
|
|
rvl.reserve(5);
|
|
rvl.emplace_back(GetFile()->ToVal());
|
|
|
|
OCSP_ONEREQ* one_req = OCSP_request_onereq_get0(req, i);
|
|
OCSP_CERTID* cert_id = OCSP_onereq_get0_id(one_req);
|
|
|
|
ocsp_add_cert_id(cert_id, &rvl, bio);
|
|
|
|
if ( ocsp_request_certificate )
|
|
event_mgr.Enqueue(ocsp_request_certificate, std::move(rvl));
|
|
}
|
|
|
|
BIO_free(bio);
|
|
}
|
|
|
|
void OCSP::ParseResponse(OCSP_RESPONSE* resp) {
|
|
// OCSP_RESPBYTES *resp_bytes = resp->responseBytes;
|
|
OCSP_BASICRESP* basic_resp = nullptr;
|
|
OCSP_RESPDATA* resp_data = nullptr;
|
|
OCSP_RESPID* resp_id = nullptr;
|
|
const ASN1_GENERALIZEDTIME* produced_at = nullptr;
|
|
const STACK_OF(X509)* certs = nullptr;
|
|
|
|
int resp_count, num_ext = 0;
|
|
VectorVal* certs_vector = nullptr;
|
|
int len = 0;
|
|
|
|
char buf[OCSP_STRING_BUF_SIZE];
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
const char* status_str = OCSP_response_status_str(OCSP_response_status(resp));
|
|
auto status_val = make_intrusive<StringVal>(strlen(status_str), status_str);
|
|
|
|
if ( ocsp_response_status )
|
|
event_mgr.Enqueue(ocsp_response_status, GetFile()->ToVal(), status_val);
|
|
|
|
// if (!resp_bytes)
|
|
// {
|
|
// Unref(status_val);
|
|
// return;
|
|
// }
|
|
|
|
BIO* bio = BIO_new(BIO_s_mem());
|
|
// i2a_ASN1_OBJECT(bio, resp_bytes->responseType);
|
|
// int len = BIO_read(bio, buf, sizeof(buf));
|
|
// BIO_reset(bio);
|
|
|
|
zeek::Args vl;
|
|
vl.reserve(8);
|
|
|
|
// get the basic response
|
|
basic_resp = OCSP_response_get1_basic(resp);
|
|
if ( ! basic_resp )
|
|
goto clean_up;
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
resp_data = basic_resp->tbsResponseData;
|
|
if ( ! resp_data )
|
|
goto clean_up;
|
|
#endif
|
|
|
|
vl.emplace_back(GetFile()->ToVal());
|
|
vl.emplace_back(std::move(status_val));
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
vl.emplace_back(val_mgr->Count((uint64_t)ASN1_INTEGER_get(resp_data->version)));
|
|
#else
|
|
vl.emplace_back(parse_basic_resp_data_version(basic_resp));
|
|
#endif
|
|
|
|
// responderID
|
|
if ( OCSP_RESPID_bio(basic_resp, bio) ) {
|
|
len = BIO_read(bio, buf, sizeof(buf));
|
|
vl.emplace_back(make_intrusive<StringVal>(len, buf));
|
|
BIO_reset(bio);
|
|
}
|
|
else {
|
|
reporter->Weird("OpenSSL failed to get OCSP responder id");
|
|
vl.emplace_back(val_mgr->EmptyString());
|
|
}
|
|
|
|
// producedAt
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
produced_at = resp_data->producedAt;
|
|
#else
|
|
produced_at = OCSP_resp_get0_produced_at(basic_resp);
|
|
#endif
|
|
|
|
vl.emplace_back(make_intrusive<TimeVal>(GetTimeFromAsn1(produced_at, GetFile(), reporter)));
|
|
|
|
// responses
|
|
|
|
resp_count = OCSP_resp_count(basic_resp);
|
|
|
|
for ( int i = 0; i < resp_count; i++ ) {
|
|
OCSP_SINGLERESP* single_resp = OCSP_resp_get0(basic_resp, i);
|
|
|
|
if ( ! single_resp )
|
|
continue;
|
|
|
|
zeek::Args rvl;
|
|
rvl.reserve(10);
|
|
rvl.emplace_back(GetFile()->ToVal());
|
|
|
|
// cert id
|
|
const OCSP_CERTID* cert_id = nullptr;
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
cert_id = single_resp->certId;
|
|
#else
|
|
cert_id = OCSP_SINGLERESP_get0_id(single_resp);
|
|
#endif
|
|
|
|
ocsp_add_cert_id(cert_id, &rvl, bio);
|
|
BIO_reset(bio);
|
|
|
|
// certStatus
|
|
int status = V_OCSP_CERTSTATUS_UNKNOWN;
|
|
int reason = OCSP_REVOKED_STATUS_NOSTATUS;
|
|
ASN1_GENERALIZEDTIME* revoke_time = nullptr;
|
|
ASN1_GENERALIZEDTIME* this_update = nullptr;
|
|
ASN1_GENERALIZEDTIME* next_update = nullptr;
|
|
|
|
if ( ! OCSP_resp_find_status(basic_resp, const_cast<OCSP_CERTID*>(cert_id), &status, &reason, &revoke_time,
|
|
&this_update, &next_update) )
|
|
reporter->Weird("OpenSSL failed to find status of OCSP response");
|
|
|
|
const char* cert_status_str = OCSP_cert_status_str(status);
|
|
rvl.emplace_back(make_intrusive<StringVal>(strlen(cert_status_str), cert_status_str));
|
|
|
|
// revocation time and reason if revoked
|
|
if ( status == V_OCSP_CERTSTATUS_REVOKED ) {
|
|
rvl.emplace_back(make_intrusive<TimeVal>(GetTimeFromAsn1(revoke_time, GetFile(), reporter)));
|
|
|
|
if ( reason != OCSP_REVOKED_STATUS_NOSTATUS ) {
|
|
const char* revoke_reason = OCSP_crl_reason_str(reason);
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x30200000L
|
|
// OpenSSL 3.2.0 and later return the right strings for
|
|
// OCSP_REVOKED_STATUS_PRIVILEGEWITHDRAWN (9) and
|
|
// OCSP_REVOKED_STATUS_AACOMPROMISE (10).
|
|
//
|
|
// For versions older than that, fix it up by hand.
|
|
if ( (reason == 9 || reason == 10) && zeek::util::streq(revoke_reason, "(UNKNOWN)") ) {
|
|
revoke_reason = reason == 9 ? "privilegeWithdrawn" : "aACompromise";
|
|
}
|
|
#endif
|
|
rvl.emplace_back(make_intrusive<StringVal>(strlen(revoke_reason), revoke_reason));
|
|
}
|
|
else
|
|
rvl.emplace_back(make_intrusive<StringVal>(0, ""));
|
|
}
|
|
else {
|
|
rvl.emplace_back(make_intrusive<TimeVal>(0.0));
|
|
rvl.emplace_back(make_intrusive<StringVal>(0, ""));
|
|
}
|
|
|
|
if ( this_update )
|
|
rvl.emplace_back(make_intrusive<TimeVal>(GetTimeFromAsn1(this_update, GetFile(), reporter)));
|
|
else
|
|
rvl.emplace_back(make_intrusive<TimeVal>(0.0));
|
|
|
|
if ( next_update )
|
|
rvl.emplace_back(make_intrusive<TimeVal>(GetTimeFromAsn1(next_update, GetFile(), reporter)));
|
|
else
|
|
rvl.emplace_back(make_intrusive<TimeVal>(0.0));
|
|
|
|
if ( ocsp_response_certificate )
|
|
event_mgr.Enqueue(ocsp_response_certificate, std::move(rvl));
|
|
|
|
num_ext = OCSP_SINGLERESP_get_ext_count(single_resp);
|
|
for ( int k = 0; k < num_ext; ++k ) {
|
|
X509_EXTENSION* ex = OCSP_SINGLERESP_get_ext(single_resp, k);
|
|
if ( ! ex )
|
|
continue;
|
|
|
|
ParseExtension(ex, ocsp_extension, false);
|
|
}
|
|
}
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
i2a_ASN1_OBJECT(bio, basic_resp->signatureAlgorithm->algorithm);
|
|
len = BIO_read(bio, buf, sizeof(buf));
|
|
vl.emplace_back(make_intrusive<StringVal>(len, buf));
|
|
BIO_reset(bio);
|
|
#else
|
|
vl.emplace_back(parse_basic_resp_sig_alg(basic_resp, bio, buf, sizeof(buf)));
|
|
#endif
|
|
|
|
// i2a_ASN1_OBJECT(bio, basic_resp->signature);
|
|
// len = BIO_read(bio, buf, sizeof(buf));
|
|
// ocsp_resp_record->Assign(7, make_intrusive<StringVal>(len, buf));
|
|
// BIO_reset(bio);
|
|
|
|
certs_vector = new VectorVal(id::find_type<VectorType>("x509_opaque_vector"));
|
|
vl.emplace_back(AdoptRef{}, certs_vector);
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
certs = basic_resp->certs;
|
|
#else
|
|
certs = OCSP_resp_get0_certs(basic_resp);
|
|
#endif
|
|
|
|
if ( certs ) {
|
|
int num_certs = sk_X509_num(certs);
|
|
for ( int i = 0; i < num_certs; i++ ) {
|
|
::X509* this_cert = X509_dup(helper_sk_X509_value(certs, i));
|
|
//::X509 *this_cert = X509_dup(sk_X509_value(certs, i));
|
|
if ( this_cert )
|
|
certs_vector->Assign(i, make_intrusive<X509Val>(this_cert));
|
|
else
|
|
reporter->Weird("OpenSSL returned null certificate");
|
|
}
|
|
}
|
|
|
|
if ( ocsp_response_bytes )
|
|
event_mgr.Enqueue(ocsp_response_bytes, std::move(vl));
|
|
|
|
// ok, now that we are done with the actual certificate - let's parse extensions :)
|
|
num_ext = OCSP_BASICRESP_get_ext_count(basic_resp);
|
|
for ( int k = 0; k < num_ext; ++k ) {
|
|
X509_EXTENSION* ex = OCSP_BASICRESP_get_ext(basic_resp, k);
|
|
if ( ! ex )
|
|
continue;
|
|
|
|
ParseExtension(ex, ocsp_extension, true);
|
|
}
|
|
|
|
clean_up:
|
|
if ( basic_resp )
|
|
OCSP_BASICRESP_free(basic_resp);
|
|
BIO_free(bio);
|
|
}
|
|
|
|
void OCSP::ParseExtensionsSpecific(X509_EXTENSION* ex, bool global, ASN1_OBJECT* ext_asn, const char* oid) {
|
|
// In OpenSSL 1.0.2+, we can get the extension by using NID_ct_cert_scts.
|
|
// In OpenSSL <= 1.0.1, this is not yet defined yet, so we have to manually
|
|
// look it up by performing a string comparison on the oid.
|
|
#ifdef NID_ct_cert_scts
|
|
if ( OBJ_obj2nid(ext_asn) == NID_ct_cert_scts )
|
|
#else
|
|
if ( strcmp(oid, "1.3.6.1.4.1.11129.2.4.5") == 0 )
|
|
#endif
|
|
ParseSignedCertificateTimestamps(ex);
|
|
}
|
|
|
|
} // namespace zeek::file_analysis::detail
|