14.4.3. Itse allekirjoitetut varmenteet#

Itse allekirjoitettu varmenne on nopein tapa saada TLS toimimaan kahden hallitsemasi laitteen välillä: molemmat päät luottavat yhteen itse luomaasi varmenteeseen. Se kattaa jokaisen käyttöönoton jossa määrität yhteyden molemmat puolet – julkinen varmentaja (Certificate Authority) tulee kuvaan vasta kun kolmannen osapuolen asiakkaiden on yhdistettävä ilman että heitä neuvotaan luottamaan mukautettuun varmenteeseen.

14.4.3.1. Itse allekirjoitetun varmenteen luominen#

Suorita OpenSSL kehityskoneellasi. subjectAltName (SAN) on se mitä nykyaikaiset TLS-asiakkaat tarkistavat isäntänimen todennuksen aikana, joten aseta se isäntänimi(i)n ja/tai IP-osoittee(seen/siin) joita asiakkaat käyttävät kameran tavoittamiseen (pelkkä CN on vanhentunut ja monet asiakkaat jättävät sen huomiotta). Korvaa DNS:openmv / IP:192.168.1.50 osoitteella johon asiakkaasi todella yhdistävät.

ECDSA P-256 – suositeltu:

# 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 – vahvempi, suurempi/hitaampi:

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 – paras yhteensopivuus:

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"

Muista

Asiakasvarmenne (käytetään keskinäiseen todennukseen, alla) luodaan täsmälleen näillä samoilla komennoilla – itse varmenteessa ei ole mitään asiakaskohtaista. Luo vain toinen, riippumaton avain/varmenne-pari eri nimillä (esim. client.key / client.crt) ja käytä sitä asiakkaalla kuten mTLS-esimerkissä näytetään. subjectAltName on merkityksellinen vain sille puolelle jonka isäntänimen vertaisosapuoli todentaa (asiakas tarkistaa palvelimen nimen; mikään ei tarkista asiakkaan nimeä), joten sen voi jättää pois pelkästään asiakkaalle tarkoitetusta varmenteesta. -subj / CN on niin ikään vain merkintä asiakasvarmenteessa – palvelinpuoli tässä tarkistaa vain että varmenne ketjuuntuu luotettuun CA:han, se ei koskaan täsmää nimeen – joten aseta se mihin tahansa joka tunnistaa kyseisen asiakkaan (esim. /CN=sensor-01). Säilytä jokin -subj-arvo joka tapauksessa, jotta OpenSSL voi luoda varmenteen ei-interaktiivisesti.

Varmenteen voimassaoloajan asettaa -days; varmenteet vanhenevat ja ne on luotava uudelleen ja otettava uudelleen käyttöön ennen sitä.

14.4.3.2. Muuntaminen DER-muotoon#

Muunna sekä varmenne että yksityinen avain DER-muotoon ennen niiden kopioimista kameralle:

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. Tiedostojen kopioiminen kameralle#

Kopioi DER-tiedostot kameran tiedostojärjestelmään – esimerkiksi vetämällä ne OpenMV Camin USB-asemaan, tai komennoilla mpremote cp server.der : ja mpremote cp server.key.der :. Kopioi todennuksen tekevälle puolelle myös CA- / vertaisvarmenne DER-muodossa.

DER-tiedostojen ei tarvitse sijaita kirjoitettavalla tiedostojärjestelmällä. MicroPython voi myös liittää vain luku -tilaisen ROMFS-levykuvan polkuun /rom, ja sinne sijoitetut varmenteet ladataan täsmälleen kuten mikä tahansa muu tiedosto – esim. ctx.load_cert_chain("/rom/server.der", "/rom/server.key.der"). ROMFS-levykuva valmistellaan kehityskoneellasi ja se on vain luettavissa ajon aikana, joten varmennetta ei voi muuttaa laitteella – hyödyllistä tuotantoyksikön lukitsemiseen. Huomaa että ROMFS:ssä tallennettu yksityinen avain on silti kameralla suoritettavan koodin luettavissa; ROMFS suojaa muokkaamiselta, ei poimimiselta. ROMFS:ssä sijaitsevan varmenteen voi korvata vain rakentamalla ja flashaamalla levykuvan uudelleen.

14.4.3.4. Varmenteen käyttäminen#

Täydellinen asiakas joka asettaa kellon, avaa pistokkeen, todentaa itse allekirjoitetun palvelimen ja vaihtaa dataa:

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

Täydellinen palvelin joka esittää varmenteensa ja avaimensa:

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

Keskinäisessä todennuksessa (mTLS) palvelin lisäksi vaatii ja todentaa asiakasvarmenteen, ja asiakas esittää oman varmenteensa:

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

Katso täydellinen API ssl-moduulin dokumentaatiosta.

Muista

Kaikki tällä sivulla pätee muuttumattomana DTLS:ään (TLS UDP:n yli). Avaimet, varmenteet, DER-muoto, luottamusmalli, vanhenemiseen liittyvät huolet sekä load_cert_chain / load_verify_locations -kutsut ovat identtisiä; vain siirtotapa eroaa – kääräiset socket.SOCK_DGRAM-pistokkeen ja valitset ssl.PROTOCOL_DTLS_CLIENT / ssl.PROTOCOL_DTLS_SERVER TLS-protokollavakioiden sijaan. Yksi ylimääräinen mutka on palvelinpuolen huijaamisenestoeväste – ensimmäisen yhteyden uudelta asiakkaalta odotetaan epäonnistuvan ja asiakas yksinkertaisesti yrittää uudelleen; ks. DTLS-tuki lisätietoja.