Completed
Push — master ( 147d11...90c036 )
by Roberto
05:30 queued 02:17
created

Asn1::oidHexMarker()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 22
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5

Importance

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