[devel] X509v3: CRL Distribution Points: help is needed

Paul Wolneykien manowar на altlinux.org
Пт Авг 10 15:52:26 MSK 2018


08.08.2018 19:52, Paul Wolneykien пишет:
> 08.08.2018 19:33, Alexey V. Vissarionov пишет:
>> On 2018-08-08 18:43:25 +0300, manowar на altlinux.org wrote:
>>  > Вот как выглядит в разобранном виде та часть файла подписи,
>>  > которая отвечает за CRL: [...]
>>  > Теперь, собственно, сам вопрос: структура выше соответствует
>>  > двум разным CRL?
>>
>> Нет - это один CRL, для которого предусмотрена возможность взять
>> его как с локального зеркала (pki-lan), так и снаружи у ГРЧЦ.

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

  Начинается всё с

    SEQUENCE(2 elem)  --- Так кодируется экземпляр расширения
(extension) X.509. Элементами списка (именно --- 2 элемента) являются:

      OBJECT IDENTIFIER 2.5.29.31 --- кодовый номер расширения и
      OCTET STRING (длинная строка, длиной 153 байта) --- его
содержимое, которое мы разбираем ниже:

        SEQUENCE(2 elem) --- Снова список. На этот раз --- это список,
состоящий из нескольких DistributionPoint, каждый из которых является
тоже списком с количеством элементов от 0 до 3 (поскольку все они
опциональные):

          SEQUENCE(1 elem) --- Это DistributionPoint с единственным
указанным элементом, осталось понять, каким:

            [0](1 elem) --- Теперь ясно, что это элемент с тегом [0], а
именно --- DistributionPointName. Он, в свою очередь может быть
представлен двумя различными способами, поэтому следом снова указывается:

              [0](1 elem) --- Тем самым выбирается вариант fullName,
помеченный в схеме тегом [0] и имеющим тип GeneralNames. Тип
GeneralNames представляет собой список из 1 или более альтернативных
значений, в котором каждая альтернатива обозначается тегом с номером от
[0] до [8]. Поэтому следом идёт наконец:

                [6]http://pki-lan/ocsp... --- Это
uniformResourceIdentifier (тег [6]) типа IA5String.


  Второй DistributionPoint оформлен точно так же, как первый. Поэтому
формально --- это именно два разных DistributionPoint, т.е. два разных
CRL. И в каждом DistributionPoint только один URI.
  То, что возможно сделать иначе: задать несколько URI для каждой
DistributionPoint --- можно узнать, например, и следующей инструкции:


https://www.pixelstech.net/article/1445498968-Generate-certificate-with-cRLDistributionPoints-extension-using-OpenSSL


08.08.2018 19:33, Alexey V. Vissarionov пишет:
> On 2018-08-08 18:43:25 +0300, manowar на altlinux.org wrote:
>  > не Интернет. А это значит, что издатель подписи (сертификата)
>  > рассчитывал на то, что оба указанных им адреса будут расценены
>  > как альтернативные и, при недоступности первого, проверяющий
>  > перейдёт по второму.
>
> Именно так. Локальное зеркало - best practice, ибо недоступность
> CRL может привести к тому, что отозванный сертификат будет принят
> как рабочий.
>
>  > Но dirmngr (из пакета gnupg2) считает иначе: он расценивает
>  > указанную информацию как список из двух различных CRL, которые,
>  > следовательно, оба требуются для проверки подписи.
>
> Идея здравая, но реализована, мягко говоря, per rectum.
> ...
> Проверять, действительно, нужно все источники (на случай, если
> какое-то свежее изменение в апстриме не доехало до зеркала), но
> отваливаться по UTV (unable to verify|validate) следует только
> когда недоступны _все_ источники.

  А вот теперь вопрос, чья это идея (последний абзац выше): это твоё
личное представление о том, как должно быть или всё таки нечто
общепринятое? Допустим, ты сомневаешься насчёт верности реализации в
GnuPG. Но как тебе такое:

static X509_CRL *load_crl_crldp(STACK_OF(DIST_POINT) *crldp)
{
    int i;
    const char *urlptr = NULL;
    for (i = 0; i < sk_DIST_POINT_num(crldp); i++) {
        DIST_POINT *dp = sk_DIST_POINT_value(crldp, i);
        urlptr = get_dp_url(dp);
        if (urlptr)
            return load_crl(urlptr, FORMAT_HTTP);
    }
    return NULL;
}

  Это я обнаружил в OpenSSL. И там, как видно, внутри цикла выход по
return на _первой_ же непустой DistributionPoint. Следовательно,
реализация OpenSSL рассчитана на то, что _все_ указанные источники будут
доступны. И если какой-то недоступен, то будет ошибка (там bio_err
внутри load_crl).
  Проверяем на нашем примере:

$ openssl verify -engine gost -CAfile parsed2.txt -crl_download
-crl_check parsed.txt
engine "gost" set.
Error loading CRL from
http://pki-lan/ocsp/6b00868389d200cf56b86be4e336101e1f72aec3.crl
140430750978520:error:2006A066:BIO routines:BIO_get_host_ip:bad hostname
lookup:b_sock.c:146:host=pki-lan
parsed.txt: 1.2.643.100.3 = ...
error 3 at 0 depth lookup:unable to get certificate CRL

  Получаем тот же результат, что и через GnuPG. С той лишь разницей, что
в GnuPG заложен перебор нескольких альтернативных URI для одной
DistributionPoint, а вот OpenSSL даже не предполагает альтернатив ---
все должны быть доступны.

  Получается, что предположение о том, что в разбираемом сертификате оба
URI нужно расценивать как альтернативные, не подтверждается ни теорией
(структурой в ASN.1), ни практикой (openssl verify).
  Или скажешь, что OpenSSL тоже не аргумент? А кто же тогда у них главный?


Подробная информация о списке рассылки Devel