Spec-Zone.ru › Ruby 3

class OpenSSL::Timestamp::Factory

Parent:
Объект

Используется для генерации 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.open('ts.p12', 'rb'), 'pwd')
inter1 = OpenSSL::X509::Certificate.new(File.open('inter1.cer', 'rb')
inter2 = OpenSSL::X509::Certificate.new(File.open('inter2.cer', 'rb')
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

Атрибуты

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((VALUE (*)(VALUE))obj_to_asn1obj, (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((VALUE (*)(VALUE))ossl_evp_get_digestbyname, 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((VALUE (*)(VALUE))ossl_obj2bio, (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)
        ossl_raise(eTimestampError, 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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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