14.4.5. Vérifier un serveur public (caméra en tant que client)¶
Tout ce que la page précédente disait à propos d’un client qui « possède déjà la racine » est vrai pour les navigateurs, les téléphones et les PC – ce n’est pas vrai pour la caméra. Le module ssl de MicroPython est livré sans magasin de confiance intégré : une caméra fraîchement flashée ne fait confiance à aucune autorité de certification, et la valeur par défaut (ssl.CERT_NONE) ne vérifie rien et reste grande ouverte à une attaque de l’homme du milieu. Ainsi, lorsque la caméra est le client qui se connecte à un serveur TLS public (une API HTTPS, un courtier MQTT, …) et que vous voulez qu’elle vérifie réellement ce serveur, vous devez fournir vous-même l’ancre de confiance.
Le mécanisme est le même que dans l’exemple de client auto-signé de Certificats auto-signés ; la seule différence est que le fichier que vous chargez est un véritable certificat d’autorité de certification au lieu du propre certificat du pair :
Obtenez le certificat de l’autorité de certification qui ancre la chaîne du serveur. « Ancre » désigne le certificat situé au sommet (ou près du sommet) de la chaîne du serveur que vous choisissez comme point de départ de votre confiance. Un serveur TLS envoie son certificat feuille et généralement son ou ses certificats intermédiaires ; il n’envoie jamais sa racine. Vous devez obtenir cette ancre de confiance vous-même et indépendamment du serveur – se contenter de faire confiance à ce qu’un serveur vous présente irait à l’encontre de tout l’intérêt de la vérification.
Commencez par déterminer quelle autorité de certification a réellement émis le certificat du serveur. Par exemple, pour
openmv.ioopenssl s_client -connect openmv.io:443 -showcerts < /dev/nullLe bloc
Certificate chainliste chaque certificat avec son sujet (s:) et son émetteur (i:) ; les versions plus récentes d’OpenSSL affichent aussi des lignesa:(type de clé) etv:(validité) que vous pouvez ignorer iciCertificate 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
L’entrée 0 est la feuille (
openmv.io), émise par l’intermédiaireE8. L’entrée 1 est cet intermédiaire, émis par la racineISRG Root X1. L’émetteur (i:) de l’entrée la plus haute nomme la racine – iciISRG Root X1. (L’intermédiaire estE8plutôt que lesR10/R11que vous avez pu voir ailleurs parce queopenmv.ioutilise un certificat ECDSA ; Let’s Encrypt signe les feuilles ECDSA avec ses intermédiaires de la sérieEet les feuilles RSA avec ceux de la sérieR. Tous deux remontent àISRG Root X1.)OpenSSL affiche aussi des lignes
depth=et peut signaler la racine avecVerification: OK. Cela ne se produit que parce que votre PC fait déjà confiance àISRG Root X1– le serveur ne l’a pas envoyée (un serveur n’envoie jamais sa racine), et la caméra, n’ayant aucun magasin de confiance, ne l’aura pas non plus. C’est exactement pour cela que vous devez la fournir.Téléchargez cette racine depuis les racines publiées par l’autorité de certification elle-même. Let’s Encrypt répertorie toutes les siennes sur la page des certificats de Let’s Encrypt ; le fichier direct pour ISRG Root X1 est isrgrootx1.pem (ils le proposent aussi pré-encodé sous la forme isrgrootx1.der). D’autres autorités de certification publient les leurs sur une page similaire « certificats racine » / « dépôt » ; l’ensemble public de référence est le programme CA de Mozilla (CCADB). Confirmez que vous avez récupéré le bon fichier en comparant son empreinte à la valeur publiée par l’autorité de certification (ajoutez
-inform DERsi vous avez téléchargé le.der)openssl x509 -in isrgrootx1.pem -noout -subject -fingerprint -sha256Si vous préférez ne pas suivre une racine, vous pouvez à la place copier l”intermédiaire directement depuis la sortie
-showcerts(le deuxième bloc-----BEGIN CERTIFICATE-----), lui faire confiance, et accepter de devoir le rafraîchir chaque fois que l’autorité de certification fait tourner l’intermédiaire – bien plus souvent que la racine (voir le compromis ci-dessous).Convertissez-le en DER, exactement comme précédemment
openssl x509 -in isrgrootx1.pem -outform DER -out ca.derCopiez
ca.dersur la caméra (système de fichiers ou ROMFS) et chargez-le comme ancre de confianceimport 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_hostnameest requis ici : il pilote le SNI et constitue le nom vérifié par rapport ausubjectAltNamedu certificat du serveur.
Astuce
Raccourci pour le cas courant. Let’s Encrypt est l’autorité de certification publique la plus utilisée, et ses certificats RSA comme ECDSA remontent actuellement à ISRG Root X1 (comme le montre l’exemple openmv.io ci-dessus). Si les serveurs avec lesquels votre caméra communique utilisent Let’s Encrypt, vous pouvez sauter complètement l’inspection : placez simplement isrgrootx1.der sur la caméra et passez-le à load_verify_locations.
Cela ne fait pas fonctionner le TLS vers tous les sites. Un serveur dont le certificat provient d’une autre autorité de certification (DigiCert, Google Trust Services, Amazon, Sectigo, …) échouera toujours à la vérification, et comme la caméra ne fait confiance qu’à un seul certificat DER par ssl.SSLContext, vous ne pouvez pas regrouper toutes les racines comme le fait un navigateur. En cas de doute, identifiez l’autorité de certification réelle du serveur comme montré ci-dessus et faites confiance à cette racine.
Le certificat auquel vous faites confiance est un compromis :
La racine (recommandée). De longue durée – souvent des décennies – de sorte que
ca.derchange rarement. Elle exige que le serveur envoie son intermédiaire afin que mbedTLS puisse construire le chemin feuille → intermédiaire → votre racine de confiance ; pratiquement tous les serveurs publics correctement configurés le font.L’intermédiaire. Fonctionne également, et continue de fonctionner même si un serveur omet l’intermédiaire, mais les intermédiaires sont renouvelés bien plus souvent que les racines, vous devrez donc rafraîchir
ca.derplus fréquemment.La feuille elle-même (épinglage de certificat). La plus stricte, mais la feuille change à chaque renouvellement – environ tous les 90 jours pour Let’s Encrypt – ce qui n’a donc de sens que si vous contrôlez également le serveur et pouvez pousser le nouvel épinglage à chaque caméra de manière synchronisée. C’est exactement ce que fait l’exemple de client auto-signé.
Note
ssl.SSLContext.load_verify_locations() prend un seul certificat d’autorité de certification encodé en DER, de sorte que la caméra ne fait confiance qu’à une seule ancre à la fois. Pour atteindre des serveurs relevant de différentes autorités de certification, utilisez un ssl.SSLContext distinct par ancre. Et comme ce certificat finira lui-même par expirer ou être renouvelé par l’autorité de certification, traitez-le comme n’importe quel autre certificat sur l’appareil.