类 OpenSSL::Timestamp::Response

对从时间戳服务器接收到的关联 Request 后返回的时间戳响应的不可变且只读表示。允许访问有关响应的特定信息,但也允许验证 Response

常量

GRANTED

表示成功响应。等于 0

GRANTED_WITH_MODS

表示可能包含来自初始请求的修改的成功响应。等于 1

REJECTION

表示失败。没有创建时间戳令牌。等于 2

REVOCATION_NOTIFICATION

表示失败。没有创建时间戳令牌。证书已被吊销。等于 5

REVOCATION_WARNING

表示失败。没有创建时间戳令牌。证书即将吊销。等于 4

WAITING

表示失败。没有创建时间戳令牌。等于 3

公共类方法

OpenSSL::Timestamp::Response.new(file) → response 点击以切换源代码
OpenSSL::Timestamp::Response.new(string) → response

Filestring 参数创建 Response,相应的 Filestring 必须是 DER 编码的。请注意,Response 是一个不可变的只读类。如果您想创建时间戳,请改为参考 Factory

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

公共实例方法

failure_info → nil 或 symbol 点击以切换源代码

在没有创建时间戳令牌的情况下,此字段包含有关响应创建失败原因的更多信息。该方法返回 nil(请求成功且已创建时间戳令牌)或以下之一

  • :BAD_ALG - 表示时间戳服务器拒绝 Request 中使用的消息摘要算法

  • :BAD_REQUEST - 表示时间戳服务器无法正确处理 Request

  • :BAD_DATA_FORMAT - 表示时间戳服务器无法解析 Request 中的某些数据

  • :TIME_NOT_AVAILABLE - 表示服务器无法访问其时间源

  • :UNACCEPTED_POLICY - 表示时间戳服务器不识别或不支持请求的策略标识符

  • :UNACCEPTED_EXTENSIION - 表示 Request 中的扩展名不受时间戳服务器支持

  • :ADD_INFO_NOT_AVAILABLE - 表示请求的附加信息要么不被理解,要么当前不可用

  • :SYSTEM_FAILURE - Timestamp 创建失败,因为时间戳服务器上发生了内部错误

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 (从不为 nil) 点击以切换源代码

返回 GRANTEDGRANTED_WITH_MODSREJECTIONWAITINGREVOCATION_WARNINGREVOCATION_NOTIFICATION 之一。仅当 status 等于 GRANTEDGRANTED_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 → 字符串数组或 nil 点击以切换源代码

在失败的情况下,此字段可能包含一个字符串数组,进一步描述了失败的来源。

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 点击以切换源代码

以 DER 编码形式返回 Response

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 或 OpenSSL::PKCS7 点击以切换源代码

如果存在时间戳令牌,则以 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 或 OpenSSL::Timestamp::TokenInfo 点击以切换源代码

获取响应的令牌信息(如果存在)。

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 或 nil 点击以切换源代码

如果 Request 指定请求 TSA 证书(Request#cert_requested = true),则此字段包含时间戳颁发机构的证书。

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 点击以切换源代码
verify(Request, root_store, [intermediate_cert]) → Response

通过检查签名、验证 tsa_certificate 隐含的证书链以及检查与给定 Request 的一致性来验证时间戳令牌。必需参数是与该 Response 关联的 Request,以及受信任根的 OpenSSL::X509::Store

可以可选地提供中间证书以创建证书链。这些中间证书必须都是 OpenSSL::X509::Certificate 的实例。

如果验证失败,可能会引发几种类型的异常

  • TypeError 如果类型不匹配

  • TimestampError 如果时间戳令牌本身有问题,如果它不符合 Request,或者如果时间戳证书链的验证失败。

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