AuthorityKeyIdentifierExtension::_fromDER()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 23
cts 23
cp 1
rs 8.8177
c 0
b 0
f 0
nc 6
cc 6
nop 2
crap 6
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace X509\Certificate\Extension;
6
7
use ASN1\Element;
8
use ASN1\Type\UnspecifiedType;
9
use ASN1\Type\Constructed\Sequence;
10
use ASN1\Type\Primitive\Integer;
11
use ASN1\Type\Primitive\OctetString;
12
use ASN1\Type\Tagged\ImplicitlyTaggedType;
13
use Sop\CryptoTypes\Asymmetric\PublicKeyInfo;
14
use X509\GeneralName\GeneralNames;
15
16
/**
17
 * Implements 'Authority Key Identifier' certificate extension.
18
 *
19
 * @link https://tools.ietf.org/html/rfc5280#section-4.2.1.1
20
 */
21
class AuthorityKeyIdentifierExtension extends Extension
22
{
23
    /**
24
     * Key identifier.
25
     *
26
     * @var string|null $_keyIdentifier
27
     */
28
    protected $_keyIdentifier;
29
    
30
    /**
31
     * Issuer name.
32
     *
33
     * @var GeneralNames|null $_authorityCertIssuer
34
     */
35
    protected $_authorityCertIssuer;
36
    
37
    /**
38
     * Issuer serial number.
39
     *
40
     * @var string|null $_authorityCertSerialNumber
41
     */
42
    protected $_authorityCertSerialNumber;
43
    
44
    /**
45
     * Constructor.
46
     *
47
     * @param bool $critical Conforming CA's must mark as non-critical (false)
48
     * @param string|null $keyIdentifier
49
     * @param GeneralNames|null $issuer
50
     * @param string|null $serial
51
     */
52 27
    public function __construct(bool $critical, $keyIdentifier,
53
        GeneralNames $issuer = null, $serial = null)
54
    {
55 27
        parent::__construct(self::OID_AUTHORITY_KEY_IDENTIFIER, $critical);
56 27
        $this->_keyIdentifier = $keyIdentifier;
57 27
        $this->_authorityCertIssuer = $issuer;
58 27
        $this->_authorityCertSerialNumber = isset($serial) ? strval($serial) : null;
59 27
    }
60
    
61
    /**
62
     * Create from public key info.
63
     *
64
     * @param PublicKeyInfo $pki
65
     * @return AuthorityKeyIdentifierExtension
66
     */
67 1
    public static function fromPublicKeyInfo(PublicKeyInfo $pki)
68
    {
69 1
        return new self(false, $pki->keyIdentifier());
70
    }
71
    
72
    /**
73
     *
74
     * {@inheritdoc}
75
     * @return self
76
     */
77 20
    protected static function _fromDER(string $data, bool $critical): self
78
    {
79 20
        $seq = UnspecifiedType::fromDER($data)->asSequence();
80 20
        $keyIdentifier = null;
81 20
        $issuer = null;
82 20
        $serial = null;
83 20
        if ($seq->hasTagged(0)) {
84 20
            $keyIdentifier = $seq->getTagged(0)
85 20
                ->asImplicit(Element::TYPE_OCTET_STRING)
86 20
                ->asOctetString()
87 20
                ->string();
88
        }
89 20
        if ($seq->hasTagged(1) || $seq->hasTagged(2)) {
90 10
            if (!$seq->hasTagged(1) || !$seq->hasTagged(2)) {
91 1
                throw new \UnexpectedValueException(
92
                    "AuthorityKeyIdentifier must have both" .
93
                         " authorityCertIssuer and authorityCertSerialNumber" .
94 1
                         " present or both absent.");
95
            }
96 9
            $issuer = GeneralNames::fromASN1(
97 9
                $seq->getTagged(1)
98 9
                    ->asImplicit(Element::TYPE_SEQUENCE)
99 9
                    ->asSequence());
100 9
            $serial = $seq->getTagged(2)
101 9
                ->asImplicit(Element::TYPE_INTEGER)
102 9
                ->asInteger()
103 9
                ->number();
104
        }
105 19
        return new self($critical, $keyIdentifier, $issuer, $serial);
106
    }
107
    
108
    /**
109
     * Whether key identifier is present.
110
     *
111
     * @return bool
112
     */
113 12
    public function hasKeyIdentifier(): bool
114
    {
115 12
        return isset($this->_keyIdentifier);
116
    }
117
    
118
    /**
119
     * Get key identifier.
120
     *
121
     * @throws \LogicException
122
     * @return string
123
     */
124 12
    public function keyIdentifier(): string
125
    {
126 12
        if (!$this->hasKeyIdentifier()) {
127 1
            throw new \LogicException("keyIdentifier not set.");
128
        }
129 11
        return $this->_keyIdentifier;
130
    }
131
    
132
    /**
133
     * Whether issuer is present.
134
     *
135
     * @return bool
136
     */
137 5
    public function hasIssuer(): bool
138
    {
139 5
        return isset($this->_authorityCertIssuer);
140
    }
141
    
142
    /**
143
     * Get issuer.
144
     *
145
     * @throws \LogicException
146
     * @return GeneralNames
147
     */
148 3
    public function issuer(): GeneralNames
149
    {
150 3
        if (!$this->hasIssuer()) {
151 1
            throw new \LogicException("authorityCertIssuer not set.");
152
        }
153 2
        return $this->_authorityCertIssuer;
154
    }
155
    
156
    /**
157
     * Get serial number.
158
     *
159
     * @throws \LogicException
160
     * @return string Base 10 integer string
161
     */
162 3
    public function serial(): string
163
    {
164
        // both issuer and serial must be present or both absent
165 3
        if (!$this->hasIssuer()) {
166 1
            throw new \LogicException("authorityCertSerialNumber not set.");
167
        }
168 2
        return $this->_authorityCertSerialNumber;
169
    }
170
    
171
    /**
172
     *
173
     * {@inheritdoc}
174
     * @return Sequence
175
     */
176 49
    protected function _valueASN1(): Sequence
177
    {
178 49
        $elements = array();
179 49
        if (isset($this->_keyIdentifier)) {
180 49
            $elements[] = new ImplicitlyTaggedType(0,
181 49
                new OctetString($this->_keyIdentifier));
182
        }
183
        // if either issuer or serial is set, both must be set
184 49
        if (isset($this->_authorityCertIssuer) ||
185 49
             isset($this->_authorityCertSerialNumber)) {
186 16
            if (!isset($this->_authorityCertIssuer,
187 16
                $this->_authorityCertSerialNumber)) {
188 1
                throw new \LogicException(
189
                    "AuthorityKeyIdentifier must have both" .
190
                     " authorityCertIssuer and authorityCertSerialNumber" .
191 1
                     " present or both absent.");
192
            }
193 15
            $elements[] = new ImplicitlyTaggedType(1,
194 15
                $this->_authorityCertIssuer->toASN1());
195 15
            $elements[] = new ImplicitlyTaggedType(2,
196 15
                new Integer($this->_authorityCertSerialNumber));
197
        }
198 48
        return new Sequence(...$elements);
199
    }
200
}
201