Passed
Push — master ( 87c83f...ac88b3 )
by Sam
03:00
created

CERT   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 72
dl 0
loc 222
ccs 61
cts 61
cp 1
rs 10
c 1
b 0
f 0
wmc 23

14 Methods

Rating   Name   Duplication   Size   Complexity  
A toWire() 0 3 1
A fromWire() 0 14 1
A setAlgorithm() 0 9 3
A setKeyTag() 0 3 1
A toText() 0 6 3
A fromText() 0 10 1
A setCertificateType() 0 9 3
A getCertificate() 0 3 1
A getKeyTag() 0 3 1
A getCertificateType() 0 3 1
A getAlgorithm() 0 3 1
A getKeyTypeValue() 0 7 2
A getKeyTypeMnemonic() 0 7 2
A setCertificate() 0 7 2
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\Algorithms as _Algorithms;
17
use Badcow\DNS\Parser\Tokens;
18
19
/*
20
 * {@link https://tools.ietf.org/html/rfc4398#section-2.1}.
21
 */
22
class CERT implements RdataInterface
23
{
24
    use RdataTrait;
25
26
    const TYPE = 'CERT';
27
    const TYPE_CODE = 37;
28
29
    const KEY_TYPE_PKIX = 1;
30
    const KEY_TYPE_SPKI = 2;
31
    const KEY_TYPE_PGP = 3;
32
    const KEY_TYPE_IPKIX = 4;
33
    const KEY_TYPE_ISPKI = 5;
34
    const KEY_TYPE_IPGP = 6;
35
    const KEY_TYPE_ACPKIX = 7;
36
    const KEY_TYPE_IACPKIX = 8;
37
    const KEY_TYPE_URI = 253;
38
    const KEY_TYPE_OID = 254;
39
40
    const MNEMONICS = [
41
        self::KEY_TYPE_PKIX => 'PKIX',
42
        self::KEY_TYPE_SPKI => 'SPKI',
43
        self::KEY_TYPE_PGP => 'PGP',
44
        self::KEY_TYPE_IPKIX => 'IPKIX',
45
        self::KEY_TYPE_ISPKI => 'ISPKI',
46
        self::KEY_TYPE_IPGP => 'IPGP',
47
        self::KEY_TYPE_ACPKIX => 'ACPKIX',
48
        self::KEY_TYPE_IACPKIX => 'IACPKIX',
49
        self::KEY_TYPE_URI => 'URI',
50
        self::KEY_TYPE_OID => 'OID',
51
    ];
52
53
    /**
54
     * @var int
55
     */
56
    private $certificateType;
57
58
    /**
59
     * @var int
60
     */
61
    private $keyTag;
62
63
    /**
64
     * @var int
65
     */
66
    private $algorithm;
67
68
    /**
69
     * @var string
70
     */
71
    private $certificate;
72
73
    /**
74
     * @return int
75
     */
76 1
    public function getCertificateType(): int
77
    {
78 1
        return $this->certificateType;
79
    }
80
81
    /**
82
     * @param int|string $certificateType
83
     *
84
     * @throws \InvalidArgumentException
85
     */
86 4
    public function setCertificateType($certificateType): void
87
    {
88 4
        if (is_int($certificateType) || 1 === preg_match('/^\d+$/', $certificateType)) {
89 1
            $this->certificateType = (int) $certificateType;
90
91 1
            return;
92
        }
93
94 4
        $this->certificateType = self::getKeyTypeValue((string) $certificateType);
95 4
    }
96
97
    /**
98
     * @return int
99
     */
100 1
    public function getKeyTag(): int
101
    {
102 1
        return $this->keyTag;
103
    }
104
105
    /**
106
     * @param int $keyTag
107
     */
108 4
    public function setKeyTag(int $keyTag): void
109
    {
110 4
        $this->keyTag = $keyTag;
111 4
    }
112
113
    /**
114
     * @return int
115
     */
116 1
    public function getAlgorithm(): int
117
    {
118 1
        return $this->algorithm;
119
    }
120
121
    /**
122
     * @param string|int $algorithm
123
     *
124
     * @throws \InvalidArgumentException
125
     */
126 4
    public function setAlgorithm($algorithm): void
127
    {
128 4
        if (is_int($algorithm) || 1 === preg_match('/^\d+$/', $algorithm)) {
129 4
            $this->algorithm = (int) $algorithm;
130
131 4
            return;
132
        }
133
134 1
        $this->algorithm = _Algorithms::getAlgorithmValue((string) $algorithm);
135 1
    }
136
137
    /**
138
     * @param string $certificate Base64 encoded string
139
     *
140
     * @throws \InvalidArgumentException
141
     */
142 5
    public function setCertificate(string $certificate): void
143
    {
144 5
        if (false === $decoded = base64_decode($certificate, true)) {
145 1
            throw new \InvalidArgumentException('The certificate must be a valid Base64 encoded string.');
146
        }
147
148 4
        $this->certificate = $decoded;
149 4
    }
150
151
    /**
152
     * @return string Base64 encoded string
153
     */
154 2
    public function getCertificate(): string
155
    {
156 2
        return base64_encode($this->certificate);
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 1
    public function toText(): string
163
    {
164 1
        $type = (array_key_exists($this->certificateType, self::MNEMONICS)) ? self::MNEMONICS[$this->certificateType] : (string) $this->certificateType;
165 1
        $algorithm = (array_key_exists($this->algorithm, _Algorithms::MNEMONICS)) ? _Algorithms::MNEMONICS[$this->algorithm] : (string) $this->algorithm;
166
167 1
        return sprintf('%s %s %s %s', $type, (string) $this->keyTag, $algorithm, $this->getCertificate());
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 1
    public function toWire(): string
174
    {
175 1
        return pack('nnC', $this->certificateType, $this->keyTag, $this->algorithm).$this->certificate;
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181 1
    public static function fromText(string $text): RdataInterface
182
    {
183 1
        $rdata = explode(Tokens::SPACE, $text);
184 1
        $cert = new static();
185 1
        $cert->setCertificateType((string) array_shift($rdata));
186 1
        $cert->setKeyTag((int) array_shift($rdata));
187 1
        $cert->setAlgorithm((string) array_shift($rdata));
188 1
        $cert->setCertificate(implode('', $rdata));
189
190 1
        return $cert;
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196 1
    public static function fromWire(string $rdata, int &$offset = 0, ?int $rdLength = null): RdataInterface
197
    {
198 1
        $integers = unpack('ntype/nkeyTag/Calgorithm', $rdata, $offset);
199 1
        $offset += 5;
200 1
        $cert = new static();
201 1
        $cert->setCertificateType((int) $integers['type']);
202 1
        $cert->setKeyTag((int) $integers['keyTag']);
203 1
        $cert->setAlgorithm((int) $integers['algorithm']);
204
205 1
        $certLen = ($rdLength ?? strlen($rdata)) - 5;
206 1
        $cert->setCertificate(base64_encode(substr($rdata, $offset, $certLen)));
207 1
        $offset += $certLen;
208
209 1
        return $cert;
210
    }
211
212
    /**
213
     * @param string $keyTypeMnemonic
214
     *
215
     * @return int
216
     *
217
     * @throws \InvalidArgumentException
218
     */
219 5
    public static function getKeyTypeValue(string $keyTypeMnemonic): int
220
    {
221 5
        if (false === $keyTypeValue = array_search($keyTypeMnemonic, self::MNEMONICS, true)) {
222 1
            throw new \InvalidArgumentException(sprintf('"%s" is not a valid key type mnemonic.', $keyTypeMnemonic));
223
        }
224
225 5
        return (int) $keyTypeValue;
226
    }
227
228
    /**
229
     * Get the associated mnemonic of a key type.
230
     *
231
     * @param int $keyTypeValue
232
     *
233
     * @return string
234
     *
235
     * @throws \InvalidArgumentException
236
     */
237 1
    public static function getKeyTypeMnemonic(int $keyTypeValue): string
238
    {
239 1
        if (!array_key_exists($keyTypeValue, self::MNEMONICS)) {
240 1
            throw new \InvalidArgumentException(sprintf('"%d" is not a valid key type.', $keyTypeValue));
241
        }
242
243 1
        return self::MNEMONICS[$keyTypeValue];
244
    }
245
}
246