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,但可能会返回成功创建的错误响应。