Создание части RDATA DNSKEY RR

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

Биллинговая система отправляет следующие данные, связанные с SAMPLE DNSSEC, в мой плагин PHP:

'dnsSecInfo' =>
  array (
    0 =>
    array (
      'keyAlg' => 5,
      'digestAlg' => 1,
      'digest' => '1d181b34061ee98088b7a9e6db6e41a130674df0',
      'key' => 'AwEAAaqZeENizOE6uvpDtIfQBB26YebvRdZA/ZjXjKLZdMmMK641sBIvho+yrTveIYclM+8lEVHiq64MY8R2G1IPmKDKXG26rM7NVE0Qx1KL2wRVbRrduRdBmKgJo3XQ3niueviKYXXmeVIO3EhrJsCq272Tm3DaDvng/M7uw1vDnanR2pYNcxI08fZOA6PLGDoUWlDNLGAHHkCvfdWUktVt1DA0GtL/qE/WUgxK6hJyeaXXb0+yq3qCMZh48WgluMFib54D0GN3PI3ZZvBMblAZHmFGqgyVwtPKEimXm/VREe2QtZy3cRgPbfOuiQi8gRhzO+/If8Wi9YnyLovjdsSjRsE=',
    ),
  ),

RFC 4034 содержит следующее:

2.1.  DNSKEY RDATA Wire Format

   The RDATA for a DNSKEY RR consists of a 2 octet Flags Field, a 1
   octet Protocol Field, a 1 octet Algorithm Field, and the Public Key
   Field.

                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              Flags            |    Protocol   |   Algorithm   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                                                               /
   /                            Public Key                         /
   /                                                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Приложение Б того же протокола:

The input is the wire
format of the RDATA portion of the DNSKEY RR.
.....
  unsigned int
   keytag (
           unsigned char key[],  /* the RDATA part of the DNSKEY RR */
           unsigned int keysize  /* the RDLENGTH */
          )
   {
           unsigned long ac;     /* assumed to be 32 bits or larger */
           int i;                /* loop index */

           for ( ac = 0, i = 0; i < keysize; ++i )
                   ac += (i & 1) ? key[i] : key[i] << 8;
           ac += (ac >> 16) & 0xFFFF;
           return ac & 0xFFFF;
   }

Реестр, в котором регистрируется домен, занимает 4 обязательных поля:

  1. Брелок
  2. Алгоритм (считается равным keyAlg во входных данных плагина)
  3. Тип дайджеста (я полагаю, что он называется дайджестАлг во входных данных плагина)
  4. Дайджест (то же самое, что и дайджест, вероятно)

Другие Необязательные поля: Флаги, Протокол, Алгоритм, Открытый ключ (который является «ключом» в плагине...)

Вот тут-то я и теряюсь... Как мне реализовать указанную выше функцию C в PHP?

  1. Как создать «DNSKEY RDATA», который представляет собой массив символов key? (Я ПРЕДПОЛАГАЮ, что октеты флагов являются значениями по умолчанию, например, 0, 256 или 257, еще не уверен), тогда октет протокола является значением keyAlg 5 в примере, за которым следует октет алгоритма, который всегда равен 3, и, наконец, октет ключа является ключом . Это верное предположение??)
  2. Является ли массив char key[] RDATA двоичным массивом? или символы ascii? (имеется в виду, что после создания мне не нужно сначала преобразовывать его в двоичные биты?)
  3. Что такое & 0xFFFF цель в алгоритме? что такое эквивалент php? Я склонен думать, что это почти то же самое, поскольку PHP основан на синтаксисе C... но без правильных примеров ввода/вывода будет сложно убедиться, что я правильно понял...

person Carmageddon    schedule 11.02.2018    source источник


Ответы (1)


Ваш вопрос не очень ясен. Вы создаете систему регистратора или что-то, что подключается к регистратору? Также в вашем заголовке говорится о создании DNSKEY RDATA, но тогда все содержание вашего вопроса связано с вычислением keyid/keytag, который в любом случае не публикуется с записью DNSKEY (опубликуется только с записями RRSIG, но такие инструменты, как dig, могут пересчитать его, чтобы показать это комментарий, который поможет вам, когда вы увидите записи DNSKEY).

В любом случае вам не придется иметь дело с форматом передачи данных DNSSEC. В первом случае (система регистрации) вы взаимодействуете с реестром, как правило, через EPP, который имеет специальное расширение для данных DNSSEC, называемое secDNS. См. RFC5910.

Теперь, что касается самого DNSSEC. Он использует криптографию, поэтому лучше не пытаться делать что-то вручную. Кажется, в PHP есть Net_DNS2, которые могут помочь.

Но чего я не понимаю, так это почему вы должны гадить со значениями. Если вы являетесь регистратором, вы передаете в реестр значения, которые предоставили вам ваши клиенты; вы можете немного проверить их синтаксис, но, кроме того, вы просто передаете их. Если вы отправляете данные регистратору, как клиент, опять же вы откуда-то взяли эти данные, я не понимаю, почему вы должны действовать по ним.

Теперь вы говорите о реестре, так что пока я представлю, что вы регистратор. Начните с чтения RFC5910. Вы увидите, что есть два интерфейса, а на самом деле 3 случая, в порядке от наиболее часто используемого сейчас к менее частому:

  1. интерфейс dsData, где вы, как регистратор, предоставляете реестру запись DS, которую реестр будет публиковать; эти данные (действительно 4 поля, вы перечисляете их в своем первом наборе) построены на основе ключа, который вы или хостинговая компания опубликуете в файле зоны домена в виде записи DNSKEY.
  2. интерфейс keyData, опять же с 4-мя полями, но не такими, как 4 предыдущих (есть в вашем втором наборе, или структура PHP вверху вашего поста), где по сути вы отправляете в реестр ключ (его публичную часть ), из которого реестр сам вычислит запись DS.
  3. и смешанный случай, когда это в основном dsData с keyData внутри, что означает, что вы отправляете как DS для публикации, так и соответствующий ключ, который бесполезен, но реестр может повторить вычисление DS для проверки, исходя из ключа.

Если вы прочтете RFC, у вас будут объяснения по 2 наборам из 4 полей и их значениям.

Для некоторых из них можно использовать только несколько дискретных значений:

Что касается ваших конкретных вопросов, которые, похоже, вы пытаетесь вычислить keyID / keytag из содержимого ключа (удивительно, но было обнаружено, что этот алгоритм имеет недостатки, но в любом случае), как я уже говорил ранее, вы не должны пытаться повторить это самостоятельно. Если возможно, попробуйте найти PHP-библиотеку, которая сделает это за вас, или, по крайней мере, используйте существующие инструменты, но это зависит от того, как генерируются ваши ключи, откуда вы их берете и т. д. См., например, этот инструмент : https://linux.die.net/man/8/dnssec-keygen

В противном случае у вас есть этот код: https://www.v13.gr/blog/?p=239 Он написан на Python, но вы можете получить из него версию PHP. Помните, что keytag зависит только от содержимого ключа, а значение DS-хэша зависит как от ключа, так и от доменного имени (поэтому, даже если вы используете один и тот же ключ для разных доменных имен, значение DS будет другим).

Итак, для вашего 1) + 2), которые составляют 4 поля, необходимые для интерфейса keyData:

  • флаг: либо 256, либо 257 в зависимости от того, используется ли ключ как KSK или ZSK; поскольку регистратор отправляет значения ключей в реестры, это должны быть только ключи KSK, поэтому значение 257.
  • протокол: всегда значение 3, см. 2.1.2. RFC4034
  • алгоритм: взят из Приложения 1 того же RFC, который в основном представляет собой первую ссылку из двух вышеперечисленных, идущих к iana.org
  • вводом алгоритма является значение DNSKEY RDATA, как написано в разделе 2.2: «Поле открытого ключа ДОЛЖНО быть представлено как кодировка открытого ключа Base64», поэтому это список символов.

Что касается 3): выполнение & 0xFFFF означает использование 16 наименее значащих битов (обычно самые правые 16 бит при их записи), потому что & является логическим И, а 0xFFFF - 2 ^ 16 - 1 (65535), то есть установлено 16 бит при значении 1. Иными словами, если конечное значение превышает 65535, мы сохраняем только его часть с помощью этой операции, поскольку ключевой тег определяется как 16-битное значение.

Кстати, вы можете использовать команду dnssec-keygen для создания ключей и их меток, чтобы проверить собственный алгоритм.

dnssec-keygen -a RSASHA256 -b 2048 test1 будет производить:

Generating key pair.......+++ ............................+++ 
Ktest1.+008+05433

В сгенерированном имени файла 008 — это алгоритм (из RSASHA256), а 05433 — вычисленный keyId (keytag). Если вы посмотрите на файл, вычисленный в конце .key, у вас есть полная запись DNSKEY с ключом, закодированным как Base64, в соответствии со спецификацией (которая является входом алгоритма для вычисления идентификатора ключа).

Я надеюсь, что вы найдете хотя бы несколько полезных идей в материалах выше, но я боюсь, что недостаточно хорошо понял ваш вопрос, чтобы быть более конкретным.

person Patrick Mevzek    schedule 13.02.2018