Подтвердить что ты не робот

Как ASN.1 кодирует идентификатор объекта?

Мне трудно понять основные понятия ASN.1.

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

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

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

Соответствует ли соответствующий 1.3.6.1.5.5.7.48.1 закодированному в двоичном формате точно так же?

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

4b9b3361

Ответ 1

Да, 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/.

Ответ 2

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

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

Вы можете декодировать, прочитав первый байт в целое число

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

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

1.2

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

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

Короткая форма - если октет начинается с 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 * значение1 + значение2. (Это однозначно, поскольку значение 1 ограничено значениями 0, 1 и 2; значение2 ограничено диапазон от 0 до 39, когда значение 1 равно 0 или 1; и, согласно X.208, n является всегда не менее 2.)

Следующие октеты, если они есть, кодируют значение3,..., 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 f7 0d. Это приводит к следующему кодированию 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;
    }

}

Ответ 3

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

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

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