Indicates a successful response. Equal to 0
.
Indicates a successful response that probably contains modifications from the initial request. Equal to 1
.
Indicates a failure. No timestamp token was created. Equal to 2
.
Indicates a failure. No timestamp token was created. Equal to 3
.
Indicates a failure. No timestamp token was created. Revocation of a certificate is imminent. Equal to 4
.
Indicates a failure. No timestamp token was created. A certificate has been revoked. Equal to 5
.
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;
}
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.");
}
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_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);
}
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_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;
}
In cases of failure this field may contain an array of strings further describing the origin of the failure.
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);
}
Returns the Response
in DER-encoded form.
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;
}
If a timestamp token is present, this returns it in the form of a OpenSSL::PKCS7
.
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;
}
Get the response’s token info if present.
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);
}
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_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;
}
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 theRequest
, or if validation of the timestamp certificate chain fails.