Passed
Branch dev-v4 (e16a63)
by Sam
19:58
created

TKEY::fromWire()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 29
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 3.0067

Importance

Changes 0
Metric Value
cc 3
eloc 21
nc 3
nop 3
dl 0
loc 29
ccs 20
cts 22
cp 0.9091
crap 3.0067
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Badcow DNS Library.
7
 *
8
 * (c) Samuel Williams <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Badcow\DNS\Rdata;
15
16
use Badcow\DNS\Parser\Tokens;
17
use Badcow\DNS\Validator;
18
19
/**
20
 * {@link https://tools.ietf.org/html/rfc2930}.
21
 */
22
class TKEY implements RdataInterface
23
{
24
    use RdataTrait;
25
26
    const TYPE = 'TKEY';
27
    const TYPE_CODE = 249;
28
29
    /**
30
     * The algorithm name is in the form of a domain name with the same
31
     * meaning as in [RFC 2845]{@link https://tools.ietf.org/html/rfc2845}.
32
     * The algorithm determines how the secret keying material agreed to
33
     * using the TKEY RR is actually used to derive the algorithm specific key.
34
     *
35
     * @var string
36
     */
37
    private $algorithm;
38
39
    /**
40
     * @var \DateTime
41
     */
42
    private $inception;
43
44
    /**
45
     * @var \DateTime
46
     */
47
    private $expiration;
48
49
    /**
50
     * The mode field specifies the general scheme for key agreement or the
51
     * purpose of the TKEY DNS message. 16-bit integer.
52
     *
53
     * The following values of the Mode octet are defined, available, or reserved:
54
     *
55
     *      Value    Description
56
     *      -----    -----------
57
     *      0        - reserved, see section 7
58
     *      1       server assignment
59
     *      2       Diffie-Hellman exchange
60
     *      3       GSS-API negotiation
61
     *      4       resolver assignment
62
     *      5       key deletion
63
     *      6-65534   - available, see section 7
64
     *      65535     - reserved, see section 7
65
     *
66
     * @var int
67
     */
68
    private $mode;
69
70
    /**
71
     * The error code field is an extended RCODE.  The following values are defined:.
72
     *
73
     *      Value   Description
74
     *      -----   -----------
75
     *      0       - no error
76
     *      1-15   a non-extended RCODE
77
     *      16     BADSIG   (TSIG)
78
     *      17     BADKEY   (TSIG)
79
     *      18     BADTIME  (TSIG)
80
     *      19     BADMODE
81
     *      20     BADNAME
82
     *      21     BADALG
83
     *
84
     * @var int
85
     */
86
    private $error = 0;
87
88
    /**
89
     * @var string
90
     */
91
    private $keyData;
92
93
    /**
94
     * @var string
95
     */
96
    private $otherData;
97
98
    /**
99
     * @return string
100
     */
101 1
    public function getAlgorithm(): string
102
    {
103 1
        return $this->algorithm;
104
    }
105
106
    /**
107
     * @param string $algorithm
108
     */
109 4
    public function setAlgorithm(string $algorithm): void
110
    {
111 4
        if (!Validator::fullyQualifiedDomainName($algorithm)) {
112
            throw new \InvalidArgumentException('Algorithm must be a fully qualified domain name.');
113
        }
114 4
        $this->algorithm = $algorithm;
115 4
    }
116
117
    /**
118
     * @return \DateTime
119
     */
120 1
    public function getInception(): \DateTime
121
    {
122 1
        return $this->inception;
123
    }
124
125
    /**
126
     * @param \DateTime $inception
127
     */
128 4
    public function setInception(\DateTime $inception): void
129
    {
130 4
        $this->inception = $inception;
131 4
    }
132
133
    /**
134
     * @return \DateTime
135
     */
136 1
    public function getExpiration(): \DateTime
137
    {
138 1
        return $this->expiration;
139
    }
140
141
    /**
142
     * @param \DateTime $expiration
143
     */
144 4
    public function setExpiration(\DateTime $expiration): void
145
    {
146 4
        $this->expiration = $expiration;
147 4
    }
148
149
    /**
150
     * @return int
151
     */
152 1
    public function getMode(): int
153
    {
154 1
        return $this->mode;
155
    }
156
157
    /**
158
     * @param int $mode
159
     */
160 4
    public function setMode(int $mode): void
161
    {
162 4
        if (!Validator::isUnsignedInteger($mode, 16)) {
163
            throw new \InvalidArgumentException('Mode must be 16-bit integer.');
164
        }
165 4
        $this->mode = $mode;
166 4
    }
167
168
    /**
169
     * @return int
170
     */
171 1
    public function getError(): int
172
    {
173 1
        return $this->error;
174
    }
175
176
    /**
177
     * @param int $error
178
     */
179 4
    public function setError(int $error): void
180
    {
181 4
        if (!Validator::isUnsignedInteger($error, 16)) {
182
            throw new \InvalidArgumentException('Error must be 16-bit integer.');
183
        }
184 4
        $this->error = $error;
185 4
    }
186
187
    /**
188
     * @return string
189
     */
190 1
    public function getKeyData(): string
191
    {
192 1
        return $this->keyData;
193
    }
194
195
    /**
196
     * @param string $keyData binary stream
197
     */
198 4
    public function setKeyData(string $keyData): void
199
    {
200 4
        $this->keyData = $keyData;
201 4
    }
202
203
    /**
204
     * @return string
205
     */
206 1
    public function getOtherData(): string
207
    {
208 1
        return $this->otherData;
209
    }
210
211
    /**
212
     * @param string $otherData binary stream
213
     */
214 4
    public function setOtherData(string $otherData): void
215
    {
216 4
        $this->otherData = $otherData;
217 4
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222 1
    public function toText(): string
223
    {
224 1
        return sprintf('%s %d %d %d %d %s %s',
225 1
            $this->algorithm,
226 1
            $this->inception->format('U'),
227 1
            $this->expiration->format('U'),
228 1
            $this->mode,
229 1
            $this->error,
230 1
            base64_encode($this->keyData),
231 1
            base64_encode($this->otherData)
232
        );
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238 1
    public function toWire(): string
239
    {
240 1
        $wire = self::encodeName($this->algorithm);
241 1
        $wire .= pack('NNnnn',
242 1
            $this->inception->format('U'),
243 1
            $this->expiration->format('U'),
244 1
            $this->mode,
245 1
            $this->error,
246 1
            strlen($this->keyData)
247
        );
248 1
        $wire .= $this->keyData;
249 1
        $wire .= pack('n', strlen($this->otherData));
250 1
        $wire .= $this->otherData;
251
252 1
        return $wire;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258 1
    public function fromText(string $text): void
259
    {
260 1
        $rdata = explode(Tokens::SPACE, $text);
261 1
        $this->setAlgorithm((string) array_shift($rdata));
262 1
        if (false === $inception = \DateTime::createFromFormat('U', (string) array_shift($rdata))) {
263
            throw new \UnexpectedValueException('Unable to parse inception date of TKEY Rdata.');
264
        }
265 1
        $this->setInception($inception);
266
267 1
        if (false === $expiration = \DateTime::createFromFormat('U', (string) array_shift($rdata))) {
268
            throw new \UnexpectedValueException('Unable to parse expiration date of TKEY Rdata.');
269
        }
270 1
        $this->setExpiration($expiration);
271
272 1
        $this->setMode((int) array_shift($rdata));
273 1
        $this->setError((int) array_shift($rdata));
274 1
        $this->setKeyData((string) base64_decode((string) array_shift($rdata)));
275 1
        $this->setOtherData((string) base64_decode((string) array_shift($rdata)));
276 1
    }
277
278
    /**
279
     * {@inheritdoc}
280
     */
281 1
    public function fromWire(string $rdata, int &$offset = 0, ?int $rdLength = null): void
282
    {
283 1
        $algorithm = self::decodeName($rdata, $offset);
284 1
        $integers = unpack('N<inception>/N<expiration>/n<mode>/n<error>/n<keySize>', $rdata, $offset);
285 1
        $offset += 14;
286 1
        $keySize = (int) $integers['<keySize>'];
287 1
        $keyData = substr($rdata, $offset, $keySize);
288 1
        $offset = (int) $offset + $keySize;
289 1
        $otherDataSize = unpack('n', $rdata, $offset)[1];
290 1
        $offset += 2;
291 1
        $otherData = substr($rdata, $offset, $otherDataSize);
292 1
        $offset += $otherDataSize;
293
294 1
        $this->setAlgorithm($algorithm);
295
296 1
        if (false === $inception = \DateTime::createFromFormat('U', (string) $integers['<inception>'])) {
297
            throw new \UnexpectedValueException('Unable to parse inception date of TKEY Rdata.');
298
        }
299 1
        $this->setInception($inception);
300
301 1
        if (false === $expiration = \DateTime::createFromFormat('U', (string) $integers['<expiration>'])) {
302
            throw new \UnexpectedValueException('Unable to parse expiration date of TKEY Rdata.');
303
        }
304 1
        $this->setExpiration($expiration);
305
306 1
        $this->setMode((int) $integers['<mode>']);
307 1
        $this->setError((int) $integers['<error>']);
308 1
        $this->setKeyData($keyData);
309 1
        $this->setOtherData($otherData);
310 1
    }
311
}
312