class OpenSSL::Timestamp::Factory
用于从头生成一个 Response。
请记住,实现始终会应用并优先使用请求中给出的策略对象标识符,而不是 Factory 中指定的默认策略 ID。因此,只有当没有给出 Request#policy_id 时,才会应用 default_policy_id。但也意味着,在创建 Response 之前,需要手动检查请求中的策略标识符,例如检查它是否符合一组特定的可接受策略。
除了时间戳证书之外,还可以添加证书(OpenSSL::X509::Certificate 的实例),如果 Request#cert_requested? 为 true,则会将这些证书包含在生成的时间戳令牌中。理想情况下,还应该包括任何中间证书(可以省略根证书 - 为了信任它,任何验证方都必须拥有它)。这简化了时间戳的验证,因为这些中间证书“已经存在”,无需再将其作为外部参数传递给 Response#verify,从而最大限度地减少验证所需的外部资源。
示例:包含(不受信任的)中间证书¶ ↑
假设我们收到了一个时间戳请求,该请求已将 Request#policy_id 设置为 nil,并将 Request#cert_requested? 设置为 true。原始请求字节存储在名为 req_raw 的变量中。我们仍然希望集成必要的中间证书(在 inter1.cer 和 inter2.cer 中),以简化对生成的 Response 的验证。ts.p12 是一个与 PKCS#12 兼容的文件,其中包含私钥和时间戳证书。
req = OpenSSL::Timestamp::Request.new(raw_bytes) p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd') inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer')) inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer')) fac = OpenSSL::Timestamp::Factory.new fac.gen_time = Time.now fac.serial_number = 1 fac.allowed_digests = ["sha256", "sha384", "sha512"] #needed because the Request contained no policy identifier fac.default_policy_id = '1.2.3.4.5' fac.additional_certificates = [ inter1, inter2 ] timestamp = fac.create_timestamp(p12.key, p12.certificate, req)
属性¶ ↑
default_policy_id¶ ↑
如果 Request 中存在 Request#policy_id,则始终优先使用它,只有当 Request#policy_id 为 nil 时才会使用 default_policy。如果两者都不存在,则在尝试创建 Response 时将引发 TimestampError。
调用序列
factory.default_policy_id = "string" -> string factory.default_policy_id -> string or nil
serial_number¶ ↑
设置或检索用于创建时间戳的序列号。必须存在才能创建时间戳。
调用序列
factory.serial_number = number -> number factory.serial_number -> number or nil
gen_time¶ ↑
设置或检索要在 Response 中使用的 Time 值。必须存在才能创建时间戳。
调用序列
factory.gen_time = Time -> Time factory.gen_time -> Time or nil
additional_certs¶ ↑
设置或检索除了时间戳证书之外,要添加到 Response 中的其他证书(例如中间证书)。必须是 Array 类型的 OpenSSL::X509::Certificate。
调用序列
factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ] factory.additional_certs -> array or nil
allowed_digests¶ ↑
设置或检索工厂允许为其创建时间戳的摘要算法。应尽可能不允许已知的易受攻击或弱算法。必须是 String 或 OpenSSL::Digest 子类实例的 Array。
调用序列
factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ]
factory.allowed_digests                                               -> array or nil
  属性
公共实例方法
源代码
static VALUE
ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
{
    VALUE serial_number, def_policy_id, gen_time, additional_certs, allowed_digests;
    VALUE str;
    STACK_OF(X509) *inter_certs;
    VALUE tsresp, ret = Qnil;
    EVP_PKEY *sign_key;
    X509 *tsa_cert;
    TS_REQ *req;
    TS_RESP *response = NULL;
    TS_RESP_CTX *ctx = NULL;
    BIO *req_bio;
    ASN1_INTEGER *asn1_serial = NULL;
    ASN1_OBJECT *def_policy_id_obj = NULL;
    long lgen_time;
    const char * err_msg = NULL;
    int status = 0;
    tsresp = NewTSResponse(cTimestampResponse);
    tsa_cert = GetX509CertPtr(certificate);
    sign_key = GetPrivPKeyPtr(key);
    GetTSRequest(request, req);
    gen_time = ossl_tsfac_get_gen_time(self);
    if (!rb_obj_is_instance_of(gen_time, rb_cTime)) {
        err_msg = "@gen_time must be a Time.";
        goto end;
    }
    lgen_time = NUM2LONG(rb_funcall(gen_time, rb_intern("to_i"), 0));
    serial_number = ossl_tsfac_get_serial_number(self);
    if (NIL_P(serial_number)) {
        err_msg = "@serial_number must be set.";
        goto end;
    }
    asn1_serial = num_to_asn1integer(serial_number, NULL);
    def_policy_id = ossl_tsfac_get_default_policy_id(self);
    if (NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {
        err_msg = "No policy id in the request and no default policy set";
        goto end;
    }
    if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {
        def_policy_id_obj = (ASN1_OBJECT*)rb_protect(obj_to_asn1obj_i, (VALUE)def_policy_id, &status);
        if (status)
            goto end;
    }
    if (!(ctx = TS_RESP_CTX_new())) {
        err_msg = "Memory allocation failed.";
        goto end;
    }
    TS_RESP_CTX_set_serial_cb(ctx, ossl_tsfac_serial_cb, &asn1_serial);
    if (!TS_RESP_CTX_set_signer_cert(ctx, tsa_cert)) {
        err_msg = "Certificate does not contain the timestamping extension";
        goto end;
    }
    additional_certs = ossl_tsfac_get_additional_certs(self);
    if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {
        inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status);
        if (status)
                goto end;
        /* this dups the sk_X509 and ups each cert's ref count */
        TS_RESP_CTX_set_certs(ctx, inter_certs);
        sk_X509_pop_free(inter_certs, X509_free);
    }
    TS_RESP_CTX_set_signer_key(ctx, sign_key);
    if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req))
        TS_RESP_CTX_set_def_policy(ctx, def_policy_id_obj);
    if (TS_REQ_get_policy_id(req))
        TS_RESP_CTX_set_def_policy(ctx, TS_REQ_get_policy_id(req));
    TS_RESP_CTX_set_time_cb(ctx, ossl_tsfac_time_cb, &lgen_time);
    allowed_digests = ossl_tsfac_get_allowed_digests(self);
    if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {
        int i;
        VALUE rbmd;
        const EVP_MD *md;
        for (i = 0; i < RARRAY_LEN(allowed_digests); i++) {
            rbmd = rb_ary_entry(allowed_digests, i);
            md = (const EVP_MD *)rb_protect(ossl_evp_get_digestbyname_i, rbmd, &status);
            if (status)
                goto end;
            TS_RESP_CTX_add_md(ctx, md);
        }
    }
    str = rb_protect(ossl_to_der, request, &status);
    if (status)
        goto end;
    req_bio = (BIO*)rb_protect(ossl_obj2bio_i, (VALUE)&str, &status);
    if (status)
        goto end;
    response = TS_RESP_create_response(ctx, req_bio);
    BIO_free(req_bio);
    if (!response) {
        err_msg = "Error during response generation";
        goto end;
    }
    /* bad responses aren't exceptional, but openssl still sets error
     * information. */
    ossl_clear_error();
    SetTSResponse(tsresp, response);
    ret = tsresp;
end:
    ASN1_INTEGER_free(asn1_serial);
    ASN1_OBJECT_free(def_policy_id_obj);
    TS_RESP_CTX_free(ctx);
    if (err_msg)
        rb_exc_raise(ossl_make_error(eTimestampError, rb_str_new_cstr(err_msg)));
    if (status)
        rb_jump_tag(status);
    return ret;
}
          借助 OpenSSL::PKey、OpenSSL::X509::Certificate 和 Request 创建 Response。
需要在请求中设置的创建时间戳的强制参数
需要在工厂中设置的强制参数
此外,必须设置 Request#policy_id 或 Factory#default_policy_id 中的一个。
如果创建失败,则引发 TimestampError,但可能会返回成功创建的错误响应。