Spec-Zone.ru › Ruby 3.1

класс 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.

вызов:

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

Устанавливает или получает значение Time, которое будет использоваться в Response. Должен присутствовать для создания отметки времени.

вызов:

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

Устанавливает или получает алгоритмы хеширования, которые фабрика разрешает использовать для создания отметок времени. Известные уязвимые или слабые алгоритмы, где это возможно, должны быть запрещены. Должен быть массивом Array String или экземпляров подклассов OpenSSL::Digest.

вызов:

factory.allowed_digests = ["sha1", OpenSSL::Digest.new('SHA256').new] -> [ "sha1", OpenSSL::Digest) ]
factory.allowed_digests                                               -> array or nil

Атрибуты

additional_certs[RW]
allowed_digests[RW]
default_policy_id[RW]
gen_time[RW]
serial_number[RW]

Публичные методы экземпляра

create_timestamp(key, certificate, request) → Response Показать исходный код
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#algorithm

  • Request#message_imprint

Обязательные параметры, которые должны быть заданы в фабрике:

  • Factory#serial_number

  • Factory#gen_time

  • Factory#allowed_digests

Кроме того, должен быть задан либо Request#policy_id, либо Factory#default_policy_id.

Выбрасывает TimestampError, если создание завершится неудачно, хотя могут быть возвращены успешно созданные ответы об ошибках.

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API