source: branches/2.3/security/classes/CertificadoB.php @ 4916

Revision 4916, 11.9 KB checked in by rafaelraymundo, 13 years ago (diff)

Ticket #2157 - Mensagem assinada (usando certificado digital) não abre .

Line 
1<?php
2require_once('funcoes_auxiliares.php');
3require_once('Verifica_Certificado_conf.php');
4require_once('Verifica_Certificado.php');
5
6//  Pre-requisito: A extensao openssl deve estar disponivel no PHP ....
7class certificadoB
8{
9  public $dados = array();        # Area para armazenar os dados recuperados do certificado.
10  public $apresentado = false;    # Deve ser testado para verificar se no certificado processado foi localizado o CPF
11  public $erros_ssl = array();
12  public $cert_assinante = '';
13  public $msg_sem_assinatura = '';  #conteï¿œdo da mensagem sem assinatura, que retorna da funᅵᅵo verify do openssl
14  public $arquivos_para_deletar = array();
15
16  public function __construct()
17  {
18    if(!extension_loaded('openssl'))
19    {
20      #PHP sem suporte ao openssl.....
21      return false;
22    }
23    $this->dados = array();
24    $this->dados_xml = '';
25    $this->apresentado = false;
26    $this->erros_ssl = array();
27    $this->cert_assinante = '';
28    $this->msg_sem_assinatura = '';
29    $this->arquivos_para_deletar = array();
30  }
31
32public function __destruct()
33  {
34    #Remover arquivos temporarios.....
35    deleta_arquivos_temporarios($this->arquivos_para_deletar);
36  }
37
38# Recupera dados de um certificado no formato pem
39  function certificado($certificado_pem)
40  {
41      if (!$certificado_pem)
42    {
43        $this->apresentado = False;
44        return False;    # Sem parametro ...
45    }
46   $this->dados = recupera_dados_do_ceritificado_digital($certificado_pem);
47   $this->dados_xml = gera_xml_com_dados_do_certificado($this->dados);
48     # Certificado foi processado, as informacoes obtidas estao em $this->dados.
49  $this->apresentado = true;
50  }
51
52# Encriptar senha ......
53        public function encriptar_senha($s,$c)
54        {
55                if($s == '')    return false;
56                if($c == '')    return false;
57                $senha_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
58                //echo $senha_arquivo_temporario.'<br>';
59                if(!grava_arquivo($senha_arquivo_temporario,$s))
60                {
61                        return false;
62                }
63                $cert_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
64                //echo $cert_arquivo_temporario.'<br>';
65                if(!grava_arquivo($cert_arquivo_temporario,$c))
66                {
67                        return false;
68                }
69                $senha_criptografada_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
70                //echo $senha_criptografada_arquivo_temporario.'<br>';
71
72                $w = exec('openssl rsautl -in ' . $senha_arquivo_temporario . ' -out ' . $senha_criptografada_arquivo_temporario . ' -inkey ' . $cert_arquivo_temporario . ' -certin -pkcs -keyform PEM -encrypt',$saida);
73
74                if(!file_exists($senha_criptografada_arquivo_temporario))
75                {
76                        deleta_arquivos_temporarios($this->arquivos_para_deletar);
77                        $this->arquivos_para_deletar = array();
78                        return false;
79                }
80
81                # Recupera a senha criptada, binario.....
82                $retorno = file_get_contents($senha_criptografada_arquivo_temporario);
83
84                deleta_arquivos_temporarios($this->arquivos_para_deletar);
85                $this->arquivos_para_deletar = array();
86
87                if(strlen($retorno) != 128) return false;
88
89                return base64_encode($retorno);
90        }
91
92
93# Encriptar uma msg($m) para o(s) destinatario(s) $c(array com certificados)com os headers passados em $h.
94        public function encriptar($m,$c,$h)
95        {
96                if($m == '')    return false;
97                if(!is_array($c))       return false;
98                $aux = count($c);
99                if($aux < 1)    return false;
100                if(!is_array($h) )      return false;
101                # Tem de verificar todos os certificados que serao utilizados para criptografar a msg..
102                # Inserir a rotina aqui....
103                $m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
104                //echo $m_arquivo_temporario.'<br>';
105                if(!grava_arquivo($m_arquivo_temporario,$m))
106                {
107                        return false;
108                }
109                $enc_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
110                //echo $enc_arquivo_temporario.'<br>';
111
112                // LIMPA ERROS ... Pode ser um problema para outras aplicacoes que usam openssl(fonte de erros unica).
113                while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
114                $this->erros_ssl = array();
115                $resultado = openssl_pkcs7_encrypt($m_arquivo_temporario,$enc_arquivo_temporario,$c,$h,$flags=0,$cipherid=OPENSSL_CIPHER_DES);
116                //$resultado = openssl_pkcs7_encrypt($m_arquivo_temporario,$enc_arquivo_temporario,$c,$h);
117                if(!$resultado)
118                {
119                        // Guarda msgs de erro ...
120                        while ($erro = openssl_error_string())
121                        {
122                                $this->erros_ssl[] = $erro;
123                        }
124                        deleta_arquivos_temporarios($this->arquivos_para_deletar);
125                        $this->arquivos_para_deletar = array();
126                        return false;
127                }
128                # Recupera a msg criptada......
129                $retorno = file_get_contents($enc_arquivo_temporario);
130                deleta_arquivos_temporarios($this->arquivos_para_deletar);
131                $this->arquivos_para_deletar = array();
132                return $retorno;
133        }
134
135
136# Verifica uma msg($m) assinada...
137        public function verificar($m)
138        {
139                if($m == '')
140                {
141                    $this->erros_ssl[] = 'Não foi possível verificar a assinatura gerada. Contate o administrador';
142                    return false;
143                }
144                if(!$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar))
145                    {
146                        $this->erros_ssl[] = 'Não foi possível verificar a assinatura gerada. Contate o administrador';
147                        $this->arquivos_para_deletar = array();
148                        return false;
149                    }
150                if(!grava_arquivo($m_arquivo_temporario,$m))
151                {
152                        $this->erros_ssl[] = 'Não foi possível verificar a assinatura gerada. Contate o administrador';
153                        deleta_arquivos_temporarios($this->arquivos_para_deletar);
154                        $this->arquivos_para_deletar = array();
155                        return false;
156                }
157                if(!$vrf_cert_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar))
158                    {
159                        $this->erros_ssl[] = 'Não foi possível verificar a assinatura gerada. Contate o administrador';
160                        $this->arquivos_para_deletar = array();
161                        return false;
162                    }
163                if(!$vrf_msg_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar))
164                    {
165                        $this->erros_ssl[] = 'Não foi possível verificar a assinatura gerada. Contate o administrador';
166                        $this->arquivos_para_deletar = array();
167                        return false;
168                    }
169                $this->erros_ssl = array();
170                while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
171                $resultado = openssl_pkcs7_verify($m_arquivo_temporario,0, $vrf_cert_arquivo_temporario,array($GLOBALS['CAs']),$GLOBALS['CAs'],$vrf_msg_arquivo_temporario);
172                if($resultado === -1)
173                {
174                    $this->erros_ssl[] = 'Erro verificando assinatura. Contate o administrador';
175                    while ($erro = openssl_error_string())
176                        {
177                                $this->erros_ssl[] = $erro;
178                        }
179                    $retorno = false;
180                }
181                if($resultado === False)
182                    {
183                        while ($erro = openssl_error_string())
184                            {
185                                if(substr($erro, 0,20) === 'error:21075075:PKCS7')
186                                    {
187                                        $this->erros_ssl = array();
188                                        while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
189                                        $resultado = openssl_pkcs7_verify($m_arquivo_temporario,PKCS7_NOVERIFY, $vrf_cert_arquivo_temporario,array($GLOBALS['CAs']),$GLOBALS['CAs'],$vrf_msg_arquivo_temporario);
190                                        break;
191                                    }
192                                $this->erros_ssl[] = $erro;
193                            }
194                    }
195                $retorno = true;
196
197                if($resultado === False)
198                {
199                        # Indica ocorrencia de erro ...
200                        $this->erros_ssl[] = 'Erro. ';
201                        $retorno = false;
202                        // Guarda msgs de erro ...
203                        while ($erro = openssl_error_string())
204                        {
205                                $this->erros_ssl[] = $erro;
206                        }
207                        If(file_exists($vrf_msg_arquivo_temporario))
208                                {
209                                        $this->msg_sem_assinatura =  file_get_contents($vrf_msg_arquivo_temporario);
210                                }
211                        else
212                                {
213                                        $this->msg_sem_assinatura =  'Nao pode exibir a msg(CD-1)';
214                                        $this->erros_ssl[] = 'Nao pode exibir a msg(CD-1)';
215                                }
216                        # Reexecuta o comando com um nivel menor de criticas.
217                        $this->cert_assinante = $this->extrai_certificado_da_msg_assinada($m);
218                        if(!$this->cert_assinante)
219                        {
220                                # Se nao foi possivel obter o certificado retorna com falso .....
221                                If(file_exists($vrf_msg_arquivo_temporario))
222                                        {
223                                                $this->msg_sem_assinatura =  file_get_contents($vrf_msg_arquivo_temporario);
224                                        }
225                                else
226                                        {
227                                                $this->msg_sem_assinatura =  'Nao pode exibir a msg(CD-2)';
228                                                $this->erros_ssl[] = 'Nao pode exibir a msg(CD-2)';
229                                        }
230                                deleta_arquivos_temporarios($this->arquivos_para_deletar);
231                                $this->arquivos_para_deletar = array();
232                                return false;
233                        }
234                }
235                else
236                {
237                        # Guarda o certificado usado para assinar a msg
238                        $this->cert_assinante  =   file_get_contents($vrf_cert_arquivo_temporario);
239                 }
240                If(file_exists($vrf_msg_arquivo_temporario))  $this->msg_sem_assinatura =  file_get_contents($vrf_msg_arquivo_temporario);
241                $this->certificado($this->cert_assinante);
242                if (!$this->apresentado)
243                {
244                        $this->erros_ssl[] = 'Certificado da Msg nao pode ser tratado.';
245                        $retorno = false;
246                }
247                else
248                {
249                        while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
250                        # Certificado poderia ter assinado um email??
251                        if(!($this->dados['KEYUSAGE']['digitalSignature']))
252                        {
253                                $this->erros_ssl[] = 'Certificado nao poderia ter sido utilizado para assinar email.';
254                                while ($erro = openssl_error_string())
255                                        {
256                                                $this->erros_ssl[] = $erro;
257                                        }
258                                $retorno = false;
259                        }
260                        $revogado = new Verifica_Certificado($this->dados,$this->cert_assinante);
261                        $this->dados['REVOGADO'] = false;
262                        if(!$revogado->status){
263                                $this->erros_ssl[] = $revogado->msgerro;
264                                foreach ($revogado->erros_ssl as $item)
265                                        {
266                                                $this->erros_ssl[] = $item;
267                                        }
268                                if ($revogado->revogado)
269                                        $this->dados['REVOGADO'] = true;
270                                $retorno  = false;
271                        }
272                }
273                deleta_arquivos_temporarios($this->arquivos_para_deletar);
274                $this->arquivos_para_deletar = array();
275                return $retorno;
276        }
277
278        public function extrai_certificado_da_msg_assinada($m)
279        {
280                $retorno = false;
281                if(!$m)
282                {
283                        return $retorno;
284                }
285                $m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
286                if(!grava_arquivo($m_arquivo_temporario,$m))
287                {
288                        deleta_arquivos_temporarios($this->arquivos_para_deletar);
289                        $this->arquivos_para_deletar = array();
290                        return $retorno;
291                }
292                $w='';
293                $saida = array();
294                $w = exec('cat ' . $m_arquivo_temporario . ' | openssl smime -pk7out | openssl pkcs7 -print_certs',$saida);
295                if(!$w=='')
296                {
297                        deleta_arquivos_temporarios($this->arquivos_para_deletar);
298                        $this->arquivos_para_deletar = array();
299                        return $retorno;
300                }
301                $aux1 = '';
302                // gera uma unica string com o conteudo retornado pelo comando...
303                foreach($saida as $linha)
304                {
305                        $aux1 .= $linha.chr(0x0A);
306                }
307                // cria um array com os certificados retornados..
308                $aux2 = explode('-----BEGIN CERTIFICATE-----',$aux1);
309                array_shift($aux2);
310                // isolando certificados..
311                $aux5 = array();
312                foreach($aux2 as $item)
313                {
314                        $aux3 = explode('-----END CERTIFICATE-----',$item);
315                        $aux4 = '-----BEGIN CERTIFICATE-----' . $aux3[0] . '-----END CERTIFICATE-----';
316                        $aux5[] = $aux4;
317                }
318                // Testa qual dos certificados nao he uma CA ....
319                foreach($aux5 as $item)
320                {
321                        $Dados_cert = recupera_dados_do_ceritificado_digital($item);
322                        if(!$Dados_cert['CA'])
323                                {
324                                        $retorno = $item;
325                                        break;
326                                }
327                }
328                deleta_arquivos_temporarios($this->arquivos_para_deletar);
329                $this->arquivos_para_deletar = array();
330                return $retorno;
331        }
332}
333?>
Note: See TracBrowser for help on using the repository browser.