Я нахожусь в процессе завершения плагина Регистратора домена для биллинговой системы (которая в этом случае также управляет подготовкой домена), и последний бит связан с реализацией поддержки DNSSEC.
Биллинговая система отправляет в мой плагин PHP следующие данные, относящиеся к SAMPLE DNSSEC:
'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 /
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Приложение B того же протокола:
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 обязательных поля:
Другой Необязательный поля: флаги, протокол, алгоритм, открытый ключ (который является «ключом» в плагине …)
Теперь я заблудился …
Как мне реализовать вышеупомянутую функцию C в PHP?
key
массив символов? (Я думаю, что флаги& 0xFFFF
цель в алгоритме? Что такое эквивалент PHP? Я склонен думать, что это почти то же самое, так как PHP основан на C в синтаксисе … но без правильных примеров ввода / вывода будет трудно убедиться, что я все понял правильно …Ваш вопрос не очень понятен. Вы строите систему регистратора или что-то, что соединяется с регистратором?
Также ваш заголовок говорит о построении RDATA DNSKEY, но тогда весь ваш вопрос касается вычисления keyid / keytag, который все равно не публикуется с записью DNSKEY (только публикуется с записями RRSIG, но такими инструментами, как dig
можно пересчитать его, чтобы отобразить его как комментарий, чтобы помочь вам при просмотре записей DNSKEY).
В любом случае вам не нужно иметь дело с форматом передачи данных DNSSEC. В первом случае (система регистратора) вы взаимодействуете с реестром, как правило, с EPP, который имеет специальное расширение для данных DNSSEC, называемое secDNS. Увидеть RFC5910
Теперь что касается самого DNSSEC. Он использует криптографию, поэтому лучше не пытаться переделывать вещи вручную. Кажется, PHP имеет Net_DNS2
это могло бы помочь.
Но то, что я не понимаю, это то, почему вы должны испортить ценности. Если вы являетесь регистратором, вы передаете в реестр значения, которые дали вам ваши клиенты; Вы можете немного проверить их синтаксис, но, кроме того, вы просто передаете их. Если вы предоставляете данные регистратору в качестве клиента, вы снова откуда-то получили эти данные, я не понимаю, почему вы должны действовать в соответствии с ними.
Теперь вы говорите о реестре, так что пока я представлю, что вы регистратор. Начните с чтения RFC5910. Вы увидите, что есть два интерфейса, а на самом деле 3 случая, в порядке от наиболее часто используемого сейчас до менее часто:
dsData
интерфейс, в котором вы, как регистратор, даете реестру запись DS в основном для публикации в реестре; эти данные (на самом деле 4 поля, вы перечисляете их в первом наборе) составлены из ключа, который вы или хостинговая компания опубликуете в доменном файле зоны как запись DNSKEY.keyData
интерфейс, опять же с 4 полями, но не такой, как у 4 предыдущих (есть в вашем втором наборе или структуре PHP в верхней части вашего поста), где на самом деле вы отправляете ключу реестра (его публичную часть), из которого реестр будет вычислять саму запись DSdsData
с 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 из него. Помните, что метка ключа зависит только от содержимого ключа, где значение хеш-функции DS зависит как от ключа, так и от имени домена (поэтому даже если вы используете один и тот же ключ для разных доменных имен, значение DS будет отличаться).
Так что для вашего 1) + 2) примерно 4 поля, необходимые для keyData
интерфейс:
iana.org
Что касается 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, согласно спецификации (которая является входом алгоритма для вычисления keyid).
Я надеюсь, что вы найдете хотя бы некоторые полезные идеи в вышеприведенном материале, но я боюсь, что не понял ваш вопрос достаточно хорошо, чтобы быть более конкретным.
Других решений пока нет …