Jump to content
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

Icepick.pt

Autoridade Tributária - Utilização de webservice com SSL

Recommended Posts

Icepick.pt

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...)

Share this post


Link to post
Share on other sites
Icepick.pt

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?

Share this post


Link to post
Share on other sites
pmg

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!

Share this post


Link to post
Share on other sites
Icepick.pt

@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 ...

Share this post


Link to post
Share on other sites
eSkiSo

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

Share this post


Link to post
Share on other sites
Jorge Lima

Boas, o PDF dos gajos tem um exemplo completo para o Header mas não para o Body. Alguém pode dar um exemplo de um pedido SOAP que efectivamente funcione?

Share this post


Link to post
Share on other sites
robotical

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

Share this post


Link to post
Share on other sites
eSkiSo

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

Share this post


Link to post
Share on other sites
robotical

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!

Share this post


Link to post
Share on other sites
eSkiSo

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

Share this post


Link to post
Share on other sites
robotical

CURL Version: 7.35.0

CURL SSL Version: OpenSSL/1.0.1f

PHP Version: 5.5.9-1ubuntu4.5

No .conf do apache tiveste que efetuar alguma alteração ou adicionar os certificados?

Share this post


Link to post
Share on other sites
robotical

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

Share this post


Link to post
Share on other sites
robotical

Verifica a data do certificado, pode ter expirado

Endereços de testes não estão a funcionar só com os 401 !!

UM GRANDE OBRIGADO !!!!

Share this post


Link to post
Share on other sites
Sant0s

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

Share this post


Link to post
Share on other sites
blacksnacke

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...

Share this post


Link to post
Share on other sites
iznougudpt

Eu também continuo coo o erro do

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

quer em Windows quer em Linux. Alguém que tenha tido este erro já o conseguiu resolver?

Share this post


Link to post
Share on other sites
apocsantos

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"

Share this post


Link to post
Share on other sites
Sant0s

Já alguém conseguiu comunicar para o URL de testes? Em produção tenho tudo bem mas em testes estou com o erro:

Unknown SSL protocol error

 

 

 

Edited by Sant0s

Share this post


Link to post
Share on other sites
Nuno Bagulho Marques

Bom dia!

Utilizei o código do @eSkiSo ( e desde já obrigado). Fiz as alterações recomendadas, nomeadamente a alteração do formato do certificado, mas não consigo ligar ao web-servivce

não obtenho nenhuma resposta, depois da instrução

$response = curl_exec($curl);  

resultado vem em branco

Alguma ajuda? Obrigado

Share this post


Link to post
Share on other sites
Nuno Bagulho Marques
Em 21/08/2017 às 12:19, Nuno Bagulho Marques disse:

Bom dia!

Utilizei o código do @eSkiSo ( e desde já obrigado). Fiz as alterações recomendadas, nomeadamente a alteração do formato do certificado, mas não consigo ligar ao web-servivce

não obtenho nenhuma resposta, depois da instrução

$response = curl_exec($curl);  

resultado vem em branco

Alguma ajuda? Obrigado

progredi...

agora obtenho Unable to load client key

como passo do ficheiro saPubKey.jks para ChavePublicaAT.cer ... ou não preciso disto para nada?

já tentei extrair com o keytool, mas nada - pede uma password

Share this post


Link to post
Share on other sites
eSkiSo

Verifica o /var/log/apache2/error_log , ve se tem la algum erro mais especifico.

O Servidor de testes tambem pode ja nao estar a funcionar, os 401 devem funcionar direito


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

Share this post


Link to post
Share on other sites

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

×

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.