Passed
Pull Request — master (#120)
by Roberto
02:29
created

Asn1::xBase128()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3.0987

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 7
cts 9
cp 0.7778
rs 9.4285
cc 3
eloc 10
nc 4
nop 3
crap 3.0987
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 string $data
91
     * @return integer
92
     */
93 14
    protected static function getLength($data)
94
    {
95 14
        $len = ord($data[1]);
96
        //check if len <= 127 bytes,
97
        //if so, then $lenis length of content
98 14
        if ($len > 127) {
99
            $bytes = $len & 0x0f;
100
            $len = 0;
101
            for ($i = 0; $i < $bytes; $i++) {
102
                $len = ($len << 8) | ord($data[$i + 2]);
103
            }
104
        }
105 14
        return $len;
106
    }
107
    
108
    /**
109
     * Convert number OID in ASC Hex representation includes
110
     * in DER format certificate
111
     * @param string $oid OID formated number
112
     * @return string hexadecimal representation
113
     */
114 17
    protected static function oidHexMarker($oid)
115
    {
116 17
        $abBinary = array();
117 17
        $partes = explode('.', $oid);
118 17
        $bun = 0;
119 17
        $npart = count($partes);
120 17
        for ($num = 0; $num < $npart; $num++) {
121 17
            if ($num == 0) {
122 17
                $bun = 40 * $partes[$num];
123 17
            } elseif ($num == 1) {
124 17
                $bun +=  $partes[$num];
125 17
                $abBinary[] = $bun;
126
            } else {
127 17
                $abBinary = self::xBase128((array) $abBinary, (integer) $partes[$num], true);
128
            }
129
        }
130 17
        $value = chr(0x06) . chr(count($abBinary));
131 17
        foreach ($abBinary as $item) {
132 17
            $value .= chr($item);
133
        }
134 17
        return $value;
135
    }
136
137
    /**
138
     * Converts to Base128
139
     * @param array $abIn
140
     * @param integer $qIn
141
     * @param boolean $flag
142
     * @return integer
143
     */
144 17
    protected static function xBase128($abIn, $qIn, $flag)
145
    {
146 17
        $abc = $abIn;
147 17
        if ($qIn > 127) {
148
            $abc = self::xBase128($abc, floor($qIn/128), false);
149
        }
150 17
        $qIn2 = $qIn % 128;
151 17
        if ($flag) {
152 17
            $abc[] = $qIn2;
153
        } else {
154
            $abc[] = 0x80 | $qIn2;
155
        }
156 17
        return $abc;
157
    }
158
}
159