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.