Spec-Zone.ru › Ruby 3.1

модуль OpenSSL::ASN1

Абстрактная система обозначений один (или ASN.1) — это синтаксис обозначений для описания структур данных и определен в ITU-T X.680. Сам ASN.1 не навязывает никаких правил кодирования или разбора, но обычно структуры данных ASN.1 кодируются с помощью Правил разграничения Encoding (DER) или реже с помощью Основных Encoding правил (BER), описанных в ITU-T X.690. Кодировки DER и BER — это двоичные кодировки тег-длина-значение (TLV), которые довольно компактны по сравнению с другими популярными форматами описания данных, такими как XML, JSON и т. д. Структуры данных ASN.1 очень распространены в криптографических приложениях, например, сертификаты открытых ключей X.509 или списки отзыва сертификатов (CRL) определены в ASN.1 и закодированы с помощью DER. ASN.1, DER и BER — это строительные блоки прикладной криптографии. Модуль ASN1 предоставляет необходимые классы для генерации структур данных ASN.1 и методов для их кодирования с помощью кодирования DER. Метод decode позволяет парсить произвольные данные, закодированные в BER/DER, в объект Ruby, который затем можно изменять и повторно кодировать по своему усмотрению.

Иерархия классов ASN.1

Базовый класс, представляющий структуры ASN.1, — это ASN1Data. ASN1Data предлагает атрибуты для чтения и задания тега, класса тега и, наконец, значения конкретного элемента ASN.1. При разборе любые помеченные значения (явные или неявные) будут представлены экземплярами ASN1Data, поскольку их «реальный тип» можно определить только с использованием внеполосной информации из объявления типа ASN.1. Поскольку эта информация обычно известна при кодировании типа, все подклассы ASN1Data предлагают дополнительный атрибут tagging, который позволяет кодировать значение неявно (:IMPLICIT) или явно (:EXPLICIT).

Constructive

Constructive — это, как следует из названия, базовый класс для всех конструктивных кодировок, то есть тех, которые состоят из нескольких значений, в отличие от «примитивных» кодировок с одним единственным значением. Значение Constructive всегда является Array.

ASN1::Set и ASN1::Sequence

Наиболее распространёнными конструктивными кодировками являются SET и SEQUENCE, поэтому существуют два подкласса Constructive, представляющие каждый из них.

Primitive

Это суперкласс всех примитивных значений. Сам Primitive не используется при разборе данных ASN.1, все значения являются либо экземплярами соответствующего подкласса Primitive, либо экземплярами ASN1Data, если значение было помечено неявно или явно. См. документацию по Primitive для получения подробной информации о подклассах и их соответствующих сопоставлениях типов данных ASN.1 с объектами Ruby.

Возможные значения для tagging

При построении объекта ASN1Data определение типа ASN.1 может потребовать, чтобы определенные элементы были помечены неявно или явно. Это можно сделать, вручную установив атрибут tagging для подклассов ASN1Data. Используйте символ :IMPLICIT для неявной маркировки и :EXPLICIT для явной маркировки элемента.

Возможные значения для tag_class

Возможна создание произвольных объектов ASN1Data, которые также поддерживают частный или прикладной класс тега. Возможные значения атрибута tag_class:

  • :UNIVERSAL (по умолчанию для непомеченных значений)

  • :CONTEXT_SPECIFIC (по умолчанию для помеченных значений)

  • :APPLICATION

  • :PRIVATE

Константы тегов

Для каждого универсального тега определена константа:

  • OpenSSL::ASN1::EOC (0)

  • OpenSSL::ASN1::BOOLEAN (1)

  • OpenSSL::ASN1::INTEGER (2)

  • OpenSSL::ASN1::BIT_STRING (3)

  • OpenSSL::ASN1::OCTET_STRING (4)

  • OpenSSL::ASN1::NULL (5)

  • OpenSSL::ASN1::OBJECT (6)

  • OpenSSL::ASN1::ENUMERATED (10)

  • OpenSSL::ASN1::UTF8STRING (12)

  • OpenSSL::ASN1::SEQUENCE (16)

  • OpenSSL::ASN1::SET (17)

  • OpenSSL::ASN1::NUMERICSTRING (18)

  • OpenSSL::ASN1::PRINTABLESTRING (19)

  • OpenSSL::ASN1::T61STRING (20)

  • OpenSSL::ASN1::VIDEOTEXSTRING (21)

  • OpenSSL::ASN1::IA5STRING (22)

  • OpenSSL::ASN1::UTCTIME (23)

  • OpenSSL::ASN1::GENERALIZEDTIME (24)

  • OpenSSL::ASN1::GRAPHICSTRING (25)

  • OpenSSL::ASN1::ISO64STRING (26)

  • OpenSSL::ASN1::GENERALSTRING (27)

  • OpenSSL::ASN1::UNIVERSALSTRING (28)

  • OpenSSL::ASN1::BMPSTRING (30)

UNIVERSAL_TAG_NAME константа

Array, хранящая имя заданного номера тега. Эти имена совпадают с именем константы тега, которая также определена, например, +UNIVERSAL_TAG_NAME = “INTEGER”+ и +OpenSSL::ASN1::INTEGER = 2+.

Пример использования

Декодирование и просмотр DER-закодированного файла

require 'openssl'
require 'pp'
der = File.binread('data.der')
asn1 = OpenSSL::ASN1.decode(der)
pp der

Создание структуры ASN.1 и её DER-кодирование

require 'openssl'
version = OpenSSL::ASN1::Integer.new(1)
# Explicitly 0-tagged implies context-specific tag class
serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC)
name = OpenSSL::ASN1::PrintableString.new('Data 1')
sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] )
der = sequence.to_der

Константы

UNIVERSAL_TAG_NAME

Array, хранящая имена тегов по индексу тега.

Открытые методы класса

OpenSSL::ASN1.decode(der) → ASN1Data Показать исходный код
static VALUE
ossl_asn1_decode(VALUE self, VALUE obj)
{
    VALUE ret;
    unsigned char *p;
    VALUE tmp;
    long len, read = 0, offset = 0;

    obj = ossl_to_der_if_possible(obj);
    tmp = rb_str_new4(StringValue(obj));
    p = (unsigned char *)RSTRING_PTR(tmp);
    len = RSTRING_LEN(tmp);
    ret = ossl_asn1_decode0(&p, len, &offset, 0, 0, &read);
    RB_GC_GUARD(tmp);
    int_ossl_decode_sanity_check(len, read, offset);
    return ret;
}

Декодирует значение, закодированное в BER или DER, и создает экземпляр ASN1Data. der может быть String или любым объектом, который имеет метод .to_der, преобразующий его в строку BER/DER.

Пример

der = File.binread('asn1data')
asn1 = OpenSSL::ASN1.decode(der)
OpenSSL::ASN1.decode_all(der) → Массив ASN1Data Показать исходный код
static VALUE
ossl_asn1_decode_all(VALUE self, VALUE obj)
{
    VALUE ary, val;
    unsigned char *p;
    long len, tmp_len = 0, read = 0, offset = 0;
    VALUE tmp;

    obj = ossl_to_der_if_possible(obj);
    tmp = rb_str_new4(StringValue(obj));
    p = (unsigned char *)RSTRING_PTR(tmp);
    len = RSTRING_LEN(tmp);
    tmp_len = len;
    ary = rb_ary_new();
    while (tmp_len > 0) {
        long tmp_read = 0;
        val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
        rb_ary_push(ary, val);
        read += tmp_read;
        tmp_len -= tmp_read;
    }
    RB_GC_GUARD(tmp);
    int_ossl_decode_sanity_check(len, read, offset);
    return ary;
}

Аналогично decode, с той разницей, что decode ожидает одно уникальное значение, представленное в der. decode_all, наоборот, декодирует последовательность последовательных значений BER/DER, расположенных в der, и возвращает их в виде массива.

Пример

ders = File.binread('asn1data_seq')
asn1_ary = OpenSSL::ASN1.decode_all(ders)
OpenSSL::ASN1.traverse(asn1) → nil Показать исходный код
static VALUE
ossl_asn1_traverse(VALUE self, VALUE obj)
{
    unsigned char *p;
    VALUE tmp;
    long len, read = 0, offset = 0;

    obj = ossl_to_der_if_possible(obj);
    tmp = rb_str_new4(StringValue(obj));
    p = (unsigned char *)RSTRING_PTR(tmp);
    len = RSTRING_LEN(tmp);
    ossl_asn1_decode0(&p, len, &offset, 0, 1, &read);
    RB_GC_GUARD(tmp);
    int_ossl_decode_sanity_check(len, read, offset);
    return Qnil;
}

Если задан блок, он выводит каждый из встреченных элементов. Параметры блока (в порядке следования):

  • depth: Глубина рекурсии, плюс один при каждом встреченном конструктивном значении (Integer)

  • offset: Текущий байтовый смещение (Integer)

  • длина заголовка: Общая длина в байтах заголовков тега и длины. (Integer)

  • length: Общая оставшаяся длина всех данных (Integer)

  • constructed: Является ли это значение конструктивным или нет (Булево)

  • tag_class: Текущий класс тега (Symbol)

  • tag: Текущий номер тега (Integer)

Пример

der = File.binread('asn1data.der')
OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag|
  puts "Depth: #{depth} Offset: #{offset} Length: #{length}"
  puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}"
end

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