123456789_123456789_123456789_123456789_123456789_

Class: OpenSSL::OCSP::BasicResponse

Relationships & Source Files
Inherits: Object
Defined in: ext/openssl/ossl_ocsp.c

Overview

An BasicResponse contains the status of a certificate check which is created from an Request. A BasicResponse is more detailed than a Response.

Class Method Summary

Instance Method Summary

Constructor Details

.new(der_string = nil) ⇒ basic_response

Creates a new BasicResponse. If der_string is given, decodes der_string as DER.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 699

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;
}

Instance Method Details

#add_nonce(nonce = nil)

Adds nonce to this response. If no nonce was provided a random nonce will be added.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 752

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;
}

#add_status(certificate_id, status, reason, revocation_time, this_update, next_update, extensions) ⇒ basic_response

Adds a certificate status for certificate_id. status is the status, and must be one of these:

reason and revocation_time can be given only when status is 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.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 817

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);
    GetOCSPCertId(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;
}

#copy_nonce(request) ⇒ Integer

Copies the nonce from request into this response. Returns 1 on success and 0 on failure.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 730

static VALUE
ossl_ocspbres_copy_nonce(VALUE self, VALUE request)
{
    OCSP_BASICRESP *bs;
    OCSP_REQUEST *req;
    int ret;

    GetOCSPBasicRes(self, bs);
    GetOCSPReq(request, req);
    ret = OCSP_copy_nonce(bs, req);

    return INT2NUM(ret);
}

#find_response(certificate_id) ⇒ SingleResponse | nil

Returns a SingleResponse whose CertId matches with certificate_id, or nil if this BasicResponse does not contain it.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 982

static VALUE
ossl_ocspbres_find_response(VALUE self, VALUE target)
{
    OCSP_BASICRESP *bs;
    OCSP_SINGLERESP *sres, *sres_new;
    OCSP_CERTID *id;
    int n;

    GetOCSPCertId(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);
}

#initialize_copy(other)

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 672

static VALUE
ossl_ocspbres_initialize_copy(VALUE self, VALUE other)
{
    OCSP_BASICRESP *bs, *bs_old, *bs_new;

    rb_check_frozen(self);
    GetOCSPBasicRes(self, bs_old);
    GetOCSPBasicRes(other, bs);

    bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);
    if (!bs_new)
	ossl_raise(eOCSPError, "ASN1_item_dup");

    SetOCSPBasicRes(self, bs_new);
    OCSP_BASICRESP_free(bs_old);

    return self;
}

#responsesArray of SingleResponse

Returns an Array of SingleResponse for this BasicResponse.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 949

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;
}

#sign(cert, key, certs = nil, flags = 0, digest = nil) ⇒ self

Signs this ::OpenSSL::OCSP response using the cert, key and optional digest. This behaves in the similar way as Request#sign.

flags can include:

OpenSSL::OCSP::NOCERTS

don’t include certificates

OpenSSL::OCSP::NOTIME

don’t set producedAt

OpenSSL::OCSP::RESPID_KEY

use signer’s public key hash as responderID

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 1017

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 = ossl_evp_get_digestbyname(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;
}

#statusstatuses

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::Extension.

This should be superseded by #responses and #find_response that return SingleResponse.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 895

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;
}

#to_derString

Encodes this basic response into a DER-encoded string.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 1134

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;
}

#verify(certificates, store, flags = 0) ⇒ Boolean

Verifies the signature of the response using the given certificates and store. This works in the similar way as Request#verify.

[ GitHub ]

  
# File 'ext/openssl/ossl_ocsp.c', line 1058

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;
}