openssl-win-root : utiliser le magasin de certificats Windows avec Ruby
Si vous utilisez Ruby sous Windows, vous verrez tôt ou tard une requête HTTPS échouer avec une erreur de vérification de certificat, alors que le même site s’ouvre sans problème dans votre navigateur. openssl-win-root est un petit gem qui aide précisément dans ce cas.
Rendons d’abord à César ce qui est à César : le gem a été écrit par Stas Ukolov, et le dépôt d’origine est github.com/ukoloff/openssl-win-root. Sa première version date de 2015. Ma contribution est modeste, je la décris plus bas.
Le problème
L’OpenSSL de Ruby ne consulte pas le magasin de certificats Windows. Il a besoin de ses propres certificats d’autorités de certification. RubyInstaller fournit un fichier cacert.pem, mais comme le souligne le README du gem, ce fichier n’est pas mis à jour automatiquement. Il s’agit du bundle datant de la compilation de votre version de Ruby ; des certificats racine plus récents peuvent donc manquer.
Windows, en revanche, tient son propre magasin de certificats racine de confiance à jour. Ce magasin contient aussi les certificats que votre entreprise installe, par exemple via une stratégie de groupe. Ruby ne les voit tout simplement pas.
Ce que fait le gem
Lorsque vous le chargez sous Windows, openssl-win-root :
- lit les certificats racine de confiance dans le magasin système de Windows (via l’API
crypt32, à l’aide de Fiddle), - les écrit sous forme de fichiers PEM dans un dossier
pemà l’intérieur du répertoire du gem, nommés comme OpenSSL l’attend pour un répertoire de certificats, - ajoute ce dossier au magasin de certificats par défaut d’OpenSSL et y fait pointer la variable d’environnement
SSL_CERT_DIR.
Aucun accès réseau n’est nécessaire. Sur les autres systèmes d’exploitation, le gem ne fait rien ; vous pouvez donc l’inclure sans risque dans un projet multiplateforme.
Utilisation
Ajoutez-le à votre Gemfile, uniquement pour Windows :
gem 'openssl-win-root' if Gem.win_platform?
Lancez ensuite bundle, ou installez-le directement :
gem install openssl-win-root
Chargez-le avant d’effectuer des requêtes HTTPS :
require 'openssl/win/root'
require 'net/http'
Net::HTTP.get(URI('https://www.ruby-lang.org/')).length
Si votre projet utilise Bundler.require, comme Rails, le require explicite est inutile.
Les certificats exportés peuvent aussi servir en dehors de Ruby. Faites pointer SSL_CERT_DIR, ou l’option -CApath de la commande openssl, vers le dossier renvoyé par :
OpenSSL::Win::Root.path
Points à garder à l’esprit
- Les certificats sont exportés dans le répertoire du gem à chaque
require; le processus doit donc y avoir un accès en écriture. - Sous Windows Server, il arrive que le magasin de certificats n’ait pas encore activé un certificat racine. Le contournement décrit dans le README consiste à ouvrir le site une fois dans un navigateur (Microsoft), ou à effectuer une requête via
WinHttpRequestavecwin32ole. Cela amène Windows, d’une manière ou d’une autre, à activer le certificat racine manquant. - La dernière version, 1.1.2, date de janvier 2023, et le gem appelle l’API Windows via Fiddle. Testez-le avec la version de Ruby que vous utilisez réellement.
Mon rôle
À la sortie de Ruby 3.2, le gem a cessé de fonctionner : il appelait File.exists?, que Ruby 3.2 a supprimé. C’est le même problème que celui décrit dans mon article sur le gem file_exists. J’ai ouvert une pull request avec la correction d’un seul mot.
Je suis l’un des deux propriétaires du gem sur RubyGems, et en janvier 2023 j’ai publié la version 1.1.2 depuis mon fork. Cette version a très peu changé :
File.exists?est devenuFile.exist?, si bien que le gem fonctionne à nouveau sous Ruby 3.2,- l’étape inutilisée de compilation d’extension a été retirée du gemspec,
- le README a reçu des remarques sur le
cacert.pemde RubyInstaller et la réserve concernant Windows Server mentionnée plus haut.
Tout le reste, l’idée et l’implémentation, est le travail de Stas.