Spec-Zone.ru › Ruby 2.5

модуль OpenSSL::ASN1

Абстрактная синтаксическая нотация один (или ASN.1) — это синтаксис нотации для описания структур данных и определён в ITU-T X.680. Сам ASN.1 не предписывает никаких правил кодирования или разбора, но обычно структуры данных ASN.1 кодируются с помощью Правил отличительного кодирования (DER) или реже Правил базового кодирования (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 предлагает атрибуты для чтения и установки тега, класса тега и, наконец, значения конкретного элемента ASN.1. При разборе любые помеченные значения (явные или неявные) будут представлены экземплярами ASN1Data, поскольку их «реальный тип» может быть определён только с помощью внеполосной информации из объявления типа ASN.1. Поскольку эта информация обычно известна при кодировании типа, все подклассы ASN1Data предлагают дополнительный атрибут tagging, который позволяет кодировать значение неявно (:IMPLICIT) или явно (:EXPLICIT).

Конструктивные

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

ASN1::Set и ASN1::Sequence

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

Примитивный

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

Возможные значения для 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

Массив, который хранит имя заданного номера тега. Эти имена совпадают с именем константы тега, которая также определена, например, 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

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

Публичные методы класса

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 может быть строкой или любым объектом, имеющим метод .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;
}

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

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

  • смещение: Текущее байтовое смещение (целое число)

  • длина заголовка: Объединённая длина в байтах заголовков тега и длины. (целое число)

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

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

  • класс тега: Текущий класс тега (символ)

  • тег: Текущий номер тега (целое число)

Пример

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

Spec-Zone.ru

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