Structure des implémentations FIPS 140-2 et FIPS 140-3 de la bibliothèque cryptographique standard de Go

FIPS 140 (Federal Information Processing Standard Publication 140)
FIPS 140 est une norme de certification de la sécurité des modules cryptographiques établie par le NIST des États-Unis. Cette norme évalue si un module ou une bibliothèque cryptographique spécifique satisfait aux exigences de sécurité définies par le NIST. Par conséquent, la réussite de la certification FIPS 140 signifie que le module a officiellement acquis une sécurité digne de confiance, ce qui signifie qu'il peut être utilisé dans des domaines où la sécurité est essentielle, tels que la finance, la santé ou la défense.
La norme FIPS 140, initialement établie en 1994, a été révisée en FIPS 140-2 en 2001, puis en FIPS 140-3 en 2019. Encore aujourd'hui, de nombreux systèmes et applications exigent une certification FIPS 140-2 ou FIPS 140-3.
FIPS 140 et les langages de programmation
Pour cette raison, les modules cryptographiques certifiés FIPS 140 sont utilisés comme une norme de fait dans de nombreux langages de programmation et environnements. Parmi les plus représentatifs figurent OpenSSL, BoringSSL, LibreSSL et NSS, qui sont les modules les plus largement utilisés dans les applications où la sécurité est primordiale.
La plupart des modules certifiés FIPS 140 sont écrits en C ou en C++. C'est pourquoi des langages tels que PHP, Python et JavaScript configurent généralement un environnement FIPS en se connectant à ces modules via un module Provider externe, plutôt que de les utiliser directement. Toutefois, cette approche présente plusieurs limites.
Problème de non-concordance des versions
La certification FIPS 140 n'est accordée que pour une version spécifique. Par conséquent, pour utiliser une version plus récente du module, il faut repasser par le processus de certification, et il peut en résulter une non-concordance de versions entre le module utilisé par l'application et le module certifié FIPS. Si une version non autorisée est utilisée, l'environnement concerné n'est plus considéré comme un environnement certifié FIPS.
Chargement dynamique et dégradation des performances
La plupart des langages chargent les modules certifiés FIPS 140 sous forme de bibliothèques dynamiques. Cette méthode peut entraîner une dégradation des performances lors de l'initialisation et de l'exécution, et si un problème survient à l'exécution, il existe un risque d'impact direct sur la stabilité de l'ensemble de l'application.
Vulnérabilités de sécurité
Comme mentionné précédemment, dans une architecture qui intègre un module externe, comme le Provider OpenSSL, les vulnérabilités de sécurité de ce module risquent de se propager directement à l'application. De plus, la couche de communication entre l'application et le module externe constitue elle-même une surface d'attaque supplémentaire, ce qui nécessite une couche de sécurité distincte pour la protéger. Cette complexité accrue peut engendrer des vulnérabilités imprévues.
FIPS 140 et Golang
Pour ces raisons, Golang a adopté une stratégie différente. Go a choisi de ne pas dépendre d'outils externes pour la certification FIPS 140, mais de la prendre en charge directement dans sa bibliothèque cryptographique officielle. Ainsi, les développeurs peuvent utiliser le package standard crypto tel quel, sans installer ni configurer de Provider, et il leur suffit d'activer le mode FIPS (GOFIPS=1). Ce procédé supprime la frontière de communication avec les modules externes, ce qui renforce la sécurité, et comme seul un binaire unique compilé statiquement doit être déployé, l'exploitation est également simplifiée.
FIPS 140-2 et Golang
Pour y parvenir, Golang a intégré au runtime Go le module BoringCrypto, dérivé de BoringSSL, et a obtenu la certification FIPS 140-2. BoringCrypto peut être activé sur certaines distributions à partir de la version Go 1.19, ce qui permet aux applications Go de constituer un environnement certifié FIPS 140-2 sans module externe.
Cependant, BoringCrypto reposant sur OpenSSL, une dépendance au langage C subsiste. Par conséquent, les applications Go ne sont pas compilées en un binaire totalement indépendant, et il était nécessaire de distribuer conjointement les bibliothèques C requises.
FIPS 140-3 et Golang
Afin de surmonter ces limites, l'équipe Go a amélioré la bibliothèque standard cryptographique de Go pour qu'elle soit conforme à la norme FIPS 140-3. Ce module amélioré a commencé à être proposé à titre expérimental à partir de la version Go 1.21, et son évaluation dans le cadre de la certification FIPS 140-3 par le NIST est actuellement en cours.Liste des modules en cours d'évaluation FIPS 140-3 par le NIST
Cela témoigne de la maturité de la bibliothèque cryptographique de Go et permet désormais à Go de fournir un environnement certifié FIPS 140-3 sous la forme d'un binaire unique et totalement indépendant.
De plus, l'équipe Go ne s'est pas contentée de satisfaire à la norme FIPS 140-3, mais a également renforcé la sécurité de sa propre implémentation.
Fail Fast
Le mode FIPS de Go applique un modèle de sécurité Fail Fast : lorsqu'un algorithme non certifié est appelé, il interrompt immédiatement l'exécution en provoquant un panic. Contrairement aux modèles fondés sur des Providers dans d'autres langages, qui laissent subsister une possibilité de repli (fallback), cette approche offre une garantie plus stricte et plus claire en matière de sécurité et de conformité réglementaire.
Hedged Signature
La norme FIPS 140-3 recommande la méthode RFC 6979 pour les signatures ECDSA. Go, quant à lui, introduit en complément la méthode Hedged, qui offre une protection plus robuste contre les attaques par canaux auxiliaires pouvant survenir lors du processus de signature.
Générateur de nombres aléatoires renforcé
Le générateur de nombres aléatoires de Go utilise un DRBG (Deterministic Random Bit Generator) en espace utilisateur, tout en injectant en complément de l'entropie provenant du noyau du système d'exploitation, ce qui lui permet de générer des nombres aléatoires de haute qualité aussi bien en espace utilisateur qu'en espace noyau. Cette approche renforce encore la sécurité du générateur de nombres aléatoires.