0

我正在为计费系统完成域注册器插件(在这种情况下还管理域配置),最后一点与实现 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 个必填字段

  1. 钥匙标签
  2. 算法(被认为等于插件输入中的 keyAlg)
  3. 摘要类型(我相信它在插件输入中称为 digestAlg)
  4. 摘要(可能与摘要相同)

其他可选字段是:标志、协议、算法、公钥(在插件中是“密钥”...)

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

  1. 如何构造作为key字符数组的“DNSKEY RDATA”?(我猜测标志八位字节是默认值,比如 0、256 或 257 还不确定),然后协议八位字节是示例中的 keyAlg 值 5,然后是始终为 3 的算法八位字节,最后 - 关键八位字节是关键. 猜对了吗??)
  2. char key[] 数组 RDATA 是二进制数组吗?还是ASCII字符?(意思是,一旦构建,我不必先将其转换为二进制位?)
  3. 算法的目的是什么& 0xFFFF?什么是 php 等价物?我倾向于认为它几乎相同,因为 PHP 在语法上是基于 C 的......但是如果没有正确的输入/输出示例,将很难确保我正确理解它......
4

1 回答 1

1

你的问题不是很清楚。您是否正在构建注册商系统或连接到注册商的东西?此外,您的标题还谈到了构建 DNSKEY RDATA,但是您问题的全部内容涉及计算 keyid/keytag,无论如何都不会与 DNSKEY 记录一起发布(仅与 RRSIG 记录一起发布,但是像dig可以重新计算它的工具来显示它作为评论以在您看到 DNSKEY 记录时为您提供帮助)。

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

现在,至于 DNSSEC 本身。它使用密码学,因此最好不要尝试手动重做。似乎 PHP 有Net_DNS2帮助。

但我不明白的是为什么你必须对这些价值观嗤之以鼻。如果您是注册商,您将客户提供给您的值传递给注册中心;您可以稍微验证它们的语法,但除此之外您只需传递它们。如果您将数据提交给注册商,作为客户,您又从某个地方获得了这些数据,我不明白您为什么必须对其采取行动。

现在您谈到注册管理机构,所以现在我假设您是注册服务商。从阅读 RFC5910 开始。您将看到有两个接口,实际上是 3 种情况,按照从现在最常用到不常用的顺序排列:

  1. dsData您作为注册服务商的界面向注册管理机构提供 DS 记录,基本上注册管理机构将发布该记录;此数据(确实是 4 个字段,您将它们列在第一组中)由您或托管公司将在域区域文件中作为 DNSKEY 记录发布的密钥构建
  2. 界面,同样有 4 个字段,但与之前的keyData4 个字段不同(在您的第二组中,或您帖子顶部的 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 值也会有所不同)。

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

  • flag:是 256 还是 257,具体取决于密钥是用作 KSK 还是 ZSK;作为向注册机构提交密钥值的注册商,它应该只是 KSK,因此值为 257。
  • 协议:始终为值 3,参见 2.1.2。RFC4034
  • 算法:来自同一个RFC的附录1,基本上是上面两个的第一个链接iana.org
  • 算法的输入是 DNSKEY RDATA 的值,如第 2.2 节所述:“公钥字段必须表示为公钥的 Base64 编码。”,所以它是一个字符列表。

至于 3) :doing& 0xFFFF意味着取 16 位最低有效位(通常是写它们时最右边的 16 位),因为&是逻辑 AND 并且 0xFFFF 是 2^16 - 1 (65535),即 16 位设置为值1. 否则,如果最终值超过 65535,我们只保留其中的一部分用于该操作,因为 keytag 被定义为 16 位值。

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

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

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

在生成的文件名中,008是算法(来自 RSASHA256)并且05433是计算的 keyId(keytag)。如果您查看.key完整的 DNSKEY 记录中的文件计算完成,按照规范(这是计算 keyid 的算法的输入),密钥编码为 Base64。

我希望您至少能在上面的内容中找到一些有用的想法,但我担心您的问题理解得不够透彻,无法更具体。

于 2018-02-13T05:43:01.810 回答