Support for the Ruby 2.4 series has ended. See here for reference.
Object
An OpenSSL::OCSP::BasicResponse
contains the status of a certificate check which is created from an OpenSSL::OCSP::Request
. A BasicResponse
is more detailed than a Response
.
Creates a new BasicResponse
. If der_string
is given, decodes der_string
as DER.
static VALUE ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg; OCSP_BASICRESP *res, *res_new; const unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if (!NIL_P(arg)) { GetOCSPBasicRes(self, res); arg = ossl_to_der_if_possible(arg); StringValue(arg); p = (unsigned char *)RSTRING_PTR(arg); res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg)); if (!res_new) ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP"); SetOCSPBasicRes(self, res_new); OCSP_BASICRESP_free(res); } return self; }
Adds nonce
to this response. If no nonce was provided a random nonce will be added.
static VALUE ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self) { OCSP_BASICRESP *bs; VALUE val; int ret; rb_scan_args(argc, argv, "01", &val); if(NIL_P(val)) { GetOCSPBasicRes(self, bs); ret = OCSP_basic_add1_nonce(bs, NULL, -1); } else{ StringValue(val); GetOCSPBasicRes(self, bs); ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val)); } if(!ret) ossl_raise(eOCSPError, NULL); return self; }
Adds a certificate status for certificate_id
. status
is the status, and must be one of these:
OpenSSL::OCSP::V_CERTSTATUS_GOOD
OpenSSL::OCSP::V_CERTSTATUS_REVOKED
OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
reason
and revocation_time
can be given only when status
is OpenSSL::OCSP::V_CERTSTATUS_REVOKED. reason
describes the reason for the revocation, and must be one of OpenSSL::OCSP::REVOKED_STATUS_* constants. revocation_time
is the time when the certificate is revoked.
this_update
and next_update
indicate the time at which ths status is verified to be correct and the time at or before which newer information will be available, respectively. next_update
is optional.
extensions
is an Array of OpenSSL::X509::Extension
to be included in the SingleResponse
. This is also optional.
Note that the times, revocation_time
, this_update
and next_update
can be specified in either of Integer
or Time object. If they are Integer
, it is treated as the relative seconds from the current time.
static VALUE ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, VALUE reason, VALUE revtime, VALUE thisupd, VALUE nextupd, VALUE ext) { OCSP_BASICRESP *bs; OCSP_SINGLERESP *single; OCSP_CERTID *id; ASN1_TIME *ths = NULL, *nxt = NULL, *rev = NULL; int st, rsn = 0, error = 0, rstatus = 0; long i; VALUE tmp; GetOCSPBasicRes(self, bs); SafeGetOCSPCertId(cid, id); st = NUM2INT(status); if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */ ext = rb_check_array_type(ext); for (i = 0; i < RARRAY_LEN(ext); i++) OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext); } if (st == V_OCSP_CERTSTATUS_REVOKED) { rsn = NUM2INT(reason); tmp = rb_protect(add_status_convert_time, revtime, &rstatus); if (rstatus) goto err; rev = (ASN1_TIME *)tmp; } tmp = rb_protect(add_status_convert_time, thisupd, &rstatus); if (rstatus) goto err; ths = (ASN1_TIME *)tmp; if (!NIL_P(nextupd)) { tmp = rb_protect(add_status_convert_time, nextupd, &rstatus); if (rstatus) goto err; nxt = (ASN1_TIME *)tmp; } if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){ error = 1; goto err; } if(!NIL_P(ext)){ X509_EXTENSION *x509ext; for(i = 0; i < RARRAY_LEN(ext); i++){ x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i)); if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){ error = 1; goto err; } } } err: ASN1_TIME_free(ths); ASN1_TIME_free(nxt); ASN1_TIME_free(rev); if(error) ossl_raise(eOCSPError, NULL); if(rstatus) rb_jump_tag(rstatus); return self; }
Copies the nonce from request
into this response. Returns 1 on success and 0 on failure.
static VALUE ossl_ocspbres_copy_nonce(VALUE self, VALUE request) { OCSP_BASICRESP *bs; OCSP_REQUEST *req; int ret; GetOCSPBasicRes(self, bs); SafeGetOCSPReq(request, req); ret = OCSP_copy_nonce(bs, req); return INT2NUM(ret); }
Returns a SingleResponse
whose CertId matches with certificate_id
, or nil if this BasicResponse
does not contain it.
static VALUE ossl_ocspbres_find_response(VALUE self, VALUE target) { OCSP_BASICRESP *bs; OCSP_SINGLERESP *sres, *sres_new; OCSP_CERTID *id; int n; SafeGetOCSPCertId(target, id); GetOCSPBasicRes(self, bs); if ((n = OCSP_resp_find(bs, id, -1)) == -1) return Qnil; sres = OCSP_resp_get0(bs, n); sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres); if (!sres_new) ossl_raise(eOCSPError, "ASN1_item_dup"); return ossl_ocspsres_new(sres_new); }
Returns an Array of SingleResponse
for this BasicResponse
.
static VALUE ossl_ocspbres_get_responses(VALUE self) { OCSP_BASICRESP *bs; VALUE ret; int count, i; GetOCSPBasicRes(self, bs); count = OCSP_resp_count(bs); ret = rb_ary_new2(count); for (i = 0; i < count; i++) { OCSP_SINGLERESP *sres, *sres_new; sres = OCSP_resp_get0(bs, i); sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres); if (!sres_new) ossl_raise(eOCSPError, "ASN1_item_dup"); rb_ary_push(ret, ossl_ocspsres_new(sres_new)); } return ret; }
Signs this OCSP
response using the cert
, key
and optional digest
. This behaves in the similar way as OpenSSL::OCSP::Request#sign
.
flags
can include:
don't include certificates
don't set producedAt
use signer's public key hash as responderID
static VALUE ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self) { VALUE signer_cert, signer_key, certs, flags, digest; OCSP_BASICRESP *bs; X509 *signer; EVP_PKEY *key; STACK_OF(X509) *x509s = NULL; unsigned long flg = 0; const EVP_MD *md; int ret; rb_scan_args(argc, argv, "23", &signer_cert, &signer_key, &certs, &flags, &digest); GetOCSPBasicRes(self, bs); signer = GetX509CertPtr(signer_cert); key = GetPrivPKeyPtr(signer_key); if (!NIL_P(flags)) flg = NUM2INT(flags); if (NIL_P(digest)) md = EVP_sha1(); else md = GetDigestPtr(digest); if (NIL_P(certs)) flg |= OCSP_NOCERTS; else x509s = ossl_x509_ary2sk(certs); ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg); sk_X509_pop_free(x509s, X509_free); if (!ret) ossl_raise(eOCSPError, NULL); return self; }
Returns an Array of statuses for this response. Each status contains a CertificateId
, the status (0 for good, 1 for revoked, 2 for unknown), the reason for the status, the revocation time, the time of this update, the time for the next update and a list of OpenSSL::X509::Extensions.
This should be superseded by BasicResponse#responses
and find_response
that return SingleResponse
.
static VALUE ossl_ocspbres_get_status(VALUE self) { OCSP_BASICRESP *bs; OCSP_SINGLERESP *single; OCSP_CERTID *cid; ASN1_TIME *revtime, *thisupd, *nextupd; int status, reason; X509_EXTENSION *x509ext; VALUE ret, ary, ext; int count, ext_count, i, j; GetOCSPBasicRes(self, bs); ret = rb_ary_new(); count = OCSP_resp_count(bs); for(i = 0; i < count; i++){ single = OCSP_resp_get0(bs, i); if(!single) continue; revtime = thisupd = nextupd = NULL; status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd); if(status < 0) continue; if(!(cid = OCSP_CERTID_dup((OCSP_CERTID *)OCSP_SINGLERESP_get0_id(single)))) /* FIXME */ ossl_raise(eOCSPError, NULL); ary = rb_ary_new(); rb_ary_push(ary, ossl_ocspcertid_new(cid)); rb_ary_push(ary, INT2NUM(status)); rb_ary_push(ary, INT2NUM(reason)); rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil); rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil); rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil); ext = rb_ary_new(); ext_count = OCSP_SINGLERESP_get_ext_count(single); for(j = 0; j < ext_count; j++){ x509ext = OCSP_SINGLERESP_get_ext(single, j); rb_ary_push(ext, ossl_x509ext_new(x509ext)); } rb_ary_push(ary, ext); rb_ary_push(ret, ary); } return ret; }
Encodes this basic response into a DER-encoded string.
static VALUE ossl_ocspbres_to_der(VALUE self) { OCSP_BASICRESP *res; VALUE str; long len; unsigned char *p; GetOCSPBasicRes(self, res); if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0) ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); p = (unsigned char *)RSTRING_PTR(str); if (i2d_OCSP_BASICRESP(res, &p) <= 0) ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); return str; }
Verifies the signature of the response using the given certificates
and store
. This works in the similar way as OpenSSL::OCSP::Request#verify
.
static VALUE ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self) { VALUE certs, store, flags; OCSP_BASICRESP *bs; STACK_OF(X509) *x509s; X509_STORE *x509st; int flg, result; rb_scan_args(argc, argv, "21", &certs, &store, &flags); GetOCSPBasicRes(self, bs); x509st = GetX509StorePtr(store); flg = NIL_P(flags) ? 0 : NUM2INT(flags); x509s = ossl_x509_ary2sk(certs); #if (OPENSSL_VERSION_NUMBER < 0x1000202fL) || defined(LIBRESSL_VERSION_NUMBER) /* * OpenSSL had a bug that it doesn't use the certificates in x509s for * verifying the chain. This can be a problem when the response is signed by * a certificate issued by an intermediate CA. * * root_ca * | * intermediate_ca * |-------------| * end_entity ocsp_signer * * When the certificate hierarchy is like this, and the response contains * only ocsp_signer certificate, the following code wrongly fails. * * store = OpenSSL::X509::Store.new; store.add_cert(root_ca) * basic_response.verify([intermediate_ca], store) * * So add the certificates in x509s to the embedded certificates list first. * * This is fixed in OpenSSL 0.9.8zg, 1.0.0s, 1.0.1n, 1.0.2b. But it still * exists in LibreSSL 2.1.10, 2.2.9, 2.3.6, 2.4.1. */ if (!(flg & (OCSP_NOCHAIN | OCSP_NOVERIFY)) && sk_X509_num(x509s) && sk_X509_num(bs->certs)) { int i; bs = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs); if (!bs) { sk_X509_pop_free(x509s, X509_free); ossl_raise(eOCSPError, "ASN1_item_dup"); } for (i = 0; i < sk_X509_num(x509s); i++) { if (!OCSP_basic_add1_cert(bs, sk_X509_value(x509s, i))) { sk_X509_pop_free(x509s, X509_free); OCSP_BASICRESP_free(bs); ossl_raise(eOCSPError, "OCSP_basic_add1_cert"); } } result = OCSP_basic_verify(bs, x509s, x509st, flg); OCSP_BASICRESP_free(bs); } else { result = OCSP_basic_verify(bs, x509s, x509st, flg); } #else result = OCSP_basic_verify(bs, x509s, x509st, flg); #endif sk_X509_pop_free(x509s, X509_free); if (result <= 0) ossl_clear_error(); return result > 0 ? Qtrue : Qfalse; }