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.