update copyright year
[GitHub/Stricted/Domain-Control-Panel.git] / lib / util / DNSSECUtil.class.php
1 <?php
2 namespace dns\util;
3
4 /**
5 * @author Jan Altensen (Stricted)
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @copyright 2015-2016 Jan Altensen (Stricted)
8 */
9 class DNSSECUtil {
10 // see: http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
11 public static $availableAlgorithm = array(3, 5, 6, 7, 8, 10, 12, 13, 14);
12
13 /**
14 * calculate the DS record for parent zone
15 *
16 * @param string $owner
17 * @param string $algorithm
18 * @param string $publicKey
19 * @return array
20 */
21 public static function calculateDS ($owner, $algorithm, $publicKey) {
22 $owner = self::convertOwner($owner);
23 $flags = '0101';
24 $protocol = '03';
25 $algorithm = '0'.dechex($algorithm);
26 $publicKey = bin2hex(base64_decode($publicKey));
27
28 $string = hex2bin($owner.$flags.$protocol.$algorithm.$publicKey);
29
30 $sha1 = strtoupper(sha1($string));
31 $sha256 = strtoupper(hash('sha256', $string));
32
33 return array('sha1' => $sha1, 'sha256' => $sha256);
34 }
35
36 /**
37 * convert the domain name to HEX
38 *
39 * @param string $owner
40 * @return string
41 */
42 public static function convertOwner ($owner) {
43 if (substr($owner, -1) == '.') {
44 $owner = substr($owner, 0, -1);
45 }
46
47 $return = '';
48
49 $parts = explode(".", $owner);
50 foreach ($parts as $part) {
51 $len = dechex(strlen($part));
52 $return .= str_repeat('0', 2 - strlen($len)).$len;
53 $part = str_split($part);
54 $count = count($part);
55 for ($i = 0; $i < $count; $i++) {
56 $byte = strtoupper(dechex(ord($part[$i])));
57 $byte = str_repeat('0', 2 - strlen($byte)).$byte;
58 $return .= $byte;
59 }
60 }
61
62 $return .= '00';
63
64 return $return;
65 }
66
67 /**
68 * validate DNSSEC public key
69 *
70 * @param string $content
71 * @return boolean
72 */
73 public static function validatePublicKey ($content) {
74 // unify newlines
75 $content = preg_replace("/(\r\n)|(\r)/", "\n", $content);
76
77 $pattern = "; This is a (key|zone)-signing key, keyid (?P<keyid>[0-9]+), for (?P<domain>[\s\S]+)\.\n";
78 $pattern .= "; Created: (?P<created>[0-9]+) \(([a-z0-9: ]+)\)\n";
79 $pattern .= "; Publish: (?P<publish>[0-9]+) \(([a-z0-9: ]+)\)\n";
80 $pattern .= "; Activate: (?P<activate>[0-9]+) \(([a-z0-9: ]+)\)\n";
81 $pattern .= "([\s\S]+). IN DNSKEY 25(6|7) 3 (?P<algorithm>[0-9]+) (?P<key>[\s\S]+)(\n)?";
82 preg_match('/'.$pattern.'/i', $content, $matches);
83 if (!empty($matches)) {
84 if (!in_array($matches['algorithm'], self::$availableAlgorithm)) {
85 return false;
86 }
87
88 $data = explode(' ', $matches['key']);
89 foreach ($data as $d) {
90 if (base64_encode(base64_decode($d, true)) !== $d) {
91 return false;
92 }
93 }
94 }
95 else {
96 return false;
97 }
98
99 return true;
100 }
101
102 /**
103 * validate DNSSEC private key
104 *
105 * @param string $content
106 * @return boolean
107 */
108 public static function validatePrivateKey ($content) {
109 // unify newlines
110 $content = preg_replace("/(\r\n)|(\r)/", "\n", $content);
111
112 $pattern = "Private-key-format: v([0-9a-z.]+)\n";
113 $pattern .= "Algorithm: (?P<algorithm>[0-9]+) \(([0-9a-z\-]+)\)\n";
114 $pattern .= "Modulus: (?P<modulus>[\s\S]+)\n";
115 $pattern .= "PublicExponent: (?P<publicexponent>[\s\S]+)\n";
116 $pattern .= "PrivateExponent: (?P<privatexponent>[\s\S]+)\n";
117 $pattern .= "Prime1: (?P<prime1>[\s\S]+)\n";
118 $pattern .= "Prime2: (?P<prime2>[\s\S]+)\n";
119 $pattern .= "Exponent1: (?P<exponent1>[\s\S]+)\n";
120 $pattern .= "Exponent2: (?P<exponent2>[\s\S]+)\n";
121 $pattern .= "Coefficient: (?P<coefficient>[\s\S]+)\n";
122 $pattern .= "Created: (?P<created>[0-9]+)\n";
123 $pattern .= "Publish: (?P<publish>[0-9]+)\n";
124 $pattern .= "Activate: (?P<activate>[0-9]+)(\n)?";
125
126 preg_match('/'.$pattern.'/i', $content, $matches);
127 if (!empty($matches)) {
128 if (!in_array($matches['algorithm'], self::$availableAlgorithm)) {
129 return false;
130 }
131 else if (base64_encode(base64_decode($matches['modulus'], true)) !== $matches['modulus']) {
132 return false;
133 }
134 else if (base64_encode(base64_decode($matches['publicexponent'], true)) !== $matches['publicexponent']) {
135 return false;
136 }
137 else if (base64_encode(base64_decode($matches['privatexponent'], true)) !== $matches['privatexponent']) {
138 return false;
139 }
140 else if (base64_encode(base64_decode($matches['prime1'], true)) !== $matches['prime1']) {
141 return false;
142 }
143 else if (base64_encode(base64_decode($matches['prime2'], true)) !== $matches['prime2']) {
144 return false;
145 }
146 else if (base64_encode(base64_decode($matches['exponent1'], true)) !== $matches['exponent1']) {
147 return false;
148 }
149 else if (base64_encode(base64_decode($matches['exponent2'], true)) !== $matches['exponent2']) {
150 return false;
151 }
152 else if (base64_encode(base64_decode($matches['coefficient'], true)) !== $matches['coefficient']) {
153 return false;
154 }
155 }
156 else {
157 return false;
158 }
159
160 return true;
161 }
162 }