14.4.5. Provjera javnog poslužitelja (kamera kao klijent)¶
Sve sa prethodne stranice o klijentu koji „već ima korijenski certifikat” vrijedi za preglednike, telefone i osobna računala – ali ne vrijedi za kameru. MicroPython-ov ssl dolazi bez ugrađene pohrane povjerenja: svježe flashana kamera ne vjeruje nijednom CA-u, a zadana postavka (ssl.CERT_NONE) ne provjerava ništa i potpuno je otvorena za napad posrednika (man-in-the-middle). Stoga, kada je kamera klijent koji se povezuje s javnim TLS poslužiteljem (HTTPS API, MQTT broker, …) i želite da ona doista provjeri taj poslužitelj, morate sami osigurati sidro povjerenja.
Mehanika je ista kao u primjeru samopotpisanog klijenta na Samopotpisani certifikati; jedina je razlika u tome što je datoteka koju učitavate stvarni CA certifikat umjesto vlastitog certifikata druge strane:
Dohvatite CA certifikat koji sidri lanac poslužitelja. „Sidri” znači certifikat na (ili blizu) vrha poslužiteljevog lanca koji odaberete kao svoju početnu točku povjerenja. TLS poslužitelj šalje svoj listni certifikat i obično svoje posredne certifikate; nikada ne šalje svoj korijenski certifikat. Morate sami pribaviti to sidro povjerenja i to neovisno o poslužitelju – jednostavno vjerovanje bilo čemu što poslužitelj pošalje poništilo bi cijelu svrhu provjere.
Najprije saznajte koji je CA zapravo izdao poslužiteljev certifikat. Na primjer, za
openmv.ioopenssl s_client -connect openmv.io:443 -showcerts < /dev/nullBlok
Certificate chainnavodi svaki certifikat s njegovim subjektom (s:) i izdavateljem (i:); noviji OpenSSL također ispisuje retkea:(vrsta ključa) iv:(valjanost) koje ovdje možete zanemariti:Certificate chain 0 s:CN=openmv.io i:C=US, O=Let's Encrypt, CN=E8 1 s:C=US, O=Let's Encrypt, CN=E8 i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
Unos 0 je listni certifikat (
openmv.io), koji je izdao posredni certifikatE8. Unos 1 je taj posredni certifikat, koji je izdao korijenski certifikatISRG Root X1. Izdavatelj (i:) najgornjeg unosa imenuje korijenski certifikat – ovdjeISRG Root X1. (Posredni certifikat jeE8umjestoR10/R11koje ste možda vidjeli drugdje jeropenmv.iokoristi ECDSA certifikat; Let’s Encrypt potpisuje ECDSA listne certifikate svojim posrednim certifikatima serijeE, a RSA listne certifikate onima serijeR. Oba se lančano vežu naISRG Root X1.)OpenSSL također ispisuje retke
depth=i može prijaviti korijenski certifikat sVerification: OK. To se događa samo zato što vaše osobno računalo već vjeruje certifikatuISRG Root X1– poslužitelj ga nije poslao (poslužitelj nikada ne šalje svoj korijenski certifikat), a kamera, koja nema pohranu povjerenja, neće ga imati. Upravo zato ga morate sami osigurati.Preuzmite taj korijenski certifikat s CA-ovih vlastitih objavljenih korijenskih certifikata. Let’s Encrypt katalogizira sve svoje na stranici s certifikatima Let’s Encrypt; izravna datoteka za ISRG Root X1 je isrgrootx1.pem (također ga nude unaprijed kodiran kao isrgrootx1.der). Drugi CA-ovi objavljuju svoje na sličnoj stranici „root certificates” / „repository”; kanonski javni skup je Mozilla CA program (CCADB). Potvrdite da ste dohvatili pravu datoteku usporedbom njezinog otiska s vrijednošću koju CA objavljuje (dodajte
-inform DERako ste preuzeli.der):openssl x509 -in isrgrootx1.pem -noout -subject -fingerprint -sha256Ako ne želite pratiti korijenski certifikat, umjesto toga možete kopirati posredni certifikat ravno iz izlaza
-showcerts(drugi blok-----BEGIN CERTIFICATE-----), vjerovati njemu i prihvatiti da ga morate osvježavati svaki put kada CA rotira posredni certifikat – daleko češće od korijenskog (pogledajte kompromis u nastavku).Pretvorite ga u DER, točno kao i prije:
openssl x509 -in isrgrootx1.pem -outform DER -out ca.derKopirajte
ca.derna kameru (datotečni sustav ili ROMFS) i učitajte ga kao sidro povjerenja:import socket import ssl import ntptime ntptime.settime() # validity check needs the clock addr = socket.getaddrinfo("api.example.com", 443)[0][-1] sock = socket.socket() sock.connect(addr) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx.verify_mode = ssl.CERT_REQUIRED ctx.load_verify_locations(cafile="ca.der") ssock = ctx.wrap_socket(sock, server_hostname="api.example.com")
server_hostnameje ovdje obavezan: on pokreće SNI i ime je koje se provjerava u odnosu nasubjectAltNameposlužiteljevog certifikata.
Savjet
Prečac za uobičajeni slučaj. Let’s Encrypt je najčešće korišteni javni CA, a i njegovi RSA i ECDSA certifikati trenutno se lančano vežu na ISRG Root X1 (kao što gornji primjer openmv.io pokazuje). Ako poslužitelji s kojima vaša kamera komunicira koriste Let’s Encrypt, možete u potpunosti preskočiti inspekciju: samo stavite isrgrootx1.der na kameru i izvršite load_verify_locations nad njim.
Ovo ne omogućuje rad TLS-a sa svakom lokacijom. Poslužitelj čiji certifikat dolazi od drugog CA-a (DigiCert, Google Trust Services, Amazon, Sectigo, …) i dalje neće proći provjeru, a budući da kamera vjeruje jednom DER certifikatu po ssl.SSLContext, ne možete spojiti svaki korijenski certifikat onako kako to radi preglednik. Kada ste u nedoumici, identificirajte stvarni CA poslužitelja kako je gore prikazano i vjerujte tom korijenskom certifikatu.
Kojem certifikatu vjerujete je kompromis:
Korijenski certifikat (preporučeno). Dugog vijeka trajanja – često desetljećima – pa se
ca.derrijetko mijenja. Zahtijeva od poslužitelja da pošalje svoj posredni certifikat kako bi mbedTLS mogao izgraditi put listni → posredni → vaš pouzdani korijenski; praktički svaki ispravno konfiguriran javni poslužitelj to radi.Posredni certifikat. Također radi i nastavlja raditi čak i ako poslužitelj izostavi posredni certifikat, ali posredni se certifikati rotiraju daleko češće od korijenskih, pa ćete morati osvježavati
ca.derčešće.Sam listni certifikat (pričvršćivanje certifikata, pinning). Najstrože, ali listni se certifikat mijenja pri svakoj obnovi – otprilike svakih 90 dana za Let’s Encrypt – pa ovo ima smisla samo kada i sami kontrolirate poslužitelj i možete usklađeno proslijediti novi pin svakoj kameri. Upravo to radi primjer samopotpisanog klijenta.
Napomena
ssl.SSLContext.load_verify_locations() prima jedan DER kodirani CA certifikat, pa kamera vjeruje točno jednom sidru istovremeno. Da biste dosegnuli poslužitelje pod različitim CA-ovima, koristite zaseban ssl.SSLContext po sidru. A budući da će i taj certifikat na kraju isteći ili ga CA rotirati, tretirajte ga kao bilo koji drugi certifikat na uređaju.