14.4.3. Certificate auto-semnate

Un certificat auto-semnat este cea mai rapidă modalitate de a face TLS să funcționeze între două dispozitive pe care le controlați: ambele capete au încredere într-un singur certificat pe care îl generați chiar dumneavoastră. Acesta acoperă orice implementare în care configurați ambele părți ale conexiunii – o Autoritate de Certificare publică intră în joc doar atunci când clienți terți trebuie să se conecteze fără a li se cere să aibă încredere într-un certificat personalizat.

14.4.3.1. Crearea unui certificat auto-semnat

Rulați OpenSSL pe mașina dumneavoastră de dezvoltare. subjectAltName (SAN) este ceea ce verifică clienții TLS moderni în timpul verificării numelui de gazdă, așa că setați-l la numele de gazdă și/sau adresa (adresele) IP pe care clienții le vor folosi pentru a accesa camera (CN singur este învechit și este ignorat de mulți clienți). Înlocuiți DNS:openmv / IP:192.168.1.50 cu adresa la care se conectează efectiv clienții dumneavoastră.

ECDSA P-256 – recomandat:

# 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 – mai puternic, mai mare/mai lent:

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 – compatibilitate maximă:

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"

Notă

Un certificat de client (folosit pentru autentificarea reciprocă, mai jos) se creează exact cu aceleași comenzi – nu există nimic specific clientului în certificatul în sine. Generați pur și simplu o a doua pereche independentă de cheie/certificat sub nume diferite (de ex. client.key / client.crt) și folosiți-o pe client așa cum se arată în exemplul mTLS. subjectAltName contează doar pentru partea al cărei nume de gazdă este verificat de partener (clientul verifică numele serverului; nimic nu verifică numele clientului), așa că poate fi omis pentru un certificat destinat exclusiv clientului. -subj / CN este, de asemenea, doar o etichetă pe un certificat de client – partea de server de aici verifică doar că certificatul se leagă printr-un lanț de un CA de încredere, nu compară niciodată numele – așa că setați-l la orice identifică acel client (de ex. /CN=sensor-01). Păstrați totuși o valoare -subj, indiferent de situație, pentru ca OpenSSL să poată genera certificatul fără interacțiune.

Durata de viață a certificatului se setează cu -days; certificatele expiră și trebuie regenerate și reimplementate înainte de acel moment.

14.4.3.2. Conversia în DER

Convertiți atât certificatul, cât și cheia privată în DER înainte de a le copia pe cameră:

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. Copierea fișierelor pe cameră

Copiați fișierele DER pe sistemul de fișiere al camerei – de exemplu trăgându-le pe unitatea USB a OpenMV Cam sau cu mpremote cp server.der : și mpremote cp server.key.der :. Pe partea care efectuează verificarea, copiați de asemenea certificatul CA / al partenerului în format DER.

Fișierele DER nu trebuie neapărat să se afle pe sistemul de fișiere care permite scrierea. MicroPython poate de asemenea monta o imagine ROMFS read-only la /rom, iar certificatele plasate acolo se încarcă exact ca orice alt fișier – de ex. ctx.load_cert_chain("/rom/server.der", "/rom/server.key.der"). O imagine ROMFS este pregătită pe mașina dumneavoastră de dezvoltare și este read-only la runtime, așa că certificatul nu poate fi modificat pe dispozitiv – util pentru securizarea unei unități de producție. Rețineți că o cheie privată stocată în ROMFS poate fi în continuare citită de codul care rulează pe cameră; ROMFS protejează împotriva modificării, nu a extragerii. Un certificat aflat în ROMFS poate fi înlocuit doar prin reconstruirea și reprogramarea imaginii.

14.4.3.4. Utilizarea certificatului

Un client complet care setează ceasul, deschide un socket, verifică un server auto-semnat și schimbă date:

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

Un server complet care își prezintă certificatul și cheia:

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

Pentru autentificarea reciprocă (mTLS), serverul solicită și verifică în plus un certificat de client, iar clientul prezintă unul propriu:

# 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")

Consultați documentația modulului ssl pentru API-ul complet.

Notă

Tot ce este pe această pagină se aplică neschimbat la DTLS (TLS peste UDP). Cheile, certificatele, formatul DER, modelul de încredere, aspectele legate de expirare și apelurile load_cert_chain / load_verify_locations sunt identice; diferă doar transportul – înfășurați un socket socket.SOCK_DGRAM și selectați ssl.PROTOCOL_DTLS_CLIENT / ssl.PROTOCOL_DTLS_SERVER în locul constantelor de protocol TLS. Singura particularitate suplimentară este un cookie anti-spoofing pe partea de server – se așteaptă ca prima conexiune de la un client nou să eșueze, iar clientul pur și simplu reîncearcă; consultați Suport DTLS pentru detalii.