1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace X509\Certificate; |
4
|
|
|
|
5
|
|
|
use ASN1\Type\Constructed\Sequence; |
6
|
|
|
use CryptoUtil\ASN1\AlgorithmIdentifier; |
7
|
|
|
use CryptoUtil\ASN1\AlgorithmIdentifier\Feature\SignatureAlgorithmIdentifier; |
8
|
|
|
use CryptoUtil\ASN1\PublicKeyInfo; |
9
|
|
|
use CryptoUtil\Crypto\Crypto; |
10
|
|
|
use CryptoUtil\Crypto\Signature; |
11
|
|
|
use CryptoUtil\PEM\PEM; |
12
|
|
|
use X509\Certificate\TBSCertificate; |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Implements <i>Certificate</i> ASN.1 type. |
17
|
|
|
* |
18
|
|
|
* @link https://tools.ietf.org/html/rfc5280#section-4.1 |
19
|
|
|
*/ |
20
|
|
|
class Certificate |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* "To be signed" certificate information. |
24
|
|
|
* |
25
|
|
|
* @var TBSCertificate $_tbsCertificate |
26
|
|
|
*/ |
27
|
|
|
protected $_tbsCertificate; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Signature algorithm. |
31
|
|
|
* |
32
|
|
|
* @var SignatureAlgorithmIdentifier $_signatureAlgorithm |
33
|
|
|
*/ |
34
|
|
|
protected $_signatureAlgorithm; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Signature value. |
38
|
|
|
* |
39
|
|
|
* @var Signature $_signatureValue |
40
|
|
|
*/ |
41
|
|
|
protected $_signatureValue; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Constructor |
45
|
|
|
* |
46
|
|
|
* @param TBSCertificate $tbsCert |
47
|
|
|
* @param SignatureAlgorithmIdentifier $algo |
48
|
|
|
* @param Signature $signature |
49
|
|
|
*/ |
50
|
30 |
|
public function __construct(TBSCertificate $tbsCert, |
51
|
|
|
SignatureAlgorithmIdentifier $algo, Signature $signature) { |
52
|
30 |
|
$this->_tbsCertificate = $tbsCert; |
53
|
30 |
|
$this->_signatureAlgorithm = $algo; |
54
|
30 |
|
$this->_signatureValue = $signature; |
55
|
30 |
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Initialize from ASN.1. |
59
|
|
|
* |
60
|
|
|
* @param Sequence $seq |
61
|
|
|
* @return self |
62
|
|
|
*/ |
63
|
18 |
View Code Duplication |
public static function fromASN1(Sequence $seq) { |
|
|
|
|
64
|
18 |
|
$tbsCert = TBSCertificate::fromASN1($seq->at(0)->asSequence()); |
65
|
18 |
|
$algo = AlgorithmIdentifier::fromASN1($seq->at(1)->asSequence()); |
66
|
18 |
|
if (!$algo instanceof SignatureAlgorithmIdentifier) { |
67
|
1 |
|
throw new \UnexpectedValueException( |
68
|
1 |
|
"Unsupported signature algorithm " . $algo->oid() . "."); |
69
|
|
|
} |
70
|
17 |
|
$signature = Signature::fromASN1($seq->at(2)->asBitString()); |
71
|
17 |
|
return new self($tbsCert, $algo, $signature); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Initialize from DER. |
76
|
|
|
* |
77
|
|
|
* @param string $data |
78
|
|
|
* @return self |
79
|
|
|
*/ |
80
|
16 |
|
public static function fromDER($data) { |
81
|
16 |
|
return self::fromASN1(Sequence::fromDER($data)); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Initialize from PEM. |
86
|
|
|
* |
87
|
|
|
* @param PEM $pem |
88
|
|
|
* @throws \UnexpectedValueException |
89
|
|
|
* @return self |
90
|
|
|
*/ |
91
|
17 |
|
public static function fromPEM(PEM $pem) { |
92
|
17 |
|
if ($pem->type() != PEM::TYPE_CERTIFICATE) { |
93
|
1 |
|
throw new \UnexpectedValueException("Invalid PEM type."); |
94
|
|
|
} |
95
|
16 |
|
return self::fromDER($pem->data()); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Get certificate information. |
100
|
|
|
* |
101
|
|
|
* @return TBSCertificate |
102
|
|
|
*/ |
103
|
79 |
|
public function tbsCertificate() { |
104
|
79 |
|
return $this->_tbsCertificate; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Get signature algorithm. |
109
|
|
|
* |
110
|
|
|
* @return SignatureAlgorithmIdentifier |
111
|
|
|
*/ |
112
|
40 |
|
public function signatureAlgorithm() { |
113
|
40 |
|
return $this->_signatureAlgorithm; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Get signature value. |
118
|
|
|
* |
119
|
|
|
* @return Signature |
120
|
|
|
*/ |
121
|
2 |
|
public function signatureValue() { |
122
|
2 |
|
return $this->_signatureValue; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Check whether certificate is self-issued. |
127
|
|
|
* |
128
|
|
|
* @return bool |
129
|
|
|
*/ |
130
|
40 |
|
public function isSelfIssued() { |
131
|
40 |
|
return $this->_tbsCertificate->subject()->equals( |
132
|
40 |
|
$this->_tbsCertificate->issuer()); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Check whether certificate is semantically equal to another. |
137
|
|
|
* |
138
|
|
|
* @param Certificate $cert Certificate to compare to |
139
|
|
|
* @return bool |
140
|
|
|
*/ |
141
|
17 |
|
public function equals(Certificate $cert) { |
142
|
17 |
|
return $this->_hasEqualSerialNumber($cert) && |
143
|
17 |
|
$this->_hasEqualPublicKey($cert) && $this->_hasEqualSubject($cert); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* Check whether certificate has serial number equal to another. |
148
|
|
|
* |
149
|
|
|
* @param Certificate $cert |
150
|
|
|
* @return bool |
151
|
|
|
*/ |
152
|
17 |
|
private function _hasEqualSerialNumber(Certificate $cert) { |
153
|
17 |
|
$sn1 = $this->_tbsCertificate->serialNumber(); |
154
|
17 |
|
$sn2 = $cert->_tbsCertificate->serialNumber(); |
155
|
17 |
|
return $sn1 == $sn2; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Check whether certificate has public key equal to another. |
160
|
|
|
* |
161
|
|
|
* @param Certificate $cert |
162
|
|
|
* @return bool |
163
|
|
|
*/ |
164
|
16 |
|
private function _hasEqualPublicKey(Certificate $cert) { |
165
|
16 |
|
$kid1 = $this->_tbsCertificate->subjectPublicKeyInfo()->keyIdentifier(); |
166
|
16 |
|
$kid2 = $cert->_tbsCertificate->subjectPublicKeyInfo()->keyIdentifier(); |
167
|
16 |
|
return $kid1 == $kid2; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Check whether certificate has subject equal to another. |
172
|
|
|
* |
173
|
|
|
* @param Certificate $cert |
174
|
|
|
* @return bool |
175
|
|
|
*/ |
176
|
7 |
|
private function _hasEqualSubject(Certificate $cert) { |
177
|
7 |
|
$dn1 = $this->_tbsCertificate->subject(); |
178
|
7 |
|
$dn2 = $cert->_tbsCertificate->subject(); |
179
|
7 |
|
return $dn1->equals($dn2); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Generate ASN.1 structure. |
184
|
|
|
* |
185
|
|
|
* @return Sequence |
186
|
|
|
*/ |
187
|
5 |
|
public function toASN1() { |
188
|
5 |
|
return new Sequence($this->_tbsCertificate->toASN1(), |
189
|
5 |
|
$this->_signatureAlgorithm->toASN1(), |
190
|
5 |
|
$this->_signatureValue->toBitString()); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Get certificate as a DER. |
195
|
|
|
* |
196
|
|
|
* @return string |
197
|
|
|
*/ |
198
|
3 |
|
public function toDER() { |
199
|
3 |
|
return $this->toASN1()->toDER(); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Get certificate as a PEM. |
204
|
|
|
* |
205
|
|
|
* @return PEM |
206
|
|
|
*/ |
207
|
3 |
|
public function toPEM() { |
208
|
3 |
|
return new PEM(PEM::TYPE_CERTIFICATE, $this->toDER()); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Verify certificate signature. |
213
|
|
|
* |
214
|
|
|
* @param Crypto $crypto |
215
|
|
|
* @param PublicKeyInfo $pubkey_info Issuer's public key |
216
|
|
|
* @return bool True if certificate signature is valid |
217
|
|
|
*/ |
218
|
36 |
|
public function verify(Crypto $crypto, PublicKeyInfo $pubkey_info) { |
219
|
36 |
|
$data = $this->_tbsCertificate->toASN1()->toDER(); |
220
|
36 |
|
return $crypto->verify($data, $this->_signatureValue, $pubkey_info, |
221
|
36 |
|
$this->_signatureAlgorithm); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Get certificate as a PEM formatted string. |
226
|
|
|
* |
227
|
|
|
* @return string |
228
|
|
|
*/ |
229
|
1 |
|
public function __toString() { |
230
|
1 |
|
return $this->toPEM()->string(); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
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.