ssl — SSL/TLS-module¶
Deze module biedt toegang tot Transport Layer Security (voorheen en algemeen bekend als “Secure Sockets Layer”) encryptie- en peerauthenticatievoorzieningen voor netwerksockets, zowel aan de clientzijde als aan de serverzijde.
Tip
Nieuw met TLS op de camera? Begin met de Werken met TLS-certificaten-tutorial. Deze behandelt het kiezen van sleuteltypen, het maken en converteren van certificaten naar het DER-formaat dat de camera vereist, het op het apparaat krijgen ervan en het verifiëren van servers en clients – met volledige werkende voorbeelden.
Notitie
MicroPython implementeert ssl.SSLError niet. SSL/TLS-fouten worden in plaats daarvan opgeworpen als OSError.
Voorbeelden¶
TLS-client die het certificaat van de server verifieert aan de hand van een CA-certificaat (in DER-formaat) dat op het bestandssysteem is opgeslagen:
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()
Voor een snelle, onveilige verbinding (zonder certificaatvalidatie) kan in plaats daarvan de hulpfunctie ssl.wrap_socket() worden gebruikt:
ssock = ssl.wrap_socket(sock, server_hostname="example.com")
TLS-server die zijn eigen certificaat en privésleutel presenteert (DER-formaat):
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()
Functies¶
- 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¶
Verpakt de opgegeven sock en geeft een nieuw wrapped-socket-object terug. De implementatie van deze functie maakt eerst een
SSLContextaan en roept vervolgens de methodeSSLContext.wrap_socket()aan op dat contextobject. De argumenten sock, server_side en server_hostname worden ongewijzigd doorgegeven aan de methodeaanroep. Het argument do_handshake wordt doorgegeven als do_handshake_on_connect. De overige argumenten hebben het volgende gedrag:cert_reqs bepaalt of de peer (server of client) een geldig certificaat moet presenteren. Merk op dat
ssl.CERT_NONEenssl.CERT_OPTIONALgeen enkel certificaat valideren; alleenssl.CERT_REQUIREDdoet dat.cadata is een bytes-object dat de CA-certificaatketen (in DER-formaat) bevat die het certificaat van de peer zal valideren. Momenteel wordt alleen één DER-gecodeerd certificaat ondersteund.
Classes¶
- class ssl.SSLContext(protocol: int, /)¶
Maakt een nieuwe SSLContext-instantie aan. Het argument protocol moet een van de
PROTOCOL_*-constanten zijn.- load_cert_chain(certfile: str | bytes, keyfile: str | bytes) None¶
Laadt een privésleutel en het bijbehorende certificaat. certfile is een string met het bestandspad van het certificaat. keyfile is een string met het bestandspad van de privésleutel.
Verschil met CPython
MicroPython-uitbreiding: certfile en keyfile kunnen bytes-objecten zijn in plaats van strings, in welk geval ze worden geïnterpreteerd als de daadwerkelijke certificaat-/sleutelgegevens.
- load_verify_locations(cafile: str | None = None, cadata: bytes | None = None) None¶
Laadt de CA-certificaatketen die het certificaat van de peer zal valideren. cafile is het bestandspad van de CA-certificaten. cadata is een bytes-object dat de CA-certificaten bevat. Slechts één van deze argumenten mag worden opgegeven.
- get_ciphers() List[str]¶
Geeft een lijst met ingeschakelde ciphers terug, als een lijst van strings.
- set_ciphers(ciphers: List[str]) None¶
Stelt de beschikbare ciphers in voor sockets die met deze context worden aangemaakt. ciphers moet een lijst van strings zijn in de IANA cipher suite-indeling .
- 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¶
Neemt een stream sock (meestal een socket.socket-instantie van het type
SOCK_STREAM) en geeft een instantie van ssl.SSLSocket terug die de onderliggende stream verpakt. Het teruggegeven object heeft de gebruikelijke stream-interfacemethoden zoalsread(),write(), enz.server_side selecteert of de verpakte socket zich aan de server- of clientzijde bevindt. Een server-side SSL-socket moet worden aangemaakt vanuit een normale socket die wordt teruggegeven door
accept()op een niet-SSL luisterende serversocket.do_handshake_on_connect bepaalt of de handshake wordt uitgevoerd als onderdeel van de
wrap_socketof dat deze wordt uitgesteld tot de eerste leesacties of schrijfacties. Voor blokkerende sockets is het direct uitvoeren van de handshake standaard. Voor niet-blokkerende sockets (d.w.z. wanneer de sock die aanwrap_socketwordt doorgegeven in niet-blokkerende modus staat) moet de handshake in het algemeen worden uitgesteld, omdatwrap_socketanders blokkeert totdat deze is voltooid.server_hostname is bedoeld voor gebruik als client en stelt de hostnaam in om te controleren tegen het ontvangen servercertificaat. Het stelt ook de naam in voor Server Name Indication (SNI), waardoor de server het juiste certificaat kan presenteren.
client_id is een MicroPython-specifiek uitbreidingsargument dat alleen wordt gebruikt bij het implementeren van een DTLS-server. Zie DTLS-ondersteuning voor details.
Waarschuwing
Standaard wordt er geen certificaatvalidatie uitgevoerd (
ssl.CERT_NONE). Voor een beveiligde verbinding moet je het certificaat van de peer verifiëren door cert_reqs /SSLContext.verify_modein te stellen opssl.CERT_REQUIRED; anders is de verbinding kwetsbaar voor man-in-the-middle-aanvallen.CPython’s
wrap_socketgeeft eenSSLSocket-object terug dat methoden heeft die typisch zijn voor sockets, zoalssend,recv, enz. MicroPython’swrap_socketgeeft een object terug dat meer lijkt op CPython’sSSLObject, dat deze socketmethoden niet heeft.
- verify_mode¶
Stelt het gedrag voor de verificatie van peercertificaten in of vraagt het op. Moet een van de
CERT_*-constanten zijn.Notitie
ssl.CERT_REQUIREDvereist dat de datum/tijd van het apparaat correct is ingesteld, bijv. met mpremote rtc --set ofntptime, enserver_hostnamemoet aan de clientzijde worden opgegeven.
DTLS-ondersteuning¶
Verschil met CPython
Dit is een MicroPython-uitbreiding.
Deze module ondersteunt DTLS in client- en servermodus via de constanten PROTOCOL_DTLS_CLIENT en PROTOCOL_DTLS_SERVER, die kunnen worden gebruikt als het protocol-argument van SSLContext.
In dit geval wordt verwacht dat de onderliggende socket zich gedraagt als een datagram-socket (d.w.z. zoals de socket die wordt geopend met socket.socket met socket.AF_INET als af en socket.SOCK_DGRAM als type).
DTLS-serverondersteuning¶
MicroPython’s DTLS-serverondersteuning is geconfigureerd met “Hello Verify” zoals vereist voor DTLS 1.2. Dit is transparant voor DTLS-clients, maar er zijn relevante overwegingen bij het implementeren van een DTLS-server in MicroPython:
De server moet een extra argument client_id doorgeven bij het aanroepen van
SSLContext.wrap_socket(). Deze ID moet eenbytes-object (of vergelijkbaar) zijn met een transportspecifieke identificatie die de client vertegenwoordigt.De eenvoudigste aanpak is om de tuple
(client_ip, client_port)die wordt teruggegeven doorsocket.recv_from()om te zetten in een byte-string, d.w.z.:_, 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())
De eerste keer dat een client verbinding maakt, zal de serveraanroep van
wrap_socketmislukken met eenOSError-fout “Hello Verify Required”. Dit komt doordat de DTLS “Hello Verify”-cookie nog niet bekend is bij de client. Als dezelfde client een tweede keer verbinding maakt, dan zalwrap_socketslagen.DTLS-cookies voor “Hello Verify” zijn gekoppeld aan het
SSLContext-object, dus hetzelfdeSSLContext-object moet worden gebruikt om een volgende verbinding van dezelfde client te verpakken. De cookie-implementatie bevat een time-out en heeft een constant geheugengebruik, ongeacht hoeveel clients verbinding maken, dus het is prima om hetzelfdeSSLContext-object te hergebruiken gedurende de levensduur van de server.
Constanten¶
- ssl.PROTOCOL_TLS_CLIENT: int¶
Ondersteunde waarde voor de parameter protocol, die de TLS-clientmodus selecteert.
- ssl.PROTOCOL_TLS_SERVER: int¶
Ondersteunde waarde voor de parameter protocol, die de TLS-servermodus selecteert.
- ssl.PROTOCOL_DTLS_CLIENT: int¶
Ondersteunde waarde voor de parameter protocol, die de DTLS-clientmodus selecteert.
- ssl.PROTOCOL_DTLS_SERVER: int¶
Ondersteunde waarde voor de parameter protocol, die de DTLS-servermodus selecteert.
- ssl.CERT_NONE: int¶
Ondersteunde waarde voor de parameter cert_reqs en het attribuut
SSLContext.verify_mode. Er wordt geen certificaatverificatie op de peer uitgevoerd.
- ssl.CERT_OPTIONAL: int¶
Ondersteunde waarde voor de parameter cert_reqs en het attribuut
SSLContext.verify_mode. Certificaatverificatie is optioneel. Merk op dat dit op de OpenMV Cam zich gedraagt alsssl.CERT_NONE.
- ssl.CERT_REQUIRED: int¶
Ondersteunde waarde voor de parameter cert_reqs en het attribuut
SSLContext.verify_mode. Er is een geldig certificaat van de peer vereist.