certreq / certutil et AC Microsoft : obtenir plusieurs SAN sur un certificat (modèle Appliance)

Vous soumettez un CSR d’appliance à une AC Microsoft pour obtenir un certificat au modèle Appliance avec plusieurs SAN… mais seul le premier est conservé ? Voici l’analyse, les causes probables et surtout des procédures fiables qui fonctionnent en production.

Sommaire

Problème : impossibilité d’obtenir plusieurs SAN avec certreq / certutil

Lors d’une soumission directe en ligne de commande, l’attribut -attrib regroupe le modèle et les SAN :

certreq -submit `
  -attrib "CertificateTemplate:Appliance\nSAN:dns=entry1.contoso.com&dns=entry2.contoso.com&dns=entry3.contoso.com" `
  cert.csr

Le certificat est bien émis, mais l’extension Subject Alternative Name (SAN) ne contient que entry1.contoso.com. Les autres noms semblent ignorés.

Contexte

  • CSR généré sur une appliance (clé privée non exportable ou environnement verrouillé).
  • Objectif : certificat basé sur le modèle Appliance avec plusieurs SAN DNS.
  • Soumission via certreq -submit, en passant les SAN dans -attrib plutôt que dans le CSR.

Symptômes observés

  • Dans un certutil -dump du certificat émis : un seul SAN (le premier) est présent.
  • Événements AC sans erreur explicite ; la demande est “valide” mais tronquée.
  • Répéter la soumission avec plus de SAN ne change rien : seul le premier est conservé.

Causes probables

Syntaxe de l’attribut SAN

SAN: ne doit apparaître qu’une seule fois. Tous les noms sont enchaînés derrière, séparés par &, sans retour à la ligne ni répétition de SAN:. Exemple correct :

SAN:dns=host1.contoso.com&dns=host2.contoso.com&dns=host3.contoso.com

La moindre rupture de ligne, espace parasite, guillemet manquant, ou répétition de l’étiquette SAN: peut faire échouer l’agrégation.

Limitation côté certreq avec -attrib

Des retours terrain concordants montrent que certreq interprète correctement le premier élément SAN mais ignore les suivants lorsqu’on combine CertificateTemplate et SAN=... dans la même chaîne -attrib. Le résultat : un certificat émis, mais avec un SAN réduit à une seule entrée.

Stratégie de l’AC (AD CS)

Si l’autorité ne copie pas l’attribut subjectAltName depuis la requête, elle n’inclura pas tous les noms alternatifs demandés. Sur une AC Microsoft, vérifier et, si besoin, activer :

certutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
net stop certsrv & net start certsrv

Sans ce drapeau, l’AC peut ignorer ou tronquer les SAN fournis dans la demande.

Solutions éprouvées

SolutionRésultat
Conserver le CSR de l’appliance et passer plusieurs SAN via -attribNe fonctionne pas : seul le 1er SAN est retenu
Générer un CSR local via un fichier INF (Subject vide, SubjectAltName complet), puis certreq -new req.inf req.csrFonctionne : tous les SAN sont présents dans le certificat
Convertir le PFX obtenu en PEM et extraire clé / cert / chaîne via openssl pkcs12 -in file.pfx -nodesPermet d’importer le certificat sur l’appliance malgré l’absence de prise en charge directe du PFX

Procédure INF de référence

req.inf de base (modèle Appliance, SAN DNS multiples) :

[Version]             ; identique pour toutes les requêtes
Signature="$Windows NT$"

\[NewRequest]          ; section principale
KeySpec            = 1
KeyLength          = 2048
Exportable         = TRUE
MachineKeySet      = TRUE
SMIME              = FALSE
Silent             = TRUE
RequestType        = CMC           ; ou PKCS10
CertificateTemplate= Appliance     ; nom exact du modèle

\[Extensions]          ; ---- extension SAN ----
2.5.29.17 = "{text}"
*continue* = "dns=entry1.contoso.com&"
*continue* = "dns=entry2.contoso.com&"
*continue* = "dns=entry3.contoso.com" 

Enchaînez ensuite :

certreq -new req.inf req.csr
certreq -submit req.csr issued.cer   # ou passer par l’EAC/WebEnroll
certreq -accept issued.cer

Étapes détaillées pas à pas

  1. Préparer le fichier INF en listant tous les SAN dans la section [Extensions]. Garder Subject vide si le modèle impose “Supply in the request”.
  2. Générer le CSR avec certreq -new. Conservez le .csr et le .inf pour audit ultérieur.
  3. Soumettre à l’AC via certreq -submit ou via l’interface Web d’inscription. Sélectionner le modèle Appliance le cas échéant.
  4. Accepter et lier le certificat via certreq -accept (associe le cert au couple clé/CSR local).
  5. Exporter si nécessaire un PFX depuis le magasin machine (certlm.msc) pour remise à l’appliance.
  6. Convertir PFX en PEM si l’appliance n’accepte pas le PFX : openssl pkcs12 -in device.pfx -nodes -out bundle.pem # Séparer ensuite : # - clé privée : -----BEGIN PRIVATE KEY----- ... # - certificat : -----BEGIN CERTIFICATE----- # - chaîne : certificats CA intermédiaire + racine (si requis par la cible)
  7. Importer sur l’appliance la clé privée et le certificat/chaîne, selon son format attendu.

Variantes d’attributs SAN dans un INF

Vous pouvez mélanger différents types de SAN. Syntaxes usuelles :

[Extensions]
2.5.29.17 = "{text}"
; DNS
_continue_ = "dns=www.contoso.com&"
; IP
_continue_ = "ipaddress=10.10.10.10&"
; Adresse e-mail
_continue_ = "rfc822Name=alerts@contoso.com&"
; UPN (souvent pour authent. Kerberos)
_continue_ = "otherName=1.3.6.1.4.1.311.20.2.3;UTF8:device01@contoso.com&"
; URI
_continue_ = "url=http://status.contoso.com"

Astuce : terminez toutes les lignes par & sauf la dernière. Évitez les espaces en trop, ils comptent.

Quand utiliser CMC plutôt que PKCS#10 ?

PKCS#10 suffit dans la majorité des cas. CMC (Certificate Management over CMS) devient utile pour transporter des attributs additionnels, des données d’autorisation ou des demandes groupées. Pour ce cas précis (plusieurs SAN), PKCS#10 + section [Extensions] est simple et fiable.

Vérifications et diagnostic

Valider l’extension SAN du certificat

certutil -dump issued.cer | findstr /I "Alternative"
# Depuis n’importe quel poste avec OpenSSL
openssl x509 -in issued.cer -noout -text | sed -n '/Subject Alternative Name:/,/X509v3/p'

Contrôler la demande côté AC

  • Journal Windows → Applications and Services LogsCertificationAuthority : présence d’événements d’émission et de copie d’attributs.
  • certutil -config - -ping pour valider la connectivité AC.
  • certutil -getreg policy\EditFlags pour inspecter les drapeaux actifs (EDITF_ATTRIBUTESUBJECTALTNAME2 attendu).

Checklist rapide

Point de contrôleAttenduCommande / Indice
Syntaxe -attribUn seul SAN:, valeurs séparées par &Revoir guillemets et retours de ligne
ModèleCertificateTemplate correct, droits d’inscription OKConsole AC → Certificate Templates
Copie du SANEDITF_ATTRIBUTESUBJECTALTNAME2 activécertutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
Source du SANSAN inclus dans le CSR (INF/OpenSSL)certreq -new avec [Extensions]
Validation finaleTous les SAN présentscertutil -dump / openssl x509 -text

Bonnes pratiques PKI pour ce scénario

  • Mettre les SAN dans le CSR (INF/OpenSSL/PowerShell) plutôt que dans -attrib.
  • Éviter les modifications manuelles des SAN au moment de l’émission : préférez des workflows reproductibles.
  • Limiter les droits sur le modèle Appliance : seuls les opérateurs autorisés doivent pouvoir inscrire des certificats avec SAN multiples.
  • Journaliser les demandes et conserver les .inf/.csr associés.
  • Tester en préproduction chaque changement (modèle, flags AC, versions d’OS).

Alternatives et compléments

  • PowerShell / ACME : si l’appliance ou l’environnement autorise ACME (par ex. via New-PACertificate), laissez le protocole gérer les SAN. Utile pour le renouvellement automatisé.
  • OpenSSL natif : générez la paire clé/CSR sur une station sécurisée, insérez les SAN dans openssl.cnf, puis ne livrez à l’appliance que la clé et le certificat final.
  • Modèle “Supply in the request” : dans le Certificate Template, cochez Subject Name → Supply in the request pour autoriser la copie de subjectAltName depuis la demande.

Exemples prêts à copier

Commande certreq avec SAN correct (un seul attribut)

certreq -submit `
  -attrib "CertificateTemplate:Appliance" `
  req.csr
# Tous les SAN sont dans req.csr, pas dans -attrib

INF avec SAN DNS + IP

[Version]
Signature="$Windows NT$"

\[NewRequest]
KeySpec=1
KeyLength=2048
Exportable=TRUE
MachineKeySet=TRUE
RequestType=PKCS10
CertificateTemplate=Appliance

\[Extensions]
2.5.29.17="{text}"
*continue*="dns=app01.contoso.com&"
*continue*="dns=app01&"               ; court alias DNS interne
*continue*="ipaddress=192.0.2.15" 

Validation rapide après émission

certutil -dump issued.cer | more

Extraction de la chaîne depuis un PFX

openssl pkcs12 -in device.pfx -nodes -out device-all.pem
awk 'BEGIN{RS=""} /BEGIN CERTIFICATE/{print > "device-cert.pem"}' device-all.pem
# Ajustez selon votre politique d’extraction ; vérifiez les en-têtes.

FAQ

Pourquoi un seul SAN apparaît-il lorsque j’utilise -attrib ?
Parce que combiner CertificateTemplate:... et SAN:... dans la même chaîne -attrib conduit certreq à ne traiter que la première valeur SAN. C’est un comportement couramment observé en production.

Puis-je répéter SAN: plusieurs fois ?
Non. Utilisez SAN: une seule fois et séparez les valeurs par &.

Comment ajouter des SAN IP, e-mail, UPN ?
Dans [Extensions] : ipaddress=1.2.3.4, rfc822Name=user@contoso.com, ou otherName=1.3.6.1.4.1.311.20.2.3;UTF8:upn@contoso.com.

Le sujet (CN) doit-il être vide ?
Si le modèle impose Supply in the request, laissez le Subject vide et fournissez tout via SAN. Beaucoup de modèles modernes évitent d’utiliser le CN.

Faut-il redémarrer le service CA après changement de stratégie ?
Oui : net stop certsrv & net start certsrv après avoir modifié les EditFlags.

Que faire si l’appliance n’accepte que PEM ?
Exportez un PFX, puis convertissez-le en PEM avec openssl pkcs12 -nodes et séparez clé/cert/chaîne.

Erreurs fréquentes et comment les éviter

  • Retour à la ligne dans -attrib : supprimez-le. La chaîne doit être contiguë.
  • Espaces accidentels avant/après & ou = : proscrits.
  • Nom de modèle incorrect (CertificateTemplate) : orthographe exacte requise.
  • Absence de EDITF_ATTRIBUTESUBJECTALTNAME2 : l’AC n’insèrera pas (ou pas entièrement) les SAN depuis la demande.
  • Droits d’inscription insuffisants : l’AC peut substituer un modèle par défaut ou refuser des attributs.

Synthèse exécutable

  • Constat : certreq -attrib combinant CertificateTemplate et plusieurs SAN ne conserve que le premier SAN.
  • Solution robuste : placez tous les SAN dans le CSR (INF/OpenSSL/PowerShell). N’utilisez -attrib que pour le modèle ou des attributs simples.
  • Vérifications : modèle configuré en Supply in the request et drapeau EDITF_ATTRIBUTESUBJECTALTNAME2 activé sur l’AC.
  • Livraison : si l’appliance ne supporte pas PFX, convertissez en PEM et séparez clé/cert/chaîne.

Procédure express à garder sous la main

; req.inf
[Version]
Signature="$Windows NT$"
[NewRequest]
KeySpec=1
KeyLength=2048
Exportable=TRUE
MachineKeySet=TRUE
RequestType=PKCS10
CertificateTemplate=Appliance
[Extensions]
2.5.29.17="{text}"
_continue_="dns=entry1.contoso.com&"
_continue_="dns=entry2.contoso.com&"
_continue_="dns=entry3.contoso.com"
certreq -new req.inf req.csr
certreq -submit req.csr issued.cer
certreq -accept issued.cer
# Vérifier :
certutil -dump issued.cer | findstr /I "Alternative"

Conclusion

Retenez ceci : pour les SAN multiples avec une AC Microsoft, n’utilisez pas -attrib SAN:... combiné à CertificateTemplate. Placez plutôt tous les SAN dans la demande (INF/OpenSSL/PowerShell). Assurez-vous que le modèle et l’AC autorisent la copie de subjectAltName (EDITF_ATTRIBUTESUBJECTALTNAME2), puis validez le résultat avec certutil ou openssl. Cette approche évite les surprises et garantit un certificat final conforme à vos besoins d’appliance.

Sommaire