构建DNSKEY RR的RDATA部分

时间:2018-02-11 05:14:09

标签: php c dns dnssec

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

  1. 密钥标牌
  2. 算法(被认为等于插件输入中的keyAlg)
  3. 摘要类型(我相信它在插件输入中称为digestAlg)
  4. 摘要(可能与消化相同)
  5. 其他可选字段包括:标志,协议,算法,公钥(插件中的'键')

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

    1. 如何构建“{DNSKEY RDATA”,即key char数组? (我正在争先恐后的旗帜 八位字节是默认值,如0,256或257还不确定),然后 Protocol octet是示例中的keyAlg值5,后跟 算法八位字节总是3,最后 - 关键八位字节是 键。这是猜对吗??)
    2. char key []数组RDATA是二进制数组吗?还是ascii chars? (意思是,一旦构造,我就不必将其转换为二进制位 第一λ)
    3. 算法中的& 0xFFFF目的是什么?什么是PHP等价物?我倾向于认为它几乎相同,因为PHP是基于语法的C语言......但是如果没有正确的输入/输出示例,我很难确定我是否正确...

1 个答案:

答案 0 :(得分:0)

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

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

现在,至于DNSSEC本身。它使用密码术,因此最好不要尝试重做手工操作。似乎PHP有Net_DNS2可以提供帮助。

但我不明白为什么你必须清除这些价值观。如果您是注册商,则将您客户给您的价值传递给注册管理机构;你可以稍微验证一下它们的语法,但除此之外你只需要传递它们。如果您将数据提交给注册商,作为客户,您再次从某个地方获取此数据,我不明白为什么您必须采取行动。

现在你谈论一个注册表,所以现在我会想象你是一个注册商。首先阅读RFC5910。您将看到有两个接口,实际上有3个案例,按现在最常用的顺序排列:

  1. dsData界面,您作为注册商向注册管理机构提供基本上注册管理机构将发布的DS记录;这些数据(确实是4个字段,您在第一个集合中列出它们)是根据您或托管公司将在域zonefile中作为DNSKEY记录发布的密钥构建的。
  2. keyData界面,同样有4个字段,但与之前的4个字段不同(第二个集合中有,或者帖子顶部的PHP结构),实际上你发送了注册表密钥(其公共部分),注册表将从中计算DS记录本身
  3. 以及基本上dsData且内部带有keyData的混合大小写,这意味着您要发送DS以发布和相关密钥,该密钥是无用的,但注册表可以重做DS计算检查,从密钥出发。
  4. 如果您阅读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),这是keyData接口所需的4个字段:

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

    对于3):执行& 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记录中,按照编码为Base64的密钥,按照规范(这是计算keyid的算法的输入)。

    我希望你能在上面的内容中找到至少一些有用的想法,但我担心不能更好地理解你的问题,以便更具体。