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.
Test Failed
Push — master ( 405cf3...79c9ba )
by Joni
04:48
created

AttributeCertificateInfo::toASN1()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 14
ccs 2
cts 2
cp 1
rs 9.9332
c 0
b 0
f 0
cc 3
nc 4
nop 0
crap 3
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 7
     * @return self
117
     */
118 7
    public static function fromASN1(Sequence $seq): self
119 7
    {
120 7
        $idx = 0;
121 7
        $version = $seq->at($idx++)->asInteger()->intNumber();
122 1
        if (self::VERSION_2 !== $version) {
123
            throw new \UnexpectedValueException('Version must be 2.');
124 6
        }
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 1
        if (!$signature instanceof SignatureAlgorithmIdentifier) {
129 1
            throw new \UnexpectedValueException(
130
                'Unsupported signature algorithm ' . $signature->oid() . '.');
131 5
        }
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 5
            $obj->_issuerUniqueID = UniqueIdentifier::fromASN1(
140 5
                $seq->at($idx++)->asBitString());
141 1
        }
142 1
        if ($seq->has($idx, Element::TYPE_SEQUENCE)) {
143
            $obj->_extensions = Extensions::fromASN1(
144 5
                $seq->at($idx++)->asSequence());
145 3
        }
146 3
        return $obj;
147
    }
148 5
149
    /**
150
     * Get self with holder.
151
     *
152
     * @param Holder $holder
153
     *
154
     * @return self
155
     */
156
    public function withHolder(Holder $holder): self
157 1
    {
158
        $obj = clone $this;
159 1
        $obj->_holder = $holder;
160 1
        return $obj;
161 1
    }
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 3
     */
184
    public function withSignature(SignatureAlgorithmIdentifier $algo): self
185 3
    {
186 3
        $obj = clone $this;
187 3
        $obj->_signature = $algo;
188
        return $obj;
189
    }
190
191
    /**
192
     * Get self with serial number.
193
     *
194
     * @param int|string $serial Base 10 serial number
195
     *
196 4
     * @return self
197
     */
198 4
    public function withSerialNumber($serial): self
199 4
    {
200 4
        $obj = clone $this;
201
        $obj->_serialNumber = strval($serial);
202
        return $obj;
203
    }
204
205
    /**
206
     * Get self with random positive serial number.
207
     *
208
     * @param int $size Number of random bytes
209 1
     *
210
     * @return self
211
     */
212 1
    public function withRandomSerialNumber(int $size = 16): self
213 1
    {
214 1
        // ensure that first byte is always non-zero and having first bit unset
215 1
        $num = gmp_init(mt_rand(1, 0x7f), 10);
216
        for ($i = 1; $i < $size; ++$i) {
217 1
            $num <<= 8;
218
            $num += mt_rand(0, 0xff);
219
        }
220
        return $this->withSerialNumber(gmp_strval($num, 10));
221
    }
222
223
    /**
224
     * Get self with validity period.
225
     *
226 1
     * @param AttCertValidityPeriod $validity
227
     *
228 1
     * @return self
229 1
     */
230 1
    public function withValidity(AttCertValidityPeriod $validity): self
231
    {
232
        $obj = clone $this;
233
        $obj->_attrCertValidityPeriod = $validity;
234
        return $obj;
235
    }
236
237
    /**
238
     * Get self with attributes.
239 1
     *
240
     * @param Attributes $attribs
241 1
     *
242 1
     * @return self
243 1
     */
244
    public function withAttributes(Attributes $attribs): self
245
    {
246
        $obj = clone $this;
247
        $obj->_attributes = $attribs;
248
        return $obj;
249
    }
250
251
    /**
252 2
     * Get self with issuer unique identifier.
253
     *
254 2
     * @param UniqueIdentifier $uid
255 2
     *
256 2
     * @return self
257
     */
258
    public function withIssuerUniqueID(UniqueIdentifier $uid): self
259
    {
260
        $obj = clone $this;
261
        $obj->_issuerUniqueID = $uid;
262
        return $obj;
263
    }
264
265 2
    /**
266
     * Get self with extensions.
267 2
     *
268 2
     * @param Extensions $extensions
269 2
     *
270
     * @return self
271
     */
272
    public function withExtensions(Extensions $extensions): self
273
    {
274
        $obj = clone $this;
275
        $obj->_extensions = $extensions;
276
        return $obj;
277
    }
278 1
279
    /**
280 1
     * Get self with extensions added.
281 1
     *
282 1
     * @param Extension ...$exts One or more Extension objects
283
     *
284
     * @return self
285
     */
286
    public function withAdditionalExtensions(Extension ...$exts): self
287
    {
288
        $obj = clone $this;
289
        $obj->_extensions = $obj->_extensions->withExtensions(...$exts);
290 1
        return $obj;
291
    }
292 1
293
    /**
294
     * Get version.
295
     *
296
     * @return int
297
     */
298
    public function version(): int
299
    {
300 14
        return $this->_version;
301
    }
302 14
303
    /**
304
     * Get AC holder.
305
     *
306
     * @return Holder
307
     */
308
    public function holder(): Holder
309
    {
310 12
        return $this->_holder;
311
    }
312 12
313
    /**
314
     * Get AC issuer.
315
     *
316
     * @return AttCertIssuer
317
     */
318
    public function issuer(): AttCertIssuer
319
    {
320 21
        return $this->_issuer;
321
    }
322 21
323
    /**
324
     * Check whether signature is set.
325
     *
326
     * @return bool
327
     */
328
    public function hasSignature(): bool
329
    {
330 21
        return isset($this->_signature);
331
    }
332 21
333 1
    /**
334
     * Get signature algorithm identifier.
335 20
     *
336
     * @throws \LogicException If not set
337
     *
338
     * @return SignatureAlgorithmIdentifier
339
     */
340
    public function signature(): SignatureAlgorithmIdentifier
341
    {
342
        if (!$this->hasSignature()) {
343 22
            throw new \LogicException('signature not set.');
344
        }
345 22
        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 1
    }
357
358 21
    /**
359
     * Get AC serial number as a base 10 integer.
360
     *
361
     * @throws \LogicException If not set
362
     *
363
     * @return string
364
     */
365
    public function serialNumber(): string
366 6
    {
367
        if (!$this->hasSerialNumber()) {
368 6
            throw new \LogicException('serialNumber not set.');
369
        }
370
        return $this->_serialNumber;
371
    }
372
373
    /**
374
     * Get validity period.
375
     *
376 1
     * @return AttCertValidityPeriod
377
     */
378 1
    public function validityPeriod(): AttCertValidityPeriod
379
    {
380
        return $this->_attrCertValidityPeriod;
381
    }
382
383
    /**
384
     * Get attributes.
385
     *
386 2
     * @return Attributes
387
     */
388 2
    public function attributes(): Attributes
389
    {
390
        return $this->_attributes;
391
    }
392
393
    /**
394
     * Check whether issuer unique identifier is present.
395
     *
396 2
     * @return bool
397
     */
398 2
    public function hasIssuerUniqueID(): bool
399 1
    {
400
        return isset($this->_issuerUniqueID);
401 1
    }
402
403
    /**
404
     * Get issuer unique identifier.
405
     *
406
     * @throws \LogicException If not set
407
     *
408
     * @return UniqueIdentifier
409 4
     */
410
    public function issuerUniqueID(): UniqueIdentifier
411 4
    {
412
        if (!$this->hasIssuerUniqueID()) {
413
            throw new \LogicException('issuerUniqueID not set.');
414
        }
415
        return $this->_issuerUniqueID;
416
    }
417
418
    /**
419 19
     * Get extensions.
420
     *
421 19
     * @return Extensions
422 19
     */
423 19
    public function extensions(): Extensions
424 19
    {
425 19
        return $this->_extensions;
426 19
    }
427 3
428
    /**
429 19
     * Get ASN.1 structure.
430 8
     *
431
     * @return Sequence
432 19
     */
433
    public function toASN1(): Sequence
434
    {
435
        $elements = [new Integer($this->_version), $this->_holder->toASN1(),
436
            $this->_issuer->toASN1(), $this->signature()->toASN1(),
437
            new Integer($this->serialNumber()),
438
            $this->_attrCertValidityPeriod->toASN1(),
439
            $this->_attributes->toASN1(), ];
440
        if (isset($this->_issuerUniqueID)) {
441
            $elements[] = $this->_issuerUniqueID->toASN1();
442
        }
443 1
        if (count($this->_extensions)) {
444
            $elements[] = $this->_extensions->toASN1();
445
        }
446 1
        return new Sequence(...$elements);
447 1
    }
448 1
449 1
    /**
450
     * Create signed attribute certificate.
451 1
     *
452 1
     * @param SignatureAlgorithmIdentifier $algo         Signature algorithm
453 1
     * @param PrivateKeyInfo               $privkey_info Private key
454 1
     * @param null|Crypto                  $crypto       Crypto engine, use default if not set
455
     *
456
     * @return AttributeCertificate
457
     */
458
    public function sign(SignatureAlgorithmIdentifier $algo,
459
        PrivateKeyInfo $privkey_info, ?Crypto $crypto = null): AttributeCertificate
460
    {
461
        $crypto = $crypto ?? Crypto::getDefault();
462
        $aci = clone $this;
463
        if (!isset($aci->_serialNumber)) {
464
            $aci->_serialNumber = '0';
465
        }
466
        $aci->_signature = $algo;
467
        $data = $aci->toASN1()->toDER();
468
        $signature = $crypto->sign($data, $privkey_info, $algo);
469
        return new AttributeCertificate($aci, $algo, $signature);
470
    }
471
}
472