php - 构建DNSKEY RR的RDATA部分

标签 php c dns dnssec

我正在为计费系统(在这种情况下还可以管理域配置)完成Domain Registrar插件的过程中,最后一点与实现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                         /
   /                                                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


相同协议的附录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个必填字段:


关键字标签
算法(在插件输入中被认为等于keyAlg)
摘要类型(我相信在插件输入中称为“ digestAlg”)
摘要(可能与摘要相同)


其他可选字段包括:标志,协议,算法,公共密钥(在插件中为“密钥” ...)

现在这是我迷路的地方...
如何在PHP中实现上述C函数?


如何构造key字符数组“ DNSKEY RDATA”? (我猜到那旗
八位位组是默认值,例如0、256或257(尚不确定),然后
协议八位位组是示例中的keyAlg值5,后跟
算法八位位组始终为3,最后是-关键八位位组是
键。那猜测正确吗?)
char key []数组是RDATA,是二进制数组吗?还是ascii字符?
(意思是,一旦构建,我就不必将其转换为二进制位
第一?)
算法中& 0xFFFF的目的是什么?什么是php等效项?我倾向于认为它几乎相同,因为PHP的语法基于C。但是如果没有正确的输入/输出示例,将很难确保我正确地使用了它。

最佳答案

您的问题不是很清楚。您是在构建注册服务商系统还是与注册服务商建立联系的系统?
此外,您的标题还涉及构建DNSKEY RDATA,但是问题的全部内容涉及计算keyid / keytag,反之,该ID / keytag不会与DNSKEY记录一起发布(仅与RRSIG记录一起发布,但是dig之类的工具可以重新计算它)在您看到DNSKEY记录时将其显示为注释,以帮助您)。

无论哪种情况,您都不必处理DNSSEC数据线格式。在第一种情况下(注册服务商系统),您通常通过EPP与注册表交互,而EPP具有对DNSSEC数据的特定扩展名,称为secDNS。见RFC5910

现在,关于DNSSEC本身。它使用加密技术,因此最好不要尝试手动重做。似乎PHP具有Net_DNS2可以帮助您。

但是我不明白的是,为什么你必须嘲弄这些价值观。如果您是注册商,则将客户给您的值传递给注册商;您可以稍微验证一下它们的语法,但只需传递它们即可。如果您是作为客户向注册服务商提交数据,那么您又从某个地方获得了此数据,我不明白为什么您必须对此采取行动。

现在您谈到一个注册管理机构,因此现在我可以想象您是一个注册管理机构。首先阅读RFC5910。您将看到有两个接口,实际上是3种情况,从现在最常用的到少用的顺序:


dsData接口,您作为注册服务商,基本上向注册表提供了DS记录,该记录将由注册表发布;此数据(实际上是4个字段,您在第一个字段中列出了这些数据)是由您自己创建的密钥构造的,否则托管公司将在域zonefile中将其发布为DNSKEY记录
keyData接口,同样具有4个字段,但与之前的4个字段不同(第二个字段位于您的第二个字段中,或者您的帖子顶部为PHP结构),实际上您向注册表发送了注册表项(公共部分),注册管理机构将从中计算DS记录本身
还有一个混合情况,它基本上是dsData,里面是keyData,这意味着您同时发送了要发布的DS和相关的密钥,这是没有用的,但是注册表可以重做DS计算以进行检查,从键。


如果您阅读RFC,则会对2组4个字段进行解释,并了解其含义。

对于其中一些,您只能使用几个离散值:


算法值只能是https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#dns-sec-alg-numbers-1中的一个
哈希算法值只能是https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml中的一个


至于您的具体问题,似乎您正在尝试从密钥内容中计算出keyID / keytag(令人惊奇的是,已经发现该算法有缺陷,但是无论如何),正如我之前说过的那样,您不应该自己尝试重做。如果可能的话,请尝试找到一个可以为您执行此操作的PHP库,或者至少使用现有工具,但这取决于生成密钥的方式,从何处获取密钥等等。
例如,请参见此工具:https://linux.die.net/man/8/dnssec-keygen

否则,您将具有以下代码:https://www.v13.gr/blog/?p=239
它使用Python,但您可以从中获得PHP版本。请记住,关键字标签仅取决于关键字内容,而DS哈希值取决于关键字和域名(因此,即使您对不同的域名使用相同的关键字,DS值也会有所不同)。

因此,对于您的1)+ 2),它们大约是keyData接口所需的4个字段:


标志:是256还是257,具体取决于密钥是用作KSK还是ZSK;作为向主要注册管理机构提交关键值的注册服务机构,它应该仅为KSK,因此值为257。
protocol:始终为3,请参见2.1.2。的RFC4034
算法:来自同一RFC的附录1,基本上是上述两个链接的第一条链接,iana.org
算法的输入是DNSKEY RDATA的值,如第2.2节所述:“公钥字段必须表示为公钥的Base64编码。”,因此此处是一个字符列表。


对于3):执行& 0xFFFF意味着将16位最低有效位(通常在写入它们时,最右边的16位),因为&是逻辑AND,0xFFFF为2 ^ 16-1(65535),是设置为值1的16位。否则,如果最终值超过65535,则由于该键值被定义为16位值,因此在该操作中仅保留其中的一部分。

顺便说一句,您可以使用dnssec-keygen命令创建密钥及其密钥标签,以验证您自己的算法。

dnssec-keygen -a RSASHA256 -b 2048 test1将产生:

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


在生成的文件名中,008是算法(来自RSASHA256),而05433是所计算的keyId(密钥标签)。如果查看在.key中计算的精加工文件,则在整个DNSKEY记录内,根据规范(该密钥是计算密钥ID的算法的输入),密钥编码为Base64。

我希望您至少可以在上述内容中找到一些有用的想法,但是我担心您对问题的理解不够透彻,无法具体说明。

关于php - 构建DNSKEY RR的RDATA部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48728496/

相关文章:

php - 如何在 Wordpress 中将 Gravatar 设置为背景图片?

php - 进行多重排序 MySQL 查询的最有效方法

javascript - 在 Ajax 中选择更改/提交

java - 有没有办法用java或其他语言检索可用磁盘空间?

ios - 有没有办法在 swift 或 ObjC 中为 IPv4 和 IPv6 发出单独的 DNS 请求

ruby-on-rails - Heroku + Rails : How to allow my Users to add their own Custom Domains

php - Laravel MethodNotAllowedHttpException 无消息 - 尝试插入 mysql 表

C:将可变长度的二维数组转换为一维字符串

dns - 如何将我的域名从现有的注册商/托管服务转移到 GoDaddy 之类的服务?

python在solaris中调用外部C程序