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.

AttributeCertificateInfo   A
last analyzed

Complexity

Total Complexity 37

Size/Duplication

Total Lines 447
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 37
eloc 108
dl 0
loc 447
ccs 124
cts 124
cp 1
rs 9.44
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A withHolder() 0 5 1
A hasSignature() 0 3 1
A signature() 0 6 2
A __construct() 0 9 1
A withExtensions() 0 5 1
A sign() 0 12 2
A holder() 0 3 1
A withSignature() 0 5 1
A withSerialNumber() 0 5 1
A hasSerialNumber() 0 3 1
A hasIssuerUniqueID() 0 3 1
A attributes() 0 3 1
A withAdditionalExtensions() 0 5 1
A withIssuer() 0 5 1
A withValidity() 0 5 1
A withAttributes() 0 5 1
A toASN1() 0 14 3
A validityPeriod() 0 3 1
A fromASN1() 0 29 5
A issuer() 0 3 1
A issuerUniqueID() 0 6 2
A extensions() 0 3 1
A withIssuerUniqueID() 0 5 1
A withRandomSerialNumber() 0 9 2
A version() 0 3 1
A serialNumber() 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\Primitive\Integer;
10
use Sop\CryptoBridge\Crypto;
11
use Sop\CryptoTypes\AlgorithmIdentifier\AlgorithmIdentifier;
12
use Sop\CryptoTypes\AlgorithmIdentifier\Feature\SignatureAlgorithmIdentifier;
13
use Sop\CryptoTypes\Asymmetric\PrivateKeyInfo;
14
use Sop\X509\Certificate\Extension\Extension;
15
use Sop\X509\Certificate\Extensions;
16
use Sop\X509\Certificate\UniqueIdentifier;
17
18
/**
19
 * Implements *AttributeCertificateInfo* ASN.1 type.
20
 *
21
 * @see https://tools.ietf.org/html/rfc5755#section-4.1
22
 */
23
class AttributeCertificateInfo
24
{
25
    const VERSION_2 = 1;
26
27
    /**
28
     * AC version.
29
     *
30
     * @var int
31
     */
32
    protected $_version;
33
34
    /**
35
     * AC holder.
36
     *
37
     * @var Holder
38
     */
39
    protected $_holder;
40
41
    /**
42
     * AC issuer.
43
     *
44
     * @var AttCertIssuer
45
     */
46
    protected $_issuer;
47
48
    /**
49
     * Signature algorithm identifier.
50
     *
51
     * @var SignatureAlgorithmIdentifier
52
     */
53
    protected $_signature;
54
55
    /**
56
     * AC serial number as a base 10 integer.
57
     *
58
     * @var string
59
     */
60
    protected $_serialNumber;
61
62
    /**
63
     * Validity period.
64
     *
65
     * @var AttCertValidityPeriod
66
     */
67
    protected $_attrCertValidityPeriod;
68
69
    /**
70
     * Attributes.
71
     *
72
     * @var Attributes
73
     */
74
    protected $_attributes;
75
76
    /**
77
     * Issuer unique identifier.
78
     *
79
     * @var null|UniqueIdentifier
80
     */
81
    protected $_issuerUniqueID;
82
83
    /**
84
     * Extensions.
85
     *
86
     * @var Extensions
87
     */
88
    protected $_extensions;
89
90
    /**
91
     * Constructor.
92
     *
93
     * @param Holder                $holder   AC holder
94
     * @param AttCertIssuer         $issuer   AC issuer
95
     * @param AttCertValidityPeriod $validity Validity
96
     * @param Attributes            $attribs  Attributes
97
     */
98 8
    public function __construct(Holder $holder, AttCertIssuer $issuer,
99
        AttCertValidityPeriod $validity, Attributes $attribs)
100
    {
101 8
        $this->_version = self::VERSION_2;
102 8
        $this->_holder = $holder;
103 8
        $this->_issuer = $issuer;
104 8
        $this->_attrCertValidityPeriod = $validity;
105 8
        $this->_attributes = $attribs;
106 8
        $this->_extensions = new Extensions();
107 8
    }
108
109
    /**
110
     * Initialize from ASN.1.
111
     *
112
     * @param Sequence $seq
113
     *
114
     * @throws \UnexpectedValueException
115
     *
116
     * @return self
117
     */
118 7
    public static function fromASN1(Sequence $seq): self
119
    {
120 7
        $idx = 0;
121 7
        $version = $seq->at($idx++)->asInteger()->intNumber();
122 7
        if (self::VERSION_2 !== $version) {
123 1
            throw new \UnexpectedValueException('Version must be 2.');
124
        }
125 6
        $holder = Holder::fromASN1($seq->at($idx++)->asSequence());
126 6
        $issuer = AttCertIssuer::fromASN1($seq->at($idx++));
127 6
        $signature = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence());
128 6
        if (!$signature instanceof SignatureAlgorithmIdentifier) {
129 1
            throw new \UnexpectedValueException(
130 1
                'Unsupported signature algorithm ' . $signature->oid() . '.');
131
        }
132 5
        $serial = $seq->at($idx++)->asInteger()->number();
133 5
        $validity = AttCertValidityPeriod::fromASN1($seq->at($idx++)->asSequence());
134 5
        $attribs = Attributes::fromASN1($seq->at($idx++)->asSequence());
135 5
        $obj = new self($holder, $issuer, $validity, $attribs);
136 5
        $obj->_signature = $signature;
137 5
        $obj->_serialNumber = $serial;
138 5
        if ($seq->has($idx, Element::TYPE_BIT_STRING)) {
139 1
            $obj->_issuerUniqueID = UniqueIdentifier::fromASN1(
140 1
                $seq->at($idx++)->asBitString());
141
        }
142 5
        if ($seq->has($idx, Element::TYPE_SEQUENCE)) {
143 3
            $obj->_extensions = Extensions::fromASN1(
144 3
                $seq->at($idx++)->asSequence());
145
        }
146 5
        return $obj;
147
    }
148
149
    /**
150
     * Get self with holder.
151
     *
152
     * @param Holder $holder
153
     *
154
     * @return self
155
     */
156 1
    public function withHolder(Holder $holder): self
157
    {
158 1
        $obj = clone $this;
159 1
        $obj->_holder = $holder;
160 1
        return $obj;
161
    }
162
163
    /**
164
     * Get self with issuer.
165
     *
166
     * @param AttCertIssuer $issuer
167
     *
168
     * @return self
169
     */
170 1
    public function withIssuer(AttCertIssuer $issuer): self
171
    {
172 1
        $obj = clone $this;
173 1
        $obj->_issuer = $issuer;
174 1
        return $obj;
175
    }
176
177
    /**
178
     * Get self with signature algorithm identifier.
179
     *
180
     * @param SignatureAlgorithmIdentifier $algo
181
     *
182
     * @return self
183
     */
184 3
    public function withSignature(SignatureAlgorithmIdentifier $algo): self
185
    {
186 3
        $obj = clone $this;
187 3
        $obj->_signature = $algo;
188 3
        return $obj;
189
    }
190
191
    /**
192
     * Get self with serial number.
193
     *
194
     * @param int|string $serial Base 10 serial number
195
     *
196
     * @return self
197
     */
198 4
    public function withSerialNumber($serial): self
199
    {
200 4
        $obj = clone $this;
201 4
        $obj->_serialNumber = strval($serial);
202 4
        return $obj;
203
    }
204
205
    /**
206
     * Get self with random positive serial number.
207
     *
208
     * @param int $size Number of random bytes
209
     *
210
     * @return self
211
     */
212 1
    public function withRandomSerialNumber(int $size = 16): self
213
    {
214
        // ensure that first byte is always non-zero and having first bit unset
215 1
        $num = gmp_init(mt_rand(1, 0x7f), 10);
216 1
        for ($i = 1; $i < $size; ++$i) {
217 1
            $num <<= 8;
218 1
            $num += mt_rand(0, 0xff);
219
        }
220 1
        return $this->withSerialNumber(gmp_strval($num, 10));
221
    }
222
223
    /**
224
     * Get self with validity period.
225
     *
226
     * @param AttCertValidityPeriod $validity
227
     *
228
     * @return self
229
     */
230 1
    public function withValidity(AttCertValidityPeriod $validity): self
231
    {
232 1
        $obj = clone $this;
233 1
        $obj->_attrCertValidityPeriod = $validity;
234 1
        return $obj;
235
    }
236
237
    /**
238
     * Get self with attributes.
239
     *
240
     * @param Attributes $attribs
241
     *
242
     * @return self
243
     */
244 1
    public function withAttributes(Attributes $attribs): self
245
    {
246 1
        $obj = clone $this;
247 1
        $obj->_attributes = $attribs;
248 1
        return $obj;
249
    }
250
251
    /**
252
     * Get self with issuer unique identifier.
253
     *
254
     * @param UniqueIdentifier $uid
255
     *
256
     * @return self
257
     */
258 2
    public function withIssuerUniqueID(UniqueIdentifier $uid): self
259
    {
260 2
        $obj = clone $this;
261 2
        $obj->_issuerUniqueID = $uid;
262 2
        return $obj;
263
    }
264
265
    /**
266
     * Get self with extensions.
267
     *
268
     * @param Extensions $extensions
269
     *
270
     * @return self
271
     */
272 2
    public function withExtensions(Extensions $extensions): self
273
    {
274 2
        $obj = clone $this;
275 2
        $obj->_extensions = $extensions;
276 2
        return $obj;
277
    }
278
279
    /**
280
     * Get self with extensions added.
281
     *
282
     * @param Extension ...$exts One or more Extension objects
283
     *
284
     * @return self
285
     */
286 1
    public function withAdditionalExtensions(Extension ...$exts): self
287
    {
288 1
        $obj = clone $this;
289 1
        $obj->_extensions = $obj->_extensions->withExtensions(...$exts);
290 1
        return $obj;
291
    }
292
293
    /**
294
     * Get version.
295
     *
296
     * @return int
297
     */
298 1
    public function version(): int
299
    {
300 1
        return $this->_version;
301
    }
302
303
    /**
304
     * Get AC holder.
305
     *
306
     * @return Holder
307
     */
308 14
    public function holder(): Holder
309
    {
310 14
        return $this->_holder;
311
    }
312
313
    /**
314
     * Get AC issuer.
315
     *
316
     * @return AttCertIssuer
317
     */
318 12
    public function issuer(): AttCertIssuer
319
    {
320 12
        return $this->_issuer;
321
    }
322
323
    /**
324
     * Check whether signature is set.
325
     *
326
     * @return bool
327
     */
328 21
    public function hasSignature(): bool
329
    {
330 21
        return isset($this->_signature);
331
    }
332
333
    /**
334
     * Get signature algorithm identifier.
335
     *
336
     * @throws \LogicException If not set
337
     *
338
     * @return SignatureAlgorithmIdentifier
339
     */
340 21
    public function signature(): SignatureAlgorithmIdentifier
341
    {
342 21
        if (!$this->hasSignature()) {
343 1
            throw new \LogicException('signature not set.');
344
        }
345 20
        return $this->_signature;
346
    }
347
348
    /**
349
     * Check whether serial number is present.
350
     *
351
     * @return bool
352
     */
353 22
    public function hasSerialNumber(): bool
354
    {
355 22
        return isset($this->_serialNumber);
356
    }
357
358
    /**
359
     * Get AC serial number as a base 10 integer.
360
     *
361
     * @throws \LogicException If not set
362
     *
363
     * @return string
364
     */
365 22
    public function serialNumber(): string
366
    {
367 22
        if (!$this->hasSerialNumber()) {
368 1
            throw new \LogicException('serialNumber not set.');
369
        }
370 21
        return $this->_serialNumber;
371
    }
372
373
    /**
374
     * Get validity period.
375
     *
376
     * @return AttCertValidityPeriod
377
     */
378 6
    public function validityPeriod(): AttCertValidityPeriod
379
    {
380 6
        return $this->_attrCertValidityPeriod;
381
    }
382
383
    /**
384
     * Get attributes.
385
     *
386
     * @return Attributes
387
     */
388 1
    public function attributes(): Attributes
389
    {
390 1
        return $this->_attributes;
391
    }
392
393
    /**
394
     * Check whether issuer unique identifier is present.
395
     *
396
     * @return bool
397
     */
398 2
    public function hasIssuerUniqueID(): bool
399
    {
400 2
        return isset($this->_issuerUniqueID);
401
    }
402
403
    /**
404
     * Get issuer unique identifier.
405
     *
406
     * @throws \LogicException If not set
407
     *
408
     * @return UniqueIdentifier
409
     */
410 2
    public function issuerUniqueID(): UniqueIdentifier
411
    {
412 2
        if (!$this->hasIssuerUniqueID()) {
413 1
            throw new \LogicException('issuerUniqueID not set.');
414
        }
415 1
        return $this->_issuerUniqueID;
416
    }
417
418
    /**
419
     * Get extensions.
420
     *
421
     * @return Extensions
422
     */
423 4
    public function extensions(): Extensions
424
    {
425 4
        return $this->_extensions;
426
    }
427
428
    /**
429
     * Get ASN.1 structure.
430
     *
431
     * @return Sequence
432
     */
433 19
    public function toASN1(): Sequence
434
    {
435 19
        $elements = [new Integer($this->_version), $this->_holder->toASN1(),
436 19
            $this->_issuer->toASN1(), $this->signature()->toASN1(),
437 19
            new Integer($this->serialNumber()),
438 19
            $this->_attrCertValidityPeriod->toASN1(),
439 19
            $this->_attributes->toASN1(), ];
440 19
        if (isset($this->_issuerUniqueID)) {
441 3
            $elements[] = $this->_issuerUniqueID->toASN1();
442
        }
443 19
        if (count($this->_extensions)) {
444 8
            $elements[] = $this->_extensions->toASN1();
445
        }
446 19
        return new Sequence(...$elements);
447
    }
448
449
    /**
450
     * Create signed attribute certificate.
451
     *
452
     * @param SignatureAlgorithmIdentifier $algo         Signature algorithm
453
     * @param PrivateKeyInfo               $privkey_info Private key
454
     * @param null|Crypto                  $crypto       Crypto engine, use default if not set
455
     *
456
     * @return AttributeCertificate
457
     */
458 1
    public function sign(SignatureAlgorithmIdentifier $algo,
459
        PrivateKeyInfo $privkey_info, ?Crypto $crypto = null): AttributeCertificate
460
    {
461 1
        $crypto = $crypto ?? Crypto::getDefault();
462 1
        $aci = clone $this;
463 1
        if (!isset($aci->_serialNumber)) {
464 1
            $aci->_serialNumber = '0';
465
        }
466 1
        $aci->_signature = $algo;
467 1
        $data = $aci->toASN1()->toDER();
468 1
        $signature = $crypto->sign($data, $privkey_info, $algo);
469 1
        return new AttributeCertificate($aci, $algo, $signature);
470
    }
471
}
472