ssl — SSL/TLS-modul

Denna modul ger tillgång till funktioner för kryptering enligt Transport Layer Security (tidigare och allmänt känt som ”Secure Sockets Layer”) samt motpartsautentisering för nätverkssocketar, både på klient- och serversidan.

Tips

Ny på TLS på kameran? Börja med handledningen Arbeta med TLS-certifikat. Den går igenom hur du väljer nyckeltyper, skapar och konverterar certifikat till det DER-format som kameran kräver, får över dem till enheten samt verifierar servrar och klienter – med kompletta fungerande exempel.

Anteckning

MicroPython implementerar inte ssl.SSLError. Fel i SSL/TLS rapporteras i stället som OSError.

Exempel

TLS-klient som verifierar serverns certifikat mot ett CA-certifikat (i DER-format) som lagras i filsystemet:

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

För en snabb, osäker anslutning (utan certifikatvalidering) kan bekvämlighetsfunktionen ssl.wrap_socket() användas i stället:

ssock = ssl.wrap_socket(sock, server_hostname="example.com")

TLS-server som presenterar sitt eget certifikat och sin privata nyckel (DER-format):

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

Funktioner

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

Omslut den angivna sock och returnera ett nytt omslutet socket-objekt. Implementationen av denna funktion är att först skapa en SSLContext och sedan anropa metoden SSLContext.wrap_socket() på det kontextobjektet. Argumenten sock, server_side och server_hostname skickas oförändrade vidare till metodanropet. Argumentet do_handshake skickas vidare som do_handshake_on_connect. De återstående argumenten har följande beteende:

  • cert_reqs avgör om motparten (server eller klient) måste presentera ett giltigt certifikat. Observera att ssl.CERT_NONE och ssl.CERT_OPTIONAL inte validerar något certifikat; endast ssl.CERT_REQUIRED gör det.

  • cadata är ett bytes-objekt som innehåller CA-certifikatkedjan (i DER-format) som ska validera motpartens certifikat. För närvarande stöds endast ett enda DER-kodat certifikat.

Klasser

class ssl.SSLContext(protocol: int, /)

Skapa en ny SSLContext-instans. Argumentet protocol måste vara en av konstanterna PROTOCOL_*.

load_cert_chain(certfile: str | bytes, keyfile: str | bytes) None

Läs in en privat nyckel och motsvarande certifikat. certfile är en sträng med filsökvägen till certifikatet. keyfile är en sträng med filsökvägen till den privata nyckeln.

Skillnad mot CPython

MicroPython-tillägg: certfile och keyfile kan vara bytes-objekt i stället för strängar, i vilket fall de tolkas som själva certifikat-/nyckeldatan.

load_verify_locations(cafile: str | None = None, cadata: bytes | None = None) None

Läs in CA-certifikatkedjan som ska validera motpartens certifikat. cafile är filsökvägen till CA-certifikaten. cadata är ett bytes-objekt som innehåller CA-certifikaten. Endast ett av dessa argument bör anges.

get_ciphers() List[str]

Hämta en lista över aktiverade chiffer, returnerad som en lista med strängar.

set_ciphers(ciphers: List[str]) None

Ange de tillgängliga chiffren för socketar som skapas med denna kontext. ciphers bör vara en lista med strängar i IANA:s chiffersvitformat .

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

Tar en stream sock (vanligtvis en socket.socket-instans av typen SOCK_STREAM) och returnerar en instans av ssl.SSLSocket som omsluter den underliggande strömmen. Det returnerade objektet har de vanliga gränssnittsmetoderna för stream, såsom read(), write() osv.

  • server_side väljer om den omslutna socketen befinner sig på server- eller klientsidan. En SSL-socket på serversidan bör skapas från en vanlig socket som returneras av accept() på en icke-SSL-lyssnande serversocket.

  • do_handshake_on_connect avgör om handskakningen görs som en del av wrap_socket eller om den skjuts upp för att utföras som en del av de första läsningarna eller skrivningarna. För blockerande socketar är det standard att utföra handskakningen omedelbart. För icke-blockerande socketar (dvs. när den sock som skickas in i wrap_socket är i icke-blockerande läge) bör handskakningen i allmänhet skjutas upp eftersom wrap_socket annars blockerar tills den slutförs.

  • server_hostname är avsett att användas som klient och anger värdnamnet att kontrollera mot det mottagna servercertifikatet. Det anger även namnet för Server Name Indication (SNI), vilket gör att servern kan presentera rätt certifikat.

  • client_id är ett MicroPython-specifikt tilläggsargument som endast används vid implementering av en DTLS-server. Se DTLS-stöd för detaljer.

Varning

Som standard utförs ingen certifikatvalidering (ssl.CERT_NONE). För en säker anslutning måste du verifiera motpartens certifikat genom att sätta cert_reqs / SSLContext.verify_mode till ssl.CERT_REQUIRED; annars är anslutningen sårbar för man-in-the-middle-attacker.

CPythons wrap_socket returnerar ett SSLSocket-objekt som har metoder typiska för socketar, såsom send, recv osv. MicroPythons wrap_socket returnerar ett objekt som mer liknar CPythons SSLObject, vilket inte har dessa socket-metoder.

verify_mode

Ange eller hämta beteendet för verifiering av motpartens certifikat. Måste vara en av konstanterna CERT_*.

Anteckning

ssl.CERT_REQUIRED kräver att enhetens datum/tid är korrekt inställd, t.ex. med mpremote rtc --set eller ntptime, och server_hostname måste anges när man är på klientsidan.

DTLS-stöd

Skillnad mot CPython

Detta är ett MicroPython-tillägg.

Denna modul stöder DTLS i klient- och serverläge via konstanterna PROTOCOL_DTLS_CLIENT och PROTOCOL_DTLS_SERVER som kan användas som argumentet protocol till SSLContext.

I detta fall förväntas den underliggande socketen bete sig som en datagramsocket (dvs. som den socket som öppnas med socket.socket med socket.AF_INET som af och socket.SOCK_DGRAM som type).

Stöd för DTLS-server

MicroPythons stöd för DTLS-server är konfigurerat med ”Hello Verify” enligt kravet för DTLS 1.2. Detta är transparent för DTLS-klienter, men det finns relevanta överväganden vid implementering av en DTLS-server i MicroPython:

  • Servern bör skicka ett extra argument client_id vid anrop av SSLContext.wrap_socket(). Detta ID måste vara ett bytes-objekt (eller liknande) med en transportspecifik identifierare som representerar klienten.

    Den enklaste metoden är att konvertera tuppeln (client_ip, client_port) som returneras av socket.recv_from() till en byte-sträng, dvs.:

    _, 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())
    
  • Första gången en klient ansluter kommer serverns anrop till wrap_socket att misslyckas med ett OSError-fel ”Hello Verify Required”. Detta beror på att DTLS-kakan ”Hello Verify” ännu inte är känd av klienten. Om samma klient ansluter en andra gång kommer wrap_socket att lyckas.

  • DTLS-kakor för ”Hello Verify” är kopplade till SSLContext-objektet, så samma SSLContext-objekt bör användas för att omsluta en efterföljande anslutning från samma klient. Kakimplementationen inkluderar en timeout och har konstant minnesanvändning oavsett hur många klienter som ansluter, så det går bra att återanvända samma SSLContext-objekt under serverns livstid.

Konstanter

ssl.PROTOCOL_TLS_CLIENT: int

Stödd värde för parametern protocol, som väljer TLS-klientläge.

ssl.PROTOCOL_TLS_SERVER: int

Stödd värde för parametern protocol, som väljer TLS-serverläge.

ssl.PROTOCOL_DTLS_CLIENT: int

Stödd värde för parametern protocol, som väljer DTLS-klientläge.

ssl.PROTOCOL_DTLS_SERVER: int

Stödd värde för parametern protocol, som väljer DTLS-serverläge.

ssl.CERT_NONE: int

Stödd värde för parametern cert_reqs och attributet SSLContext.verify_mode. Ingen certifikatverifiering utförs på motparten.

ssl.CERT_OPTIONAL: int

Stödd värde för parametern cert_reqs och attributet SSLContext.verify_mode. Certifikatverifiering är valfri. Observera att detta på OpenMV Cam beter sig som ssl.CERT_NONE.

ssl.CERT_REQUIRED: int

Stödd värde för parametern cert_reqs och attributet SSLContext.verify_mode. Ett giltigt certifikat krävs från motparten.