Jump to content

Recommended Posts

Posted

Como muitos de vós devem saber, entra em vigor a 1 de Maio de 2013 o webservice da Autoridade Tributária para reporte em tempo real dos documentos de transporte emitidos. Estou a tratar da implementação dessa funcionalidade numa plataforma de faturação escrita em PHP e tenho várias dificuldades em que vou precisar de ajuda nos próximos dias, a diversos níveis. A primeira de todas é o estabelecimento da ligação segura com o servidor da AT, em:

https://servicos.portaldasfinancas.gov.pt:400/sgdtws/documentosTransporte

Já recebi da AT:

- uma chave pública, materializada no ficheiro 'chavePublica.cer'

- um certificado materializado no ficheiro 'certificado.pfx'

Também já tenho a extensão openssl activa no meu servidor, que é linux. Teóricamente seria só consultar a documentação sobre a extensão que existe no PHP.net e mais uns quantos tutoriais online, que deveria chegar lá. O problema é que a extensão está muito mal documentada em termos de exemplos práticos, e a carga técnica sobre criptografia é de tal forma grande que quem não está habituado fica completamente perdido.

Então, o que eu preciso:

- que alguém me explique a funcionalidade destes dois ficheiros;

- como é que eu os utilizo em conjunto com a extensão openssl do php para estabelecer a ligação segura, por onde vai ser enviada depois a informação ( esta será uma guerra para depois...)

Posted

Já consegui alguns avanços.

Descobri que a ligação é feita com a extensão cURL, e que esta não utiliza o certificado no formato 'pfx'.

Então, primeiro há que converter o certificado para o formato 'pem' recorrendo à linha de comando. O comando é:

$ openssl pkcs12 -in certificadoAntigo.pfx -out novoCertificado.pem

Isto gera um novo certificado no formato 'pem'. Pelo caminho pede para utilizar uma password fornecida com o certificado 'pfx'. Pede também para que estabeleçam uma password para utilização com o certificado 'pem'.

Ultrapassado com sucesso este passo, certifiquem-se que o script de PHP tem permissões de acesso ao novo certificado gerado.

De seguida vem o código.


$url = "https://servicos.portaldasfinancas.gov.pt:400/sgdtws/documentosTransporte%22;
$pemfile = 'novoCertificado.pem';
$keyfile='chavePublica.cer';
$cert_password = 'xxxxxxxxxx';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, 1.1);
curl_setopt($ch, CURLOPT_PORT, 443);

curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

curl_setopt($ch, CURLOPT_FAILonerror, 0);

curl_setopt($ch, CURLOPT_SSLCERT, $pemfile);
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $cert_password );


curl_setopt($ch, CURLOPT_SSLKEY, $keyfile);
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $cert_password);


curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_POSTFIELDS, 'qualquer_coisa');

$output = curl_exec($ch);

if(!$output) {echo "Curl Error : " . curl_error($ch);}
else {echo htmlentities($output);}

Quando testo o código, recebo a seguinte mensagem de erro cURL:

unable to set private key file: 'ChavePublica.cer' type PEM

Alguém me explica como corrigir isto?

Posted (edited)

De acordo com um post no Stack Overflow experimenta meter o path completo no $pemfile

// ...
$pemfile = '/home/Icepick/htdocs/secure/novoCertificado.pem';
// ...
Edited by pmg

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Posted

@pmg, obrigado pela dica.

Experimentei colocar o caminho absoluto para o certificado como indicaste, mas sem sucesso. Depois achei estranho o post do stack overflow, porque o meu script parecia encontrar o certificado mesmo com um caminho relativo. Para testar, adulterei o caminho e tornei-o inválido, e a mensagem mudou imediatamente:

unable to use client certificate (no key found or wrong pass phrase?)

Conclusão: ao contrário do que diz o post do Stack Overflow, a cURL não precisa do caminho absoluto para utilizar o certificado.O meu script encontra-o mesmo com um caminho relativo. O que acontece é que não consegue realizar o passo que se segue: utilizar a chave.

Só por causa das dúvidas, experimentei o caminho absoluto na chave também, mas sem sucesso. Definitivamente, o problema não está na utilização do caminho.

De volta à analise do erro original reparei num pormenor:

unable to set private key file: 'chavePublicaAT.cer' type PEM

A Autoridade Tributária enviou-me uma chave pública com o certificado, mas o script está a contar com a utilização de uma chave privada.

Poderá ser daqui? Qual é lógica de utilização deste conjunto? É que eu não tenho a chave privada, quem a tem é a Autoridade Tributária ...

  • 5 months later...
  • 4 weeks later...
Posted (edited)

Tens de extrair o TestesWebServices.pfx para .pem (Chave + Certificado) com o OpenSSL

- Extrair a chave privada para PEM ( Password: TESTEwebservice )

Código :

openssl pkcs12 -in TestesWebServices.pfx -nocerts -out pfxKey.pem

-Extrair o certificado

Código :

openssl pkcs12 -in TestesWebServices.pfx -clcerts -nokeys -out pfxcert.pem

$SoapAction = "https://servicos.portaldasfinancas.gov.pt:701/sgdtws/documentosTransporte/";
//$SoapAction = "https://servicos.portaldasfinancas.gov.pt:401/sgdtws/documentosTransporte/";
$Action = "https://servicos.portaldasfinancas.gov.pt:701/sgdtws/documentosTransporte";
//Action = "https://servicos.portaldasfinancas.gov.pt:401/sgdtws/documentosTransporte";
$cert_pem = 'pfxcert.pem'; //Caminho completo para o pfxcert.pem ou so o nome se estiver na mesma pasta
$key_pem  = 'pfxKey.pem'; //Caminho completo para o pfxKey.pem ou so o nome se estiver na mesma pasta

$pass_cert = 'TESTEwebservice';

               $curl = curl_init(trim($Action));  


               curl_setopt($curl, CURLOPT_FRESH_CONNECT, TRUE);
               curl_setopt($curl, CURLOPT_HTTPHEADER,array(
                       'Content-Type:text/xml;Charset=UTF-8',
                       'Accept: text/xml',
                       'Cache-Control: no-cache',
                       'SoapAction='.$SoapAction
               ));
               curl_setopt($curl, CURLOPT_URL, trim($Action));
               curl_setopt($curl, CURLOPT_SSLVERSION, 3);
               curl_setopt($curl, CURLOPT_VERBOSE, TRUE); // para ver o que se passa...
               curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE);
               curl_setopt($curl, CURLOPT_POST, 1);
               curl_setopt($curl, CURLOPT_POSTFIELDS, $xml);
               curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
               curl_setopt($curl, CURLOPT_SSLCERT, $cert_pem); // o certificado em formato PEM (.pem)
               curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
               curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $pass_cert);
               curl_setopt($curl, CURLOPT_SSLKEY, $key_pem);
               curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $pass_cert);
               curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
               curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  

               $response = curl_exec($curl);  
               $info = curl_getinfo($curl);
...
Edited by eSkiSo

Os meus programas em http://www.eskiso.net

  • 1 year later...
Posted

Boas,

Primeiro precisas de ter o openssl ( openssl.org ) e gerar o ficheiros .key e .csr

openssl req -new -subj "/C=PT/ST=Distrito da Sede/L=Local da Sede/O=Empresa /OU=Departamento de Informatica/CN=555555555/emailAddress=informatica@empresa.pt" -newkey rsa:2048 -nodes -out 555555555.csr -keyout 555555555.key

Para testar fazes:

openssl req -text -noout -in 555555555.csr

Abres o ficheiro .csr com o bloco de notas e copias o texto que lá esta.

Vais a https://faturas.portaldasfinancas.gov.pt/consultarPedidosAdesao.action

Fazes login e vais aonde diz "Aderir ao envio por webservice" (disponivel na pagina de produtores de software (link em baixo à direita))

Clicar no botão verde que diz "Aderir ao Serviço" -> "Efectuar Novo Pedido" e colar texto copiado do ficheiro .csr para a caixa de texto CSR (Certificate Signing Request)

Fazer check no "Aceito os termos ...."

Clicar em "Aderir".

Depois colocas o ficheiro recevido por email do pessoal da certificacão (.cer) e o ficheiro .key criado anterioremente e fazes os seguintes comandos:

//criar PFX - quando pedir pasword, colocar uma

openssl pkcs12 -export -in #######.cer -inkey #######.key -out #######.pfx

//criar o pfxKey.pm - vai pedir password 3 vezes é sempre a mesma

openssl pkcs12 -in ########.pfx -nocerts -out pfxKey.pem

//criar o pfxcert.pem - quando perdir password é a que colocaste antes

openssl pkcs12 -in ######.pfx -clcerts -nokeys -out pfxcert.pem

Boa sorte =D

Boas eSkiSo o ficheiro "ChavePublicaAT.cer" que utilizaste, foi-te facultado pela AT ou foi criado a partir do .pfx?

Esse ficheiro encontras neste tópico

https://www.portugal-a-programar.pt/topic/57734-utilizar-webservices-da-at/page__st__6020?do=findComment?comment=578028

  • Vote 1

Os meus programas em http://www.eskiso.net

Posted

Testei o teu codigo com "ChavePublicaAT.cer" que me foi enviado em resposta ao pedido de utilizador de testes obtenho o seguinte erro:

Curl error: Unknown SSL protocol error in connection to servicos.portaldasfinancas.gov.pt:701

apanhaste algo semelhante?

Estou utilizar $username= "599999993/0037"; $password= "testes1234";

Desde ja obrigado pela disponibilidade!

Posted

Que versão é que tens do PHP, do CURL e do SSL?

Usa este codigo para ver:

<?php
$version = curl_version();
echo "CURL Version: ".$version['version']."<br>";
echo "CURL SSL Version: ". $version['ssl_version']."<br>";
echo "PHP Version: ".phpversion();

Os meus programas em http://www.eskiso.net

Posted

Acho estranho ao testar o mesmo pedido com os link de produçao(401) mas com da datas de 2013, obtenho erro:

Curl error: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

  • 1 month later...
Posted (edited)

E

Testei o teu codigo com "ChavePublicaAT.cer" que me foi enviado em resposta ao pedido de utilizador de testes obtenho o seguinte erro:

Curl error: Unknown SSL protocol error in connection to servicos.portaldasfinancas.gov.pt:701

apanhaste algo semelhante?

Estou utilizar $username= "599999993/0037"; $password= "testes1234";

Desde ja obrigado pela disponibilidade!

Estou com o mesmo problema o de testes não está a funcionar..

(mesmo depois de já ter gerado o pem e o cert com o novo pfx)

Edited by Sant0s
  • 10 months later...
Posted

Boas Pessoal,

Já consegui comunicar, no entanto obtenho este erro com php:

Unknown SSL protocol error in connection to servicos.portaldasfinancas.gov.pt:701

Testei o teu codigo com "ChavePublicaAT.cer" que me foi enviado em resposta ao pedido de utilizador de testes obtenho o seguinte erro:

Curl error: Unknown SSL protocol error in connection to servicos.portaldasfinancas.gov.pt:701

apanhaste algo semelhante?

Estou utilizar $username= "599999993/0037"; $password= "testes1234";

Desde ja obrigado pela disponibilidade!

Como resolveu?

Estou com mesmo problema...

  • 6 months later...
Posted

Boa noite,

Tenta usar a versão 7.33.0-3 do curl, pois existe um bug conhecido que causa precisamente esse erro.

Cordiais cumprimentos,

Apocsantos

"A paciência é uma das coisas que se aprendeu na era do 48k" O respeito é como a escrita de código, uma vez perdido, dificilmente se retoma o habito"

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.