1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace NFePHP\Common\Certificate; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Management and use of digital certificates A1 (PKCS # 12). |
7
|
|
|
* @category NFePHP |
8
|
|
|
* @package NFePHP\Common\PublicKey |
9
|
|
|
* @copyright Copyright (c) 2008-2016 |
10
|
|
|
* @license http://www.gnu.org/licenses/lesser.html LGPL v3 |
11
|
|
|
* @author Antonio Spinelli <tonicospinelli85 at gmail dot com> |
12
|
|
|
* @link http://github.com/nfephp-org/sped-common for the canonical source repository |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
use NFePHP\Common\Exception\CertificateException; |
16
|
|
|
|
17
|
|
|
class PublicKey implements VerificationInterface |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* @var string |
21
|
|
|
*/ |
22
|
|
|
private $rawKey; |
23
|
|
|
/** |
24
|
|
|
* @var string |
25
|
|
|
*/ |
26
|
|
|
public $commonName; |
27
|
|
|
/** |
28
|
|
|
* @var \DateTime |
29
|
|
|
*/ |
30
|
|
|
public $validFrom; |
31
|
|
|
/** |
32
|
|
|
* @var \DateTime |
33
|
|
|
*/ |
34
|
|
|
public $validTo; |
35
|
|
|
/** |
36
|
|
|
* @var string |
37
|
|
|
*/ |
38
|
|
|
public $emailAddress; |
39
|
|
|
/** |
40
|
|
|
* @var string Cryptographic Service Provider |
41
|
|
|
*/ |
42
|
|
|
public $cspName; |
43
|
|
|
/** |
44
|
|
|
* @var string |
45
|
|
|
*/ |
46
|
|
|
public $serialNumber; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* PublicKey constructor. |
50
|
|
|
* @param string $publicKey |
51
|
|
|
*/ |
52
|
19 |
|
public function __construct($publicKey) |
53
|
|
|
{ |
54
|
19 |
|
$this->rawKey = $publicKey; |
55
|
19 |
|
$this->read(); |
56
|
19 |
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Load class with certificate content |
60
|
|
|
* @param string $content |
61
|
|
|
* @return \NFePHP\Common\Certificate\PublicKey |
62
|
|
|
*/ |
63
|
5 |
|
public static function createFromContent($content) |
64
|
|
|
{ |
65
|
5 |
|
$content = rtrim(chunk_split(preg_replace('/[\r\n]/', '', $content), 64, PHP_EOL)); |
66
|
|
|
$certificate = <<<CONTENT |
67
|
|
|
-----BEGIN CERTIFICATE----- |
68
|
5 |
|
{$content} |
69
|
|
|
-----END CERTIFICATE----- |
70
|
|
|
|
71
|
|
|
CONTENT; |
72
|
|
|
|
73
|
5 |
|
return new static($certificate); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Parse an X509 certificate and define the information in object |
78
|
|
|
* @link http://php.net/manual/en/function.openssl-x509-read.php |
79
|
|
|
* @link http://php.net/manual/en/function.openssl-x509-parse.php |
80
|
|
|
* @return void |
81
|
|
|
* @throws CertificateException Unable to open certificate |
82
|
|
|
*/ |
83
|
19 |
|
protected function read() |
84
|
|
|
{ |
85
|
19 |
|
if (!$resource = openssl_x509_read($this->rawKey)) { |
86
|
|
|
throw CertificateException::unableToOpen(); |
87
|
|
|
} |
88
|
19 |
|
$detail = openssl_x509_parse($resource, false); |
89
|
19 |
|
$this->commonName = $detail['subject']['commonName']; |
90
|
19 |
|
if (isset($detail['subject']['emailAddress'])) { |
91
|
1 |
|
$this->emailAddress = $detail['subject']['emailAddress']; |
92
|
|
|
} |
93
|
19 |
|
if (isset($detail['issuer']['organizationalUnitName'])) { |
94
|
19 |
|
$this->cspName = is_array($detail['issuer']['organizationalUnitName']) |
95
|
|
|
? implode(', ', $detail['issuer']['organizationalUnitName']) |
96
|
19 |
|
: $detail['issuer']['organizationalUnitName']; |
97
|
|
|
} |
98
|
19 |
|
$this->serialNumber = $detail['serialNumber']; |
99
|
19 |
|
$this->validFrom = \DateTime::createFromFormat('ymdHis\Z', $detail['validFrom']); |
|
|
|
|
100
|
19 |
|
$this->validTo = \DateTime::createFromFormat('ymdHis\Z', $detail['validTo']); |
|
|
|
|
101
|
19 |
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* Verify signature |
105
|
|
|
* @link http://php.net/manual/en/function.openssl-verify.php |
106
|
|
|
* @param string $data |
107
|
|
|
* @param string $signature |
108
|
|
|
* @param int $algorithm [optional] For more information see the list of Signature Algorithms. |
109
|
|
|
* @return bool Returns true if the signature is correct, false if it is incorrect |
110
|
|
|
* @throws CertificateException An error has occurred when verify signature |
111
|
|
|
*/ |
112
|
6 |
|
public function verify($data, $signature, $algorithm = OPENSSL_ALGO_SHA1) |
113
|
|
|
{ |
114
|
6 |
|
$verified = openssl_verify($data, $signature, $this->rawKey, $algorithm); |
115
|
6 |
|
if ($verified === self::SIGNATURE_ERROR) { |
116
|
|
|
throw CertificateException::signatureFailed(); |
117
|
|
|
} |
118
|
6 |
|
return $verified === self::SIGNATURE_CORRECT; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Check if is in valid date interval. |
123
|
|
|
* @return bool Returns true |
124
|
|
|
*/ |
125
|
4 |
|
public function isExpired() |
126
|
|
|
{ |
127
|
4 |
|
return new \DateTime('now') > $this->validTo; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Returns raw public key without markers and LF's |
132
|
|
|
* @return string |
133
|
|
|
*/ |
134
|
5 |
|
public function unFormated() |
135
|
|
|
{ |
136
|
5 |
|
$ret = preg_replace('/-----.*[\n]?/', '', $this->rawKey); |
137
|
5 |
|
return preg_replace('/[\n\r]/', '', $ret); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Returns raw public key |
142
|
|
|
* @return string |
143
|
|
|
*/ |
144
|
1 |
|
public function __toString() |
145
|
|
|
{ |
146
|
1 |
|
return $this->rawKey; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Extract CNPJ number by OID |
151
|
|
|
* @return string |
152
|
|
|
*/ |
153
|
1 |
|
public function cnpj() |
154
|
|
|
{ |
155
|
1 |
|
return Asn1::getCNPJ($this->unFormated()); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Extract CPF number by OID |
160
|
|
|
* @return string |
161
|
|
|
*/ |
162
|
2 |
|
public function cpf() |
163
|
|
|
{ |
164
|
2 |
|
return Asn1::getCPF($this->unFormated()); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.