Как АСН.1 кодируют идентификатор объекта?

У меня возникли проблемы с пониманием основных понятий ASN.1.

Если тип является OID, действительно ли соответствующее число кодируется в двоичных данных?

например, в этом определении:

id-ad-ocsp         OBJECT IDENTIFIER ::= { id-ad 1 }

соответствующий 1.3.6.1.5.5.7.48.1 кодируется в двоичном именно такой?

Я спрашиваю это, потому что я пытаюсь понять конкретное значение, которое я вижу в файле DER (сертификат), который является 04020500, и я не знаю, как это интерпретировать.

3 ответов


да, OID кодируется в двоичных данных. OID 1.3.6.1.5.5.7.48.1, который вы упоминаете, становится 2b 06 01 05 05 07 30 01 (первые два числа кодируются в одном байте, все остальные номера кодируются в одном байте, потому что все они меньше 128).

найдено хорошее описание кодировки OID здесь.

но лучший способ проанализировать ваш ASN.1 Данные должны вставляться в онлайн-декодер, например http://lapo.it/asn1js/.


если все ваши цифры меньше или равно 127, то вы очень повезло, потому что они могут быть представлены с помощью одного восьмиразрядного байта каждый. Хитрая часть, когда у вас есть большие числа, которые являются общими, такие как 1.2.840.113549.1.1.5 (sha1WithRsaEncryption). Эти примеры сосредоточены на декодировании, но кодирование как раз наоборот.

1. Первые две "цифры" представлены одним байтом

вы можете расшифровать путем чтение первого байта в целое число

var firstByteNumber = 42;
var firstDigit = firstByteNumber / 40;
var secondDigit = firstByteNumber % 40;

производит значения

1.2

2. Последующие байты представлены с помощью Количество Переменной Длины, также называемый базой 128.

VLQ имеет две формы,

Short Form - если октет начинается с 0, то он просто представлен с использованием оставшихся 7 бит.

длинная форма-Если октет начинается с 1 (самый значительный бит), объедините следующие 7 бит этого октета плюс 7 бит каждого последующего октета, пока вы не столкнетесь с октетом с 0 в качестве наиболее значимого бита (это отмечает последний октет).

значение 840 будет представлено следующими двумя байтами,

10000110
01001000

Combine to 00001101001000 and read as int.

отличный ресурс для кодирования BER,http://luca.ntop.org/Teaching/Appunti/asn1.html

первый октет имеет значение 40 * value1 + value2. (Это однозначно, поскольку value1 ограничено значениями 0, 1 и 2; value2 ограничено диапазон от 0 до 39, когда значение 1 равно 0 или 1; и, согласно X. 208, n равно всегда как минимум 2.)

следующие октеты, если таковые имеются, кодируют value3,..., valuen. Каждое значение кодируется базой 128, наиболее значимая цифра первая, с как можно меньшим количеством цифр и самым значительным битом каждого октет, за исключением последнего в кодировке значения, установлен в "1."Пример: первый октет BER-кодировки RSA Data Security, Inc.'ы объект идентификатор 40 * 1 + 2 = 42 = 2a16. Кодировка 840 = 6 * 128 + 4816 является 86 48 и кодирование 113549 = 6 * 1282 + 7716 * 128 + d16 это 86 0d с ф7. Это приводит к следующим BER кодировка:

06 06 В 2A 86 48 86 F7 и 0d с


наконец, вот декодер OID, который я только что написал в Perl.

sub getOid {
    my $bytes = shift;

    #first 2 nodes are 'special';
    use integer;
    my $firstByte = shift @$bytes;
    my $number = unpack "C", $firstByte;
    my $nodeFirst = $number / 40;
    my $nodeSecond = $number % 40;

    my @oidDigits = ($nodeFirst, $nodeSecond);

    while (@$bytes) {
        my $num = convertFromVLQ($bytes);
        push @oidDigits, $num;
    }

    return join '.', @oidDigits;
}

sub convertFromVLQ {
    my $bytes = shift;

    my $firstByte = shift @$bytes;
    my $bitString = unpack "B*", $firstByte;

    my $firstBit = substr $bitString, 0, 1;
    my $remainingBits = substr $bitString, 1, 7;

    my $remainingByte = pack "B*", '0' . $remainingBits;
    my $remainingInt = unpack "C", $remainingByte;

    if ($firstBit eq '0') {
        return $remainingInt;
    }
    else {
        my $bitBuilder = $remainingBits;

        my $nextFirstBit = "1";
        while ($nextFirstBit eq "1") {
            my $nextByte = shift @$bytes;
            my $nextBits = unpack "B*", $nextByte;

            $nextFirstBit = substr $nextBits, 0, 1;
            my $nextSevenBits = substr $nextBits, 1, 7;

            $bitBuilder .= $nextSevenBits;
        }

        my $MAX_BITS = 32;
        my $missingBits = $MAX_BITS - (length $bitBuilder);
        my $padding = 0 x $missingBits;
        $bitBuilder = $padding . $bitBuilder;

        my $finalByte = pack "B*", $bitBuilder;
        my $finalNumber = unpack "N", $finalByte;
        return $finalNumber;
    }

}

кодировка OID для чайников :):

  • каждый компонент OID кодируется в один или несколько байтов (октетов)
  • кодировка OID-это просто конкатенация этих кодировок компонентов OID
  • первые два компонента кодируются особым образом (см. ниже)
  • Если двоичное значение компонента OID имеет менее 7 бит, кодировка представляет собой всего один октет, содержащий значение компонента (обратите внимание, самый значительный бит, самый левый, всегда будет 0)
  • в противном случае, если он имеет 8 и более бит, значение "разбивается" на несколько октетов - разбейте двоичное представление на 7 битных кусков (справа), слева-поместите первый с нулями, если это необходимо, и сформируйте октеты из этих септетов, добавив самый значительный (левый) бит 1, за исключением последнего куска, который будет иметь бит 0.
  • первые два компонента (X. Y) кодируются как один компонент со значением 40*X + Y

Это переформулировать рекомендации МСЭ-Т Х. 690, глава 8.19