14.4.3. Samopotpisani certifikati

Samopotpisani certifikat najbrži je način da TLS proradi između dva uređaja koja kontrolirate: oba kraja vjeruju jednom certifikatu koji sami generirate. Pokriva svaku primjenu u kojoj konfigurirate obje strane veze – javno tijelo za izdavanje certifikata (CA) ulazi u priču samo kada se klijenti treće strane moraju povezati bez da im se kaže da vjeruju prilagođenom certifikatu.

14.4.3.1. Stvaranje samopotpisanog certifikata

Pokrenite OpenSSL na svom razvojnom računalu. subjectAltName (SAN) ono je što moderni TLS klijenti provjeravaju tijekom provjere imena hosta, pa ga postavite na ime(na) hosta i/ili IP adresu(e) koje će klijenti koristiti za dosezanje kamere (CN sam po sebi je zastario i mnogi ga klijenti zanemaruju). Zamijenite DNS:openmv / IP:192.168.1.50 adresom na koju se vaši klijenti zaista povezuju.

ECDSA P-256 – preporuč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 – jači, veći/sporiji:

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 – maksimalna kompatibilnost:

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"

Napomena

Klijentski certifikat (koji se koristi za međusobnu provjeru autentičnosti, niže) stvara se točno istim ovim naredbama – u samom certifikatu nema ničega specifičnog za klijenta. Samo generirajte drugi, neovisni par ključ/certifikat pod drugim imenima (npr. client.key / client.crt) i koristite ga na klijentu kako je prikazano u mTLS primjeru. subjectAltName bitan je samo za stranu čije ime hosta ravnopravni sudionik provjerava (klijent provjerava ime poslužitelja; ime klijenta ništa ne provjerava), pa se može izostaviti za certifikat samo za klijenta. -subj / CN također je samo oznaka na klijentskom certifikatu – poslužiteljska strana ovdje provjerava samo da se certifikat veže na pouzdani CA, nikad ne uspoređuje ime – pa ga postavite na ono što identificira tog klijenta (npr. /CN=sensor-01). Bez obzira na to zadržite neku -subj vrijednost, kako bi OpenSSL mogao generirati certifikat neinteraktivno.

Vijek trajanja certifikata postavlja se s -days; certifikati istječu i moraju se ponovno generirati i primijeniti prije toga.

14.4.3.2. Pretvaranje u DER

Pretvorite i certifikat i privatni ključ u DER prije nego što ih kopirate na kameru:

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. Kopiranje datoteka na kameru

Kopirajte DER datoteke na datotečni sustav kamere – na primjer povlačenjem na USB pogon OpenMV Cam, ili pomoću mpremote cp server.der : i mpremote cp server.key.der :. Na strani koja provjerava također kopirajte CA / certifikat ravnopravnog sudionika u DER obliku.

DER datoteke ne moraju živjeti na datotečnom sustavu s mogućnošću pisanja. MicroPython može također montirati ROMFS sliku samo-za-čitanje na /rom, a certifikati smješteni ondje učitavaju se točno kao i svaka druga datoteka – npr. ctx.load_cert_chain("/rom/server.der", "/rom/server.key.der"). ROMFS slika priprema se na vašem razvojnom računalu i tijekom izvođenja je samo-za-čitanje, pa se certifikat ne može mijenjati na uređaju – korisno za zaključavanje produkcijske jedinice. Imajte na umu da je privatni ključ pohranjen u ROMFS-u i dalje čitljiv kodu koji se izvodi na kameri; ROMFS štiti od izmjene, ne od izvlačenja. Certifikat smješten u ROMFS-u može se zamijeniti samo ponovnom izgradnjom i ponovnim programiranjem slike.

14.4.3.4. Korištenje certifikata

Potpuni klijent koji postavlja sat, otvara socket, provjerava samopotpisani poslužitelj i razmjenjuje podatke:

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

Potpuni poslužitelj koji predstavlja svoj certifikat i ključ:

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

Za međusobnu provjeru autentičnosti (mTLS) poslužitelj dodatno zahtijeva i provjerava klijentski certifikat, a klijent predstavlja vlastiti:

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

Pogledajte dokumentaciju modula ssl za cjelovit API.

Napomena

Sve na ovoj stranici primjenjuje se nepromijenjeno na DTLS (TLS preko UDP-a). Ključevi, certifikati, DER format, model povjerenja, pitanja isteka te pozivi load_cert_chain / load_verify_locations istovjetni su; razlikuje se samo transport – umotate socket.SOCK_DGRAM socket i odaberete ssl.PROTOCOL_DTLS_CLIENT / ssl.PROTOCOL_DTLS_SERVER umjesto TLS protokolnih konstanti. Jedna dodatna sitnica je kolačić protiv lažiranja na strani poslužitelja – očekuje se da prva veza od novog klijenta ne uspije, a klijent jednostavno pokušava ponovno; pogledajte Podrška za DTLS za pojedinosti.