GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Holder   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 283
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 37
eloc 79
dl 0
loc 283
ccs 92
cts 92
cp 1
rs 9.44
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A withBaseCertificateID() 0 5 1
A withObjectDigestInfo() 0 5 1
A __construct() 0 5 1
A hasEntityName() 0 3 1
B identifiesPKC() 0 16 7
A _checkEntityName() 0 14 4
A entityName() 0 6 2
A toASN1() 0 16 4
A baseCertificateID() 0 6 2
A _checkEntityAlternativeNames() 0 10 4
A withEntityName() 0 5 1
A fromPKC() 0 3 1
A hasObjectDigestInfo() 0 3 1
A hasBaseCertificateID() 0 3 1
A fromASN1() 0 23 4
A objectDigestInfo() 0 6 2
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\X509\AttributeCertificate;
6
7
use Sop\ASN1\Element;
8
use Sop\ASN1\Type\Constructed\Sequence;
9
use Sop\ASN1\Type\Tagged\ImplicitlyTaggedType;
10
use Sop\X509\Certificate\Certificate;
11
use Sop\X509\GeneralName\DirectoryName;
12
use Sop\X509\GeneralName\GeneralName;
13
use Sop\X509\GeneralName\GeneralNames;
14
15
/**
16
 * Implements *Holder* ASN.1 type.
17
 *
18
 * @see https://tools.ietf.org/html/rfc5755#section-4.1
19
 */
20
class Holder
21
{
22
    /**
23
     * Holder PKC's issuer and serial.
24
     *
25
     * @var null|IssuerSerial
26
     */
27
    protected $_baseCertificateID;
28
29
    /**
30
     * Holder PKC's subject.
31
     *
32
     * @var null|GeneralNames
33
     */
34
    protected $_entityName;
35
36
    /**
37
     * Linked object.
38
     *
39
     * @var null|ObjectDigestInfo
40
     */
41
    protected $_objectDigestInfo;
42
43
    /**
44
     * Constructor.
45
     *
46
     * @param null|IssuerSerial $issuer_serial
47
     * @param null|GeneralNames $entity_name
48
     */
49 21
    public function __construct(?IssuerSerial $issuer_serial = null,
50
        ?GeneralNames $entity_name = null)
51
    {
52 21
        $this->_baseCertificateID = $issuer_serial;
53 21
        $this->_entityName = $entity_name;
54 21
    }
55
56
    /**
57
     * Initialize from a holder's public key certificate.
58
     *
59
     * @param Certificate $cert
60
     *
61
     * @return self
62
     */
63 1
    public static function fromPKC(Certificate $cert): self
64
    {
65 1
        return new self(IssuerSerial::fromPKC($cert));
66
    }
67
68
    /**
69
     * Initialize from ASN.1.
70
     *
71
     * @param Sequence $seq
72
     */
73 7
    public static function fromASN1(Sequence $seq): self
74
    {
75 7
        $cert_id = null;
76 7
        $entity_name = null;
77 7
        $digest_info = null;
78 7
        if ($seq->hasTagged(0)) {
79 7
            $cert_id = IssuerSerial::fromASN1(
80 7
                $seq->getTagged(0)->asImplicit(Element::TYPE_SEQUENCE)
81 7
                    ->asSequence());
82
        }
83 7
        if ($seq->hasTagged(1)) {
84 3
            $entity_name = GeneralNames::fromASN1(
85 3
                $seq->getTagged(1)->asImplicit(Element::TYPE_SEQUENCE)
86 3
                    ->asSequence());
87
        }
88 7
        if ($seq->hasTagged(2)) {
89 1
            $digest_info = ObjectDigestInfo::fromASN1(
90 1
                $seq->getTagged(2)->asImplicit(Element::TYPE_SEQUENCE)
91 1
                    ->asSequence());
92
        }
93 7
        $obj = new self($cert_id, $entity_name);
94 7
        $obj->_objectDigestInfo = $digest_info;
95 7
        return $obj;
96
    }
97
98
    /**
99
     * Get self with base certificate ID.
100
     *
101
     * @param IssuerSerial $issuer
102
     *
103
     * @return self
104
     */
105 1
    public function withBaseCertificateID(IssuerSerial $issuer): self
106
    {
107 1
        $obj = clone $this;
108 1
        $obj->_baseCertificateID = $issuer;
109 1
        return $obj;
110
    }
111
112
    /**
113
     * Get self with entity name.
114
     *
115
     * @param GeneralNames $names
116
     *
117
     * @return self
118
     */
119 1
    public function withEntityName(GeneralNames $names): self
120
    {
121 1
        $obj = clone $this;
122 1
        $obj->_entityName = $names;
123 1
        return $obj;
124
    }
125
126
    /**
127
     * Get self with object digest info.
128
     *
129
     * @param ObjectDigestInfo $odi
130
     *
131
     * @return self
132
     */
133 2
    public function withObjectDigestInfo(ObjectDigestInfo $odi): self
134
    {
135 2
        $obj = clone $this;
136 2
        $obj->_objectDigestInfo = $odi;
137 2
        return $obj;
138
    }
139
140
    /**
141
     * Check whether base certificate ID is present.
142
     *
143
     * @return bool
144
     */
145 2
    public function hasBaseCertificateID(): bool
146
    {
147 2
        return isset($this->_baseCertificateID);
148
    }
149
150
    /**
151
     * Get base certificate ID.
152
     *
153
     * @throws \LogicException If not set
154
     *
155
     * @return IssuerSerial
156
     */
157 2
    public function baseCertificateID(): IssuerSerial
158
    {
159 2
        if (!$this->hasBaseCertificateID()) {
160 1
            throw new \LogicException('baseCertificateID not set.');
161
        }
162 1
        return $this->_baseCertificateID;
163
    }
164
165
    /**
166
     * Check whether entity name is present.
167
     *
168
     * @return bool
169
     */
170 2
    public function hasEntityName(): bool
171
    {
172 2
        return isset($this->_entityName);
173
    }
174
175
    /**
176
     * Get entity name.
177
     *
178
     * @throws \LogicException If not set
179
     *
180
     * @return GeneralNames
181
     */
182 2
    public function entityName(): GeneralNames
183
    {
184 2
        if (!$this->hasEntityName()) {
185 1
            throw new \LogicException('entityName not set.');
186
        }
187 1
        return $this->_entityName;
188
    }
189
190
    /**
191
     * Check whether object digest info is present.
192
     *
193
     * @return bool
194
     */
195 2
    public function hasObjectDigestInfo(): bool
196
    {
197 2
        return isset($this->_objectDigestInfo);
198
    }
199
200
    /**
201
     * Get object digest info.
202
     *
203
     * @throws \LogicException If not set
204
     *
205
     * @return ObjectDigestInfo
206
     */
207 2
    public function objectDigestInfo(): ObjectDigestInfo
208
    {
209 2
        if (!$this->hasObjectDigestInfo()) {
210 1
            throw new \LogicException('objectDigestInfo not set.');
211
        }
212 1
        return $this->_objectDigestInfo;
213
    }
214
215
    /**
216
     * Generate ASN.1 structure.
217
     *
218
     * @return Sequence
219
     */
220 20
    public function toASN1(): Sequence
221
    {
222 20
        $elements = [];
223 20
        if (isset($this->_baseCertificateID)) {
224 20
            $elements[] = new ImplicitlyTaggedType(0,
225 20
                $this->_baseCertificateID->toASN1());
226
        }
227 20
        if (isset($this->_entityName)) {
228 4
            $elements[] = new ImplicitlyTaggedType(1,
229 4
                $this->_entityName->toASN1());
230
        }
231 20
        if (isset($this->_objectDigestInfo)) {
232 1
            $elements[] = new ImplicitlyTaggedType(2,
233 1
                $this->_objectDigestInfo->toASN1());
234
        }
235 20
        return new Sequence(...$elements);
236
    }
237
238
    /**
239
     * Check whether Holder identifies given certificate.
240
     *
241
     * @param Certificate $cert
242
     *
243
     * @return bool
244
     */
245 19
    public function identifiesPKC(Certificate $cert): bool
246
    {
247
        // if neither baseCertificateID nor entityName are present
248 19
        if (!$this->_baseCertificateID && !$this->_entityName) {
249 1
            return false;
250
        }
251
        // if baseCertificateID is present, but doesn't match
252 18
        if ($this->_baseCertificateID &&
253 18
            !$this->_baseCertificateID->identifiesPKC($cert)) {
254 3
            return false;
255
        }
256
        // if entityName is present, but doesn't match
257 15
        if ($this->_entityName && !$this->_checkEntityName($cert)) {
258 1
            return false;
259
        }
260 14
        return true;
261
    }
262
263
    /**
264
     * Check whether entityName matches the given certificate.
265
     *
266
     * @param Certificate $cert
267
     *
268
     * @return bool
269
     */
270 4
    private function _checkEntityName(Certificate $cert): bool
271
    {
272 4
        $name = $this->_entityName->firstDN();
273 4
        if ($cert->tbsCertificate()->subject()->equals($name)) {
274 2
            return true;
275
        }
276 2
        $exts = $cert->tbsCertificate()->extensions();
277 2
        if ($exts->hasSubjectAlternativeName()) {
278 2
            $ext = $exts->subjectAlternativeName();
279 2
            if ($this->_checkEntityAlternativeNames($ext->names())) {
280 1
                return true;
281
            }
282
        }
283 1
        return false;
284
    }
285
286
    /**
287
     * Check whether any of the subject alternative names match entityName.
288
     *
289
     * @param GeneralNames $san
290
     *
291
     * @return bool
292
     */
293 2
    private function _checkEntityAlternativeNames(GeneralNames $san): bool
294
    {
295
        // only directory names supported for now
296 2
        $name = $this->_entityName->firstDN();
297 2
        foreach ($san->allOf(GeneralName::TAG_DIRECTORY_NAME) as $dn) {
298 2
            if ($dn instanceof DirectoryName && $dn->dn()->equals($name)) {
299 2
                return true;
300
            }
301
        }
302 1
        return false;
303
    }
304
}
305