Rückblick: Vor ein paar Jahren habe ich unter S/MIME-Zertifikate mittels klickfertiger OpenSSL-CA selbst erstellen erläutert, wie mittels ein paar Scripts basierend auf OpenSSL eine Certificate Authority (CA) instanziiert und zur Zertifikatsausstellung genutzt wird.
Mit diesem Blog-Post hier demonstriere ich, wie unter Verwendung von Windows 11 Bordmitteln (Powershell, es wird kein OpenSSL benötigt) eine CA erstellt und daraus Code-Signing-Zertifikate, Webserver-Zertifikate, Benutzer-Zertifikate für TLS-Client-Auth, S/MIME Mail-Signatur und Mail-Verschlüsselung sowie Smartcard-Anmeldung ausgestellt werden.
Die nachfolgende Anleitung nutzt hierzu das in Windows enthaltene PowerShell-Commandlet New-SelfSignedCertificate, welches von Microsoft grundsätzlich ausreichend dokumentiert ist. Aber: Der dokumentierte und intendierte Zweck seitens Microsoft ist augenscheinlich damit (nur) Selfsigned-Zertifikate auszustellen. Dieses PowerShell-Commandlet eignet sich aber nicht nur zur Erstellung von Self-Signed-Zertifikaten. Es kann als universelles Zertifikats-Erstellungs-Instrument genutzt werden, mit dem wir nun eine CA, sowie von dieser CA signierte Zertifikate für unterschiedliche Zwecke ausstellen werden.
Das PowerShell-Commandlet New-SelfSignedCertificate steht sowohl in der mit Windows 11 mitgelieferten PowerShell Version 5, als auch in der modernen PowerShell 7 zur Verfügung.
Die PowerShell-Code-Zeilen können grundsätzlich inklusive der hervorgehobenen Kommentarzeilen direkt 1:1 in die PowerShell-Konsole kopiert werden um den Vorgang nachzuvollziehen.
CA, Root-Zertifikat, Certificate Authority
Das CA-Zertifikat erzeugen wir uns mit folgenden PowerShell-Code-Zeilen:
# Die TextExtension des CA-Zertifikats vorbereiten
$BasicConstraintsCA = "2.5.29.19={critical}{text}CA=1" # Basic Constraints: CA = True
$ExtendedKeyUsageCA = "2.5.29.37={text}" # Extended Key Usage:
$ExtendedKeyUsageCA += "1.3.6.1.5.5.7.3.1," # Server Authentication
$ExtendedKeyUsageCA += "1.3.6.1.5.5.7.3.2," # Client Authentication
$ExtendedKeyUsageCA += "1.3.6.1.5.5.7.3.3," # Code Signing
$ExtendedKeyUsageCA += "1.3.6.1.5.5.7.3.4," # Secure Email (SMIME)
$ExtendedKeyUsageCA += "1.3.6.1.5.5.7.3.8," # Timestamp Signing
$ExtendedKeyUsageCA += "1.3.6.1.4.1.311.20.2.2" # Smartcard Logon
# Ein CA-Zertifikat erzeugen, im Windows CertStore des Benutzers ablegen
$myCA = New-SelfSignedCertificate -Type Custom `
-Subject "CN=HITCo Certificate Authority - Demo-CA, OU=PKI, O=HITCo.at, C=AT" `
-KeyAlgorithm ECDSA_secp384r1 -HashAlgorithm SHA384 `
-TextExtension @( $BasicConstraintsCA, $ExtendedKeyUsageCA ) `
-KeyUsage CertSign, CRLSign, DigitalSignature `
-NotBefore "01.01.2026 12:00:00" -NotAfter "31.12.2040 12:00:00" `
-KeyExportPolicy Exportable -CertStoreLocation "Cert:\CurrentUser\My"
# Das Zertifikat inkl. Private Key in ein PFX = P12/PKCS12 File sichern
$myPassword = ConvertTo-SecureString -String 'myPassword' -Force -AsPlainText
$MyCaPfxFile = $MyCA | Export-PfxCertificate -FilePath C:\Temp\MyCA.pfx -Password $myPassword
# Das Zertifikat (ohne Private Key) in eine CRT-Datei exportieren
$myCAfile = $MyCA | Export-Certificate -FilePath C:\Temp\MyCA.crt -Type CERT
Abweichend von den von mir hier zusammengestellten Code-Zeilen ist für den jeweiligen konkreten Bedarf anzupassen: Die Subject-Strings und eventuell der Gültigkeitszeitraum.
Ich habe einen modernen ECDSA Algorithmus mit NIST P-384 Elliptic Curve gewählt. Wer lieber traditionell mit RSA arbeitet, kann die Parameter entsprechend anpassen.
Der relevante Teil diese Code-Zeilen liegt in der Zusammenstellung der BasicConstraints (das Zertifikat muss mit „CA = true“ ausgestellt werden), sowie in der Zusammenstellung der passenden Extended Key Usages, für welche das CA-Zertifikat sich anschließend eignen soll. Die meisten OIDs können der Microsoft Dokumentation entnommen werden, fehlendes lässt sich mit Recherche rasch ermitteln. Meine Zusammenstellung dürfte für die allermeisten UseCases (jedenfalls aber für die von mir hier nachfolgend skizzierten) geeignet sein.
Das exportierte MyCA.pfx enthält auch den Private-Key und dient als Backup der CA. Dieses gemeinsam mit dem für den Export gewählten Passwort sicher verwahren.
Für die Verteilung der CA dient die exportierte CRT-Datei des Zertifikats (ohne PrivateKey). Diese CRT-Datei kann nun auf allen Geräten auf denen diese getrustet werden soll importiert werden. Das erfolgt z.B. wie folgt: Entweder als Administrator in den Maschinen-Zertifikats-Store, oder als Benutzer in den User-Zertifikats-Store:
# a) CA tusten: Als Administrator in den Maschinen Store Vertrauenswürdige Stammzertifikate importieren:
Import-Certificate -FilePath "C:\Temp\MyCA.crt" -CertStoreLocation 'Cert:\LocalMachine\Root\'
# b) CA trusten: Alternativ als Benutzer (ohne Administrator-Rechte) in den User-Store:
Import-Certificate -FilePath "C:\Temp\MyCA.crt" -CertStoreLocation 'Cert:\CurrentUser\Root\'
Sichtprüfung des Root-CA-Zertifikats
Noch eine Sichtprüfung mittels Windows-Zertifikatsverwaltung:

Sowie noch eine optionale Sichtprüfung mittels OpenSSL:
# Sichtprüfung mit OpenSSL
openssl x509 -in "C:\Temp\MyCA.crt" -noout -text >"C:\Temp\MyCA.txt"
type "C:\Temp\MyCA.txt"
...
Signature Algorithm: ecdsa-with-SHA384
...
Validity
Not Before: Jan 1 10:00:00 2026 GMT
Not After : Dec 31 10:00:00 2040 GMT
Subject: C=AT, O=HITCo.at, OU=PKI, CN=HITCo Certificate Authority - Demo-CA
...
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication,
Code Signing, E-mail Protection, Time Stamping, Microsoft Smartcard Login
...
Wir haben somit ein modernes CA-Root-Zertifikat (Basic Constraints: CA = True) mit 14 Jahren Gültigkeit erstellt, welches sich in Folge zur Ausstellung all unserer angedachten Zertifikats-Verwendungszwecke eignet.
Code-Signing-Zertifikat
Wir stellen uns nun aus der soeben generierten Root-CA ein Authenticode-Signing-Zertifikat aus. Dieses dient der Signatur von Executables, Makro-Code, PowerShell-Scripts, Catalog-Files, u.v.m
# Das CA-Zertifikat für die Erstellung lokalisieren
$caSubject = "*HITCo Certificate Authority - Demo-CA*"
$caCert = Get-ChildItem -Path "Cert:\CurrentUser\My" | Where-Object { $_.Subject -like $caSubject } | Select-Object -First 1
# Die TextExtension des Code-Signing-Zertifikats vorbereiten
$BasicConstraints = "2.5.29.19={critical}{text}CA=0" # Basic Constraints: CA = false (Leaf-Certificate)
$ExtendedKeyUsageCodeSigning = "2.5.29.37={text}" # Extended Key Usage:
$ExtendedKeyUsageCodeSigning += "1.3.6.1.5.5.7.3.3" # Code Signing
# Zertifikat erstellen, mittels "Signer" wählt man das CA-Zertifikat, sodass es sich nicht um ein SelfSignedCertificate handelt
$myCodeSigningCert = New-SelfSignedCertificate -Type Custom `
-Subject "CN=HITCo Demo-Authenticode-Signer, OU=Dev-Department, O=HITCo.at, C=AT" `
-Signer $caCert -KeyAlgorithm ECDSA_secp384r1 -HashAlgorithm SHA384 `
-TextExtension @( $BasicConstraints, $ExtendedKeyUsageCodeSigning ) `
-KeyUsage DigitalSignature `
-NotBefore "01.01.2026 12:00:00" -NotAfter "31.12.2035 12:00:00" `
-KeyExportPolicy Exportable -CertStoreLocation "Cert:\CurrentUser\My"
# Das Zertifikat inkl. Private Key in ein PFX = P12/PKCS12 File sichern
$myPassword = ConvertTo-SecureString -String 'myPassword' -Force -AsPlainText
$myCertPFXfile = $myCodeSigningCert | Export-PfxCertificate -FilePath C:\Temp\MyCodeSigningCert.pfx -Password $myPassword
# Das Zertifikat (ohne Private Key) in eine CRT-Datei exportieren
$myCertfile = $myCodeSigningCert | Export-Certificate -FilePath C:\Temp\MyCodeSigningCert.crt -Type CERT
# Das Zertifikat eventuell als Trusted Publisher = Vertrauenswürdiger Herausgeber im Machine Store hinterlegen
Import-Certificate -FilePath "C:\Temp\MyCodeSigningCert.crt" -CertStoreLocation 'Cert:\LocalMachine\TrustedPublisher\'
Abweichend von den von mir hier zusammengestellten Code-Zeilen ist für den jeweiligen konkreten Bedarf anzupassen: Der Name des CA-Zertifikats, das zur Ausstellung verwendet werden soll, sowie das Subject des zu erstellenden Code-Signing-Zertifikats.
Der Import des Code-Signing-Zertifikats in den Trusted Publisher Store der Maschine ist unter Windows nur in bestimmten Szenarien nötig. Für das signieren von EXE-, DLL-, PowerShell- & Catalog-Files, etc … ist das in der Regel nicht erforderlich. Um aber zum Beispiel das Zertifikat zum Trusten für AppLocker-Policies zu verwenden, oder Treiber damit zu signieren ist dieser Schritt (optional) durchzuführen.
Werfen wir einen Blick auf dieses Zertifikat, Sichtprüfung:

TLS-WebServer Zertifikat mit Wildcard *.hitco.at
Nun stellen wir uns ein TLS-WebServer-Zertifikat mitWildcard-Subject-Alternative-Name aus.
# Das CA-Zertifikat für die Erstellung lokalisieren
$caSubject = "*HITCo Certificate Authority - Demo-CA*"
$caCert = Get-ChildItem -Path "Cert:\CurrentUser\My" | Where-Object { $_.Subject -like $caSubject } | Select-Object -First 1
# Die TextExtension des TLS-WebServer-Zertifikats vorbereiten
$BasicConstraints = "2.5.29.19={critical}{text}CA=0" # Basic Constraints: CA = false (Leaf-Certificate)
$ExtendedKeyUsageTLS = "2.5.29.37={text}" # Extended Key Usage:
$ExtendedKeyUsageTLS += "1.3.6.1.5.5.7.3.1," # Server Authentication
# Zertifikat erstellen, mittels "Signer" wählt man das CA-Zertifikat, sodass es sich nicht um ein SelfSignedCertificate handelt
$myServerCert = New-SelfSignedCertificate -Type Custom `
-Subject "CN=HITCo.at WebServer, OU=Server-Department, O=HITCo.at, C=AT" `
-DnsName "hitco.at", "*.hitco.at" `
-Signer $caCert -KeyAlgorithm ECDSA_secp384r1 -HashAlgorithm SHA384 `
-TextExtension @( $BasicConstraints, $ExtendedKeyUsageTLS ) `
-KeyUsage DigitalSignature, KeyEncipherment `
-NotBefore "01.01.2026 12:00:00" -NotAfter "31.12.2035 12:00:00" `
-KeyExportPolicy Exportable -CertStoreLocation "Cert:\CurrentUser\My"
# Das Zertifikat inkl. Private Key in ein PFX = P12/PKCS12 File sichern
$myPassword = ConvertTo-SecureString -String 'myPassword' -Force -AsPlainText
$myCertPFXfile = $myServerCert | Export-PfxCertificate -FilePath "C:\Temp\MyServerCert.pfx" -Password $myPassword
# Das Zertifikat (ohne Private Key) in eine CRT-Datei exportieren
$myCertfile = $myServerCert | Export-Certificate -FilePath "C:\Temp\MyServerCert.crt" -Type CERT
Abweichend von den von mir hier zusammengestellten Code-Zeilen ist für den jeweiligen konkreten Bedarf anzupassen: Der Name des CA-Zertifikats, das zur Ausstellung verwendet werden soll, sowie das Subject des neuen TLS-WebServer-Zertifikats und die Liste der Subject-Alternative-Names (DNSName).
Werfen wir einen Blick auf dieses Zertifikat, Sichtprüfung:

Benutzer-Zertifikat für E-Mail-Signatur/Verschlüsselung, TLS-Client-Authentifizierung, Smartcard-Anmeldung
Nun widmen wir uns der Ausstellung eines Benutzer-Zertifikats, welches sich nicht nur für die S/MIME Verschlüsselung und Signatur von E-Mails nutzen lassen soll, sondern auch zur TLS-Client-Authentifizierung gegenüber WebServern und zur Smartcard-Anmeldung z.B. an ein Windows-System verwendet werden kann.
# Das CA-Zertifikat für die Erstellung lokalisieren
$caSubject = "*HITCo Certificate Authority - Demo-CA*"
$caCert = Get-ChildItem -Path "Cert:\CurrentUser\My" | Where-Object { $_.Subject -like $caSubject } | Select-Object -First 1
# Die TextExtension des Benutzer-Zertifikats vorbereiten
$BasicConstraints = "2.5.29.19={critical}{text}CA=0" # Basic Constraints: CA = false (Leaf-Certificate)
$ExtendedKeyUsageUser = "2.5.29.37={text}" # Extended Key Usage:
$ExtendedKeyUsageUser += "1.3.6.1.5.5.7.3.2," # Client Authentication
$ExtendedKeyUsageUser += "1.3.6.1.5.5.7.3.4," # Secure Email (SMIME)
$ExtendedKeyUsageUser += "1.3.6.1.4.1.311.20.2.2" # Smartcard Logon
$SubjectAltNamesUser = "2.5.29.17={text}" # E-Mail-Addresses and UserPrincipalNames
$SubjectAltNamesUser += "email=max.mustermann@hitco.at&upn=max.mustermann@hitco.at"
# Zertifikat erstellen, mittels "Signer" wählt man das CA-Zertifikat, sodass es sich nicht um ein SelfSignedCertificate handelt
$myUserCert = New-SelfSignedCertificate -Type Custom `
-Subject "CN=Max Mustermann, OU=HR-Department, O=HITCo.at, C=AT" `
-Signer $caCert -KeyAlgorithm ECDSA_secp384r1 -HashAlgorithm SHA384 `
-TextExtension @( $BasicConstraints, $ExtendedKeyUsageUser, $SubjectAltNamesUser ) `
-KeyUsage DigitalSignature, KeyEncipherment, DataEncipherment `
-NotBefore "01.01.2026 12:00:00" -NotAfter "31.12.2035 12:00:00" `
-KeyExportPolicy Exportable -CertStoreLocation "Cert:\CurrentUser\My"
# Das Zertifikat inkl. Private Key in ein PFX = P12/PKCS12 File sichern
$myPassword = ConvertTo-SecureString -String 'myPassword' -Force -AsPlainText
$myCertPFXfile = $myUserCert | Export-PfxCertificate -FilePath "C:\Temp\MyUserCert.pfx" -Password $myPassword
# Das Zertifikat (ohne Private Key) in eine CRT-Datei exportieren
$myCertfile = $myUserCert | Export-Certificate -FilePath "C:\Temp\MyUserCert.crt" -Type CERT
Abweichend von den von mir hier zusammengestellten Code-Zeilen ist für den jeweiligen konkreten Bedarf anzupassen: Der Name des CA-Zertifikats, das zur Ausstellung verwendet werden soll, das Subject des neuen Benutzer-Zertifikats und die Liste der Subject-Alternative-Names (E-Mail-Adressen und eventuell der User-Principal-Name zur Domänen-Anmeldung).
Werfen wir einen Blick auf dieses Zertifikat, Sichtprüfung:

Test mit Thunderbird
Und noch ein abschließender Test der Nutzung des S/MIME-Zertifikats mittels Thunderbird. Geprüft wurde E-Mail-Verschlüsselung und Signatur. Hierzu muss zuerst das CA-Zertifikat in Thunderbird importiert und für den Verwendungszweck getrustet werden:

Anschließend kann das Benutzer-Zertifikat (PFX-Datei) in Thunderbird importiert, konfiguriert und benutzt werden. Das Resultat fällt positiv aus:

1 Comment