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

модуль OpenSSL::ASN1

Абстрактная синтаксическая нотация один (или ASN.1) — это нотация для описания структур данных, определённая в ITU-T X.680. Сам стандарт ASN.1 не устанавливает правила кодирования или разбора, однако структуры данных ASN.1 обычно кодируются с использованием правил Distinguished Encoding (DER) или, реже, правил Basic 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 предоставляет атрибуты для чтения и задания 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

Константы

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: суммарная длина заголовков тега и длины в байтах (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