Spec-Zone.ru › Ruby 3.4
  1. OpenSSL::
  2. ASN1

module OpenSSL::ASN1

Абстрактная синтаксическая нотация один (или ASN.1) — это нотация для описания структур данных, определённая в ITU-T X.680. Сам стандарт ASN.1 не устанавливает правила кодирования или разбора, однако структуры данных ASN.1 обычно кодируются с использованием правил Distinguished Encoding (DER) или, реже, правил Basic Encoding (BER), описанных в ITU-T X.690. Кодировки DER и BER — это двоичные кодировки Tag-Length-Value (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 предоставляет атрибуты для чтения и установки tag, tag_class и, наконец, value конкретного элемента 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, если значение было помечено неявно или явно. Подробную информацию о подклассах и соответствиях между типами данных ASN.1 и объектами Ruby см. в документации Primitive.

Допустимые значения tagging

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

Допустимые значения tag_class

Можно создавать произвольные объекты ASN1Data, поддерживающие также классы тегов PRIVATE и APPLICATION. Допустимые значения атрибута 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[2] = "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

Константы

CLASS_TAG_MAP
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) → Array of 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)

  • header length: суммарная длина заголовков Tag и Length в байтах. (Integer)

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

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

  • 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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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