An open-source PKCS#11 v3.2 cryptographic module under Simorgh Labs
English version:
FIPS_140_3.md. In case of discrepancy, the English version prevails.
Nom du module : FreeHSM Cryptographic Module (libfreehsm.so) Version : 1.0.0-FIPS Type : logiciel, Niveau 1 (multi-puces autonome, lié à l’OS) Cible de validation : FIPS 140-3 (ISO/IEC 19790:2012 + 24759:2017) Autorité de validation : NIST CMVP (US) / CCCS (Canada)
FreeHSM est un module cryptographique logiciel qui expose une interface PKCS#11 v3.2 aux applications. Il est destiné à servir de Soft HSM dans des environnements de production où un HSM matériel n’est pas disponible mais où la conformité FIPS 140-3 Niveau 1 est requise (PKI internes, serveurs de signature de code, charges SaaS régulées).
La frontière cryptographique est constituée du seul objet partagé libfreehsm.so plus le provider FIPS d’OpenSSL (fips.so) qu’il charge dynamiquement au C_Initialize. Tout le reste — application appelante, OS hôte, providers OpenSSL base/default — est hors frontière.
┌─────────────────────────────────────────────┐
│ Application │
└──────────────────┬──────────────────────────┘
│ ABI PKCS#11 v3.2 (C_*)
┌─── frontière ──────────────────┼─────────────────────────────┐
│ ▼ │
│ libfreehsm.so (ce module) │
│ fhsm_pkcs11.c — entry points (audit + dispatch) │
│ fhsm_crypto.c — KAT, AES-GCM, HMAC, PBKDF2 │
│ fhsm_token.c — token store, PIN, throttle │
│ fhsm_session.c — table de sessions │
│ fhsm_audit.c — log d'audit HMAC-chaîné │
│ fhsm_memory.c — secure heap, zéroisation │
│ fhsm_state.c — machine à états │
│ fhsm_integrity.c — self-test d'intégrité au boot │
│ ▼ │
│ Provider FIPS OpenSSL (fips.so) │
└────────────────────────────────────────────────────────────────┘
Le module supporte deux rôles d’opérateur :
| Rôle | Identifiant PKCS#11 | Authentification |
|---|---|---|
| Crypto Officer (CO) | CKU_SO |
PBKDF2-HMAC-SHA-256 200 000 itérations |
| Utilisateur | CKU_USER |
PBKDF2-HMAC-SHA-256 200 000 itérations |
L’authentification est par slot. Les PIN doivent comporter au moins 8 caractères. Après FHSM_PIN_MAX_FAILED = 5 échecs consécutifs, le rôle est verrouillé (FHSM_RV_PIN_LOCKED) ; seul C_InitPIN (pour USER, appelé par SO) ou C_InitToken (pour les deux) libère le verrou.
Entre tentatives échouées, le module applique un backoff exponentiel : delay_n = min(500 ms × 2^(n-1), 60 s). Le throttle est persisté dans le fichier token : un redémarrage du processus ne le contourne pas.
| Service | Rôles autorisés | Approuvé ? | Mode FIPS ? |
|---|---|---|---|
C_Initialize |
(aucun) | n/a | oui |
C_GetInfo |
(aucun) | n/a | oui |
C_Login |
CO, USER | n/a | oui |
C_GenerateKey |
CO, USER | oui | oui |
C_Encrypt (AES-GCM) |
USER | oui | oui |
C_Decrypt (AES-GCM) |
USER | oui | oui |
C_Sign (RSA-PSS, ECDSA, EdDSA, ML-DSA) |
USER | oui | oui |
C_Verify (idem) |
USER | oui | oui |
C_Digest (SHA-2, SHA-3) |
(aucun) | oui | oui |
C_DeriveKey (HKDF, PBKDF2) |
USER | oui | oui |
C_EncapsulateKey (ML-KEM) |
USER | oui | oui |
C_DecapsulateKey (ML-KEM) |
USER | oui | oui |
C_Sign (MD5, SHA-1, DSA, RSA-PKCS1-v1.5) |
— | non | rejeté |
Les services marqués non approuvés retournent FHSM_RV_FIPS_NOT_APPROVED quand FHSM_FIPS_ONLY = 1. Ils restent dispatchables dans les builds non approuvés pour l’interopérabilité avec des systèmes hérités ; la transition entre/hors mode approuvé est signalée dans le log d’audit (événement state_transition).
| Famille | Variante / paramètres | Référence | Cert. CAVP |
|---|---|---|---|
| AES | 128 / 192 / 256-GCM, CBC, KW, KWP | FIPS 197 / SP 800-38{A,D,F} | TBD |
| SHA-2 | SHA-256, SHA-384, SHA-512 | FIPS 180-4 | TBD |
| SHA-3 | SHA3-256/384/512, SHAKE128/256 | FIPS 202 | TBD |
| HMAC | avec toutes les SHA-2/3 approuvées ; SHA-1 en HMAC seulement | FIPS 198-1, SP 800-131A rev. 2 | TBD |
| RSA-PSS | 2048, 3072, 4096 | FIPS 186-5 | TBD |
| ECDSA | P-256, P-384, P-521 | FIPS 186-5 | TBD |
| EdDSA | Ed25519, Ed448 | FIPS 186-5 | TBD |
| ECDH/X25519/X448 | P-256, P-384, X25519, X448 | SP 800-56A | TBD |
| ML-KEM | 512 / 768 / 1024 | FIPS 203 | TBD |
| ML-DSA | 44 / 65 / 87 | FIPS 204 | TBD |
| SLH-DSA | SHA2/SHAKE × 128/192/256 × s/f | FIPS 205 | TBD |
| HKDF | avec toutes les SHA-2/3 approuvées ; SHA-1 comme PRF | SP 800-56C rev. 2 | TBD |
| PBKDF2 | HMAC-SHA-256, ≥ 200 000 itér. | SP 800-132 | TBD |
| CTR_DRBG | AES-256, derivation function | SP 800-90A | TBD |
| Source d’entropie | Linux getrandom(GRND_RANDOM) |
SP 800-90B | ESV TBD |
SHA-1, et pourquoi il figure dans deux lignes ci-dessus et dans aucune des
lignes de signature. SP 800-131A rev. 2 limite l’interdiction de SHA-1 à la
génération de signatures. Il reste acceptable à l’intérieur de HMAC, et donc
à l’intérieur des KDF fondées sur HMAC de SP 800-56C rev. 2. Le module suit
cette frontière plutôt qu’une règle globale : CKM_SHA_1_HMAC et
CKM_HKDF_DERIVE avec prfHashMechanism = CKM_SHA_1 sont acceptés en
fips-strict, tandis que C_Digest(CKM_SHA_1) et CKM_SHA1_RSA_PKCS y sont
refusés.
Jusqu’au 19/09/2026 le code ne traçait pas cette frontière. Un seul drapeau
marquait SHA-1 non approuvé pour tout usage, si bien que HMAC-SHA-1 était
approuvé par C_SignInit et refusé par le PRF de HKDF — une primitive, deux
chemins, deux réponses. L’échec était fermé, donc sans coût de sécurité ; il a
coûté les 84 vecteurs valides de hkdf_sha1_test.json et une explication à
chaque lecture du rapport. Ce tableau disait SHA-2/3 seulement, et
docs/MECHANISMS.md, qui est généré à partir du profil, disait
CKM_SHA_1_HMAC approuvé. Les deux se contredisaient sur la même primitive.
C’est le document généré qui avait raison.
Les cellules TBD seront renseignées lorsque la file d’attente CMVP avancera et que le laboratoire exécutera ACVP. Le jeu complet de vecteurs CAVP est chargé à l’initialisation du module par fhsm_kat_run_all (voir §6).
Tous les SSP sont stockés exclusivement dans le secure heap OpenSSL (OPENSSL_secure_malloc), une unique arène mmap verrouillée par mlock. Sa taille est fixée au build (8 MiB par défaut, configurable par FHSM_SECURE_HEAP_BYTES ou par le réglage secure_heap_kb) et elle contient toute valeur d’objet sensible, non seulement les DEK (#127). Les allocations sont rendues via OPENSSL_secure_clear_free, qui zéroise le bloc avant libération.
| SSP | Algorithme | Stockage | Déclencheur de zéroisation |
|---|---|---|---|
| DEK | AES-256 | Secure heap (vivante) | C_Logout, C_Finalize, lock |
| KEK dérivées du PIN | AES-256 | Secure heap (vivante) | Après écriture du token |
| Clés privées (RSA, EC, PQ) | RSA 2048-4096, EC, PQ | Secure heap (vivante) | C_DestroyObject, logout |
| Clé MAC d’audit | HMAC-SHA-256 | Secure heap (vivante) | C_Finalize |
| Plaintexts KAT | (cf. §6) | Secure heap (transit) | Fin du KAT |
| État DRBG | CTR_DRBG | Provider FIPS OpenSSL | Déchargement du provider |
Exécutés au C_Initialize, avant qu’aucun service ne devienne disponible :
libfreehsm.so calculé puis comparé à la valeur embarquée au build dans fhsm_module_integrity_digest[]. Mismatch → état ERROR.fhsm_drbg_init exécute le seed multi-source (getrandom + RDRAND + /dev/urandom + jitter TSC → conditionneur SHA-384 → RAND_add). Source indisponible → ERROR. Voir RNG.md pour le pipeline.kat/fhsm_kat_vectors.c ; v1.1.0 ajoute un set CAVP étendu dans kat/cavp_extended.c (2 AES-GCM-256 du NIST SP 800-38D Annex B + 4 HMAC-SHA-256 du RFC 4231). Tout mismatch → ERROR.| Déclencheur | Test | Implémentation |
|---|---|---|
| Déchiffrement AEAD | Vérification du tag (constant-time) | fhsm_aes_gcm_decrypt rejette sur mismatch |
| Vérification de signature | Vérification spécifique à l’algo | Inline dans C_Verify |
| Génération de paire asymétrique (§7.10.2.b) | Pair-wise consistency check : aller-retour chiffre-déchiffre (RSA), sign-verify (EC, ML-DSA, SLH-DSA), encap-decap (ML-KEM). Échec → ERROR latché + refus de persister la clé. | src/fhsm_pairwise.c, invoqué inline par C_GenerateKeyPair |
| Sortie du RNG (§7.10.3.b) | Test continu : RCT (cutoff 6 octets identiques consécutifs) + APT (W=512, cutoff 51) + CRNGT (bloc 16 octets comparé entre appels). | src/fhsm_drbg.c health_rct_apt + health_crngt |
Le module est validé pour l’environnement opérationnel suivant :
mlock et RLIMIT_MEMLOCK ≥ 1 MiBopenssl.cnfappend atomique)Les opérateurs doivent :
openssl list -providers montre fips en statut active).*.tok) et d’audit (*.audit.log) sur un FS non monté en réseau (NFS/CIFS peuvent perdre l’atomicité).CAP_IPC_LOCK pour autoriser le mlock du secure heap.| Attaque | Atténuation |
|---|---|
| Canaux temporels sur PIN | Throttle appliqué avant PBKDF2 ; compare constant-time |
| Exfiltration cold-boot DEK | Secure heap mlock + zéroisation au free |
| Fuite par coredump | prctl(PR_SET_DUMPABLE, 0) au C_Initialize |
| Injection dans le log | L’émission d’audit refuse tout octet hors [0x20, 0x7e] et [",\\] |
| Altération de l’audit | Log HMAC-chaîné + clé MAC dérivée du token |
| Brute-force sur PIN | Backoff exponentiel + verrou à 5 échecs |
| Épuisement de seed DRBG | Seuils de réamorçage SP 800-90A + point d’entrée reseed |