source: trunk/seguranca/classes_BKP/CertificadoB.php @ 1035

Revision 1035, 9.5 KB checked in by rafaelraymundo, 15 years ago (diff)

Ticket #558 - Adicionada funcionalidade de assinatura e criptografia de e-mails.

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