|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace NFePHP\Common\Certificate; |
|
4
|
|
|
|
|
5
|
|
|
/** |
|
6
|
|
|
* Class to obtain the encrypted data contained in a digital |
|
7
|
|
|
* certificate PKCS #12. |
|
8
|
|
|
* See Abstract Syntax Notation One (ASN.1) |
|
9
|
|
|
* for Distinguished Encoding Rules (DER) |
|
10
|
|
|
* This data may be formatted and encoded into multiple data formats, so to |
|
11
|
|
|
* extracted it is necessary to identify which format was inserted then |
|
12
|
|
|
* it can be decrypted in a readable structure |
|
13
|
|
|
* @category NFePHP |
|
14
|
|
|
* @package NFePHP\Common\Asn1 |
|
15
|
|
|
* @copyright Copyright (c) 2008-2016 |
|
16
|
|
|
* @license http://www.gnu.org/licenses/lesser.html LGPL v3 |
|
17
|
|
|
* @author Roberto L. Machado <linux.rlm at gmail dot com> |
|
18
|
|
|
* @link http://github.com/nfephp-org/nfephp for the canonical source repository |
|
19
|
|
|
*/ |
|
20
|
|
|
|
|
21
|
|
|
use NFePHP\Common\Certificate; |
|
22
|
|
|
|
|
23
|
|
|
class Asn1 |
|
24
|
|
|
{ |
|
25
|
|
|
/** |
|
26
|
|
|
* Get CNPJ owner number from digital certificate |
|
27
|
|
|
* (more specifically, from public key) |
|
28
|
|
|
* @param string $publickeyUnformated |
|
29
|
|
|
* @return string CNPJ |
|
30
|
|
|
*/ |
|
31
|
17 |
|
public static function getCNPJ($publickeyUnformated) |
|
32
|
|
|
{ |
|
33
|
17 |
|
return self::getOIDdata('2.16.76.1.3.3', $publickeyUnformated); |
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* Recovers information regarding the OID contained in the certificate |
|
38
|
|
|
* method assumes that the OID is embedded within a structure of |
|
39
|
|
|
* type "sequence", as the first element of the structure |
|
40
|
|
|
* @param string $publickeyUnformated |
|
41
|
|
|
* @param string $oidNumber OID formated number |
|
42
|
|
|
* @return array |
|
43
|
|
|
*/ |
|
44
|
17 |
|
public static function getOIDdata($oidNumber, $publickeyUnformated) |
|
45
|
|
|
{ |
|
46
|
17 |
|
$ret = ''; |
|
47
|
17 |
|
$certder = base64_decode($publickeyUnformated); |
|
48
|
|
|
//converts the OID number from text to hexadecimal |
|
49
|
17 |
|
$oidMarker = self::oidHexMarker($oidNumber); |
|
50
|
|
|
//Divide the certificate using the OID as a marker, |
|
51
|
|
|
//geting the first part before the OID marker and |
|
52
|
|
|
//the other containing the OID data and so own. |
|
53
|
|
|
//Usually the certificate will be divided into only two parts, |
|
54
|
|
|
//because there are usually only one OID of each type in |
|
55
|
|
|
//the certificate, but can be more. In this case only |
|
56
|
|
|
//first occurency will be returned. |
|
57
|
17 |
|
$partes = explode($oidMarker, $certder); |
|
58
|
|
|
//if count($partes) > 1 so OID was located |
|
59
|
17 |
|
$tot = count($partes); |
|
60
|
17 |
|
if ($tot > 1) { |
|
61
|
|
|
//The beginning of the sequence that interests us, can be 3 or 2 |
|
62
|
|
|
//digits before the start of OID, it depends on the number of |
|
63
|
|
|
//bytes used to identify the size of this data sequence,and before |
|
64
|
|
|
//len digits exists a separator digit like 0x30 |
|
65
|
14 |
|
$xcv4 = substr($partes[0], -4); |
|
66
|
14 |
|
$xcv = substr($xcv4, -2); |
|
67
|
|
|
//exists Hex 030 |
|
68
|
14 |
|
if ($xcv4[0] == chr(0x30)) { |
|
69
|
|
|
$xcv = $xcv4; |
|
70
|
14 |
|
} elseif ($xcv4[1] == chr(0x30)) { |
|
71
|
|
|
$xcv = substr($xcv4, -3); |
|
72
|
|
|
} |
|
73
|
|
|
//rebuild the sequency |
|
74
|
14 |
|
$data = $xcv . $oidMarker . $partes[1]; |
|
75
|
|
|
//converts do decimal the second digit of sequency |
|
76
|
14 |
|
$bytes = strlen($oidMarker); |
|
77
|
|
|
//get length of OID data |
|
78
|
14 |
|
$len = self::getLength((string) $data); |
|
79
|
|
|
//get only a string with bytes belongs to OID |
|
80
|
14 |
|
$oidData = substr($data, 2 + $bytes, $len-($bytes)); |
|
81
|
|
|
//parse OID data many possibel formats and structures |
|
82
|
14 |
|
$head = strlen($oidData) - strlen($xcv) - 2; |
|
83
|
14 |
|
$ret = substr($oidData, -$head); |
|
84
|
|
|
} |
|
85
|
17 |
|
return $ret; |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* Get length of data field of a sequency from certifcate |
|
90
|
|
|
* @param integer $len |
|
|
|
|
|
|
91
|
|
|
* @param integer $bytes |
|
|
|
|
|
|
92
|
|
|
* @param string $data |
|
93
|
|
|
* @return integer |
|
94
|
|
|
*/ |
|
95
|
14 |
|
protected static function getLength($data) |
|
96
|
|
|
{ |
|
97
|
14 |
|
$len = ord($data[1]); |
|
98
|
|
|
//check if len <= 127 bytes, |
|
99
|
|
|
//if so, then $lenis length of content |
|
100
|
14 |
|
if ($len > 127) { |
|
101
|
|
|
$bytes = $len & 0x0f; |
|
102
|
|
|
$len = 0; |
|
103
|
|
|
for ($i = 0; $i < $bytes; $i++) { |
|
104
|
|
|
$len = ($len << 8) | ord($data[$i + 2]); |
|
105
|
|
|
} |
|
106
|
|
|
} |
|
107
|
14 |
|
return $len; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
/** |
|
111
|
|
|
* Convert number OID in ASC Hex representation includes |
|
112
|
|
|
* in DER format certificate |
|
113
|
|
|
* @param string $oid OID formated number |
|
114
|
|
|
* @return string hexadecimal representation |
|
115
|
|
|
*/ |
|
116
|
17 |
|
protected static function oidHexMarker($oid) |
|
117
|
|
|
{ |
|
118
|
17 |
|
$abBinary = array(); |
|
119
|
17 |
|
$partes = explode('.', $oid); |
|
120
|
17 |
|
$bun = 0; |
|
121
|
17 |
|
for ($num = 0; $num < count($partes); $num++) { |
|
|
|
|
|
|
122
|
17 |
|
if ($num == 0) { |
|
123
|
17 |
|
$bun = 40 * $partes[$num]; |
|
124
|
17 |
|
} elseif ($num == 1) { |
|
125
|
17 |
|
$bun += $partes[$num]; |
|
126
|
17 |
|
$abBinary[] = $bun; |
|
127
|
|
|
} else { |
|
128
|
17 |
|
$abBinary = self::xBase128((array) $abBinary, (integer) $partes[$num], true); |
|
129
|
|
|
} |
|
130
|
|
|
} |
|
131
|
17 |
|
$value = chr(0x06) . chr(count($abBinary)); |
|
132
|
17 |
|
foreach ($abBinary as $item) { |
|
133
|
17 |
|
$value .= chr($item); |
|
134
|
|
|
} |
|
135
|
17 |
|
return $value; |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* Converts to Base128 |
|
140
|
|
|
* @param array $abIn |
|
141
|
|
|
* @param integer $qIn |
|
142
|
|
|
* @param boolean $flag |
|
143
|
|
|
* @return integer |
|
144
|
|
|
*/ |
|
145
|
17 |
|
protected static function xBase128($abIn, $qIn, $flag) |
|
146
|
|
|
{ |
|
147
|
17 |
|
$abc = $abIn; |
|
148
|
17 |
|
if ($qIn > 127) { |
|
149
|
|
|
$abc = $this->xBase128($abc, floor($qIn/128), false); |
|
|
|
|
|
|
150
|
|
|
} |
|
151
|
17 |
|
$qIn2 = $qIn % 128; |
|
152
|
17 |
|
if ($flag) { |
|
153
|
17 |
|
$abc[] = $qIn2; |
|
154
|
|
|
} else { |
|
155
|
|
|
$abc[] = 0x80 | $qIn2; |
|
156
|
|
|
} |
|
157
|
17 |
|
return $abc; |
|
158
|
|
|
} |
|
159
|
|
|
} |
|
160
|
|
|
|
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italyis not defined by the methodfinale(...).The most likely cause is that the parameter was removed, but the annotation was not.