1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace X509\Certificate; |
4
|
|
|
|
5
|
|
|
use ASN1\Element; |
6
|
|
|
use ASN1\Type\Constructed\Sequence; |
7
|
|
|
use ASN1\Type\Primitive\Integer; |
8
|
|
|
use ASN1\Type\Tagged\ExplicitlyTaggedType; |
9
|
|
|
use ASN1\Type\Tagged\ImplicitlyTaggedType; |
10
|
|
|
use CryptoUtil\ASN1\AlgorithmIdentifier; |
11
|
|
|
use CryptoUtil\ASN1\AlgorithmIdentifier\Feature\SignatureAlgorithmIdentifier; |
12
|
|
|
use CryptoUtil\ASN1\PrivateKeyInfo; |
13
|
|
|
use CryptoUtil\ASN1\PublicKeyInfo; |
14
|
|
|
use CryptoUtil\Crypto\Crypto; |
15
|
|
|
use X501\ASN1\Name; |
16
|
|
|
use X509\Certificate\Extension\AuthorityKeyIdentifierExtension; |
17
|
|
|
use X509\Certificate\Extension\Extension; |
18
|
|
|
use X509\Certificate\Extension\SubjectKeyIdentifierExtension; |
19
|
|
|
use X509\CertificationRequest\CertificationRequest; |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Implements <i>TBSCertificate</i> ASN.1 type. |
24
|
|
|
* |
25
|
|
|
* @link https://tools.ietf.org/html/rfc5280#section-4.1.2 |
26
|
|
|
*/ |
27
|
|
|
class TBSCertificate |
28
|
|
|
{ |
29
|
|
|
// Certificate version enumerations |
30
|
|
|
const VERSION_1 = 0; |
31
|
|
|
const VERSION_2 = 1; |
32
|
|
|
const VERSION_3 = 2; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Certificate version. |
36
|
|
|
* |
37
|
|
|
* @var int |
38
|
|
|
*/ |
39
|
|
|
protected $_version; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Serial number. |
43
|
|
|
* |
44
|
|
|
* @var int|string |
45
|
|
|
*/ |
46
|
|
|
protected $_serialNumber; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Signature algorithm. |
50
|
|
|
* |
51
|
|
|
* @var SignatureAlgorithmIdentifier |
52
|
|
|
*/ |
53
|
|
|
protected $_signature; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Certificate issuer. |
57
|
|
|
* |
58
|
|
|
* @var Name $_issuer |
59
|
|
|
*/ |
60
|
|
|
protected $_issuer; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Certificate validity period. |
64
|
|
|
* |
65
|
|
|
* @var Validity $_validity |
66
|
|
|
*/ |
67
|
|
|
protected $_validity; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Certificate subject. |
71
|
|
|
* |
72
|
|
|
* @var Name $_subject |
73
|
|
|
*/ |
74
|
|
|
protected $_subject; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Subject public key. |
78
|
|
|
* |
79
|
|
|
* @var PublicKeyInfo $_subjectPublicKeyInfo |
80
|
|
|
*/ |
81
|
|
|
protected $_subjectPublicKeyInfo; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Issuer unique identifier. |
85
|
|
|
* |
86
|
|
|
* @var UniqueIdentifier|null $_issuerUniqueID |
87
|
|
|
*/ |
88
|
|
|
protected $_issuerUniqueID; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Subject unique identifier. |
92
|
|
|
* |
93
|
|
|
* @var UniqueIdentifier|null $_subjectUniqueID |
94
|
|
|
*/ |
95
|
|
|
protected $_subjectUniqueID; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Extensions. |
99
|
|
|
* |
100
|
|
|
* @var Extensions $_extensions |
101
|
|
|
*/ |
102
|
|
|
protected $_extensions; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Constructor |
106
|
|
|
* |
107
|
|
|
* @param Name $subject Certificate subject |
108
|
|
|
* @param PublicKeyInfo $pki Subject public key |
109
|
|
|
* @param Name $issuer Certificate issuer |
110
|
|
|
* @param Validity $validity Validity period |
111
|
|
|
*/ |
112
|
18 |
|
public function __construct(Name $subject, PublicKeyInfo $pki, Name $issuer, |
113
|
|
|
Validity $validity) { |
114
|
18 |
|
$this->_subject = $subject; |
115
|
18 |
|
$this->_subjectPublicKeyInfo = $pki; |
116
|
18 |
|
$this->_issuer = $issuer; |
117
|
18 |
|
$this->_validity = $validity; |
118
|
18 |
|
$this->_extensions = new Extensions(); |
119
|
18 |
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Initialize from ASN.1. |
123
|
|
|
* |
124
|
|
|
* @param Sequence $seq |
125
|
|
|
* @return self |
126
|
|
|
*/ |
127
|
12 |
|
public static function fromASN1(Sequence $seq) { |
128
|
12 |
|
$idx = 0; |
129
|
12 |
|
if ($seq->hasTagged(0)) { |
130
|
9 |
|
$idx++; |
131
|
9 |
|
$version = intval( |
132
|
9 |
|
$seq->getTagged(0) |
133
|
9 |
|
->asExplicit() |
134
|
9 |
|
->asInteger() |
135
|
9 |
|
->number()); |
136
|
9 |
|
} else { |
137
|
3 |
|
$version = self::VERSION_1; |
138
|
|
|
} |
139
|
12 |
|
$serial = $seq->at($idx++) |
140
|
12 |
|
->asInteger() |
141
|
12 |
|
->number(); |
142
|
12 |
|
$algo = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence()); |
143
|
12 |
|
if (!$algo instanceof SignatureAlgorithmIdentifier) { |
144
|
|
|
throw new \UnexpectedValueException( |
145
|
|
|
"Unsupported signature algorithm " . $algo->oid() . "."); |
146
|
|
|
} |
147
|
12 |
|
$issuer = Name::fromASN1($seq->at($idx++)->asSequence()); |
148
|
12 |
|
$validity = Validity::fromASN1($seq->at($idx++)->asSequence()); |
149
|
12 |
|
$subject = Name::fromASN1($seq->at($idx++)->asSequence()); |
150
|
12 |
|
$pki = PublicKeyInfo::fromASN1($seq->at($idx++)->asSequence()); |
151
|
12 |
|
$tbs_cert = new self($subject, $pki, $issuer, $validity); |
152
|
12 |
|
$tbs_cert->_version = $version; |
153
|
12 |
|
$tbs_cert->_serialNumber = $serial; |
154
|
12 |
|
$tbs_cert->_signature = $algo; |
155
|
12 |
View Code Duplication |
if ($seq->hasTagged(1)) { |
|
|
|
|
156
|
1 |
|
$tbs_cert->_issuerUniqueID = UniqueIdentifier::fromASN1( |
157
|
1 |
|
$seq->getTagged(1) |
158
|
1 |
|
->asImplicit(Element::TYPE_BIT_STRING) |
159
|
1 |
|
->asBitString()); |
160
|
1 |
|
} |
161
|
12 |
View Code Duplication |
if ($seq->hasTagged(2)) { |
|
|
|
|
162
|
1 |
|
$tbs_cert->_subjectUniqueID = UniqueIdentifier::fromASN1( |
163
|
1 |
|
$seq->getTagged(2) |
164
|
1 |
|
->asImplicit(Element::TYPE_BIT_STRING) |
165
|
1 |
|
->asBitString()); |
166
|
1 |
|
} |
167
|
12 |
|
if ($seq->hasTagged(3)) { |
168
|
9 |
|
$tbs_cert->_extensions = Extensions::fromASN1( |
169
|
9 |
|
$seq->getTagged(3) |
170
|
9 |
|
->asExplicit() |
171
|
9 |
|
->asSequence()); |
172
|
9 |
|
} |
173
|
12 |
|
return $tbs_cert; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Initialize from certification request. |
178
|
|
|
* |
179
|
|
|
* Note that signature is not verified and must be done by the caller. |
180
|
|
|
* |
181
|
|
|
* @param CertificationRequest $cr |
182
|
|
|
* @return self |
183
|
|
|
*/ |
184
|
1 |
|
public static function fromCSR(CertificationRequest $cr) { |
185
|
1 |
|
$cri = $cr->certificationRequestInfo(); |
186
|
1 |
|
$tbs_cert = new self($cri->subject(), $cri->subjectPKInfo(), new Name(), |
187
|
1 |
|
Validity::fromStrings(null, null)); |
188
|
|
|
// if CSR has Extension Request attribute |
189
|
1 |
|
if ($cri->hasAttributes()) { |
190
|
1 |
|
$attribs = $cri->attributes(); |
191
|
1 |
|
if ($attribs->hasExtensionRequest()) { |
192
|
1 |
|
$tbs_cert = $tbs_cert->withExtensions( |
193
|
1 |
|
$attribs->extensionRequest() |
194
|
1 |
|
->extensions()); |
195
|
1 |
|
} |
196
|
1 |
|
} |
197
|
|
|
// add Subject Key Identifier extension |
198
|
1 |
|
$tbs_cert = $tbs_cert->withAdditionalExtensions( |
199
|
1 |
|
new SubjectKeyIdentifierExtension(false, |
200
|
1 |
|
$cri->subjectPKInfo() |
201
|
1 |
|
->keyIdentifier())); |
202
|
1 |
|
return $tbs_cert; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Get self with fields set from the issuer's certificate. |
207
|
|
|
* |
208
|
|
|
* Issuer shall be set to issuing certificate's subject. |
209
|
|
|
* Authority key identifier extensions shall be added with a key identifier |
210
|
|
|
* set to issuing certificate's public key identifier. |
211
|
|
|
* |
212
|
|
|
* @param Certificate $cert Issuing party's certificate |
213
|
|
|
* @return self |
214
|
|
|
*/ |
215
|
1 |
|
public function withIssuerCertificate(Certificate $cert) { |
216
|
1 |
|
$obj = clone $this; |
217
|
|
|
// set issuer DN from cert's subject |
218
|
1 |
|
$obj->_issuer = $cert->tbsCertificate()->subject(); |
219
|
|
|
// add authority key identifier extension |
220
|
1 |
|
$key_id = $cert->tbsCertificate() |
221
|
1 |
|
->subjectPublicKeyInfo() |
222
|
1 |
|
->keyIdentifier(); |
223
|
1 |
|
$obj->_extensions = $obj->_extensions->withExtensions( |
224
|
1 |
|
new AuthorityKeyIdentifierExtension(false, $key_id)); |
225
|
1 |
|
return $obj; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Get self with given version. |
230
|
|
|
* |
231
|
|
|
* If version is not set, appropriate version is automatically |
232
|
|
|
* determined during signing. |
233
|
|
|
* |
234
|
|
|
* @param int $version |
235
|
|
|
* @return self |
236
|
|
|
*/ |
237
|
4 |
|
public function withVersion($version) { |
238
|
4 |
|
$obj = clone $this; |
239
|
4 |
|
$obj->_version = $version; |
240
|
4 |
|
return $obj; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Get self with given serial number. |
245
|
|
|
* |
246
|
|
|
* @param int|string $serial Base 10 number |
247
|
|
|
* @return self |
248
|
|
|
*/ |
249
|
5 |
|
public function withSerialNumber($serial) { |
250
|
5 |
|
$obj = clone $this; |
251
|
5 |
|
$obj->_serialNumber = $serial; |
252
|
5 |
|
return $obj; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Get self with random positive serial number. |
257
|
|
|
* |
258
|
|
|
* @param int $size Number of random bytes |
259
|
|
|
* @return self |
260
|
|
|
*/ |
261
|
1 |
View Code Duplication |
public function withRandomSerialNumber($size = 16) { |
|
|
|
|
262
|
|
|
// ensure that first byte is always non-zero and having first bit unset |
263
|
1 |
|
$num = gmp_init(mt_rand(1, 0x7f), 10); |
264
|
1 |
|
for ($i = 1; $i < $size; ++$i) { |
265
|
1 |
|
$num <<= 8; |
266
|
1 |
|
$num += mt_rand(0, 0xff); |
267
|
1 |
|
} |
268
|
1 |
|
return $this->withSerialNumber(gmp_strval($num, 10)); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Get self with given signature algorithm. |
273
|
|
|
* |
274
|
|
|
* @param SignatureAlgorithmIdentifier $algo |
275
|
|
|
* @return self |
276
|
|
|
*/ |
277
|
4 |
|
public function withSignature(SignatureAlgorithmIdentifier $algo) { |
278
|
4 |
|
$obj = clone $this; |
279
|
4 |
|
$obj->_signature = $algo; |
280
|
4 |
|
return $obj; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Get self with given issuer. |
285
|
|
|
* |
286
|
|
|
* @param Name $issuer |
287
|
|
|
* @return self |
288
|
|
|
*/ |
289
|
1 |
|
public function withIssuer(Name $issuer) { |
290
|
1 |
|
$obj = clone $this; |
291
|
1 |
|
$obj->_issuer = $issuer; |
292
|
1 |
|
return $obj; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Get self with given validity. |
297
|
|
|
* |
298
|
|
|
* @param Validity $validity |
299
|
|
|
* @return self |
300
|
|
|
*/ |
301
|
2 |
|
public function withValidity(Validity $validity) { |
302
|
2 |
|
$obj = clone $this; |
303
|
2 |
|
$obj->_validity = $validity; |
304
|
2 |
|
return $obj; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
/** |
308
|
|
|
* Get self with given subject. |
309
|
|
|
* |
310
|
|
|
* @param Name $subject |
311
|
|
|
* @return self |
312
|
|
|
*/ |
313
|
1 |
|
public function withSubject(Name $subject) { |
314
|
1 |
|
$obj = clone $this; |
315
|
1 |
|
$obj->_subject = $subject; |
316
|
1 |
|
return $obj; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Get self with given subject public key info. |
321
|
|
|
* |
322
|
|
|
* @param PublicKeyInfo $pub_key_info |
323
|
|
|
* @return self |
324
|
|
|
*/ |
325
|
1 |
|
public function withSubjectPublicKeyInfo(PublicKeyInfo $pub_key_info) { |
326
|
1 |
|
$obj = clone $this; |
327
|
1 |
|
$obj->_subjectPublicKeyInfo = $pub_key_info; |
328
|
1 |
|
return $obj; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* Get self with issuer unique ID. |
333
|
|
|
* |
334
|
|
|
* @param UniqueIdentifier $id |
335
|
|
|
* @return self |
336
|
|
|
*/ |
337
|
4 |
|
public function withIssuerUniqueID(UniqueIdentifier $id) { |
338
|
4 |
|
$obj = clone $this; |
339
|
4 |
|
$obj->_issuerUniqueID = $id; |
340
|
4 |
|
return $obj; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* Get self with subject unique ID. |
345
|
|
|
* |
346
|
|
|
* @param UniqueIdentifier $id |
347
|
|
|
* @return self |
348
|
|
|
*/ |
349
|
4 |
|
public function withSubjectUniqueID(UniqueIdentifier $id) { |
350
|
4 |
|
$obj = clone $this; |
351
|
4 |
|
$obj->_subjectUniqueID = $id; |
352
|
4 |
|
return $obj; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Get self with given extensions. |
357
|
|
|
* |
358
|
|
|
* @param Extensions $extensions |
359
|
|
|
* @return self |
360
|
|
|
*/ |
361
|
4 |
|
public function withExtensions(Extensions $extensions) { |
362
|
4 |
|
$obj = clone $this; |
363
|
4 |
|
$obj->_extensions = $extensions; |
364
|
4 |
|
return $obj; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Get self with extensions added. |
369
|
|
|
* |
370
|
|
|
* @param Extension ...$exts One or more Extension objects |
371
|
|
|
* @return self |
372
|
|
|
*/ |
373
|
3 |
|
public function withAdditionalExtensions(Extension ...$exts) { |
374
|
3 |
|
$obj = clone $this; |
375
|
3 |
|
$obj->_extensions = $obj->_extensions->withExtensions(...$exts); |
376
|
3 |
|
return $obj; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* Check whether version is set. |
381
|
|
|
* |
382
|
|
|
* @return bool |
383
|
|
|
*/ |
384
|
41 |
|
public function hasVersion() { |
385
|
41 |
|
return isset($this->_version); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Get certificate version. |
390
|
|
|
* |
391
|
|
|
* @return int |
392
|
|
|
*/ |
393
|
41 |
|
public function version() { |
394
|
41 |
|
if (!$this->hasVersion()) { |
395
|
1 |
|
throw new \LogicException("version not set."); |
396
|
|
|
} |
397
|
40 |
|
return $this->_version; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Check whether serial number is set. |
402
|
|
|
* |
403
|
|
|
* @return bool |
404
|
|
|
*/ |
405
|
44 |
|
public function hasSerialNumber() { |
406
|
44 |
|
return isset($this->_serialNumber); |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* Get serial number. |
411
|
|
|
* |
412
|
|
|
* @return int|string Base 10 integer |
413
|
|
|
*/ |
414
|
44 |
|
public function serialNumber() { |
415
|
44 |
|
if (!$this->hasSerialNumber()) { |
416
|
1 |
|
throw new \LogicException("serialNumber not set."); |
417
|
|
|
} |
418
|
43 |
|
return $this->_serialNumber; |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
/** |
422
|
|
|
* Check whether signature algorithm is set. |
423
|
|
|
* |
424
|
|
|
* @return bool |
425
|
|
|
*/ |
426
|
41 |
|
public function hasSignature() { |
427
|
41 |
|
return isset($this->_signature); |
428
|
|
|
} |
429
|
|
|
|
430
|
|
|
/** |
431
|
|
|
* Get signature algorithm. |
432
|
|
|
* |
433
|
|
|
* @return SignatureAlgorithmIdentifier |
434
|
|
|
*/ |
435
|
41 |
|
public function signature() { |
436
|
41 |
|
if (!$this->hasSignature()) { |
437
|
1 |
|
throw new \LogicException("signature not set."); |
438
|
|
|
} |
439
|
40 |
|
return $this->_signature; |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* Get issuer. |
444
|
|
|
* |
445
|
|
|
* @return Name |
446
|
|
|
*/ |
447
|
37 |
|
public function issuer() { |
448
|
37 |
|
return $this->_issuer; |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
/** |
452
|
|
|
* Get validity period. |
453
|
|
|
* |
454
|
|
|
* @return Validity |
455
|
|
|
*/ |
456
|
25 |
|
public function validity() { |
457
|
25 |
|
return $this->_validity; |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
/** |
461
|
|
|
* Get subject. |
462
|
|
|
* |
463
|
|
|
* @return Name |
464
|
|
|
*/ |
465
|
36 |
|
public function subject() { |
466
|
36 |
|
return $this->_subject; |
467
|
|
|
} |
468
|
|
|
|
469
|
|
|
/** |
470
|
|
|
* Get subject public key. |
471
|
|
|
* |
472
|
|
|
* @return PublicKeyInfo |
473
|
|
|
*/ |
474
|
31 |
|
public function subjectPublicKeyInfo() { |
475
|
31 |
|
return $this->_subjectPublicKeyInfo; |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
/** |
479
|
|
|
* Whether issuer unique identifier is present. |
480
|
|
|
* |
481
|
|
|
* @return bool |
482
|
|
|
*/ |
483
|
3 |
|
public function hasIssuerUniqueID() { |
484
|
3 |
|
return isset($this->_issuerUniqueID); |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Get issuerUniqueID. |
489
|
|
|
* |
490
|
|
|
* @return UniqueIdentifier |
491
|
|
|
*/ |
492
|
2 |
|
public function issuerUniqueID() { |
493
|
2 |
|
if (!$this->hasIssuerUniqueID()) { |
494
|
1 |
|
throw new \LogicException("issuerUniqueID not set."); |
495
|
|
|
} |
496
|
1 |
|
return $this->_issuerUniqueID; |
497
|
|
|
} |
498
|
|
|
|
499
|
|
|
/** |
500
|
|
|
* Whether subject unique identifier is present. |
501
|
|
|
* |
502
|
|
|
* @return bool |
503
|
|
|
*/ |
504
|
2 |
|
public function hasSubjectUniqueID() { |
505
|
2 |
|
return isset($this->_subjectUniqueID); |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
/** |
509
|
|
|
* Get subjectUniqueID. |
510
|
|
|
* |
511
|
|
|
* @return UniqueIdentifier |
512
|
|
|
*/ |
513
|
2 |
|
public function subjectUniqueID() { |
514
|
2 |
|
if (!$this->hasSubjectUniqueID()) { |
515
|
1 |
|
throw new \LogicException("subjectUniqueID not set."); |
516
|
|
|
} |
517
|
1 |
|
return $this->_subjectUniqueID; |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
/** |
521
|
|
|
* Get extensions. |
522
|
|
|
* |
523
|
|
|
* @return Extensions |
524
|
|
|
*/ |
525
|
35 |
|
public function extensions() { |
526
|
35 |
|
return $this->_extensions; |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
/** |
530
|
|
|
* Generate ASN.1 structure. |
531
|
|
|
* |
532
|
|
|
* @return Sequence |
533
|
|
|
*/ |
534
|
38 |
|
public function toASN1() { |
535
|
38 |
|
$elements = array(); |
536
|
38 |
|
$version = $this->version(); |
537
|
|
|
// if version is not default |
538
|
38 |
|
if ($version != self::VERSION_1) { |
539
|
29 |
|
$elements[] = new ExplicitlyTaggedType(0, new Integer($version)); |
540
|
29 |
|
} |
541
|
38 |
|
$serial = $this->serialNumber(); |
542
|
38 |
|
$signature = $this->signature(); |
543
|
|
|
// add required elements |
544
|
38 |
|
array_push($elements, new Integer($serial), $signature->toASN1(), |
545
|
38 |
|
$this->_issuer->toASN1(), $this->_validity->toASN1(), |
546
|
38 |
|
$this->_subject->toASN1(), $this->_subjectPublicKeyInfo->toASN1()); |
547
|
38 |
|
if (isset($this->_issuerUniqueID)) { |
548
|
3 |
|
$elements[] = new ImplicitlyTaggedType(1, |
549
|
3 |
|
$this->_issuerUniqueID->toASN1()); |
550
|
3 |
|
} |
551
|
38 |
|
if (isset($this->_subjectUniqueID)) { |
552
|
3 |
|
$elements[] = new ImplicitlyTaggedType(2, |
553
|
3 |
|
$this->_subjectUniqueID->toASN1()); |
554
|
3 |
|
} |
555
|
38 |
|
if (count($this->_extensions)) { |
556
|
25 |
|
$elements[] = new ExplicitlyTaggedType(3, |
557
|
25 |
|
$this->_extensions->toASN1()); |
558
|
25 |
|
} |
559
|
38 |
|
return new Sequence(...$elements); |
560
|
|
|
} |
561
|
|
|
|
562
|
|
|
/** |
563
|
|
|
* Create signed certificate. |
564
|
|
|
* |
565
|
|
|
* @param Crypto $crypto Crypto engine |
566
|
|
|
* @param SignatureAlgorithmIdentifier $algo Algorithm used for signing |
567
|
|
|
* @param PrivateKeyInfo $privkey_info Private key used for signing |
568
|
|
|
* @return Certificate |
569
|
|
|
*/ |
570
|
9 |
|
public function sign(Crypto $crypto, SignatureAlgorithmIdentifier $algo, |
571
|
|
|
PrivateKeyInfo $privkey_info) { |
572
|
9 |
|
$tbsCert = clone $this; |
573
|
9 |
|
if (!isset($tbsCert->_version)) { |
574
|
9 |
|
$tbsCert->_version = $tbsCert->_determineVersion(); |
575
|
9 |
|
} |
576
|
9 |
|
if (!isset($tbsCert->_serialNumber)) { |
577
|
9 |
|
$tbsCert->_serialNumber = 0; |
578
|
9 |
|
} |
579
|
9 |
|
$tbsCert->_signature = $algo; |
580
|
9 |
|
$data = $tbsCert->toASN1()->toDER(); |
581
|
9 |
|
$signature = $crypto->sign($data, $privkey_info, $algo); |
582
|
9 |
|
return new Certificate($tbsCert, $algo, $signature); |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
/** |
586
|
|
|
* Determine minimum version for the certificate. |
587
|
|
|
* |
588
|
|
|
* @return int |
589
|
|
|
*/ |
590
|
9 |
|
protected function _determineVersion() { |
591
|
|
|
// if extensions are present |
592
|
9 |
|
if (count($this->_extensions)) { |
593
|
3 |
|
return self::VERSION_3; |
594
|
|
|
} |
595
|
|
|
// if UniqueIdentifier is present |
596
|
6 |
|
if (isset($this->_issuerUniqueID) || isset($this->_subjectUniqueID)) { |
597
|
3 |
|
return self::VERSION_2; |
598
|
|
|
} |
599
|
3 |
|
return self::VERSION_1; |
600
|
|
|
} |
601
|
|
|
} |
602
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.