Spec-Zone.ru › Ruby 2.3

модуль OpenSSL::ASN1

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

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

Массив, хранящий имя заданного номера тега. Эти имена такие же, как имя константы тега, которая также определена, например, 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 может быть String или любым объектом, имеющим метод #to_der, преобразующий его в String, закодированное в 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: Глубина рекурсии, плюс один для каждого встреченного составного значения (число)

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

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

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

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

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

  • tag: Текущий тег (число)

Пример

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