Certreq e SAN multipli su Microsoft CA: guida definitiva con INF e PowerShell

Stai richiedendo un certificato TLS a una CA Microsoft e con certreq -submit -attrib ottieni solo il primo Subject Alternative Name? In questa guida trovi cause, soluzioni e procedure operative affidabili per avere tutti i SAN desiderati, con esempi pronti all’uso in INF e PowerShell.

Indice

Contesto: perché i SAN “spariscono” con certreq -attrib

Quando si inviano attributi a una Certification Authority (CA) Microsoft tramite certreq -submit -attrib, i parametri sono interpretati come coppie chiave:valore separate da ritorni a capo. Se si tenta di comprimere tutto in una singola stringa (per esempio SAN:DNS=a&DNS=b&DNS=c subito dopo CertificateTemplate:), alcune CA considerano solo la prima voce oppure ignorano completamente i SAN. Il comportamento varia tra versioni e configurazioni, ma l’effetto percepito è identico: nel certificato finito compare soltanto il primo SAN.

Le cause più frequenti sono tre:

  • Template non allineato: il modello non è configurato su “Supply in the request”, quindi la CA scarta qualunque estensione SAN portata nella CSR/attributi.
  • Formattazione dell’attributo: certreq si aspetta attributi multipli separati da veri ritorni a capo; usare l’escape testuale \n in CMD non produce un newline reale.
  • Escaping dei caratteri speciali: il carattere & (usato per concatenare più DNS=) è un operatore sia in CMD che in PowerShell se non correttamente quotato/escapato.

Roadmap rapida: la soluzione più affidabile

La via maestra è generare la CSR partendo da un file INF che contenga tutte le SAN. È ripetibile, leggibile e funziona in modo consistente con le CA Microsoft moderne.

  1. Verifica e prepara il template: il template deve essere impostato su Supply in the request e pubblicato sulla CA.
  2. Crea un INF con 2.5.29.17 (Subject Alternative Name) già popolato di dns=.
  3. Genera la CSR con certreq -new e inviala con certreq -submit.
  4. Accetta il certificato nel computer che possiede la chiave con certreq -accept.

Se devi per forza usare -attrib, funziona bene aggiungere un vero newline tra CertificateTemplate: e SAN: (PowerShell è ideale, perché `n diventa newline reale). Maggiori dettagli più avanti.

Checklist del template CA (fondamentale)

Prima di toccare i comandi, conferma questi punti nella Console dei Template dei Certificati:

  • Scheda “Subject Name”: seleziona Supply in the request. In caso contrario, la CA non copierà i SAN dalla richiesta.
  • Permessi: l’entità che richiede (computer/utente/servizio) deve avere almeno Enroll (e se serve Autoenroll).
  • Pubblicazione del template: la CA deve “conoscere” quel template (aggiunto alla CA) e non applicare restrizioni che rimuovono l’estensione SAN.

Soluzioni a confronto (con pro e contro)

Passo / SoluzioneDettagli operativiPunti di attenzione
Controllo del templateImposta il template su Supply in the request e pubblicalo sulla CA.Senza questa opzione la CA ignora o sovrascrive i SAN presenti nella richiesta.
Attributi con “a capo” realeUsa un newline reale tra gli attributi, per esempio in PowerShell: "CertificateTemplate:Appliance`nSAN:DNS=a&DNS=b&DNS=c".\n in CMD resta letterale; in PowerShell `n genera il vero newline. Quota/escapa bene il carattere &.
CSR da file INF (consigliata)Definisci l’OID 2.5.29.17 con tutte le SAN nel file INF, poi certreq -new e -submit.È la strada più stabile: la CA copia i SAN già nella CSR, evitando edge case di -attrib.
Post‑processing per applianceSe il dispositivo accetta solo PEM: esporta PFX, converti in PEM con OpenSSL e separa KEY / CERT / CHAIN.Richiede passi extra ma garantisce compatibilità con dispositivi che non supportano PFX.

Procedura passo‑passo con file INF (best practice)

INF per chiave RSA (server web tipico)

; san-rsa.inf
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=appliance.example.com"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE               ; metti FALSE in ambienti altamente protetti
MachineKeySet = TRUE            ; TRUE per certificati macchina
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
SMIME = FALSE
HashAlgorithm = sha256
KeyUsage = 0xa0

[Extensions]
; 2.5.29.17 = Subject Alternative Name
2.5.29.17 = "{text}"
continue = "dns=appliance.example.com&dns=api.example.com&dns=internal.example.local"
; eventuale SAN IP:
; continue = "ipaddress=192.0.2.10"

[RequestAttributes]
CertificateTemplate = Appliance   ; o il tuo template (es. WebServer)

INF per chiave ECDSA (P‑256)

; san-ecdsa.inf
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=appliance.example.com"
KeySpec = 1
Exportable = TRUE
MachineKeySet = TRUE
KeyAlgorithm = ECDSA_P256
ProviderName = "Microsoft Software Key Storage Provider"
RequestType = PKCS10
HashAlgorithm = sha256

[Extensions]
2.5.29.17 = "{text}"
continue = "dns=appliance.example.com&dns=api.example.com"

[RequestAttributes]
CertificateTemplate = Appliance

Generazione e invio

# Genera CSR e chiave privata
certreq -new .\san-rsa.inf .\san.req

Invia alla CA (specifica il nome esatto della tua CA)

certreq -submit -config "CAHOST\NOME-CA" .\san.req .\san.cer

Installa il certificato nel computer che possiede la chiave

certreq -accept .\san.cer

Note importanti:

  • Macchina di destinazione: esegui certreq -new nel sistema dove deve risiedere la chiave privata (o usa UseExistingKeySet=TRUE se devi rigenerare solo la CSR).
  • Exportable: imposta Exportable=TRUE solo se devi esportare la chiave in PFX per un’appliance. In ambienti ad alta sicurezza, valuta FALSE e l’uso di HSM/KSP dedicati.
  • CA interattiva: senza -config, certreq apre una finestra per scegliere la CA pubblicata in AD. Indicando -config eviti l’interazione.

Metodo alternativo: -attrib con newline reale

Se devi usare -attrib, il trucco è separare gli attributi con un vero a‑capo. In PowerShell è immediato perché `n (backtick + n) viene espanso in newline.

Esempio PowerShell “tutto in uno”

$attrib = @"
CertificateTemplate:Appliance
SAN:DNS=appliance.example.com&DNS=api.example.com&DNS=internal.example.local
"@

certreq -submit -config "CAHOST\NOME-CA" -attrib $attrib .\san.req .\san.cer

In alternativa, con stringa singola:

certreq -submit -config "CAHOST\NOME-CA" `
  -attrib "CertificateTemplate:Appliance`nSAN:DNS=appliance.example.com&DNS=api.example.com&DNS=internal.example.local" `
  .\san.req .\san.cer

Attenzione all’escaping:

  • In PowerShell l’operatore di chiamata è &. Dentro stringhe quotate rimane letterale; se componi l’attributo per concatenazione non quotata, escapa con backtick `& o racchiudi sempre il valore completo tra doppi apici.
  • In CMD, & è un operatore di concatenazione comandi: racchiudi sempre l’intero valore di -attrib tra virgolette oppure preferisci PowerShell.
  • La sequenza \n non crea un newline in CMD: verrà passata come testo letterale.

Verifica: come controllare che i SAN ci siano davvero

Subito dopo l’emissione/accettazione:

REM Dump rapido con certutil
certutil -dump .\san.cer | findstr /I "Alternative DNS IP"

REM Oppure con OpenSSL
openssl x509 -in .\san.cer -noout -text | findstr /I "Subject Alternative Name"

Se vedi solo un SAN nel blocco Subject Alternative Name, riparti dalla verifica del template e del formato dell’attributo/INF.

Esportazione e conversione per appliance (PEM)

Molti dispositivi richiedono tre file separati in formato PEM: key, cert e chain. Procedura tipica:

Esporta in PFX (con chiave)

# Trova il certificato per thumbprint
$thumb = "INSERISCI-THUMBPRINT-SHA1"
$cert = Get-ChildItem Cert:\LocalMachine\My\$thumb

Esporta in PFX con password

$pwd = ConvertTo-SecureString 'S3greta!' -AsPlainText -Force
Export-PfxCertificate -Cert $cert -FilePath .\appliance.pfx -Password $pwd

Converti in PEM e separa i pezzi

# Estrai tutto in un unico PEM (senza cifrare la key: -nodes)
openssl pkcs12 -in appliance.pfx -out bundle.pem -nodes

Separa key e cert "foglia"

openssl pkey -in bundle.pem -out key.pem
openssl x509 -in bundle.pem -out cert.pem

Estrai la chain (CA intermedie + radice, se presente)

openssl crl2pkcs7 -nocrl -certfile bundle.pem -out chain.p7b
openssl pkcs7 -print_certs -in chain.p7b -out chain.pem

Carica key.pem, cert.pem e chain.pem sull’appliance nell’ordine richiesto. Se il dispositivo pretende un bundle singolo, concatena cert.pem + chain.pem in un file unico.

Automazione: generare INF e CSR da una lista di FQDN

Se crei spesso certificati con molti SAN, automatizza la generazione dell’INF e dei comandi:

$DnsNames = @(
  "appliance.example.com",
  "api.example.com",
  "internal.example.local"
)

$sanText = ($DnsNames | ForEach-Object { "dns=$_" }) -join "&"
$inf = @"
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=$($DnsNames[0])"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
HashAlgorithm = sha256

[Extensions]
2.5.29.17 = "{text}"
continue = "$sanText"

[RequestAttributes]
CertificateTemplate = Appliance
"@

$infPath = ".\san-auto.inf"
$reqPath = ".\san-auto.req"
$cerPath = ".\san-auto.cer"

$inf | Set-Content -Encoding ASCII $infPath
certreq -new $infPath $reqPath
certreq -submit -config "CAHOST\NOME-CA" $reqPath $cerPath
certreq -accept $cerPath 

Vantaggi:

  • La logica di composizione dei SAN è centralizzata e leggibile.
  • Il template è fissato in [RequestAttributes], evitando l’uso di -attrib.
  • Riduci gli errori umani su escape/quoting.

Diagnostica: come capire dove si rompe il flusso

  • Solo il primo SAN appare: quasi sempre separatore di attributi mancante (nessun newline reale) o template non “Supply in the request”.
  • Nessun SAN appare: la CA ha ignorato l’estensione (template errato) o la CSR non conteneva 2.5.29.17.
  • Errore al submit: controlla Application e System nel Visualizzatore Eventi sul server CA; verifica anche permessi di enroll.
  • CSR rigettata: alcune policy CA impediscono caratteri non ammessi nei SAN (spazi, caratteri non DNS). Mantieni i DNS Name conformi a RFC (niente underscore a meno di accettazione esplicita).

CMD vs PowerShell: differenze pratiche su quoting ed escape

ShellQuoting consigliatoNewline realeCarattere &Nota operativa
CMDVirgolette doppie attorno all’intero -attribNon supportato con \n; difficile da inserire inlineOperatore; necessario quotare tutto o evitare CMDPer -attrib con più linee, preferisci PowerShell o INF
PowerShellStringhe tra doppi apici o here‑string @"..."@`n si espande in newline realeOperatore di chiamata, ma letterale dentro le stringheÈ il modo più semplice per usare -attrib con SAN multipli

Domande frequenti

Posso usare DNS= maiuscolo o dns= minuscolo?

Sì, la dicitura non è case‑sensitive nell’estensione testuale dell’INF. Mantieni coerenza per leggibilità.

Posso aggiungere SAN IP o URI?

Sì. Nelle righe continue usa ipaddress=198.51.100.10 oppure url=https://esempio.tld secondo necessità. Verifica che il template non imponga restrizioni al tipo di SAN.

È obbligatorio impostare MachineKeySet?

Per certificati macchina sì, perché la chiave deve finire nello store LocalMachine. Per certificati utente usa lo store CurrentUser (MachineKeySet=FALSE o ometti).

Le CA più vecchie hanno limiti sul numero di SAN?

Alcune implementazioni datate o policy personalizzate possono imporre limiti (dimensione della richiesta o numero di voci). Se sospetti un limite, prova prima con INF e pochi SAN, poi aumenta progressivamente.

Quando usare Exportable=FALSE?

Quando la chiave non deve lasciare il sistema (policy di sicurezza). Se devi fornire file PEM a un dispositivo esterno, imposta Exportable=TRUE solo per la generazione e conserva il PFX in modo sicuro.

Procedura completa “dal zero al certificato” (copiabile)

  1. Template: crea/clona il template (es. WebServer → Appliance), abilita Supply in the request, pubblicalo sulla CA e assegna i permessi di enroll.
  2. INF: prepara san.inf includendo tutti i SAN in 2.5.29.17 e il CertificateTemplate in [RequestAttributes].
  3. CSR: certreq -new .\san.inf .\san.req nel computer target.
  4. Invio: certreq -submit -config "CAHOST\NOME-CA" .\san.req .\san.cer.
  5. Installazione: certreq -accept .\san.cer.
  6. Verifica: certutil -dump .\san.cer e controlla Subject Alternative Name.
  7. Export/PEM (se serve): Export-PfxCertificate + OpenSSL come da esempi.

Raccomandazioni pratiche

  1. Prima scelta: genera sempre la CSR con tutte le SAN in un file INF. È deterministico e compatibile con le CA Microsoft recenti.
  2. Seconda scelta: se devi usare -attrib, separa gli attributi con un vero newline (in PowerShell con `n o here‑string).
  3. Template: assicurati che il modello sia su Supply in the request e che la CA non applichi policy che rimuovono i SAN.
  4. Quoting: tratta & con cura (quoting/escaping); evita composizioni non quotate in CMD/PowerShell.
  5. Automazione: usa script per generare INF/CSR da liste di FQDN, riducendo errori manuali.

Appendice: esempi di comandi utili

Selezionare quando la CA chiede la scelta del template

Se la tua CA ignora [RequestAttributes] o devi forzare il template via attributo, usa PowerShell con newline reale:

$attrib = @"
CertificateTemplate:WebServer
SAN:DNS=www.example.com&DNS=api.example.com
"@
certreq -submit -config "CAHOST\NOME-CA" -attrib $attrib .\web.req .\web.cer

Rigenerare una CSR da chiave esistente

; renew.inf
[Version]
Signature="$Windows NT$"

[NewRequest]
Subject = "CN=appliance.example.com"
UseExistingKeySet = TRUE
RequestType = PKCS10

[Extensions]
2.5.29.17 = "{text}"
continue = "dns=appliance.example.com&dns=api.example.com"

[RequestAttributes]
CertificateTemplate = Appliance
certreq -new .\renew.inf .\renew.req
certreq -submit -config "CAHOST\NOME-CA" .\renew.req .\renew.cer
certreq -accept .\renew.cer

Verifica catena di fiducia lato server

# Simula la presentazione lato server
openssl s_client -connect appliance.example.com:443 -servername appliance.example.com -showcerts < /dev/null

Conclusione

Il problema dei “SAN monchi” con certreq -attrib non è un mistero: nasce dalla combinazione di formattazione degli attributi, escaping e impostazioni del template. Impostando il template su Supply in the request e generando la CSR da INF (includendo l’estensione 2.5.29.17), ottieni risultati coerenti e ripetibili. Quando serve usare -attrib, passa per PowerShell e inserisci un ritorno a capo reale tra CertificateTemplate: e SAN:. Con queste accortezze, la CA emetterà certificati con tutti i SAN richiesti, senza workaround faticosi.


Indice