类 OpenSSL::Timestamp::Factory
用于从头开始生成 Response
。
请注意,实现将始终应用并优先考虑请求中给出的策略对象标识符,而不是 Factory
中指定的默认策略 ID。因此,default_policy_id
仅在没有给出 Request#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#policy_id
如果存在于 Request
中,将始终优先于此,只有当 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
中。必须是 OpenSSL::X509::Certificate
的数组。
调用序列
factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ] factory.additional_certs -> array or nil
allowed_digests
¶ ↑
设置或检索工厂允许为其创建时间戳的摘要算法。尽可能不应允许已知的易受攻击或弱算法。必须是字符串或 OpenSSL::Digest
子类实例的数组。
调用序列
factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ] factory.allowed_digests -> array or nil
属性
公共实例方法
使用 OpenSSL::PKey
、OpenSSL::X509::Certificate
和 Request
创建 Response
。
需要在 Request 中设置的时间戳创建的强制参数
需要在 Factory 中设置的强制参数
此外,必须设置 Request#policy_id
或 Factory#default_policy_id
之一。
如果创建失败,则会引发 TimestampError
,尽管可能会返回成功创建的错误响应。
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; }