I am in the process of finishing a Domain Registrar plugin for a billing system (which also manages domain provisioning in this case), and the last bit is related to implementing DNSSEC support.
The Billing system is sending the following SAMPLE DNSSEC related data to my PHP plugin:
'dnsSecInfo' =>
array (
0 =>
array (
'keyAlg' => 5,
'digestAlg' => 1,
'digest' => '1d181b34061ee98088b7a9e6db6e41a130674df0',
'key' => 'AwEAAaqZeENizOE6uvpDtIfQBB26YebvRdZA/ZjXjKLZdMmMK641sBIvho+yrTveIYclM+8lEVHiq64MY8R2G1IPmKDKXG26rM7NVE0Qx1KL2wRVbRrduRdBmKgJo3XQ3niueviKYXXmeVIO3EhrJsCq272Tm3DaDvng/M7uw1vDnanR2pYNcxI08fZOA6PLGDoUWlDNLGAHHkCvfdWUktVt1DA0GtL/qE/WUgxK6hJyeaXXb0+yq3qCMZh48WgluMFib54D0GN3PI3ZZvBMblAZHmFGqgyVwtPKEimXm/VREe2QtZy3cRgPbfOuiQi8gRhzO+/If8Wi9YnyLovjdsSjRsE=',
),
),
RFC 4034 has the following:
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 /
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Appendix B of the same protocol:
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;
}
The Registry where a domain is being registered, takes 4 mandatory fields:
- Keytag
- Algorithm (believed to be equal to keyAlg in plugin inputs)
- Digest Type (I believe its called digestAlg in the plugin inputs)
- Digest (same as digest probably)
Other Optional fields are: Flags, Protocol, Algorithm, Public Key (which is 'key' in Plugin...)
Now this is where I am getting lost... How do I implement the above C function in PHP?
- How do I construct the "DNSKEY RDATA" which is the
keychar array? (I am GUESSING that Flags octets are default values, like0, 256 or 257 not sure yet), then Protocol octet is the keyAlg value 5 in the example, followed by Algorithm octet that is always 3 and finally - the key octet is the key. Is that guess correct??) - Is the char key[] array RDATA, a binary array? or ascii chars? (meaning, once constructed, I dont have to convert it to binary bits first?)
- What is
& 0xFFFFpurpose in Algorithm? what is the php equivalent? I am inclined to think its pretty much the same, as PHP is C based in syntax... but without a correct input/output examples, it is going to be difficult to be sure I got it correctly...
Your question is not very clear. Are you building a registrar system or something that connects to a registrar? Also your title speaks about building the DNSKEY RDATA but then the whole content of your question deals with computing the keyid/keytag, which is not published with the DNSKEY record anyway (only published with RRSIG records, but tools like
digcan recompute it to show it as comment to help you when you see DNSKEY records).In either case, you should not have to deal with DNSSEC data wire format. In the first case (registrar system), you interface with the registry typically with EPP that has a specific extension for DNSSEC data, called secDNS. See RFC5910
Now, as for DNSSEC itself. It uses cryptography, so it is better not to try to redo things manuall. It seems PHP has
Net_DNS2that could help.But what I do not understand is why you have to muck wit the values. If you are a registrar you pass to the registry the values your clients gave you; you can verify their syntax a little but besides that you just pass them. If you are submitting data to a registrar, as a client, again you got this data from somewhere, I do not understand why you have to act on it.
Now you speak about a registry so for now I will imagine you are a registrar. Start by reading the RFC5910. You will see that there are two interfaces and in fact 3 cases, in the order from most often used right now to less often:
dsDatainterface where you as a registrar give the registry a DS record basically that the registry will publish; this data (4 fields indeed, you list them in your first set) is constructed from a key that you, or the hosting company will publish in the domain zonefile as a DNSKEY recordkeyDatainterface, again with 4 fields, but not the same as the 4 previous ones (there are in your second set, or the PHP structure at top of your post), where in fact you send the registry the key (its public part), from which the registry will compute the DS record itselfdsDatawith akeyDatainside which means you send both the DS to publish and the related key, that one being useless, but the registry can redo the DS computation to check, going from the key.If you read the RFC you will have explanations on the 2 sets of 4 fields, and their meanings.
For some of them, there are only a few discrete values you can use:
As for your specific questions, which seem you are trying to compute the keyID/keytag from the key content (amazingly it has been discovered that this algorithm has flaws, but anyway), as I said previously you should not try to redo this yourself. If possible, try to find a PHP library that does it for you, or at the very least use existing tools, but this depends on how your keys are generated, where do you get them from, etc... See for example this tool: https://linux.die.net/man/8/dnssec-keygen
Otherwise you have this code: https://www.v13.gr/blog/?p=239 It is in Python, but you could derive a PHP version from it. Remember that the keytag depends only on the key content where the DS hash value depends on both the key and the domain name (so even if you use the same key for different domain names, the DS value will be different).
So for your 1) + 2) which are about the 4 fields needed for a
keyDatainterface:iana.orgAs for 3) : doing
& 0xFFFFmeans taking the 16 bits least significant (typically the right most 16 bits when you write them), because&is a logical AND and 0xFFFF is 2^16 - 1 (65535), that is 16 bits set at value 1. Said otherwise, if the final value is over 65535, we keep only part of it with that operation, as the keytag is defined to be a 16 bits value.By the way, you can use the
dnssec-keygencommand to create keys and their keytags, to verify your own algorithm.dnssec-keygen -a RSASHA256 -b 2048 test1will produce:In the generated file name,
008is the algorithm (from RSASHA256) and05433is the keyId (keytag) computed. If you look at the file computed finishing in.keyyou have inside the full DNSKEY record, with the key encoded as Base64, per the specification (which is the input of the algorithm to compute the keyid).I hope you will find at least some useful ideas in the stuff above, but I fear not to have understood your question well enough to be more specific.