ssl — SSL/TLS modul

Ez a modul hozzáférést biztosít a Transport Layer Security (korábban és széles körben „Secure Sockets Layer” néven ismert) titkosítási és partnerhitelesítési szolgáltatásokhoz a hálózati socketek számára, mind a kliens, mind a szerver oldalon.

Javaslat

Most ismerkedsz a TLS-sel a kamerán? Kezdd a TLS tanúsítványok kezelése oktatóanyaggal. Ez végigvezet a kulcstípusok kiválasztásán, a tanúsítványok létrehozásán és a kamera által megkövetelt DER formátumra való átalakításán, az eszközre juttatásukon, valamint a szerverek és kliensek ellenőrzésén – teljes, működő példákkal.

Megjegyzés

A MicroPython nem valósítja meg az ssl.SSLError kivételt. Az SSL/TLS hibák helyette OSError formájában keletkeznek.

Példák

TLS kliens, amely a szerver tanúsítványát egy fájlrendszeren tárolt (DER formátumú) CA-tanúsítvánnyal ellenőrzi:

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

Gyors, nem biztonságos kapcsolathoz (tanúsítvány-ellenőrzés nélkül) helyette a ssl.wrap_socket() kényelmi függvény használható:

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

TLS szerver, amely saját tanúsítványát és privát kulcsát (DER formátum) mutatja be:

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

Függvények

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

Csomagolja be a megadott sock objektumot, és adjon vissza egy új, becsomagolt socket objektumot. A függvény megvalósítása először létrehoz egy SSLContext objektumot, majd meghívja annak SSLContext.wrap_socket() metódusát. A sock, server_side és server_hostname argumentumok változatlanul kerülnek átadásra a metódushívásnak. A do_handshake argumentum do_handshake_on_connect néven kerül átadásra. A fennmaradó argumentumok az alábbi módon viselkednek:

  • A cert_reqs határozza meg, hogy a partnernek (szervernek vagy kliensnek) érvényes tanúsítványt kell-e bemutatnia. Vedd figyelembe, hogy az ssl.CERT_NONE és az ssl.CERT_OPTIONAL nem ellenőriz egyetlen tanúsítványt sem; csak az ssl.CERT_REQUIRED teszi ezt.

  • A cadata egy bytes objektum, amely a partner tanúsítványát ellenőrző CA-tanúsítványláncot (DER formátumban) tartalmazza. Jelenleg csak egyetlen DER-kódolású tanúsítvány támogatott.

Osztályok

class ssl.SSLContext(protocol: int, /)

Új SSLContext példányt hoz létre. A protocol argumentumnak a PROTOCOL_* konstansok egyikének kell lennie.

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

Betölt egy privát kulcsot és a hozzá tartozó tanúsítványt. A certfile egy karakterlánc, amely a tanúsítvány fájl elérési útját adja meg. A keyfile egy karakterlánc, amely a privát kulcs fájl elérési útját adja meg.

Eltérés a CPython-tól

MicroPython kiterjesztés: a certfile és a keyfile karakterláncok helyett bytes objektumok is lehetnek, ebben az esetben magát a tanúsítvány-/kulcsadatot jelentik.

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

Betölti a partner tanúsítványát ellenőrző CA-tanúsítványláncot. A cafile a CA-tanúsítványok fájl elérési útja. A cadata egy bytes objektum, amely a CA-tanúsítványokat tartalmazza. Ezek közül csak az egyik argumentumot szabad megadni.

get_ciphers() List[str]

Lekéri az engedélyezett titkosítók listáját, karakterláncok listájaként visszaadva.

set_ciphers(ciphers: List[str]) None

Beállítja az ezzel a kontextussal létrehozott socketekhez elérhető titkosítókat. A ciphers karakterláncok listája kell legyen az IANA cipher suite formátumban .

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

Átvesz egy stream sock objektumot (általában egy SOCK_STREAM típusú socket.socket példányt), és visszaad egy ssl.SSLSocket példányt, amely becsomagolja az alatta lévő streamet. A visszaadott objektum rendelkezik a szokásos stream interfész metódusokkal, mint a read(), write() stb.

  • A server_side azt választja ki, hogy a becsomagolt socket a szerver vagy a kliens oldalon van-e. A szerver oldali SSL socketet egy nem SSL figyelő szerver socket accept() hívásából visszakapott normál socketből kell létrehozni.

  • A do_handshake_on_connect határozza meg, hogy a kézfogás a wrap_socket részeként történik-e, vagy elhalasztódik az első olvasások vagy írások részeként. Blokkoló socketeknél a kézfogás azonnali elvégzése a szokásos. Nem blokkoló socketeknél (azaz amikor a wrap_socket hívásnak átadott sock nem blokkoló módban van) a kézfogást általában el kell halasztani, mert egyébként a wrap_socket blokkol, amíg az be nem fejeződik.

  • A server_hostname kliensként való használatra szolgál, és beállítja a kapott szervertanúsítvánnyal szemben ellenőrizendő gazdagépnevet. Beállítja a Server Name Indication (SNI) nevét is, lehetővé téve, hogy a szerver a megfelelő tanúsítványt mutassa be.

  • A client_id egy MicroPython-specifikus kiterjesztés-argumentum, amelyet csak DTLS szerver megvalósításakor használnak. A részletekért lásd: DTLS támogatás.

Figyelem

Alapértelmezetten nem történik tanúsítvány-ellenőrzés (ssl.CERT_NONE). Biztonságos kapcsolathoz ellenőrizned kell a partner tanúsítványát úgy, hogy a cert_reqs / SSLContext.verify_mode értékét ssl.CERT_REQUIRED értékre állítod; egyébként a kapcsolat sebezhető a közbeékelődéses (man-in-the-middle) támadásokkal szemben.

A CPython wrap_socket függvénye egy SSLSocket objektumot ad vissza, amely a socketekre jellemző metódusokkal rendelkezik, mint a send, recv stb. A MicroPython wrap_socket függvénye egy olyan objektumot ad vissza, amely jobban hasonlít a CPython SSLObject objektumára, és nem rendelkezik ezekkel a socket metódusokkal.

verify_mode

Beállítja vagy lekéri a partnertanúsítványok ellenőrzésének viselkedését. A CERT_* konstansok egyikének kell lennie.

Megjegyzés

Az ssl.CERT_REQUIRED megköveteli, hogy az eszköz dátuma/ideje megfelelően be legyen állítva, pl. a mpremote rtc --set vagy az ntptime segítségével, és a kliens oldalon meg kell adni a server_hostname értékét.

DTLS támogatás

Eltérés a CPython-tól

Ez egy MicroPython kiterjesztés.

Ez a modul támogatja a DTLS-t kliens és szerver módban a PROTOCOL_DTLS_CLIENT és PROTOCOL_DTLS_SERVER konstansokon keresztül, amelyek az SSLContext protocol argumentumaként használhatók.

Ebben az esetben az alatta lévő socketnek datagram socketként kell viselkednie (azaz úgy, mint a socket.socket függvénnyel megnyitott socket, ahol az af a socket.AF_INET és a type a socket.SOCK_DGRAM).

DTLS szerver támogatás

A MicroPython DTLS szerver támogatása „Hello Verify” mechanizmussal van konfigurálva, ahogyan azt a DTLS 1.2 megköveteli. Ez a DTLS kliensek számára átlátszó, de a MicroPython-ban való DTLS szerver megvalósításakor vannak releváns megfontolások:

  • A szervernek egy további client_id argumentumot kell átadnia a SSLContext.wrap_socket() hívásakor. Ez az azonosító egy bytes objektum (vagy hasonló) kell legyen, amely egy átvitel-specifikus, a klienst reprezentáló azonosítót tartalmaz.

    A legegyszerűbb megközelítés az, ha a socket.recv_from() által visszaadott (client_ip, client_port) tuple-t bájtfüzérré alakítjuk, azaz:

    _, 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())
    
  • Amikor egy kliens először csatlakozik, a szerver wrap_socket hívása egy OSError „Hello Verify Required” hibával hiúsul meg. Ez azért van, mert a DTLS „Hello Verify” sütit a kliens még nem ismeri. Ha ugyanaz a kliens másodszor is csatlakozik, akkor a wrap_socket sikeres lesz.

  • A „Hello Verify” DTLS sütik az SSLContext objektumhoz vannak társítva, ezért ugyanazt az SSLContext objektumot kell használni az ugyanattól a klienstől érkező későbbi kapcsolat becsomagolásához. A süti megvalósítása tartalmaz egy időtúllépést, és állandó memóriahasználatú, függetlenül attól, hány kliens csatlakozik, így rendben van ugyanazt az SSLContext objektumot újrahasználni a szerver teljes élettartama alatt.

Konstansok

ssl.PROTOCOL_TLS_CLIENT: int

A protocol paraméter támogatott értéke, amely TLS kliens módot választ ki.

ssl.PROTOCOL_TLS_SERVER: int

A protocol paraméter támogatott értéke, amely TLS szerver módot választ ki.

ssl.PROTOCOL_DTLS_CLIENT: int

A protocol paraméter támogatott értéke, amely DTLS kliens módot választ ki.

ssl.PROTOCOL_DTLS_SERVER: int

A protocol paraméter támogatott értéke, amely DTLS szerver módot választ ki.

ssl.CERT_NONE: int

A cert_reqs paraméter és a SSLContext.verify_mode attribútum támogatott értéke. Nem történik tanúsítvány-ellenőrzés a partneren.

ssl.CERT_OPTIONAL: int

A cert_reqs paraméter és a SSLContext.verify_mode attribútum támogatott értéke. A tanúsítvány-ellenőrzés opcionális. Vedd figyelembe, hogy az OpenMV Cam eszközön ez úgy viselkedik, mint a ssl.CERT_NONE.

ssl.CERT_REQUIRED: int

A cert_reqs paraméter és a SSLContext.verify_mode attribútum támogatott értéke. Érvényes tanúsítvány szükséges a partnertől.