Spec-Zone.ru › Ruby 2.7

модуль OpenSSL::ASN1

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

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, которые также поддерживают класс тега 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 = “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;
}

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

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

  • смещение: текущее смещение байта (Integer)

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

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

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

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

  • тег: текущий номер тега (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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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