class OpenSSL::Timestamp::Factory
Используется для генерации Response с нуля.
Обратите внимание, что реализация всегда будет применять и отдавать предпочтение идентификатору политики, указанному в запросе, над идентификатором политики по умолчанию, указанным в Factory. Вследствие этого, 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.
call-seq:
factory.default_policy_id = "string" -> string factory.default_policy_id -> string or nil
serial_number
Устанавливает или извлекает порядковый номер, который будет использоваться для создания отметки времени. Должен быть задан для создания отметки времени.
call-seq:
factory.serial_number = number -> number factory.serial_number -> number or nil
gen_time
Устанавливает или извлекает значение Time, которое будет использоваться в Response. Должен быть задан для создания отметки времени.
call-seq:
factory.gen_time = Time -> Time factory.gen_time -> Time or nil
additional_certs
Устанавливает или извлекает дополнительные сертификаты помимо сертификата маркировки времени (например, промежуточные сертификаты), которые будут добавлены к Response. Должен быть Array из OpenSSL::X509::Certificate.
call-seq:
factory.additional_certs = [cert1, cert2] -> [ cert1, cert2 ] factory.additional_certs -> array or nil
allowed_digests
Устанавливает или извлекает алгоритмы хеширования, для которых фабрика разрешает создавать отметки времени. Известные уязвимые или слабые алгоритмы должны быть запрещены, где это возможно. Должен быть Array из String или экземпляров подклассов OpenSSL::Digest.
call-seq:
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;
} Создаёт Response с помощью OpenSSL::PKey, OpenSSL::X509::Certificate и Request.
Обязательные параметры для создания отметки времени, которые должны быть заданы в запросе:
Обязательные параметры, которые должны быть заданы в фабрике:
Кроме того, должно быть задано либо Request#policy_id, либо Factory#default_policy_id.
Вызывает исключение TimestampError в случае сбоя создания, хотя успешно созданные ответы об ошибках могут быть возвращены.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.