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.