Passed
Push — master ( f45b85...1d0bb6 )
by Roberto
44s
created

Asn1::getCNPJ()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 4
cts 5
cp 0.8
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2.032
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 2
    public static function getCNPJ($publickeyUnformated)
29
    {
30
        //CNPJ
31
        //OID = 2.16.76.1.3.3
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
32 2
        $cnpj = self::getOIDdata('2.16.76.1.3.3', $publickeyUnformated);
33 2
        if (empty($cnpj)) {
34
            return "Não existe CNPJ neste certificado.";
35
        }
36 2
        return $cnpj;
37
    }
38
39
    /**
40
     * CPF
41
     * OID = 2.16.76.1.3.1 e
42
     * conteúdo = nas primeiras 8 (oito) posições,
43
     *  a data de nascimento do titular,
44
     * no formato ddmmaaaa;
45
     * nas 11 (onze) posições subseqüentes,
46
     * o Cadastro de Pessoa Física (CPF) do titular;
47
     * nas 11 (onze) posições subseqüentes,
48
     * o número de inscrição do titular no PIS/PASEP;
49
     * nas 11 (onze) posições subseqüentes,
50
     * o número do Registro Geral - RG do titular;
51
     * nas 6 (seis) posições subseqüentes,
52
     * as siglas do órgão expedidor do RG
53
     * e respectiva UF.
54
     */
55
    /**
56
     * Get CPF owner number from digital certificate
57
     * (more specifically, from public key)
58
     * @param string $publickeyUnformated
59
     * @return string CPF
60
     */
61 2
    public static function getCPF($publickeyUnformated)
62
    {
63
        //CPF
64
        //OID = 2.16.76.1.3.1
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
65 2
        $resp = self::getOIDdata('2.16.76.1.3.1', $publickeyUnformated);
66 2
        if (empty($resp)) {
67 1
            return "Não existe CPF neste certificado.";
68
        }
69 1
        $dataNascimento = substr($resp, 0, 8);
0 ignored issues
show
Unused Code introduced by
$dataNascimento is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
70 1
        $cpf = substr($resp, 8, 11);
71 1
        return $cpf;
72
    }
73
74
    /**
75
     * Recovers information regarding the OID contained in the certificate
76
     * method assumes that the OID is embedded within a structure of
77
     * type "sequence", as the first element of the structure
78
     * @param string $publickeyUnformated
79
     * @param string $oidNumber OID formated number
80
     * @return string
81
     */
82 4
    public static function getOIDdata($oidNumber, $publickeyUnformated)
83
    {
84 4
        $ret = '';
85 4
        $certder = base64_decode($publickeyUnformated);
86
        //converts the OID number from text to hexadecimal
87 4
        $oidMarker = self::oidHexMarker($oidNumber);
88
        //Divide the certificate using the OID as a marker,
89
        //geting the first part before the OID marker and
90
        //the other containing the OID data and so own.
91
        //Usually the certificate will be divided into only two parts,
92
        //because there are usually only one OID of each type in
93
        //the certificate, but can be more. In this case only
94
        //first occurency will be returned.
95 4
        if (!strpos($certder, $oidMarker)) {
96
            //OID not found return empty
97 1
            return '';
98
        }
99 3
        $partes = explode($oidMarker, $certder);
100
        //if count($partes) > 1 so OID was located
101 3
        $tot = count($partes);
102 3
        if ($tot > 1) {
103
            //The beginning of the sequence that interests us, can be 3 or 2
104
            //digits before the start of OID, it depends on the number of
105
            //bytes used to identify the size of this data sequence,and before
106
            //len digits exists a separator digit like 0x30
107 3
            $xcv4 = substr($partes[0], -4);
108 3
            $xcv = substr($xcv4, -2);
109
            //exists Hex 030
110 3
            if ($xcv4[0] == chr(0x30)) {
111
                $xcv = $xcv4;
112 3
            } elseif ($xcv4[1] == chr(0x30)) {
113
                $xcv = substr($xcv4, -3);
114
            }
115
            //rebuild the sequency
116 3
            $data = $xcv . $oidMarker . $partes[1];
117
            //converts do decimal the second digit of sequency
118 3
            $bytes = strlen($oidMarker);
119
            //get length of OID data
120 3
            $len = self::getLength($data);
121
            //get only a string with bytes belongs to OID
122 3
            $oidData = substr($data, 2 + $bytes, $len-($bytes));
123
            //parse OID data many possibel formats and structures
124 3
            $head = strlen($oidData) - strlen($xcv) - 2;
125 3
            $ret = substr($oidData, -$head);
126
        }
127 3
        return $ret;
128
    }
129
    
130
    /**
131
     * Get length of data field of a sequency from certifcate
132
     * @param string $data
133
     * @return integer
134
     */
135 3
    protected static function getLength($data)
136
    {
137 3
        $len = ord($data[1]);
138
        //check if len <= 127 bytes,
139
        //if so, then $lenis length of content
140 3
        if ($len > 127) {
141
            $bytes = $len & 0x0f;
142
            $len = 0;
143
            for ($i = 0; $i < $bytes; $i++) {
144
                $len = ($len << 8) | ord($data[$i + 2]);
145
            }
146
        }
147 3
        return $len;
148
    }
149
    
150
    /**
151
     * Convert number OID in ASC Hex representation includes
152
     * in DER format certificate
153
     * @param string $oid OID formated number
154
     * @return string hexadecimal representation
155
     */
156 4
    protected static function oidHexMarker($oid)
157
    {
158 4
        $abBinary = array();
159 4
        $partes = explode('.', $oid);
160 4
        $bun = 0;
161 4
        $npart = count($partes);
162 4
        for ($num = 0; $num < $npart; $num++) {
163 4
            if ($num == 0) {
164 4
                $bun = 40 * $partes[$num];
165 4
            } elseif ($num == 1) {
166 4
                $bun +=  $partes[$num];
167 4
                $abBinary[] = $bun;
168
            } else {
169 4
                $abBinary = self::xBase128($abBinary, (integer) $partes[$num], true);
170
            }
171
        }
172 4
        $value = chr(0x06) . chr(count($abBinary));
173 4
        foreach ($abBinary as $item) {
174 4
            $value .= chr($item);
175
        }
176 4
        return $value;
177
    }
178
179
    /**
180
     * Converts to Base128
181
     * @param array $abIn
182
     * @param integer $qIn
183
     * @param boolean $flag
184
     * @return array
185
     */
186 4
    protected static function xBase128($abIn, $qIn, $flag)
187
    {
188 4
        $abc = $abIn;
189 4
        if ($qIn > 127) {
190
            $abc = self::xBase128($abc, floor($qIn/128), false);
191
        }
192 4
        $qIn2 = $qIn % 128;
193 4
        if ($flag) {
194 4
            $abc[] = $qIn2;
195
        } else {
196
            $abc[] = 0x80 | $qIn2;
197
        }
198 4
        return $abc;
199
    }
200
}
201