14.4.3. Vlastnoručně podepsané certifikáty#

Vlastnoručně podepsaný certifikát je nejrychlejší způsob, jak zprovoznit TLS mezi dvěma zařízeními, která ovládáte: oba konce důvěřují jedinému certifikátu, který si sami vygenerujete. Pokrývá každé nasazení, kde konfigurujete obě strany spojení – veřejná certifikační autorita vstupuje do hry pouze tehdy, když se musí připojit klienti třetích stran bez toho, aby jim bylo řečeno, aby důvěřovali vlastnímu certifikátu.

14.4.3.1. Vytvoření vlastnoručně podepsaného certifikátu#

Spusťte OpenSSL na svém vývojovém počítači. subjectAltName (SAN) je to, co moderní TLS klienti kontrolují během ověřování názvu hostitele, takže jej nastavte na název(y) hostitele a/nebo IP adresu(y), které klienti použijí pro připojení ke kameře (samotné CN je zastaralé a mnoho klientů jej ignoruje). Nahraďte DNS:openmv / IP:192.168.1.50 adresou, ke které se vaši klienti skutečně připojují.

ECDSA P-256 – doporučeno:

# Generate a P-256 private key.
openssl ecparam -name prime256v1 -genkey -noout -out server.key

# Self-signed certificate valid for one year, with a SAN.
openssl req -new -x509 -key server.key -out server.crt -days 365 \
    -subj "/CN=openmv" -addext "subjectAltName=DNS:openmv,IP:192.168.1.50"

ECDSA P-384 – silnější, větší/pomalejší:

openssl ecparam -name secp384r1 -genkey -noout -out server.key

openssl req -new -x509 -key server.key -out server.crt -days 365 \
    -subj "/CN=openmv" -addext "subjectAltName=DNS:openmv,IP:192.168.1.50"

RSA-2048 – maximální kompatibilita:

openssl req -new -x509 -newkey rsa:2048 -nodes -keyout server.key \
    -out server.crt -days 365 -subj "/CN=openmv" \
    -addext "subjectAltName=DNS:openmv,IP:192.168.1.50"

Poznámka

Klientský certifikát (použitý pro vzájemnou autentizaci, níže) se vytváří přesně stejnými příkazy – na samotném certifikátu není nic specifického pro klienta. Stačí vygenerovat druhý, nezávislý pár klíč/certifikát pod jinými názvy (např. client.key / client.crt) a použít jej na klientovi, jak je ukázáno v příkladu mTLS. subjectAltName má význam pouze pro stranu, jejíž název hostitele protějšek ověřuje (klient kontroluje název serveru; nic nekontroluje název klienta), takže pro certifikát určený pouze pro klienta jej lze vynechat. -subj / CN je rovněž jen štítek na klientském certifikátu – serverová strana zde kontroluje pouze to, že certifikát řetězí k důvěryhodné CA, nikdy se neshoduje s názvem – takže jej nastavte na cokoli, co daného klienta identifikuje (např. /CN=sensor-01). Bez ohledu na to ponechte nějakou hodnotu -subj, aby OpenSSL mohlo certifikát vygenerovat neinteraktivně.

Životnost certifikátu se nastavuje pomocí -days; certifikáty vyprší a musí být před tím znovu vygenerovány a nasazeny.

14.4.3.2. Převod na DER#

Před zkopírováním na kameru převeďte certifikát i soukromý klíč na DER:

openssl x509 -in server.crt -outform DER -out server.der
openssl pkey -in server.key -outform DER -out server.key.der

14.4.3.3. Kopírování souborů na kameru#

Zkopírujte DER soubory do souborového systému kamery – například jejich přetažením na USB disk OpenMV Cam, nebo pomocí mpremote cp server.der : a mpremote cp server.key.der :. Na ověřující straně zkopírujte také certifikát CA / protějšku ve formátu DER.

DER soubory nemusí ležet na zapisovatelném souborovém systému. MicroPython může také připojit obraz ROMFS pouze pro čtení na /rom a certifikáty tam umístěné se načítají přesně jako jakýkoli jiný soubor – např. ctx.load_cert_chain("/rom/server.der", "/rom/server.key.der"). Obraz ROMFS se připravuje na vašem vývojovém počítači a za běhu je pouze pro čtení, takže certifikát nelze na zařízení změnit – to je užitečné pro uzamčení produkční jednotky. Vezměte na vědomí, že soukromý klíč uložený v ROMFS je stále čitelný kódem běžícím na kameře; ROMFS chrání proti úpravě, nikoli extrakci. Certifikát umístěný v ROMFS lze nahradit pouze opětovným sestavením a přeflashováním obrazu.

14.4.3.4. Použití certifikátu#

Kompletní klient, který nastaví hodiny, otevře socket, ověří vlastnoručně podepsaný server a vyměňuje data:

import socket
import ssl
import ntptime

ntptime.settime()                 # correct clock for the validity check

# Open a plain TCP connection.
addr = socket.getaddrinfo("openmv", 8443)[0][-1]
sock = socket.socket()
sock.connect(addr)

# Wrap it for TLS, trusting the server's self-signed certificate.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="server.der")
ssock = ctx.wrap_socket(sock, server_hostname="openmv")

ssock.write(b"hello\n")
print(ssock.read())
ssock.close()

Kompletní server předkládající svůj certifikát a klíč:

import socket
import ssl
import ntptime

ntptime.settime()                 # correct clock for the validity check

ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("server.der", "server.key.der")

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)

while True:
    client, addr = sock.accept()
    sclient = ctx.wrap_socket(client, server_side=True)
    sclient.write(b"hello\n")
    print(sclient.read())
    sclient.close()

Pro vzájemnou autentizaci (mTLS) server navíc vyžaduje a ověřuje klientský certifikát a klient předkládá svůj vlastní:

# Server side: also demand and verify a client certificate.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("server.der", "server.key.der")
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="client.der")

# Client side: present a certificate of our own.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.load_cert_chain("client.der", "client.key.der")
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="server.der")

Kompletní API najdete v dokumentaci modulu ssl.

Poznámka

Vše na této stránce platí beze změny pro DTLS (TLS přes UDP). Klíče, certifikáty, formát DER, model důvěry, otázky expirace a volání load_cert_chain / load_verify_locations jsou identické; liší se pouze transport – zabalíte socket socket.SOCK_DGRAM a místo protokolových konstant TLS zvolíte ssl.PROTOCOL_DTLS_CLIENT / ssl.PROTOCOL_DTLS_SERVER. Jeden další detail navíc je serverový anti-spoofing cookie – u prvního spojení od nového klienta se očekává selhání a klient jej jednoduše zopakuje; podrobnosti viz Podpora DTLS.