Как этот код извлекает подпись?

Я должен отлаживать старый PHP-скрипт от разработчика, который покинул компанию. Я понимаю большую часть кода, за исключением следующей функции. Мой вопрос: что …

if ($ seq == 0x03 || $ seq == 0x30)

… означает в контексте извлечения подписи из сертификата X.509?

public function extractSignature($certPemString) { $bin = $this->ConvertPemToBinary($certPemString); if(empty($certPemString) || empty($bin)) { return false; } $bin = substr($bin,4); while(strlen($bin) > 1) { $seq = ord($bin[0]); if($seq == 0x03 || $seq == 0x30) { $len = ord($bin[1]); $bytes = 0; if ($len & 0x80) { $bytes = ($len & 0x0f); $len = 0; for ($i = 0; $i < $bytes; $i++) { $len = ($len << 8) | ord($bin[$i + 2]); } } if($seq == 0x03) { return substr($bin,3 + $bytes, $len); } else { $bin = substr($bin,2 + $bytes + $len); } } else { return false; } } return false; } 

    Related of "Как этот код извлекает подпись?"

    Сертификат X.509 содержит данные в нескольких разделах (так называемые триплеты Tag-Length-Value). Каждый раздел начинается с байта тега, который указывает формат данных раздела. Здесь вы можете увидеть список этих типов данных.

    0x03 – это байт Tag для типа данных BIT STRING , а 0x30 – байт Tag для типа данных SEQUENCE .

    Таким образом, этот код предназначен для обработки типов данных BIT STRING и SEQUENCE. Если вы посмотрите на эту часть:

     if($seq == 0x03) { return substr($bin,3 + $bytes, $len); } else // $seq == 0x30 { $bin = substr($bin,2 + $bytes + $len); } 

    вы можете видеть, что функция предназначена для пропуска по последовательностям (0x30), пока не найдет бит-строку (0x03), после чего она вернет значение бит-строки.

    Возможно, вам интересно, почему магическое число равно 3 для бит-строки и 2 для последовательности . Это связано с тем, что в бит-строке первый байтовый байт представляет собой специальное дополнительное поле, которое указывает, сколько бит не используется в последнем байте данных. (Например, если вы отправляете 13 бит данных, это займет 2 байта = 16 бит, а поле « неиспользуемые биты » будет равно 3.)

    Следующий выпуск: поле Длина. Когда длина значения меньше 128 байт, длина просто указывается с использованием одного байта (самый старший бит будет равен 0). Если длина равна 128 или выше, то первый байт длины имеет бит 7, а остальные 7 бит указывают, сколько последующих байтов содержит длину (в порядке возрастания). Более подробное описание здесь . Разбор поля длины происходит в этом разделе кода:

     $len = ord($bin[1]); $bytes = 0; if ($len & 0x80) { // length is greater than 127! $bytes = ($len & 0x0f); $len = 0; for ($i = 0; $i < $bytes; $i++) { $len = ($len << 8) | ord($bin[$i + 2]); } } 

    После этого $bytes содержат количество дополнительных байтов, используемых полем длины, а $len содержит длину поля Value (в байтах).

    Вы заметили ошибку в коде? Запомнить,

    Если длина равна 128 или выше, то первый байт длины имеет бит 7, а остальные 7 бит указывают, сколько последующих байтов содержит длину.

    но код говорит $bytes = ($len & 0x0f) , который берет только младшие 4 бита байта! Должен быть:

     $bytes = ($len & 0x7f); 

    Конечно, эта ошибка является лишь проблемой для чрезвычайно длинных сообщений: она будет работать нормально до тех пор, пока значение длины будет соответствовать 0x0f = 15 байт, то есть данные должны быть меньше 256 ^ 15 байт. Это около триллиона лет, что должно быть достаточно для всех.

    Как говорит Патман, вы просто имеете логическое, если мы просто проверяем, является ли $seq 0x30 или 0x03.

    У меня такое чувство, что вы уже знаете это, так что вот так. $seq – это первый байт сертификата, который, вероятно, является либо версией сертификата, либо магическим номером, чтобы обозначить, что этот файл является сертификатом (также известный как «Я предполагаю это, потому что 10:45 некогда начинать чтение RFC ").

    В этом случае мы сравниваем 0x30 и 0x03. Эти числа выражаются в шестнадцатеричном виде (как и каждое число, начинающееся с 0x), которое является базовым 16. Это просто очень удобное сокращение двоичного кода, так как каждая шестнадцатеричная цифра соответствует ровно четырем двоичным битам. Быстрый стол:

     0 = 0000 1 = 0001 2 = 0010 3 = 0011 ... ... E = 1110 F = 1111 

    В равной степени мы могли бы сказать, что if($seq == 3 || $seq == 48) , но в этом случае шестеро проще читать и понимать.

    Я бы рискнул предположить, что это байтовая независимая проверка для идентификатора версии «3» в сертификате x.509. См. RFC 1422 , стр. 7. Остальное вытягивает байт по-байт.

    ord () получает значение символа ASCII, который вы передаете. В этом случае он проверяет, является ли символ ASCII либо 0, либо окончанием текста (в соответствии с этой таблицей ASCII ).

    0x03 и 0x30 – шестнадцатеричные значения. Посмотрите это, и у вас будет то, что $ seq соответствует