14.4.3. Sertifikat yang ditandatangani sendiri

Sertifikat yang ditandatangani sendiri adalah cara tercepat untuk membuat TLS bekerja antara dua perangkat yang Anda kendalikan: kedua ujung mempercayai satu sertifikat yang Anda buat sendiri. Ini mencakup setiap penerapan di mana Anda mengonfigurasi kedua sisi koneksi -- Certificate Authority publik hanya dibutuhkan ketika klien pihak ketiga harus terhubung tanpa diberi tahu untuk mempercayai sertifikat khusus.

14.4.3.1. Membuat sertifikat yang ditandatangani sendiri

Jalankan OpenSSL di mesin pengembangan Anda. subjectAltName (SAN) adalah apa yang diperiksa oleh klien TLS modern selama verifikasi nama host, jadi atur ke nama host dan/atau alamat IP yang akan digunakan klien untuk menjangkau kamera (CN saja merupakan warisan lama dan diabaikan oleh banyak klien). Ganti DNS:openmv / IP:192.168.1.50 dengan alamat yang benar-benar digunakan klien Anda untuk terhubung.

ECDSA P-256 -- direkomendasikan:

# 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 -- lebih kuat, lebih besar/lebih lambat:

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 -- kompatibilitas maksimum:

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"

Catatan

Sertifikat klien (digunakan untuk autentikasi mutual, di bawah) dibuat dengan perintah yang sama persis ini -- tidak ada yang spesifik untuk klien tentang sertifikat itu sendiri. Cukup buat pasangan kunci/sertifikat kedua yang independen dengan nama berbeda (misalnya client.key / client.crt) dan gunakan pada klien seperti yang ditunjukkan dalam contoh mTLS. subjectAltName hanya penting untuk sisi yang nama hostnya diverifikasi oleh peer (klien memeriksa nama server; tidak ada yang memeriksa nama klien), sehingga dapat dihilangkan untuk sertifikat khusus klien. -subj / CN juga hanya label pada sertifikat klien -- sisi server di sini hanya memeriksa bahwa sertifikat berantai ke CA yang dipercaya, tidak pernah mencocokkan nama -- jadi atur ke apa pun yang mengidentifikasi klien tersebut (misalnya /CN=sensor-01). Tetap gunakan nilai -subj apa pun, agar OpenSSL dapat membuat sertifikat secara non-interaktif.

Masa hidup sertifikat diatur oleh -days; sertifikat kedaluwarsa dan harus dibuat ulang serta diterapkan kembali sebelum itu.

14.4.3.2. Mengonversi ke DER

Konversi sertifikat dan kunci privat ke DER sebelum menyalinnya ke kamera:

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. Menyalin file ke kamera

Salin file DER ke sistem file kamera -- misalnya dengan menyeretnya ke drive USB OpenMV Cam, atau dengan mpremote cp server.der : dan mpremote cp server.key.der :. Di sisi yang memverifikasi, salin juga sertifikat CA/peer dalam format DER.

File DER tidak harus berada di sistem file yang dapat ditulis. MicroPython juga dapat memasang citra ROMFS hanya-baca di /rom, dan sertifikat yang ditempatkan di sana dimuat persis seperti file lainnya -- misalnya ctx.load_cert_chain("/rom/server.der", "/rom/server.key.der"). Citra ROMFS disiapkan di mesin pengembangan Anda dan bersifat hanya-baca saat runtime, sehingga sertifikat tidak dapat diubah di perangkat -- berguna untuk mengunci unit produksi. Perhatikan bahwa kunci privat yang disimpan di ROMFS masih dapat dibaca oleh kode yang berjalan di kamera; ROMFS melindungi dari modifikasi, bukan ekstraksi. Sertifikat yang berada di ROMFS hanya dapat diganti dengan membangun ulang dan me-reflash citranya.

14.4.3.4. Menggunakan sertifikat

Klien lengkap yang mengatur jam, membuka soket, memverifikasi server yang ditandatangani sendiri, dan bertukar data:

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

Server lengkap yang menyajikan sertifikat dan kuncinya:

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

Untuk autentikasi mutual (mTLS) server juga memerlukan dan memverifikasi sertifikat klien, dan klien menyajikan miliknya sendiri:

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

Lihat dokumentasi modul ssl untuk API lengkapnya.

Catatan

Semua yang ada di halaman ini berlaku tanpa perubahan untuk DTLS (TLS melalui UDP). Kunci, sertifikat, format DER, model kepercayaan, kekhawatiran kedaluwarsa, dan panggilan load_cert_chain / load_verify_locations adalah identik; hanya transport yang berbeda -- Anda membungkus soket socket.SOCK_DGRAM dan memilih ssl.PROTOCOL_DTLS_CLIENT / ssl.PROTOCOL_DTLS_SERVER alih-alih konstanta protokol TLS. Satu kerumitan tambahan adalah cookie anti-spoofing sisi server -- koneksi pertama dari klien baru diharapkan gagal dan klien cukup mencoba kembali; lihat Dukungan DTLS untuk detailnya.