diff --git a/epp/src/epp-update.php b/epp/src/epp-update.php index fcd7fba..4026af4 100644 --- a/epp/src/epp-update.php +++ b/epp/src/epp-update.php @@ -1813,25 +1813,25 @@ function processDomainUpdate($conn, $db, $xml, $clid, $database_type, $trans) { // Data sanity checks for keyData // Validate flags $validFlags = [256, 257]; - if (isset($flags) && !in_array($flags, $validFlags)) { + if (!isset($flags) && !in_array($flags, $validFlags)) { sendEppError($conn, $db, 2005, 'Invalid flags', $clTRID, $trans); return; } // Validate protocol - if (isset($protocol) && $protocol != 3) { + if (!isset($protocol) && $protocol != 3) { sendEppError($conn, $db, 2006, 'Invalid protocol', $clTRID, $trans); return; } // Validate algKeyData - if (isset($algKeyData)) { + if (!isset($algKeyData)) { sendEppError($conn, $db, 2005, 'Invalid algKeyData encoding', $clTRID, $trans); return; } // Validate pubKey - if (isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { + if (!isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { sendEppError($conn, $db, 2005, 'Invalid pubKey encoding', $clTRID, $trans); return; } @@ -1920,25 +1920,25 @@ function processDomainUpdate($conn, $db, $xml, $clid, $database_type, $trans) { // Data sanity checks for keyData // Validate flags $validFlags = [256, 257]; - if (isset($flags) && !in_array($flags, $validFlags)) { + if (!isset($flags) && !in_array($flags, $validFlags)) { sendEppError($conn, $db, 2005, 'Invalid flags', $clTRID, $trans); return; } // Validate protocol - if (isset($protocol) && $protocol != 3) { + if (!isset($protocol) && $protocol != 3) { sendEppError($conn, $db, 2006, 'Invalid protocol', $clTRID, $trans); return; } // Validate algKeyData - if (isset($algKeyData)) { + if (!isset($algKeyData)) { sendEppError($conn, $db, 2005, 'Invalid algKeyData encoding', $clTRID, $trans); return; } // Validate pubKey - if (isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { + if (!isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { sendEppError($conn, $db, 2005, 'Invalid pubKey encoding', $clTRID, $trans); return; } @@ -1974,36 +1974,39 @@ function processDomainUpdate($conn, $db, $xml, $clid, $database_type, $trans) { } if ($keyDataSet) { foreach ($keyDataSet as $keyDataData) { - $flags = (int) $keyDataData->xpath('secDNS:keyData/secDNS:flags')[0]; - $protocol = (int) $keyDataData->xpath('secDNS:keyData/secDNS:protocol')[0]; - $algKeyData = (int) $keyDataData->xpath('secDNS:keyData/secDNS:alg')[0]; - $pubKey = (string) $keyDataData->xpath('secDNS:keyData/secDNS:pubKey')[0]; + $flags = (int) $keyDataData->xpath('secDNS:flags')[0]; + $protocol = (int) $keyDataData->xpath('secDNS:protocol')[0]; + $algKeyData = (int) $keyDataData->xpath('secDNS:alg')[0]; + $pubKey = (string) $keyDataData->xpath('secDNS:pubKey')[0]; + $maxSigLife = $xml->xpath('//secDNS:maxSigLife') ? (int) $secDNSData->xpath('secDNS:maxSigLife')[0] : null; // Data sanity checks for keyData // Validate flags $validFlags = [256, 257]; - if (isset($flags) && !in_array($flags, $validFlags)) { + if (!isset($flags) && !in_array($flags, $validFlags)) { sendEppError($conn, $db, 2005, 'Invalid flags', $clTRID, $trans); return; } // Validate protocol - if (isset($protocol) && $protocol != 3) { + if (!isset($protocol) && $protocol != 3) { sendEppError($conn, $db, 2006, 'Invalid protocol', $clTRID, $trans); return; } // Validate algKeyData - if (isset($algKeyData)) { + if (!isset($algKeyData)) { sendEppError($conn, $db, 2005, 'Invalid algKeyData encoding', $clTRID, $trans); return; } // Validate pubKey - if (isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { + if (!isset($pubKey) && base64_encode(base64_decode($pubKey, true)) !== $pubKey) { sendEppError($conn, $db, 2005, 'Invalid pubKey encoding', $clTRID, $trans); return; } + + $dsres = dnssec_key2ds($domainName.'.', $flags, $protocol, $algKeyData, $pubKey); try { $stmt = $db->prepare("INSERT INTO `secdns` (`domain_id`, `maxsiglife`, `interface`, `keytag`, `alg`, `digesttype`, `digest`, `flags`, `protocol`, `keydata_alg`, `pubkey`) VALUES (:domain_id, :maxsiglife, :interface, :keytag, :alg, :digesttype, :digest, :flags, :protocol, :keydata_alg, :pubkey)"); @@ -2012,10 +2015,10 @@ function processDomainUpdate($conn, $db, $xml, $clid, $database_type, $trans) { ':domain_id' => $domain_id, ':maxsiglife' => $maxSigLife, ':interface' => 'dsData', - ':keytag' => $keyTag, - ':alg' => $alg, - ':digesttype' => $digestType, - ':digest' => $digest, + ':keytag' => $dsres['keytag'], + ':alg' => $dsres['algorithm'], + ':digesttype' => $dsres['digest'][1]['type'], + ':digest' => $dsres['digest'][1]['hash'], ':flags' => $flags ?? null, ':protocol' => $protocol ?? null, ':keydata_alg' => $algKeyData ?? null, diff --git a/epp/src/helpers.php b/epp/src/helpers.php index 2bd26c1..d0318ec 100644 --- a/epp/src/helpers.php +++ b/epp/src/helpers.php @@ -284,4 +284,104 @@ function getClid(PDO $db, string $clid): ?int { $result = $stmt->fetch(PDO::FETCH_ASSOC); return $result ? (int)$result['id'] : null; +} + +/** + * Calculate ds-rdata from dnskey-rdata + * For additional information please refer to RFC 5910: http://www.ietf.org/rfc/rfc5910.txt + * + * @param string owner, the coanonical name of the owner (e.g. example.com.) + * @param int flags, the flags of the dnskey (only 256 or 257) + * @param int protocol, the protocol of the dnskey (only 3) + * @param int algoritm, the algorithm of the dnskey (only 3, 5, 6, 7, 8, 10, 12, 13 or 14) + * @param string publickey, the full publickey base64 encoded (care, no spaces allowed) + * + * @return array, on success + * Array ( + * [owner] => $owner + * [keytag] => $keytag + * [algorithm] => $algorithm + * [digest] => Array ( + * [] => Array ( + * [type] => 1 + * [hash] => $digest_sha1 + * ), + * [] => Array ( + * [type] => 2 + * [hash] => $digest_sha256 + * ) + * ) + * ) + * @return int < 0, on failure + * -1, unsupported owner + * -2, unsupported flags + * -3, unsupported protocol + * -4, unsupported algorithm + * -5, unsupported publickey + */ +function dnssec_key2ds($owner, $flags, $protocol, $algorithm, $publickey) { + // define paramenter check variants + $regex_owner = '/^[a-z0-9\-]+\.[a-z]+\.$/'; + $allowed_flags = array(256, 257); + $allowed_protocol = array(3); + $allowed_algorithm = array(2, 3, 5, 6, 7, 8, 10, 13, 14, 15, 16); + $regex_publickey = '/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/'; + + // do parameter checks and break if failed + if(!preg_match($regex_owner, $owner)) return -1; + if(!in_array($flags, $allowed_flags)) return -2; + if(!in_array($protocol, $allowed_protocol)) return -3; + if(!in_array($algorithm, $allowed_algorithm)) return -4; + if(!preg_match($regex_publickey, $publickey)) return -5; + + // calculate hex of parameters + $owner_hex = ''; + $parts = explode(".", substr($owner, 0, -1)); + foreach ($parts as $part) { + $len = dechex(strlen($part)); + $owner_hex .= str_repeat('0', 2 - strlen($len)).$len; + $part = str_split($part); + for ($i = 0; $i < count($part); $i++) { + $byte = strtoupper(dechex(ord($part[$i]))); + $byte = str_repeat('0', 2 - strlen($byte)).$byte; + $owner_hex .= $byte; + } + } + $owner_hex .= '00'; + $flags_hex = sprintf("%04d", dechex($flags)); + $protocol_hex = sprintf("%02d", dechex($protocol)); + $algorithm_hex = sprintf("%02d", dechex($algorithm)); + $publickey_hex = bin2hex(base64_decode($publickey)); + + // calculate keytag using algorithm defined in rfc + $string = hex2bin($flags_hex.$protocol_hex.$algorithm_hex.$publickey_hex); + $sum = 0; + for($i = 0; $i < strlen($string); $i++) { + $b = ord($string[$i]); + $sum += ($i & 1) ? $b : $b << 8; + } + $keytag = 0xffff & ($sum + ($sum >> 16)); + + // calculate digest using rfc specified hashing algorithms + $string = hex2bin($owner_hex.$flags_hex.$protocol_hex.$algorithm_hex.$publickey_hex); + $digest_sha1 = strtoupper(sha1($string)); + $digest_sha256 = strtoupper(hash('sha256', $string)); + + // return results and also copied parameters + return array( + //'debug' => array($owner_hex, $flags_hex, $protocol_hex, $algorithm_hex, $publickey_hex), + 'owner' => $owner, + 'keytag' => $keytag, + 'algorithm' => $algorithm, + 'digest' => array( + array( + 'type' => 1, + 'hash' => $digest_sha1 + ), + array( + 'type' => 2, + 'hash' => $digest_sha256 + ) + ) + ); } \ No newline at end of file