PKI et gestion des certificats
- 1. Fondamentaux X.509 : chaîne et extensions
- 2. Architecture d'une PKI d'entreprise à deux niveaux
- 3. ADCS : autorité racine hors ligne
- 4. ADCS : autorité émettrice, modèles et autoenrollment
- 5. Durcissement ADCS : ESC1 à ESC8, Certipy et audit
- 6. Alternative open source : step-ca et ACME interne
- 7. ACME : défis, wildcard et clients
- 8. Réduction des durées de vie et automatisation
- 9. Inventaire et supervision d'expiration
- 10. Révocation : CRL, OCSP, stapling
- 11. mTLS, certificats clients et 802.1X
- 12. Signature de code et S/MIME
- 13. HSM et protection des clés privées
- 14. Certificate Transparency et CAA
- 15. Dépannage
- 16. Checklist de production
example.com, corp.example.com) et adresses sont fictifs.
1. Fondamentaux X.509 : chaîne et extensions
1.1 La chaîne de confiance
Un certificat X.509 v3 lie une clé publique à une identité, signé par une autorité (AC). Le client construit un chemin de certification du certificat feuille jusqu'à une ancre de confiance présente dans son magasin :
[Racine] CN=Example Root CA (auto-signée, dans le magasin de confiance)
|
+-- [Intermédiaire] CN=Example Issuing CA 01 (signée par la racine, envoyée par le serveur)
|
+-- [Feuille] CN=www.example.com (signée par l'intermédiaire, envoyée par le serveur)
- Le serveur doit envoyer la feuille + les intermédiaires, jamais la racine (inutile, et pénalisée par certains audits).
- Le chaînage se fait par correspondance Issuer DN / Subject DN et surtout Authority Key Identifier (AKI) / Subject Key Identifier (SKI). Deux intermédiaires de même nom mais de clés différentes (renouvellement avec nouvelle clé) sont distingués par l'AKI.
- Les certificats croisés (cross-signed) permettent plusieurs chemins valides : un client ancien remonte vers une vieille racine, un client récent vers la nouvelle. Le choix du chemin dépend de l'implémentation (CryptoAPI, NSS, OpenSSL, Java, Go n'ont pas le même algorithme de construction).
1.2 Champs et extensions qui comptent
| Extension / champ | Rôle | Valeurs typiques | Piège |
|---|---|---|---|
subjectAltName (SAN) | Identités couvertes : DNS, IP, email, URI, UPN | DNS:www.example.com, DNS:example.com, IP:192.0.2.10 | Les navigateurs ignorent le CN depuis des années : un nom absent du SAN = erreur, même s'il est dans le CN |
keyUsage (KU) | Opérations cryptographiques autorisées | Feuille RSA : digitalSignature, keyEncipherment ; ECDSA : digitalSignature ; AC : keyCertSign, cRLSign | keyEncipherment sur une clé ECDSA est incohérent ; certains clients stricts rejettent |
extendedKeyUsage (EKU) | Usages applicatifs | serverAuth (1.3.6.1.5.5.7.3.1), clientAuth (.3.2), codeSigning (.3.3), emailProtection (.3.4), Smart Card Logon (1.3.6.1.4.1.311.20.2.2) | EKU absent = « tout usage » pour beaucoup d'implémentations (cf. ESC2) ; anyExtendedKeyUsage idem |
basicConstraints | Distingue AC et entité finale | AC : critical, CA:TRUE, pathlen:0 ; feuille : CA:FALSE | Une feuille sans CA:FALSE explicite est tolérée, mais une AC sans CA:TRUE ne peut rien signer |
nameConstraints | Restreint les noms qu'une AC peut émettre | permitted;DNS:.corp.example.com | Très utile pour une AC interne croisée ; mal supporté par de vieux clients si marquée critique |
authorityInfoAccess (AIA) | Où télécharger le certificat de l'émetteur (caIssuers) et où interroger l'OCSP | caIssuers;URI:http://pki.example.com/pki/issuing01.crt | Windows et les navigateurs savent compléter une chaîne via AIA ; OpenSSL, Java, curl, Go non : une chaîne incomplète « marche dans Chrome » mais casse les API |
crlDistributionPoints (CDP) | URL de la CRL de l'émetteur | URI:http://pki.example.com/pki/issuing01.crl | Toujours en HTTP (pas HTTPS : boucle de validation) ; LDAP à éviter hors domaine |
certificatePolicies | OID de politique (CP/CPS) | Publique : 2.23.140.1.2.1 (DV), .2.2 (OV) | Obligatoire dans les certificats TLS publics |
| SCT (1.3.6.1.4.1.11129.2.4.2) | Preuves d'inscription Certificate Transparency | 2 ou 3 SCT embarqués | Absents = rejet par Chrome/Safari pour un certificat public |
1.3 Algorithmes et tailles de clés en 2026
| Usage | Recommandation | Commentaire |
|---|---|---|
| Racine hors ligne | RSA 4096 ou ECDSA P-384, SHA-256/384 | Durée 15 à 20 ans ; RSA reste le plus compatible (vieux équipements réseau, imprimantes) |
| AC émettrice | RSA 3072/4096 ou ECDSA P-256/P-384 | Durée 5 à 10 ans, toujours inférieure à la racine |
| Serveur TLS | ECDSA P-256 (préféré) ou RSA 2048/3072 | Double certificat RSA + ECDSA possible sur nginx/Apache/HAProxy |
| Interdit | SHA-1, MD5, RSA < 2048 | OpenSSL 3 au niveau de sécurité par défaut rejette les signatures SHA-1 |
2. Architecture d'une PKI d'entreprise à deux niveaux
2.1 Pourquoi deux niveaux
La clé racine est l'actif le plus critique : sa compromission oblige à redéployer l'ancre de confiance sur tous les postes. On la garde donc hors ligne (VM éteinte, machine physique sans réseau, ou HSM) et on ne l'allume que pour signer une AC émettrice ou publier une CRL. L'AC émettrice, en ligne, signe les certificats du quotidien ; si elle est compromise, on la révoque depuis la racine et on en crée une autre sans toucher aux postes.
+-------------------------------+
| ROOT CA (hors ligne) | Standalone, pas membre du domaine
| RSA 4096 - 20 ans - CRL 6 mois| allumée 2x/an (CRL) + renouvellements
+---------------+---------------+
| signe (certreq manuel, clé USB / partage temporaire)
+---------------v---------------+
| ISSUING CA 01 (Enterprise) | membre du domaine, ADCS + modèles
| RSA 4096 - 10 ans - CRL 7 j | autoenrollment GPO, OCSP optionnel
+---+-----------------------+---+
| |
+------------v-----+ +--------v-----------+
| pki.example.com | | Postes, serveurs, |
| (HTTP : CRL+AIA) | | Wi-Fi 802.1X, VPN |
+------------------+ +--------------------+
2.2 Choix de conception
| Question | Option recommandée | Justification |
|---|---|---|
| Nombre de niveaux | 2 (racine + émettrice) | 3 niveaux (racine / politique / émettrice) n'apporte rien hors très grands groupes multi-entités |
| Durée racine / émettrice / feuille | 20 ans / 10 ans / 1 an max (interne) | Règle : une AC ne peut émettre au-delà de sa propre expiration ; renouveler l'émettrice à mi-vie |
| Publication CRL/AIA | HTTP uniquement, nom DNS dédié (pki.example.com) | Indépendant du serveur ADCS : on peut migrer l'AC sans changer les URL gravées dans les certificats |
| Nom DNS de publication | Un alias stable, jamais le nom d'hôte de l'AC | Les URL CDP/AIA sont figées dans chaque certificat émis pendant des années |
| Haute disponibilité | Deux émettrices indépendantes plutôt qu'un cluster ADCS | Un cluster ADCS (failover) est complexe ; deux AC qui publient les mêmes modèles suffisent |
| Usage TLS public | Jamais la PKI interne | Les sites exposés utilisent une AC publique (ACME) ; la PKI interne sert aux noms internes, à l'authentification et au chiffrement interne |
3. ADCS : autorité racine hors ligne
3.1 Préparation
- Windows Server (2022/2025) en groupe de travail, sans carte réseau (ou carte désactivée après mises à jour), disque chiffré.
- Horloge correcte (pas de NTP : la régler à la main avant chaque session).
- Le fichier
C:\Windows\CAPolicy.infdoit exister avant l'installation du rôle : il est lu une seule fois à l'installation et à chaque renouvellement de l'AC.
3.2 CAPolicy.inf de la racine
[Version]
Signature="$Windows NT$"
[PolicyStatementExtension]
Policies=InternalPolicy
[InternalPolicy]
; OID d'exemple : utilisez un OID sous votre propre arc (PEN IANA)
OID=1.3.6.1.4.1.99999.1.1
Notice="Politique de certification interne Example"
URL=http://pki.example.com/pki/cps.html
[Certsrv_Server]
RenewalKeyLength=4096
RenewalValidityPeriod=Years
RenewalValidityPeriodUnits=20
CRLPeriod=Months
CRLPeriodUnits=6
CRLDeltaPeriodUnits=0
LoadDefaultTemplates=0
AlternateSignatureAlgorithm=0
[BasicConstraintsExtension]
PathLength=1
Critical=Yes
CRLDeltaPeriodUnits=0: pas de delta CRL sur une racine qui émet deux certificats dans sa vie.PathLength=1: la racine peut signer une AC, qui ne pourra pas en signer d'autres.AlternateSignatureAlgorithm=0: évite RSASSA-PSS, mal supporté par certains équipements.
3.3 Installation en PowerShell
Install-WindowsFeature ADCS-Cert-Authority -IncludeManagementTools
Install-AdcsCertificationAuthority `
-CAType StandaloneRootCA `
-CACommonName "Example Root CA" `
-CADistinguishedNameSuffix "O=Example,C=FR" `
-CryptoProviderName "RSA#Microsoft Software Key Storage Provider" `
-KeyLength 4096 `
-HashAlgorithmName SHA256 `
-ValidityPeriod Years -ValidityPeriodUnits 20 `
-DatabaseDirectory "C:\Windows\System32\CertLog" `
-Force
3.4 Paramétrage post-installation : CDP, AIA, durées
# Durée max des certificats signés par la racine (l'AC émettrice)
certutil -setreg CA\ValidityPeriodUnits 10
certutil -setreg CA\ValidityPeriod "Years"
# DN de configuration AD (la racine n'est pas dans le domaine : on le déclare)
certutil -setreg CA\DSConfigDN "CN=Configuration,DC=corp,DC=example,DC=com"
# CDP : fichier local + URL HTTP gravée dans les certificats émis
certutil -setreg CA\CRLPublicationURLs "1:C:\Windows\System32\CertSrv\CertEnroll\%3%8%9.crl\n2:http://pki.example.com/pki/%3%8%9.crl"
# AIA : URL HTTP du certificat de la racine
certutil -setreg CA\CACertPublicationURLs "1:C:\Windows\System32\CertSrv\CertEnroll\%1_%3%4.crt\n2:http://pki.example.com/pki/%1_%3%4.crt"
# CRL tous les 6 mois, recouvrement de 2 semaines
certutil -setreg CA\CRLPeriodUnits 6
certutil -setreg CA\CRLPeriod "Months"
certutil -setreg CA\CRLOverlapUnits 2
certutil -setreg CA\CRLOverlapPeriod "Weeks"
# Audit de toutes les opérations de l'AC
certutil -setreg CA\AuditFilter 127
auditpol /set /subcategory:"Certification Services" /success:enable /failure:enable
Restart-Service certsvc
certutil -crl
| Variable | Signification |
|---|---|
%1 | Nom DNS du serveur AC |
%3 | Nom court de l'AC (sanitized) |
%4 | Suffixe de renouvellement du certificat d'AC ((1), (2)...) |
%8 | Suffixe de renouvellement de la CRL (nouvelle clé) |
%9 | Suffixe delta CRL (+) |
Les préfixes numériques (1:, 2:) sont des masques de bits : 1 = publier le fichier à cet emplacement, 2 = inclure l'URL dans le CDP des certificats émis, etc. On publie localement, et on n'inscrit que l'URL HTTP dans les certificats.
3.5 Exporter vers le domaine
# Sur la racine : récupérer le certificat et la CRL
dir C:\Windows\System32\CertSrv\CertEnroll\
# Sur un serveur membre (Enterprise Admins) : publier dans l'AD
certutil -dspublish -f "Example Root CA.crt" RootCA
certutil -dspublish -f "Example Root CA.crl" ExampleRootCA
# Copier .crt et .crl sur le serveur web pki.example.com
# puis vérifier depuis un poste du domaine :
certutil -verify -urlfetch "Example Root CA.crt"
4. ADCS : autorité émettrice, modèles et autoenrollment
4.1 Serveur de publication HTTP
Un simple IIS (ou nginx/Apache) qui sert un répertoire /pki en HTTP, sans redirection vers HTTPS. Sous IIS, les delta CRL contiennent un + dans le nom : autoriser le double échappement.
New-Item -ItemType Directory C:\pki
New-WebVirtualDirectory -Site "Default Web Site" -Name pki -PhysicalPath C:\pki
& $env:windir\system32\inetsrv\appcmd.exe set config "Default Web Site/pki" `
-section:system.webServer/security/requestFiltering -allowDoubleEscaping:true
# Types MIME : .crl = application/pkix-crl, .crt = application/pkix-cert (déjà présents par défaut sous IIS)
includeSubDomains est posé sur example.com, utilisez un nom hors de cette zone ou vérifiez son impact.
4.2 CAPolicy.inf et installation de l'émettrice
[Version]
Signature="$Windows NT$"
[PolicyStatementExtension]
Policies=InternalPolicy
[InternalPolicy]
OID=1.3.6.1.4.1.99999.1.1
URL=http://pki.example.com/pki/cps.html
[Certsrv_Server]
RenewalKeyLength=4096
RenewalValidityPeriod=Years
RenewalValidityPeriodUnits=10
LoadDefaultTemplates=0
AlternateSignatureAlgorithm=0
[BasicConstraintsExtension]
PathLength=0
Critical=Yes
Install-WindowsFeature ADCS-Cert-Authority -IncludeManagementTools
Install-AdcsCertificationAuthority `
-CAType EnterpriseSubordinateCA `
-CACommonName "Example Issuing CA 01" `
-CryptoProviderName "RSA#Microsoft Software Key Storage Provider" `
-KeyLength 4096 -HashAlgorithmName SHA256 `
-OutputCertRequestFile C:\pki\issuing01.req -Force
# Transporter issuing01.req sur la racine, puis sur la racine :
certreq -submit -config ".\Example Root CA" C:\transfert\issuing01.req
certutil -resubmit 2 # 2 = RequestId affiché (Standalone : demande en attente)
certreq -retrieve -config ".\Example Root CA" 2 C:\transfert\issuing01.crt
# Retour sur l'émettrice :
certutil -installcert C:\pki\issuing01.crt
Start-Service certsvc
# Paramétrage de l'émettrice
certutil -setreg CA\CRLPublicationURLs "65:C:\Windows\System32\CertSrv\CertEnroll\%3%8%9.crl\n6:http://pki.example.com/pki/%3%8%9.crl\n65:\\pki01.corp.example.com\pki$\%3%8%9.crl"
certutil -setreg CA\CACertPublicationURLs "1:C:\Windows\System32\CertSrv\CertEnroll\%1_%3%4.crt\n2:http://pki.example.com/pki/%1_%3%4.crt"
certutil -setreg CA\CRLPeriodUnits 1
certutil -setreg CA\CRLPeriod "Weeks"
certutil -setreg CA\CRLDeltaPeriodUnits 1
certutil -setreg CA\CRLDeltaPeriod "Days"
certutil -setreg CA\CRLOverlapUnits 12
certutil -setreg CA\CRLOverlapPeriod "Hours"
certutil -setreg CA\ValidityPeriodUnits 2
certutil -setreg CA\ValidityPeriod "Years"
certutil -setreg CA\AuditFilter 127
Restart-Service certsvc
certutil -crl
65 = publier la CRL + publier les delta ; 6 = inscrire l'URL dans le CDP des certificats et dans l'extension IDP des CRL. Vérifiez le résultat avec pkiview.msc (Enterprise PKI) : chaque emplacement doit être « OK ».
4.3 Modèles de certificats
Ne jamais modifier les modèles par défaut : dupliquer (console certtmpl.msc), puis publier sur l'AC (certsrv.msc > Modèles de certificats > Nouveau).
| Modèle | Base | Sujet | Inscription | Points clés |
|---|---|---|---|---|
| EX-Ordinateur | Workstation Authentication | Construit depuis l'AD (DNS) | Domain Computers : Read, Enroll, Autoenroll | clientAuth seul, 1 an, clé non exportable |
| EX-ServeurWeb | Web Server | Fourni dans la requête | Groupe restreint (admins web) + approbation du gestionnaire | serverAuth seul ; c'est un modèle ESC1 potentiel : ne pas l'ouvrir à Domain Users |
| EX-ServeurAuto | Web Server | Construit depuis l'AD (DNS) | Groupe de serveurs : Autoenroll | Pour les serveurs membres ; SAN = FQDN AD uniquement |
| EX-Utilisateur | User | Construit depuis l'AD (UPN + email) | Domain Users : Autoenroll | S/MIME interne, EFS éventuellement ; archivage de clé si chiffrement |
| EX-DC | Kerberos Authentication | AD | Domain Controllers | Remplace « Domain Controller » / « Domain Controller Authentication » (supersede) |
| EX-RDP | Workstation Authentication modifié | AD | Serveurs RDS : Autoenroll | EKU Remote Desktop Authentication (1.3.6.1.4.1.311.54.1.2), GPO « Server authentication certificate template » |
# Lister les modèles publiés sur l'AC
certutil -CATemplates
Get-CATemplate
# Publier / retirer un modèle
Add-CATemplate -Name "EX-ServeurAuto" -Force
Remove-CATemplate -Name "WebServer" -Force
4.4 Autoenrollment par GPO
- GPO liée au domaine (ou aux OU ciblées) : Configuration ordinateur > Stratégies > Paramètres Windows > Paramètres de sécurité > Stratégies de clé publique > Client des services de certificats - Inscription automatique.
- Modèle de configuration : Activé, cocher « Renouveler les certificats expirés, mettre à jour les certificats en attente et supprimer les certificats révoqués » et « Mettre à jour les certificats qui utilisent les modèles de certificats ».
- Même paramètre côté Configuration utilisateur pour les certificats utilisateurs.
- Sur le modèle : permission Autoenroll (en plus de Read et Enroll) pour le groupe cible.
# Forcer sur un poste et diagnostiquer
gpupdate /force
certutil -pulse
certreq -enroll -machine -q EX-Ordinateur
# Journal : Applications and Services Logs > Microsoft > Windows > CertificateServicesClient-AutoEnrollment
Get-WinEvent -LogName "Microsoft-Windows-CertificateServicesClient-Lifecycle-System/Operational" -MaxEvents 20
Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, NotAfter, @{n='Template';e={($_.Extensions | Where-Object {$_.Oid.Value -eq '1.3.6.1.4.1.311.21.7'}).Format(0)}}
4.5 Sauvegarde de l'AC
# Base + clé (protégée par mot de passe saisi interactivement)
Backup-CARoleService -Path D:\Backup\CA -Password (Read-Host -AsSecureString)
# Configuration registre (CDP/AIA, périodes)
reg export "HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration" D:\Backup\CA\certsvc.reg
# Ne pas oublier CAPolicy.inf et la liste des modèles publiés (certutil -CATemplates)
5. Durcissement ADCS : ESC1 à ESC8, Certipy et audit
ADCS est l'un des chemins d'escalade les plus fréquents vers Domain Admin : un certificat d'authentification client permet d'obtenir un TGT Kerberos (PKINIT) au nom de l'identité inscrite dans le certificat, et il reste valide après un changement de mot de passe. La classification ESC (publiée par SpecterOps en 2021, étendue depuis jusqu'à ESC15/ESC16) décrit ces mauvaises configurations. Voir aussi Durcissement Active Directory.
5.1 Tableau des scénarios principaux
| ESC | Condition vulnérable | Impact | Correction |
|---|---|---|---|
| ESC1 | Modèle avec CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT (« Fournir dans la demande ») + EKU d'authentification client + inscription ouverte à des utilisateurs peu privilégiés + pas d'approbation | Demander un certificat avec le SAN/UPN d'un administrateur | Sujet construit depuis l'AD, ou approbation du gestionnaire, ou inscription restreinte à un groupe d'admins |
| ESC2 | Modèle avec EKU Any Purpose ou sans EKU | Certificat utilisable pour tout, y compris comme agent d'inscription | EKU explicites et minimaux |
| ESC3 | Modèle Certificate Request Agent ouvert | Demander des certificats au nom d'autres utilisateurs | Restreindre les agents d'inscription (propriétés de l'AC > Agents d'inscription) |
| ESC4 | ACL faibles sur un modèle (WriteDACL, WriteOwner, WriteProperty pour Domain Users / Authenticated Users) | Rendre un modèle vulnérable ESC1 puis l'exploiter | Auditer les ACL des objets pKICertificateTemplate |
| ESC5 | ACL faibles sur les objets PKI de l'AD (conteneur Public Key Services, objet AC, NTAuthCertificates) ou sur le serveur AC | Contrôle de la PKI | Traiter l'AC comme un actif Tier 0 |
| ESC6 | Drapeau EDITF_ATTRIBUTESUBJECTALTNAME2 sur l'AC | N'importe quel modèle accepte un SAN arbitraire | certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2 |
| ESC7 | Droits ManageCA / ManageCertificates délégués à trop de monde | Activer ESC6, approuver des demandes | Limiter aux admins PKI |
| ESC8 | Inscription web (/certsrv) ou CES en HTTP/NTLM sans EPA | Relais NTLM (coercition d'un DC via PetitPotam/PrinterBug) → certificat du DC → DCSync | Supprimer Web Enrollment si inutile ; sinon HTTPS + Extended Protection for Authentication + désactiver NTLM |
| ESC9 / ESC10 | Mapping faible des certificats (extension SID absente, StrongCertificateBindingEnforcement < 2) | Usurpation via modification d'UPN | Mode Full Enforcement du mapping fort (KB5014754) |
| ESC11 | Interface RPC de l'AC sans chiffrement exigé (IF_ENFORCEENCRYPTICERTREQUEST absent) | Relais NTLM vers RPC | Activer le drapeau (actif par défaut sur les versions récentes) |
| ESC13 / ESC15 | Politique d'émission liée à un groupe (OID group link) ; modèles en schéma v1 acceptant des Application Policies arbitraires (CVE-2024-49019) | Élévation de privilèges | Appliquer les correctifs, dupliquer les modèles v1 en v2+ et dépublier les v1 inutiles |
altSecurityIdentities au format fort). Les certificats émis hors ADCS (Intune/SCEP, AC tierce) pour l'authentification Windows doivent être vérifiés. Vérifiez l'état exact sur vos DC (événements Kdcsvc 39, 40, 41).
5.2 Auditer avec Certipy (depuis un poste d'audit autorisé)
# Inventaire complet + détection des modèles et AC vulnérables
# (authentification Kerberos avec un ticket existant : pas de mot de passe en ligne de commande)
export KRB5CCNAME=/tmp/audit.ccache
certipy find -k -no-pass -u auditeur@corp.example.com -dc-ip 10.0.0.10 -vulnerable -stdout
# Export JSON/texte pour archivage du rapport
certipy find -k -no-pass -u auditeur@corp.example.com -dc-ip 10.0.0.10 -output audit_adcs_2026-10
Côté Windows, PSPKIAudit / Locksmith (modules PowerShell) produisent un diagnostic similaire et proposent des corrections. BloodHound CE intègre les chemins ADCS (ESC1, ESC3, ESC4, ESC6, ESC9, ESC10, ESC13).
5.3 Contrôles manuels rapides
# ESC6 : le drapeau doit être ABSENT
certutil -getreg policy\EditFlags
# Le retirer s'il est présent
certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2
Restart-Service certsvc
# ESC11 : chiffrement des requêtes RPC exigé
certutil -getreg CA\InterfaceFlags # doit contenir IF_ENFORCEENCRYPTICERTREQUEST
# Modèles où le demandeur fournit le sujet (msPKI-Certificate-Name-Flag bit 1)
Get-ADObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=example,DC=com" `
-LDAPFilter "(msPKI-Certificate-Name-Flag:1.2.840.113556.1.4.803:=1)" -Properties displayName, pKIExtendedKeyUsage |
Select-Object displayName, pKIExtendedKeyUsage
# ESC8 : Web Enrollment installé ?
Get-WindowsFeature ADCS-Web-Enrollment, ADCS-Enroll-Web-Svc
5.4 Audit et détection
| Événement | Signification | Pourquoi le surveiller |
|---|---|---|
| 4886 / 4887 | Demande reçue / certificat émis | Comparer le demandeur et le SAN : un utilisateur standard qui obtient un certificat avec l'UPN d'un admin = ESC1 |
| 4888 | Demande refusée | Tentatives d'abus |
| 4890 / 4891 / 4892 | Modification des paramètres / de la configuration / d'une propriété de l'AC | Activation d'ESC6, changement d'ACL |
| 4898 / 4899 / 4900 | Modèle chargé / mis à jour / sécurité modifiée | ESC4 |
| 4768 (DC) | TGT demandé, champ Certificate Information renseigné | Authentification PKINIT inattendue |
NTAuthCertificates permet de forger des certificats d'authentification pour n'importe quel compte (« Golden Certificate »).
6. Alternative open source : step-ca et ACME interne
step-ca (Smallstep, licence Apache 2.0) est une AC en ligne légère, pensée pour l'automatisation : ACME, provisioners OIDC, JWK, X5C, SSH, Kubernetes, et des certificats très courts (24 h par défaut). Idéal pour les environnements Linux, conteneurs et services internes où ADCS n'a pas sa place.
6.1 Comparatif
| Critère | ADCS | step-ca | HashiCorp Vault PKI / OpenBao |
|---|---|---|---|
| Intégration Windows / GPO | Native (autoenrollment, Kerberos PKINIT) | Non | Non |
| ACME | Non natif | Oui (HTTP-01, DNS-01, TLS-ALPN-01, device-attest-01) | Oui (Vault 1.14+) |
| Durées courtes | Possible mais peu pratique | Conçu pour (heures/jours) | Conçu pour |
| Certificats SSH | Non | Oui | Oui |
| Révocation | CRL + OCSP | Passive par défaut (durée courte), CRL possible | CRL, OCSP |
| Cas d'usage | Parc Windows, 802.1X, smartcards | Services internes, mTLS, conteneurs | Plateformes déjà sous Vault |
6.2 Mise en place (racine hors ligne + step-ca émettrice)
# Initialiser (crée une racine et un intermédiaire ; en prod, importer plutôt
# un intermédiaire signé par votre racine hors ligne)
step ca init --name "Example Internal CA" \
--dns ca.corp.example.com --address :8443 \
--provisioner admin@corp.example.com
# Utiliser un intermédiaire existant : remplacer dans $(step path)/certs et secrets
# intermediate_ca.crt / intermediate_ca_key, puis ajuster ca.json
# Ajouter un provisioner ACME
step ca provisioner add acme --type ACME
# Durées (ca.json, bloc "claims" global ou par provisioner)
# "claims": { "minTLSCertDuration": "5m", "maxTLSCertDuration": "720h",
# "defaultTLSCertDuration": "168h" }
# Service systemd
step-ca $(step path)/config/ca.json --password-file /etc/step-ca/password.txt
# Côté client : faire confiance à la racine (empreinte affichée par step ca init)
step ca bootstrap --ca-url https://ca.corp.example.com:8443 --fingerprint <empreinte_sha256_racine> --install
# Certificat via ACME avec certbot
certbot certonly --standalone -d app01.corp.example.com \
--server https://ca.corp.example.com:8443/acme/acme/directory
# Ou directement avec step, puis renouvellement automatique
step ca certificate app01.corp.example.com app01.crt app01.key
step ca renew --daemon --exec "systemctl reload nginx" app01.crt app01.key
ca.json, une politique ("policy": {"x509": {"allow": {"dns": ["*.corp.example.com"]}}}) empêche l'émission pour des noms hors de votre zone, même si un défi ACME réussit. Pour ACME interne, l'AC doit pouvoir résoudre et joindre les noms internes (DNS interne).
7. ACME : défis, wildcard et clients
7.1 Les trois défis
| Défi | Mécanisme | Wildcard | Avantages | Contraintes |
|---|---|---|---|---|
| HTTP-01 | Fichier servi sur http://<nom>/.well-known/acme-challenge/<token>, port 80 | Non | Le plus simple, aucun accès DNS | Port 80 joignable depuis Internet (et depuis plusieurs points de vue : validation multi-perspective) ; chaque nœud d'un cluster doit servir le jeton |
| DNS-01 | Enregistrement TXT _acme-challenge.<nom> | Oui | Serveurs internes non exposés, wildcard | Nécessite un jeton API DNS : risque majeur s'il permet de modifier toute la zone |
| TLS-ALPN-01 | Certificat spécial présenté sur 443 avec ALPN acme-tls/1 | Non | Seul le 443 est ouvert | Supporté par peu de clients (Caddy, Traefik, lego) |
example.com, créez un CNAME _acme-challenge.www.example.com → www.acme.example.net pointant vers une zone dédiée (ou un serveur acme-dns), et ne donnez au client ACME que les droits sur cette zone. Les clients certbot, acme.sh et lego suivent le CNAME.
7.2 Clients ACME
| Client | Plateforme | Points forts |
|---|---|---|
| certbot | Linux | Référence EFF, plugins nginx/apache, plugins DNS (certbot-dns-*), hooks deploy |
| acme.sh | Shell POSIX | Aucune dépendance, >150 API DNS, mode délégation ; CA par défaut = ZeroSSL : forcer Let's Encrypt si voulu |
| lego | Binaire Go | Multiplateforme, nombreux fournisseurs DNS, TLS-ALPN-01 |
| win-acme (wacs.exe) | Windows | Intégration IIS, magasin Windows, RDS, Exchange, tâche planifiée |
| Posh-ACME | PowerShell | Scriptable, nombreux plugins DNS |
| Caddy, Traefik, cert-manager | Serveur / proxy / Kubernetes | ACME intégré, renouvellement transparent (voir Kubernetes) |
7.3 Exemples
# certbot, wildcard via DNS-01 (plugin Cloudflare, jeton dans un fichier 600)
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d example.com -d '*.example.com' \
--key-type ecdsa --elliptic-curve secp256r1 \
--deploy-hook "systemctl reload nginx"
# acme.sh : forcer Let's Encrypt, puis wildcard en DNS-01
acme.sh --set-default-ca --server letsencrypt
acme.sh --issue --dns dns_cf -d example.com -d '*.example.com' --keylength ec-256
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/ssl/private/example.com.key \
--fullchain-file /etc/ssl/certs/example.com.fullchain.pem \
--reloadcmd "systemctl reload nginx"
# lego, DNS-01 (identifiants via variables d'environnement du fournisseur)
lego --email ops@example.com --dns cloudflare -d example.com -d '*.example.com' --key-type ec256 run
lego --email ops@example.com --dns cloudflare -d example.com -d '*.example.com' renew --days 30
# win-acme, mode non interactif pour un site IIS
wacs.exe --source iis --siteid 1 --installation iis --emailaddress ops@example.com --accepttos
7.4 Bonnes pratiques ACME
- Tester sur l'environnement staging de l'AC avant la production (limites de débit).
- Renouveler à environ 1/3 de la durée restante ; mieux : utiliser ARI (ACME Renewal Information, RFC 9773) quand le client le supporte, pour que l'AC indique la fenêtre de renouvellement (et la raccourcisse en cas de révocation de masse).
- Un compte ACME par usage/serveur, clé de compte protégée (elle permet de révoquer).
- Recharger le service après renouvellement (deploy hook) : un certificat renouvelé sur disque mais pas rechargé expire quand même en mémoire.
- Verrouiller l'émission par CAA avec
accounturi(section 14).
8. Réduction des durées de vie et automatisation
8.1 Calendrier CA/B Forum (ballot SC-081)
Adopté en 2025, le ballot SC-081 réduit progressivement la durée maximale des certificats TLS publics et la durée de réutilisation des validations :
| À partir du | Durée max. du certificat | Réutilisation de la validation de domaine (DCV) |
|---|---|---|
| Avant le 15 mars 2026 | 398 jours | 398 jours |
| 15 mars 2026 | 200 jours | 200 jours |
| 15 mars 2027 | 100 jours | 100 jours |
| 15 mars 2029 | 47 jours | 10 jours |
La réutilisation des informations d'identité de l'organisation (OV/EV) est également ramenée à 398 jours. Ces règles ne concernent pas les PKI internes, mais tout service exposé avec un certificat public y est soumis, y compris les certificats achetés « pour un an » : l'AC les réémet alors en plusieurs fois.
8.2 Autres changements récents de l'écosystème
- Let's Encrypt a abandonné OCSP en 2025 (URL OCSP retirées des certificats, répondeurs arrêtés) au profit des CRL ; il propose des profils dont un à durée très courte (environ 6 jours) et a annoncé une réduction progressive de sa durée standard (90 jours vers 45 jours). Vérifiez le calendrier officiel avant de dimensionner vos fenêtres de renouvellement.
- EKU clientAuth : le programme racine de Chrome exige que les hiérarchies TLS publiques soient dédiées à l'authentification serveur ; les AC publiques retirent donc l'EKU
clientAuthde leurs certificats TLS (2025-2026). Conséquence : un certificat public ne peut plus servir de certificat client mTLS (connecteurs SMTP serveur-à-serveur, fédérations, VPN). Pour ces usages, utiliser une PKI privée dédiée. - Distrust : les navigateurs retirent régulièrement la confiance à des AC (Entrust en 2024 pour les certificats émis après une date butoir, par exemple). Une PKI automatisée permet de changer d'AC en quelques heures.
8.3 Ce que cela impose
| Avant | Après |
|---|---|
| Renouvellement manuel annuel, CSR envoyée par mail | Renouvellement entièrement automatique (ACME, API de l'AC commerciale, cert-manager) |
| Certificat copié à la main sur load balancer, pare-feu, appliance | Distribution par API (Ansible, Terraform, API du boîtier) ou terminaison TLS centralisée |
| Wildcard partagé sur 40 serveurs | Un certificat par service, clés distinctes, rotation indépendante |
| Inventaire Excel | Inventaire généré (scan réseau + CT logs + magasins) et alertes |
| Validation DCV « une fois pour un an » | DCV automatisable (enregistrement DNS persistant via CNAME délégué, ou HTTP-01 à chaque émission) |
9. Inventaire et supervision d'expiration
9.1 Sources d'inventaire
- Base de l'AC interne :
certutil -view(ADCS) ou base step-ca. - CT logs pour les certificats publics : tous les certificats émis pour vos domaines, y compris ceux que vous ignorez (shadow IT).
- Scan réseau des ports TLS (443, 8443, 636, 993, 995, 465, 587 STARTTLS, 3389, 5986...).
- Magasins locaux : Windows (
Cert:\), fichiers PEM, keystores Java.
# ADCS : certificats émis expirant dans les 30 jours
certutil -view -restrict "NotAfter<=now+30:00,NotAfter>=now,Disposition=20" `
-out "RequestID,RequesterName,CommonName,CertificateTemplate,NotAfter" csv > expirants.csv
9.2 Script bash : vérification d'une liste d'hôtes
#!/usr/bin/env bash
# check_certs.sh - usage : ./check_certs.sh hosts.txt 30
# hosts.txt : une ligne "nom:port" (ex. www.example.com:443)
set -u
LIST="$1"; DAYS="${2:-30}"; RC=0
while IFS=: read -r HOST PORT; do
[ -z "$HOST" ] && continue
PORT="${PORT:-443}"
PEM=$(timeout 10 openssl s_client -connect "$HOST:$PORT" -servername "$HOST" \
-verify_return_error </dev/null 2>/dev/null | openssl x509 2>/dev/null)
if [ -z "$PEM" ]; then
echo "CRIT $HOST:$PORT injoignable ou chaine invalide"; RC=2; continue
fi
END=$(echo "$PEM" | openssl x509 -noout -enddate | cut -d= -f2)
if ! echo "$PEM" | openssl x509 -noout -checkend $((DAYS*86400)) >/dev/null; then
echo "WARN $HOST:$PORT expire le $END"; [ $RC -lt 1 ] && RC=1
else
echo "OK $HOST:$PORT expire le $END"
fi
done < "$LIST"
exit $RC
9.3 Script PowerShell : magasins Windows du parc
# Certificats machine expirant sous 30 jours sur une liste de serveurs
$serveurs = Get-Content .\serveurs.txt
Invoke-Command -ComputerName $serveurs -ScriptBlock {
Get-ChildItem Cert:\LocalMachine\My |
Where-Object { $_.NotAfter -lt (Get-Date).AddDays(30) } |
Select-Object @{n='Serveur';e={$env:COMPUTERNAME}}, Subject,
@{n='SAN';e={($_.Extensions | Where-Object {$_.Oid.FriendlyName -eq 'Subject Alternative Name'}).Format(0)}},
Issuer, NotAfter, Thumbprint, HasPrivateKey
} | Sort-Object NotAfter | Export-Csv .\certs_expirants.csv -NoTypeInformation -Encoding UTF8
# Certificat lié à un site IIS / un écouteur HTTP.sys
netsh http show sslcert
9.4 Prometheus blackbox_exporter
# blackbox.yml
modules:
https_2xx:
prober: http
timeout: 10s
http:
method: GET
fail_if_not_ssl: true
preferred_ip_protocol: ip4
# règle d'alerte
groups:
- name: tls
rules:
- alert: CertificatExpireBientot
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 21
for: 1h
labels: { severity: warning }
annotations:
summary: "Certificat de {{ $labels.instance }} expire dans {{ $value | humanize }} jours"
- alert: CertificatExpireCritique
expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 7
labels: { severity: critical }
probe_ssl_earliest_cert_expiry prend l'expiration la plus proche de toute la chaîne présentée, ce qui détecte aussi un intermédiaire qui expire. Pour des fichiers locaux, x509-certificate-exporter surveille PEM, kubeconfig et secrets Kubernetes.
9.5 Zabbix
Zabbix agent 2 fournit la clé web.certificate.get[<hôte>,<port>,<adresse>] et le modèle officiel Website certificate by Zabbix agent 2 : éléments dépendants (date d'expiration, émetteur, statut de validation) et déclencheurs paramétrables par macro ({$CERT.EXPIRY.WARN}). Pour les protocoles STARTTLS, utiliser un external check basé sur le script de la section 9.2 avec -starttls.
10. Révocation : CRL, OCSP, stapling
| Mécanisme | Principe | Avantages | Inconvénients |
|---|---|---|---|
| CRL | Liste signée des numéros de série révoqués, publiée périodiquement | Simple, cachable, aucune fuite de vie privée | Taille, latence jusqu'à la prochaine publication |
| Delta CRL | Uniquement les révocations depuis la dernière CRL de base | Fraîcheur sans gros téléchargements | Support inégal hors Windows |
| OCSP | Requête en ligne sur un numéro de série | Réponse fraîche | Fuite de vie privée (l'AC voit les sites visités), point de défaillance, soft-fail |
| OCSP stapling | Le serveur joint la réponse OCSP à la négociation TLS | Pas de requête client vers l'AC | Sans objet si l'AC n'a plus d'OCSP |
| CRLSets / CRLite | Listes agrégées poussées par Chrome / Firefox | Rapide, privé | Propre aux navigateurs, pas aux API/outils |
| Durée courte | Certificat de quelques jours, pas de révocation | Aucune infrastructure de révocation | Exige une automatisation sans faille |
10.1 Conséquences pratiques en 2026
- Avec Let's Encrypt,
ssl_stapling on;(nginx) ouSSLUseStapling On(Apache) ne sert plus à rien et peut générer des avertissements dans les logs : à retirer. Certaines AC commerciales maintiennent OCSP ; le stapling reste alors pertinent. - Must-Staple (extension TLS Feature) est à proscrire : il casse le site si l'AC arrête OCSP.
- En interne, la révocation est effective pour Windows (CryptoAPI vérifie CRL/OCSP par défaut pour l'authentification), pour 802.1X (NPS vérifie la CRL : CRL expirée = Wi-Fi coupé pour tout le monde) et pour les VPN qui l'activent.
Next Update de chaque CRL publiée (y compris celle de la racine hors ligne, à republier tous les 6 mois). Exemple de contrôle :
# Prochaine mise à jour d'une CRL publiée
curl -s http://pki.example.com/pki/ExampleIssuingCA01.crl | openssl crl -inform DER -noout -lastupdate -nextupdate
# Windows : télécharger et vérifier toute la chaîne (CDP, AIA, OCSP)
certutil -verify -urlfetch .\serveur.cer
certutil -URL .\serveur.cer # interface graphique de test des URL
# Vider le cache d'URL CryptoAPI après une republication
certutil -urlcache * delete
certutil -setreg chain\ChainCacheResyncFiletime @now
10.2 Répondeur OCSP ADCS (Online Responder)
- Rôle
ADCS-Online-Cert, modèle OCSP Response Signing (avecid-pkix-ocsp-nocheck), configuration de révocation pointant vers la CRL de l'émettrice. - Ajouter l'URL OCSP dans l'AIA de l'émettrice :
certutil -setreg CA\CACertPublicationURLs "...\n32:http://ocsp.example.com/ocsp"(32 = inclure dans l'extension OCSP), puis redémarrer. - Seuls les certificats émis après la modification contiennent l'URL OCSP.
11. mTLS, certificats clients et 802.1X
11.1 Principe
En TLS mutuel, le serveur envoie un CertificateRequest listant les AC acceptées ; le client présente un certificat avec EKU clientAuth et prouve la possession de la clé. Le serveur doit valider la chaîne et autoriser l'identité (sujet/SAN), sinon tout porteur d'un certificat de la même AC passe.
11.2 nginx
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/ssl/certs/api.fullchain.pem;
ssl_certificate_key /etc/ssl/private/api.key;
# AC acceptees pour les certificats clients (PKI privee DEDIEE)
ssl_client_certificate /etc/ssl/clients/client-ca-chain.pem;
ssl_verify_client on;
ssl_verify_depth 2;
ssl_crl /etc/ssl/clients/client-ca.crl; # a rafraichir par cron
location / {
# Autorisation : n'accepter qu'une liste de sujets
if ($ssl_client_s_dn !~ "CN=(svc-facturation|svc-crm)\.corp\.example\.com") { return 403; }
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_pass http://127.0.0.1:8080;
}
}
# Apache
SSLVerifyClient require
SSLVerifyDepth 2
SSLCACertificateFile /etc/ssl/clients/client-ca-chain.pem
SSLCARevocationFile /etc/ssl/clients/client-ca.crl
SSLCARevocationCheck chain
<Location />
Require expr %{SSL_CLIENT_S_DN_CN} in {'svc-facturation.corp.example.com', 'svc-crm.corp.example.com'}
</Location>
# Test client
curl --cert client.crt --key client.key https://api.example.com/health
X-Client-DN venant d'ailleurs que du proxy.
11.3 802.1X (EAP-TLS) : Wi-Fi et filaire
- Serveur RADIUS (NPS ou FreeRADIUS) : certificat serveur avec EKU serverAuth issu de la PKI interne ; les clients doivent être configurés pour valider ce certificat (AC de confiance + nom du serveur), sinon un faux point d'accès capture les échanges.
- Postes : certificat ordinateur (autoenrollment) ou utilisateur ; profils Wi-Fi par GPO ou Intune (voir Intune : profils SCEP/PKCS, ou Microsoft Cloud PKI).
- Mapping fort : NPS s'appuie sur l'AD ; les certificats sans extension SID ou mapping fort sont refusés en mode d'application complète (KB5014754). Pour Intune SCEP, inclure l'URI SID dans le SAN selon la documentation Microsoft.
- CRL : NPS vérifie la révocation ; la publication de CRL devient un service critique.
# FreeRADIUS (mods-available/eap), extrait
eap {
default_eap_type = tls
tls-config tls-common {
private_key_file = ${certdir}/radius.key
certificate_file = ${certdir}/radius.pem
ca_file = ${cadir}/client-ca-chain.pem
check_crl = yes
ca_path = ${cadir}
tls_min_version = "1.2"
check_cert_cn = %{User-Name}
}
tls { tls = tls-common }
}
Pour le VPN, voir OpenVPN et pfSense (AC interne du pare-feu ou import de l'AC d'entreprise).
12. Signature de code et S/MIME
12.1 Signature de code
- Certificat public (logiciel distribué hors de l'entreprise) : depuis 2023, les exigences de base CA/B Forum imposent que la clé de signature de code soit générée et conservée dans un matériel certifié (HSM, jeton FIPS 140-2 niveau 2 ou équivalent, ou service de signature cloud). Plus de fichier PFX téléchargeable.
- Certificat interne (scripts PowerShell, macros, packages internes) : modèle ADCS Code Signing restreint à un groupe, clé non exportable, et AC déployée dans Trusted Publishers par GPO (voir Sécurité PowerShell).
- Horodatage obligatoire (RFC 3161) : sans horodatage, la signature devient invalide à l'expiration du certificat ; avec, elle reste valide.
# Windows : signer un exécutable (certificat dans le magasin, sélection par empreinte)
signtool sign /sha1 <empreinte> /fd SHA256 /tr <URL_TSA_de_votre_AC> /td SHA256 .\outil.exe
signtool verify /pa /v .\outil.exe
# PowerShell : signer un script
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
Set-AuthenticodeSignature -FilePath .\deploy.ps1 -Certificate $cert -TimestampServer <URL_TSA_de_votre_AC> -HashAlgorithm SHA256
Get-AuthenticodeSignature .\deploy.ps1 | Format-List
# Linux : signature détachée avec cosign / sigstore pour les artefacts et images
cosign sign-blob --key cosign.key --output-signature app.sig app.tar.gz
12.2 S/MIME
- Les certificats S/MIME publics sont régis depuis 2023 par les S/MIME Baseline Requirements du CA/B Forum (profils mailbox, organization, sponsored, individual ; profils legacy progressivement abandonnés).
- Distinguer signature (clé non archivée) et chiffrement (clé archivée : Key Recovery Agent dans ADCS), sinon les messages chiffrés deviennent illisibles après perte de la clé ou départ de l'utilisateur.
- Dans Exchange Online, la distribution des certificats publics passe par la GAL (attribut
userSMIMECertificate) ; voir Microsoft 365 / Exchange.
# Archivage de clé : inscrire un certificat Key Recovery Agent, puis le déclarer
# dans les propriétés de l'AC (onglet "Agents de récupération")
# Le modèle de chiffrement doit cocher "Archiver la clé privée du sujet"
# Récupération :
certutil -getkey <numéro_de_série> blob.out
certutil -recoverkey blob.out recup.pfx
13. HSM et protection des clés privées
| Stockage | Protection | Usage typique | Remarques |
|---|---|---|---|
| Fichier PEM/PFX | Permissions + chiffrement par mot de passe | Serveurs web, conteneurs | Acceptable pour des clés courtes et automatisées ; jamais dans un dépôt Git |
| Magasin Windows, clé non exportable | DPAPI (logicielle) | Serveurs, postes | « Non exportable » se contourne avec des droits admin (mimikatz) : ce n'est pas une barrière forte |
| TPM | Matérielle, liée à la machine | Postes (Microsoft Platform Crypto Provider), attestation | Clé réellement non extractible ; idéal pour les certificats machine/Wi-Fi |
| Carte à puce / YubiKey (PIV) | Matérielle, PIN | Comptes d'admin, signature de code interne | Authentification forte des administrateurs |
| HSM réseau / PCIe | FIPS 140-2/140-3 niveau 3, quorum (M parmi N) | Clés d'AC | Coûteux, mais exigé pour une AC critique |
| HSM USB (type YubiHSM 2) | Matérielle | Racine hors ligne de petite PKI | Bon compromis coût / sécurité |
| HSM cloud (Azure Managed HSM, AWS CloudHSM, Cloud KMS) | FIPS 140-3 niveau 3 selon offre | AC en ligne cloud, signature | Voir Azure ; attention à la réversibilité (clés non exportables) |
13.1 Cérémonie de clé (racine)
- Script écrit et relu à l'avance, liste des participants (opérateur, témoin, détenteurs de parts).
- Machine dédiée, sans réseau, OS installé depuis un média vérifié (empreinte).
- Génération de la clé dans l'HSM ; sauvegarde de la clé (wrappée) sur deux supports, stockés dans deux lieux.
- Signature de l'intermédiaire, première CRL, export des certificats publics.
- Procès-verbal signé, empreintes SHA-256 du certificat racine consignées, scellés.
# Interagir avec un HSM PKCS#11 depuis OpenSSL 3 (provider pkcs11)
openssl req -new -provider pkcs11 -provider default \
-key "pkcs11:token=CA;object=issuing01;type=private" \
-subj "/CN=Example Issuing CA 02" -out issuing02.csr
# Lister les objets d'un jeton
pkcs11-tool --module /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so --list-objects --login
14. Certificate Transparency et CAA
14.1 Certificate Transparency
- Tout certificat TLS public doit être inscrit dans des journaux CT publics et append-only ; Chrome et Safari exigent des SCT (preuves d'inscription).
- Surveillance : abonnez-vous aux notifications d'un service de monitoring CT, ou interrogez périodiquement un moteur de recherche CT (crt.sh, par exemple) pour détecter tout certificat émis à votre insu.
- Fuite d'information : chaque nom inscrit dans un certificat public devient public (
vpn-paris.example.com,jenkins-preprod.example.com). Pour les noms internes, utiliser la PKI interne ou un wildcard ; ne pas considérer un nom comme secret. - L'écosystème CT migre vers des journaux à API « statique » (tuiles), sans impact pour les clients finaux.
# Lister les certificats connus pour un domaine via l'API JSON de crt.sh
curl -s "https://crt.sh/?q=%25.example.com&output=json" | \
jq -r '.[] | [.not_before, .issuer_name, .name_value] | @tsv' | sort -u | tail -50
14.2 CAA (RFC 8659)
L'enregistrement DNS CAA liste les AC autorisées à émettre pour un domaine ; toute AC publique doit le vérifier avant émission. Les extensions RFC 8657 permettent de restreindre à un compte ACME et à des méthodes de validation.
example.com. 3600 IN CAA 0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/<id_compte>; validationmethods=dns-01"
example.com. 3600 IN CAA 0 issuewild "letsencrypt.org; validationmethods=dns-01"
example.com. 3600 IN CAA 0 iodef "mailto:securite@example.com"
# Vérifier
dig +short CAA example.com
Resolve-DnsName example.com -Type CAA
issuewild ";"interdit tout wildcard.- Le CAA est hérité en remontant l'arbre DNS, mais un CNAME est suivi : un sous-domaine qui pointe vers un SaaS peut hériter du CAA du SaaS.
- Oublier une AC utilisée par un fournisseur (CDN, hébergeur de messagerie) bloque ses renouvellements : inventorier avant de publier.
Voir aussi SSL Labs (section CAA).
15. Dépannage
| Symptôme | Cause probable | Diagnostic | Correction |
|---|---|---|---|
OK dans le navigateur, unable to get local issuer certificate dans curl / Java / Python | Chaîne incomplète : le serveur n'envoie que la feuille (le navigateur complète via AIA ou cache) | openssl s_client -connect h:443 -servername h -showcerts : un seul certificat | Configurer le fullchain (feuille + intermédiaires) |
| Erreur sur les anciens clients uniquement | Mauvais intermédiaire (ancienne chaîne, cross-sign expiré) ou racine absente des vieux magasins | Comparer AKI de la feuille et SKI de l'intermédiaire envoyé | Servir l'intermédiaire fourni avec le certificat, mettre à jour les magasins |
certificate is not yet valid / has expired alors que le certificat est neuf | Horloge du client ou du serveur fausse (VM restaurée, NTP bloqué, RTC) | date -u, w32tm /query /status | Corriger NTP ; les certificats ACME sont souvent antidatés d'une heure, mais pas plus |
NET::ERR_CERT_COMMON_NAME_INVALID, Hostname mismatch | Nom absent du SAN (souvent l'apex ou www), ou accès par IP | openssl x509 -noout -ext subjectAltName | Réémettre avec tous les noms ; un wildcard ne couvre qu'un niveau et pas l'apex |
Le service ne démarre pas : key values mismatch | Clé ne correspondant pas au certificat (renouvellement avec nouvelle clé, mauvais fichier) | Comparer les empreintes des clés publiques (voir OpenSSL) | Remettre la bonne paire |
| Windows : certificat sans clé privée après import | Import du .cer seul, ou certificat récupéré sur une autre machine que celle de la CSR | certutil -store my : « Aucun fournisseur de clé » | certutil -repairstore my <numéro_de_série> sur la machine d'origine, ou import du PFX |
| Autoenrollment sans effet | Permission Autoenroll manquante, modèle non publié, GPO non appliquée, Supersede mal configuré | Journal CertificateServicesClient-AutoEnrollment, gpresult /h | Corriger ACL / publication, certutil -pulse |
| Échec de validation sur tous les postes du domaine à date fixe | CRL (souvent celle de la racine hors ligne) expirée | certutil -verify -urlfetch : « CRL expirée » ; pkiview.msc | Allumer la racine, certutil -crl, publier ; superviser NextUpdate |
| Erreur 404 sur la delta CRL (IIS) | Le + du nom de fichier est refusé | Logs IIS : 404.11 | allowDoubleEscaping=true sur le répertoire virtuel |
Renouvellement ACME en échec : CAA record prevents issuance | CAA ne contient pas l'AC ou le compte | dig CAA sur le nom et ses parents | Ajouter l'AC / corriger accounturi |
ACME HTTP-01 : Timeout during connect | Port 80 fermé, redirection vers un autre hôte, IPv6 (AAAA) non servi | Tester depuis l'extérieur en IPv4 et IPv6 | Ouvrir 80, corriger AAAA, ou passer en DNS-01 |
| Wi-Fi 802.1X refusé après mise à jour des DC | Mapping fort : certificat sans SID | Événements Kdcsvc 39/41, logs NPS (raison 16, 22...) | Réémettre depuis un modèle à jour, ou mapping explicite fort |
Java : PKIX path building failed | AC interne absente du truststore Java (indépendant du magasin OS) | keytool -list -cacerts | keytool -importcert -cacerts -alias example-root -file root.crt (ou truststore applicatif) |
15.1 Commandes de diagnostic essentielles
# Chaîne envoyée et vérification
openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null
# Sujet / émetteur / dates / SAN
openssl x509 -in cert.pem -noout -subject -issuer -dates -ext subjectAltName
# Chaîne locale
openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem
# Windows
certutil -verify -urlfetch cert.cer
certutil -dump cert.cer
L'outil Cipher Suite du site aide à interpréter les suites négociées ; pour la configuration serveur, voir Apache.
16. Checklist de production
16.1 PKI interne
- ☐ Racine hors ligne (ou HSM), sauvegarde de la clé testée, CPS rédigée.
- ☐ CDP/AIA en HTTP sur un alias DNS stable, testés avec
certutil -verify -urlfetchdepuis un poste ET depuis un serveur Linux. - ☐ Calendrier de publication de la CRL racine (rappel à J-30 du NextUpdate) et supervision automatique de toutes les CRL.
- ☐ Modèles dupliqués, EKU minimaux, aucun modèle « sujet fourni » ouvert aux utilisateurs, modèles inutiles dépubliés.
- ☐
EDITF_ATTRIBUTESUBJECTALTNAME2absent, Web Enrollment supprimé ou protégé (HTTPS + EPA), droits ManageCA restreints. - ☐ Audit Certipy/Locksmith sans ESC ouvert, rejoué après chaque modification de modèle.
- ☐ Audit ADCS activé (
AuditFilter 127), événements 4886/4887/4899/4900 remontés au SIEM. - ☐ Serveurs AC traités en Tier 0 ; mapping fort des certificats en mode d'application complète.
- ☐ Sauvegarde ADCS (base, clé, registre, CAPolicy.inf) et procédure de restauration documentée.
16.2 Certificats publics
- ☐ Renouvellement 100 % automatique, compatible avec 47 jours (ARI si possible), rechargement du service inclus.
- ☐ Alerte sur l'échec du renouvellement ET sur l'expiration (J-21 / J-7) de toute la chaîne.
- ☐ Fullchain servie, racine non servie, clé ECDSA P-256 ou RSA ≥ 2048.
- ☐ CAA avec
accounturietvalidationmethods,iodefrenseigné. - ☐ Surveillance CT des domaines de l'organisation.
- ☐ Stapling désactivé si l'AC n'a plus d'OCSP, aucun Must-Staple.
- ☐ Aucun usage d'un certificat TLS public pour l'authentification client (EKU clientAuth retiré).
- ☐ Jetons API DNS limités à une zone de délégation
_acme-challenge. - ☐ Inventaire généré (scan + CT + magasins), propriétaire identifié pour chaque certificat.
- ☐ Note A/A+ vérifiée (SSL Labs) et audit global (Audit de sécurité).