Mostrando postagens com marcador socket. Mostrar todas as postagens
Mostrando postagens com marcador socket. Mostrar todas as postagens

sexta-feira, março 07, 2008

Python + SSL + Certificado digital

É comum durante o desenvolvimento de um programa que este precise de comunicação com serviços de terceiros disponíveis na rede.

Em Python como em outras linguagens, todo meio de comunicação via rede utiliza basicamente socket em seu nível mais baixo para prover essa comunicação, seja o meio de comunicação SOAP, rpc, http, etc.

Algumas vezes estes serviços externos fornecem a possibilidade de utilização de canais seguros para comunicação (ssl). Em alguns casos o serviço a ser utilizado pode até mesmo obrigar o uso de comunicação segura, para isso precisamos utilizar socket + ssl. Dependendo da necessidade do projeto pode ser necessário utilizar também um certificado digital juntamente com a conexão ssl como forma de autenticação.

Para utilizar comunicação segura o módulo 'socket' prove a função 'ssl', que de maneira simples executa a comunicação com o serviço desejado via ssl. Essa função também pode receber dois parâmetros , 'key_file' e 'cert_file' respectivamente o 'path' do arquivo PEM para a chave privada e o 'path' para o arquivo PEM do certificado.

Uma assinatura digital geralmente é um arquivo binário no formato 'pkcs12' com a extensão '.pfx', sendo assim precisamos abrir esse arquivo e retirar as duas informações que o 'ssl' precisa (key_file, cer_file) e salvar nos arquivos com o formato PEM. Para isso utilizamos openssl e pyopenssl, 'bindings' para python da 'lib' 'openssl'.

Com os módulos instalados, vamos abrir o certificado no formato binário, transformar no objeto 'pkcs12' e então retirar as informações do certificado e da chave privada para em seguida salvar cada um em arquivo separado.

Alguns certificados podem estar codificados sendo necessário informar a frase para decodificação, para tal temos o parâmetro 'passphrase', se não for preciso é só não informar o parâmetro como no exemplo abaixo.


from OpenSSL import crypto

# Lendo o arquivo pfx no formato pkcs12 como binario
pkcs12 = crypto.load_pkcs12(open('certificado.pfx', 'rb').read(), 'passphrase')

# Retorna a string decodificado do certificado
cert_str = crypto.dump_certificate(crypto.FILETYPE_PEM, pkcs12.get_certificate())

# Retorna a string decodificado da chave privada
key_str = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkcs12.get_privatekey())

# Gravando a string no dicso
open('cert.pem', 'wb').write(cert_str)

# Gravando a string no dicso
open('key.ptm', 'wb').write(key_str)


Agora para finalizar basta efetuar a comunicação com o serviço desejado utilizando o modulo 'socket' e a função 'ssl' passando os parâmetros de chave e certificado:


proxy = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proxy.connect(('www.lzt.com.br', 80))
proxy_ssl = socket.ssl(proxy, 'key.pem', 'cert.pem')


Pronto! Com o objeto 'proxy' podemos fazer requisições a serviços que utilizem conexão 'ssl' com certificados digitais.