ssl — módulo SSL/TLS¶
Este módulo fornece acesso a funcionalidades de encriptação Transport Layer Security (anteriormente e amplamente conhecida como «Secure Sockets Layer») e autenticação entre pares para sockets de rede, tanto do lado do cliente como do lado do servidor.
Dica
Novo no uso de TLS na câmara? Comece pelo tutorial Trabalhar com certificados TLS. Este guia explica como escolher tipos de chaves, criar e converter certificados para o formato DER exigido pela câmara, colocá-los no dispositivo, e verificar servidores e clientes – com exemplos completos e funcionais.
Nota
O MicroPython não implementa ssl.SSLError. As falhas SSL/TLS são lançadas como OSError.
Exemplos¶
Cliente TLS a verificar o certificado do servidor contra um certificado CA (em formato DER) armazenado no sistema de ficheiros:
import socket
import ssl
import ntptime
# CERT_REQUIRED checks the certificate's validity dates, so the clock
# must be set (see the certificates tutorial linked above).
ntptime.settime()
# Open a plain TCP connection.
addr = socket.getaddrinfo("example.com", 443)[0][-1]
sock = socket.socket()
sock.connect(addr)
# Wrap it for TLS and require a valid certificate.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="ca.der")
ssock = ctx.wrap_socket(sock, server_hostname="example.com")
ssock.write(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
print(ssock.read())
ssock.close()
Para uma ligação rápida insegura (sem validação de certificado), pode usar-se a função de conveniência ssl.wrap_socket()
ssock = ssl.wrap_socket(sock, server_hostname="example.com")
Servidor TLS a apresentar o seu próprio certificado e chave privada (formato DER):
import socket
import ssl
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(socket.getaddrinfo("0.0.0.0", 8443)[0][-1])
sock.listen(1)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("server.der", "server.key")
while True:
client, addr = sock.accept()
sclient = ctx.wrap_socket(client, server_side=True)
sclient.write(b"hello\n")
sclient.close()
Funções¶
- ssl.wrap_socket(sock: Any, server_side: bool = False, key: bytes | None = None, cert: bytes | None = None, cert_reqs: int = CERT_NONE, cadata: bytes | None = None, server_hostname: str | None = None, do_handshake: bool = True) Any¶
Envolve o sock fornecido e devolve um novo objeto socket encapsulado. A implementação desta função consiste em primeiro criar um
SSLContexte depois chamar o métodoSSLContext.wrap_socket()nesse objeto de contexto. Os argumentos sock, server_side e server_hostname são passados sem alteração para a chamada ao método. O argumento do_handshake é passado como do_handshake_on_connect. Os restantes argumentos têm o seguinte comportamento:cert_reqs determina se o par (servidor ou cliente) deve apresentar um certificado válido. Note que
ssl.CERT_NONEessl.CERT_OPTIONALnão validam qualquer certificado; apenasssl.CERT_REQUIREDo faz.cadata é um objeto bytes contendo a cadeia de certificados CA (em formato DER) que validará o certificado do par. Atualmente apenas é suportado um único certificado codificado em DER.
Classes¶
- class ssl.SSLContext(protocol: int, /)¶
Cria uma nova instância de SSLContext. O argumento protocol deve ser uma das constantes
PROTOCOL_*.- load_cert_chain(certfile: str | bytes, keyfile: str | bytes) None¶
Carrega uma chave privada e o certificado correspondente. O certfile é uma string com o caminho de ficheiro do certificado. O keyfile é uma string com o caminho de ficheiro da chave privada.
Diferença em relação ao CPython
Extensão MicroPython: certfile e keyfile podem ser objetos bytes em vez de strings; nesse caso são interpretados como os dados reais do certificado/chave.
- load_verify_locations(cafile: str | None = None, cadata: bytes | None = None) None¶
Carrega a cadeia de certificados CA que validará o certificado do par. cafile é o caminho de ficheiro dos certificados CA. cadata é um objeto bytes contendo os certificados CA. Apenas um destes argumentos deve ser fornecido.
- set_ciphers(ciphers: List[str]) None¶
Define os cifras disponíveis para sockets criados com este contexto. ciphers deve ser uma lista de strings no formato de suite de cifra IANA .
- wrap_socket(sock: Any, *, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname: str | None = None, client_id: bytes | None = None) Any¶
Recebe um stream sock (normalmente uma instância de socket.socket do tipo
SOCK_STREAM) e devolve uma instância de ssl.SSLSocket, encapsulando o stream subjacente. O objeto devolvido tem os métodos de interface de stream habituais comoread(),write(), etc.server_side seleciona se o socket encapsulado está no lado do servidor ou do cliente. Um socket SSL do lado do servidor deve ser criado a partir de um socket normal devolvido por
accept()num socket de escuta não-SSL.do_handshake_on_connect determina se o handshake é feito como parte do
wrap_socketou se é adiado para ser realizado como parte das leituras ou escritas iniciais. Para sockets bloqueantes, fazer o handshake imediatamente é o padrão. Para sockets não bloqueantes (ou seja, quando o sock passado parawrap_socketestá em modo não bloqueante), o handshake deve geralmente ser adiado, caso contráriowrap_socketbloqueia até que seja concluído.server_hostname destina-se a ser usado como cliente e define o nome do host a verificar contra o certificado do servidor recebido. Também define o nome para a Indicação de Nome de Servidor (SNI), permitindo ao servidor apresentar o certificado adequado.
client_id é um argumento de extensão específico do MicroPython, utilizado apenas ao implementar um Servidor DTLS. Consulte Suporte a DTLS para mais detalhes.
Aviso
Por omissão, não é realizada qualquer validação de certificado (
ssl.CERT_NONE). Para uma ligação segura deve verificar o certificado do par definindo cert_reqs /SSLContext.verify_modecomossl.CERT_REQUIRED; caso contrário a ligação é vulnerável a ataques man-in-the-middle.O
wrap_socketdo CPython devolve um objetoSSLSocketcom métodos típicos de socket, comosend,recv, etc. Owrap_socketdo MicroPython devolve um objeto mais semelhante aoSSLObjectdo CPython, que não possui esses métodos de socket.
- verify_mode¶
Define ou obtém o comportamento para verificação de certificados de pares. Deve ser uma das constantes
CERT_*.Nota
ssl.CERT_REQUIREDrequer que a data/hora do dispositivo esteja corretamente definida, por exemplo usando mpremote rtc --set ountptime, eserver_hostnamedeve ser especificado quando no lado do cliente.
Suporte a DTLS¶
Diferença em relação ao CPython
Esta é uma extensão do MicroPython.
Este módulo suporta DTLS em modo cliente e servidor através das constantes PROTOCOL_DTLS_CLIENT e PROTOCOL_DTLS_SERVER que podem ser usadas como argumento protocol de SSLContext.
Neste caso, espera-se que o socket subjacente se comporte como um socket de datagrama (ou seja, como o socket aberto com socket.socket com socket.AF_INET como af e socket.SOCK_DGRAM como type).
Suporte a servidor DTLS¶
O suporte a servidor DTLS do MicroPython está configurado com «Hello Verify» conforme exigido pelo DTLS 1.2. Isto é transparente para os clientes DTLS, mas existem considerações relevantes ao implementar um servidor DTLS em MicroPython:
O servidor deve passar um argumento adicional client_id ao chamar
SSLContext.wrap_socket(). Este ID deve ser um objetobytes(ou similar) com um identificador específico do transporte representando o cliente.A abordagem mais simples é converter o tuplo de
(client_ip, client_port)devolvido porsocket.recv_from()numa cadeia de bytes, ou seja:_, client_addr = sock.recvfrom(1, socket.MSG_PEEK) sock.connect(client_addr) # Connect back to the client sock = ssl_ctx.wrap_socket(sock, server_side=True, client_id=repr(client_addr).encode())
Na primeira vez que um cliente se liga, a chamada do servidor a
wrap_socketfalhará com um erroOSError«Hello Verify Required». Isto deve-se ao facto de o cookie «Hello Verify» do DTLS ainda não ser conhecido pelo cliente. Se o mesmo cliente se ligar uma segunda vez,wrap_socketterá sucesso.Os cookies DTLS para «Hello Verify» estão associados ao objeto
SSLContext, pelo que o mesmo objetoSSLContextdeve ser utilizado para encapsular uma ligação subsequente do mesmo cliente. A implementação do cookie inclui um tempo limite e tem uso constante de memória independentemente do número de clientes que se ligam, pelo que é seguro reutilizar o mesmo objetoSSLContextdurante o tempo de vida do servidor.
Constantes¶
- ssl.PROTOCOL_TLS_CLIENT: int¶
Valor suportado para o parâmetro protocol, que seleciona o modo de cliente TLS.
- ssl.PROTOCOL_TLS_SERVER: int¶
Valor suportado para o parâmetro protocol, que seleciona o modo de servidor TLS.
- ssl.PROTOCOL_DTLS_CLIENT: int¶
Valor suportado para o parâmetro protocol, que seleciona o modo de cliente DTLS.
- ssl.PROTOCOL_DTLS_SERVER: int¶
Valor suportado para o parâmetro protocol, que seleciona o modo de servidor DTLS.
- ssl.CERT_NONE: int¶
Valor suportado para o parâmetro cert_reqs e o atributo
SSLContext.verify_mode. Não é realizada qualquer verificação de certificado no par.
- ssl.CERT_OPTIONAL: int¶
Valor suportado para o parâmetro cert_reqs e o atributo
SSLContext.verify_mode. A verificação de certificado é opcional. Note que na OpenMV Cam este comporta-se comossl.CERT_NONE.
- ssl.CERT_REQUIRED: int¶
Valor suportado para o parâmetro cert_reqs e o atributo
SSLContext.verify_mode. É exigido um certificado válido do par.