# class OpenSSL::Timestamp::Response

Immutable and read-only representation of a timestamp response returned from a timestamp server after receiving an associated `Request`. Allows access to specific information about the response but also allows to verify the `Response`.

### Constants

GRANTED

  Indicates a successful response. Equal to `0`.

GRANTED_WITH_MODS

  Indicates a successful response that probably contains modifications from the initial request. Equal to `1`.

REJECTION

  Indicates a failure. No timestamp token was created. Equal to `2`.

REVOCATION_NOTIFICATION

  Indicates a failure. No timestamp token was created. A certificate has been revoked. Equal to `5`.

REVOCATION_WARNING

  Indicates a failure. No timestamp token was created. Revocation of a certificate is imminent. Equal to `4`.

WAITING

  Indicates a failure. No timestamp token was created. Equal to `3`.

### Public Class Methods

OpenSSL::Timestamp::Response.new(file) → response click to toggle source
OpenSSL::Timestamp::Response.new(string) → response

Creates a `Response` from a `File` or `string` parameter, the corresponding `File` or `string` must be DER-encoded. Please note that `Response` is an immutable read-only class. If you’d like to create timestamps please refer to `Factory` instead.

    static VALUE
    ossl_ts_resp_initialize(VALUE self, VALUE der)
    {
        TS_RESP *ts_resp = DATA_PTR(self);
        BIO *in;

        der = ossl_to_der_if_possible(der);
        in  = ossl_obj2bio(&der);
        ts_resp = d2i_TS_RESP_bio(in, &ts_resp);
        BIO_free(in);
        if (!ts_resp) {
            DATA_PTR(self) = NULL;
            ossl_raise(eTimestampError, "Error when decoding the timestamp response");
        }
        DATA_PTR(self) = ts_resp;

        return self;
    }

### Public Instance Methods

failure_info → nil or symbol click to toggle source

In cases no timestamp token has been created, this field contains further info about the reason why response creation failed. The method returns either nil (the request was successful and a timestamp token was created) or one of the following:

- :BAD_ALG - Indicates that the timestamp server rejects the message imprint algorithm used in the `Request`

- :BAD_REQUEST - Indicates that the timestamp server was not able to process the `Request` properly

- :BAD_DATA_FORMAT - Indicates that the timestamp server was not able to parse certain data in the `Request`

- :TIME_NOT_AVAILABLE - Indicates that the server could not access its time source

- :UNACCEPTED_POLICY - Indicates that the requested policy identifier is not recognized or supported by the timestamp server

- :UNACCEPTED_EXTENSIION - Indicates that an extension in the `Request` is not supported by the timestamp server

- :ADD_INFO_NOT_AVAILABLE -Indicates that additional information requested is either not understood or currently not available

- :SYSTEM_FAILURE - `Timestamp` creation failed due to an internal error that occurred on the timestamp server

    static VALUE
    ossl_ts_resp_get_failure_info(VALUE self)
    {
        TS_RESP *resp;
        TS_STATUS_INFO *si;

        /* The ASN1_BIT_STRING_get_bit changed from 1.0.0. to 1.1.0, making this
         * const. */
        #if defined(HAVE_TS_STATUS_INFO_GET0_FAILURE_INFO)
        const ASN1_BIT_STRING *fi;
        #else
        ASN1_BIT_STRING *fi;
        #endif

        GetTSResponse(self, resp);
        si = TS_RESP_get_status_info(resp);
        fi = TS_STATUS_INFO_get0_failure_info(si);
        if (!fi)
            return Qnil;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_ALG))
            return sBAD_ALG;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_REQUEST))
            return sBAD_REQUEST;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_DATA_FORMAT))
            return sBAD_DATA_FORMAT;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_TIME_NOT_AVAILABLE))
            return sTIME_NOT_AVAILABLE;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_POLICY))
            return sUNACCEPTED_POLICY;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_EXTENSION))
            return sUNACCEPTED_EXTENSION;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_ADD_INFO_NOT_AVAILABLE))
            return sADD_INFO_NOT_AVAILABLE;
        if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_SYSTEM_FAILURE))
            return sSYSTEM_FAILURE;

        ossl_raise(eTimestampError, "Unrecognized failure info.");
    }

status → BN (never nil) click to toggle source

Returns one of `GRANTED`, `GRANTED_WITH_MODS`, `REJECTION`, `WAITING`, `REVOCATION_WARNING` or `REVOCATION_NOTIFICATION`. A timestamp token has been created only in case `status` is equal to `GRANTED` or `GRANTED_WITH_MODS`.

    static VALUE
    ossl_ts_resp_get_status(VALUE self)
    {
        TS_RESP *resp;
        TS_STATUS_INFO *si;
        const ASN1_INTEGER *st;

        GetTSResponse(self, resp);
        si = TS_RESP_get_status_info(resp);
        st = TS_STATUS_INFO_get0_status(si);

        return asn1integer_to_num(st);
    }

status_text → Array of strings or nil click to toggle source

In cases of failure this field may contain an array of strings further describing the origin of the failure.

    static VALUE
    ossl_ts_resp_get_status_text(VALUE self)
    {
        TS_RESP *resp;
        TS_STATUS_INFO *si;
        const STACK_OF(ASN1_UTF8STRING) *text;
        ASN1_UTF8STRING *current;
        int i;
        VALUE ret = rb_ary_new();

        GetTSResponse(self, resp);
        si = TS_RESP_get_status_info(resp);
        if ((text = TS_STATUS_INFO_get0_text(si))) {
            for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) {
                current = sk_ASN1_UTF8STRING_value(text, i);
                rb_ary_push(ret, asn1str_to_str(current));
            }
        }

        return ret;
    }

to_der → string click to toggle source

Returns the `Response` in DER-encoded form.

    static VALUE
    ossl_ts_resp_to_der(VALUE self)
    {
        TS_RESP *resp;

        GetTSResponse(self, resp);
        return asn1_to_der((void *)resp, (int (*)(void *, unsigned char **))i2d_TS_RESP);
    }

token → nil or OpenSSL::PKCS7 click to toggle source

If a timestamp token is present, this returns it in the form of a `OpenSSL::PKCS7`.

    static VALUE
    ossl_ts_resp_get_token(VALUE self)
    {
        TS_RESP *resp;
        PKCS7 *p7, *copy;
        VALUE obj;

        GetTSResponse(self, resp);
        if (!(p7 = TS_RESP_get_token(resp)))
            return Qnil;

        obj = NewPKCS7(cPKCS7);

        if (!(copy = PKCS7_dup(p7)))
            ossl_raise(eTimestampError, NULL);

        SetPKCS7(obj, copy);

        return obj;
    }

token_info → nil or OpenSSL::Timestamp::TokenInfo click to toggle source

Get the response’s token info if present.

    static VALUE
    ossl_ts_resp_get_token_info(VALUE self)
    {
        TS_RESP *resp;
        TS_TST_INFO *info, *copy;
        VALUE obj;

        GetTSResponse(self, resp);
        if (!(info = TS_RESP_get_tst_info(resp)))
            return Qnil;

        obj = NewTSTokenInfo(cTimestampTokenInfo);

        if (!(copy = TS_TST_INFO_dup(info)))
            ossl_raise(eTimestampError, NULL);

        SetTSTokenInfo(obj, copy);

        return obj;
    }

tsa_certificate → OpenSSL::X509::Certificate or nil click to toggle source

If the `Request` specified to request the TSA certificate (Request#cert_requested = true), then this field contains the certificate of the timestamp authority.

    static VALUE
    ossl_ts_resp_get_tsa_certificate(VALUE self)
    {
        TS_RESP *resp;
        PKCS7 *p7;
        PKCS7_SIGNER_INFO *ts_info;
        X509 *cert;

        GetTSResponse(self, resp);
        if (!(p7 = TS_RESP_get_token(resp)))
            return Qnil;
        ts_info = sk_PKCS7_SIGNER_INFO_value(p7->d.sign->signer_info, 0);
        cert = PKCS7_cert_from_signer_info(p7, ts_info);
        if (!cert)
            return Qnil;
        return ossl_x509_new(cert);
    }

verify(Request, root_store) → Response click to toggle source
verify(Request, root_store, [intermediate_cert]) → Response

Verifies a timestamp token by checking the signature, validating the certificate chain implied by `tsa_certificate` and by checking conformance to a given `Request`. Mandatory parameters are the `Request` associated to this `Response`, and an `OpenSSL::X509::Store` of trusted roots.

Intermediate certificates can optionally be supplied for creating the certificate chain. These intermediate certificates must all be instances of `OpenSSL::X509::Certificate`.

If validation fails, several kinds of exceptions can be raised:

- `TypeError` if types don’t fit

- `TimestampError` if something is wrong with the timestamp token itself, if it is not conformant to the `Request`, or if validation of the timestamp certificate chain fails.

    static VALUE
    ossl_ts_resp_verify(int argc, VALUE *argv, VALUE self)
    {
        VALUE ts_req, store, intermediates;
        TS_RESP *resp;
        TS_REQ *req;
        X509_STORE *x509st;
        TS_VERIFY_CTX *ctx;
        STACK_OF(X509) *x509inter = NULL;
        PKCS7* p7;
        X509 *cert;
        int status, i, ok;

        rb_scan_args(argc, argv, "21", &ts_req, &store, &intermediates);

        GetTSResponse(self, resp);
        GetTSRequest(ts_req, req);
        x509st = GetX509StorePtr(store);

        if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL))) {
            ossl_raise(eTimestampError, "Error when creating the verification context.");
        }

        if (!NIL_P(intermediates)) {
            x509inter = ossl_protect_x509_ary2sk(intermediates, &status);
            if (status) {
                TS_VERIFY_CTX_free(ctx);
                rb_jump_tag(status);
            }
        } else if (!(x509inter = sk_X509_new_null())) {
            TS_VERIFY_CTX_free(ctx);
            ossl_raise(eTimestampError, "sk_X509_new_null");
        }

        if (!(p7 = TS_RESP_get_token(resp))) {
            TS_VERIFY_CTX_free(ctx);
            sk_X509_pop_free(x509inter, X509_free);
            ossl_raise(eTimestampError, "TS_RESP_get_token");
        }
        for (i=0; i < sk_X509_num(p7->d.sign->cert); i++) {
            cert = sk_X509_value(p7->d.sign->cert, i);
            if (!sk_X509_push(x509inter, cert)) {
                sk_X509_pop_free(x509inter, X509_free);
                TS_VERIFY_CTX_free(ctx);
                ossl_raise(eTimestampError, "sk_X509_push");
            }
            X509_up_ref(cert);
        }

        TS_VERIFY_CTX_set_certs(ctx, x509inter);
        TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE);
        TS_VERIFY_CTX_set_store(ctx, x509st);

        ok = TS_RESP_verify_response(ctx, resp);
        /*
         * TS_VERIFY_CTX_set_store() call above does not increment the reference
         * counter, so it must be unset before TS_VERIFY_CTX_free() is called.
         */
        TS_VERIFY_CTX_set_store(ctx, NULL);
        TS_VERIFY_CTX_free(ctx);

        if (!ok)
            ossl_raise(eTimestampError, "TS_RESP_verify_response");

        return self;
    }