1 Standards

1.1 Der X.509-Standard

 Wikipedia: X.509

Spricht man heute über Zertifikate und PKI, so meint man meist den Standard X.509v3. Viele Details dazu findet man beispielsweise auf der oben verlinkten Seite von Wikipedia.

Wichtig für das Verständnis sind die Ziele dieses von der Internationale Fernmeldeunion ITU-T im Jahre 1998 festgelegten Standards, die da wären

- technisch offen
- herstellerunabhängig
- plattformunabhängig
- erweiterbar
- Das X.509 Zertifikat besitzt einen öffentlichen und einen privaten Schlüssel. Solange der private Schlüssel nicht an Dritte weitergegeben wird, identifiziert dieser den rechtmäßigen Zertifikatsinhaber eindeutig. 

Ich hatte in den letzten Jahren mit verschiedenen Herstellern und Anbietern von Sicherheitslösungen zu tun. Man möchte es nicht glauben, aber etliche dieser Hersteller - darunter auch große Namen -, versuchen Lösungen abseits dieses Standards zu verkaufen. Die Pro-Argumente lauten dann, daß man sich mit ihrer Lösung die Kosten einer PKI-Infrastruktur sparen kann. Die Nachteile bestehen allerdings in der Herstellerabhängigkeit, schwierigere Erweiterbarkeit der Lösung, Schwierigkeiten bei Plattformwechseln, etwa win2003 auf win2008. Schließlich verwendet man keinen anerkannten Sicherheitsstandard, auf den man sich bei Überprüfungen und Audits beziehen kann.


Beispiel 1: Bestimmen des Typs der Zertifikate im currentuser/ My - Store

$cert=@()
$Cert=(GCI cert:/currentuser/my)
$Cert | format-table subject,
@{
Label="Typ"
Expression={$_.getformat()}}  -autosize

#Ausgabe

Subject                                Typ
-------                                ---
CN=Root Agency                         X509
CN=Dom1-DC1-RootCA, DC=Dom1, DC=intern X509
CN=Dom1-RootCA, DC=Dom1, DC=intern     X509
CN=Dom1-CA01, DC=Dom1, DC=intern       X509

- Die Formatierung der Tabelle ist im  Kapitel 3,1 - Formatierung des Outputs näher beschrieben

- Die Behandlung des Zertifikatsproviders erfolgt im Kapitel Handling von Zertifikaten


Ein User oder Computer, der sich X.509-zertifikatsgestützt bei einem anderen Rechner authentisiert, legt dem Zielrechner sein Zertifikat vor. Der Zielrechner überpüft nun anhand verschiedener Kriterien, ob er diesem Zertifikat vertrauen kann.

Die Kriterien lauten

a) vertraue ich generell der Certification Authority (CA), die dieses Zertifikat ausgestellt hat (Zertifikatskette)
b) wurde dieses Zertifikat wirklich von dieser CA ausgestellt
c) Liegt das heutige Datum im Gültigkeitszeitraum  (von ... bis ...)
d) ist der Absender wirklich derjenige, der er vorgibt zu sein (öffentlicher Schlüssel/ privater Schlüssel)
e) ist das Zertifikat gesperrt (Sperrliste)

Erst wenn all diese Punkte positiv geprüft wurden, vertraut der Zielrechner dem Zertifikat und damit seinem Besitzer und Absender. In den folgenden Kapiteln wird es unter anderem darum gehen, diese Fragen und Kriterien per Powershell zu überprüfen. Wiesooft erhält man als Nebeneffekt zum Skripten häufig tiefe Einblicke in das Thema, da man die Thematik erstmal gründlich verstanden haben muss, bevor ein vernünftiges Skript entwickelt werden kann.

Für mehr Hintergrundwissen besorgt euch bitte entsprechende Literatur wie das schon an anderer Stelle erwähnte Werk von Brian Komar "Windows Server 2008 - PKI and Certificate Security" aus dem MS-Press Verlag.

1.2 Public-Key Cryptography Standards (PKCS)

 Wikipedia: PKCS

 RSA Laboratories: Public-Key Cryptography Standards (PKCS)

 

 

2 CertificateLocation/ CertificateStore

Zertifikate werden lokal in einem bestimmten Zertifikatsstore (=Storename) gespeichert. die Stores können sich an zwei Speicherorten (=Storelocation) befinden. Die beiden Locations sind "CurrentUser" und "LocalMachine", entsprechend ihrem physikalischen Speicherort in der Registry:

"HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates\"

oder für die LocalMaschine

"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\"

Auf Zertifikate unter "CurrentUser" kann ein Anwender mit seinem Kontext zugreifen, auf Zertifikate unter "LocalMachine" greift das System mit dem Systemkonto zu.


In der MMC im SnapIn "Zertifikate" sind diese Stores entweder in den Storelocations "Zertifikate - Aktueller Benutzer" oder "Zertifikate (Lokaler Compute)" zu finden. Per PS-Skript können auch noch weitere Stores angelegt werden. (siehe Beispiel 3)


Beispiel 1: Aufzählung der StoreLocations

[system.enum]::getnames([System.Security.Cryptography.X509Certificates.StoreLocation])

$storelocation = [System.Security.Cryptography.X509Certificates.StoreLocation]
[system.enum]::getnames($storelocation)

#Ausgabe

CurrentUser
LocalMachine

 

Beispiel 2: Aufzählung der default Storenames (Windows 7 Ultimate)

[system.enum]::getnames([system.security.cryptography.x509certificates.storename])


 MSDN: Store Name Enumeration

Membername  

Beschreibung

AddressBook 

Der X.509-Zertifikatsspeicher für andere Benutzer.

AuthRoot 

Der X.509-Zertifikatsspeicher für Zertifizierungsstellen von Drittanbietern.

CertificateAuthority 

Der X.509-Zertifikatsspeicher für Zwischenzertifizierungsstellen.

Disallowed 

Der X.509-Zertifikatsspeicher für widerrufene Zertifikate.

My 

Der X.509-Zertifikatsspeicher für persönliche Zertifikate.

Root 

Der X.509-Zertifikatsspeicher für vertrauenswürdige Stammzertifizierungsstellen.

TrustedPeople 

Der X.509-Zertifikatsspeicher für direkt vertrauenswürdige Personen und Ressourcen.

TrustedPublisher 

Der X.509-Zertifikatsspeicher für direkt vertrauenswürdige Herausgeber.

Wichtig für das Verständnis ist, daß im My-Store Zertifikate mit privatem Schlüssel liegen. In den anderen Stores liegen in erster Linie signierte Zertifikate, die keinen privaten Schlüssel enthalten und für die Verifizierung der Zertifkatskette erforderlich sind.

 

Beispiel 3: Anzeige aller vorhandenen Stores

Get-Childitem -path cert:\CurrentUser -name

#alternativ mit QAD
#Get-QADLocalCertificateStore -StoreLocation CurrentUser | Format-Table -AutoSize

#Ausgabe #gekürzt

Name : SmartCardRoot
Name : UserDS
Name : AuthRoot
...


Beispiel 4a: Anlage eines zusätzlichen Zertifikatsstores für den "aktuellen Benutzer"
über .Net

$storename = "TestUserStore01"
$storelocation = "Currentuser"

$store = New-Object System.Security.Cryptography.X509Certificates.X509Store($storename,$storelocation)
$store.Open("ReadWrite")


Beispiel 4b: Anlage eines zusätzlichen Zertifikatsstores für den "lokalen Computer" über .Net

$storename = "TestMachineStore01"
$storelocation = "Localmachine"

$store = New-Object System.Security.Cryptography.X509Certificates.X509Store($storename,$storelocation)
$store.Open("ReadWrite")


Tipp: Man kann im Zertifikatssnapin der MMC zwischen den Stores Zertifikate per rechter Maustaste oder Drag&Drop kopieren und verschieben, um beispielsweise zu Troubleshooten oder Zertifikate zu testen. Dazu sind solche zusätzlichen leeren Stores recht nützlich.


3 Zertifikate in Dateien

3.1 Dateiformate für Zertifikate

Eine sehr gute Erklärung zu den gängigen Fileformaten für Zertifikatsdateien bietet wieder die Technet unter  Technet: Zertifikatdateiformate

"Von den Import- und Exportvorgängen für Zertifikate werden vier Dateiformate unterstützt. Wählen Sie das Format aus, das Ihren speziellen Anforderungen entspricht.

  • Privater Informationsaustausch (PKCS #12)

    Das PFX-Format (Personal Information Exchange, privater Informationsaustausch), das auch als PKCS #12 bezeichnet wird, ermöglicht die sichere Speicherung von Zertifikaten, privaten Schlüsseln und allen Zertifikaten in einem Zertifizierungspfad.

    Das PKCS #12-Format kann als einziges Dateiformat zum Exportieren eines Zertifikats und dessen privatem Schlüssel verwendet werden.

  • Syntaxstandard kryptografischer Meldungen (PKCS #7)

    Das PKCS #7-Format unterstützt die Speicherung von Zertifikaten und allen Zertifikaten im Zertifizierungspfad.

  • DER-codiert-binär X.509

    Das DER-Format (Distinguished Encoding Rules) unterstützt die Speicherung eines einzelnen Zertifikats. Der private Schlüssel oder der Zertifizierungspfad kann mit diesem Format nicht gespeichert werden.

  • Base64-codiertes X.509

    Das Base64-Format unterstützt die Speicherung eines einzelnen Zertifikats. Der private Schlüssel oder der Zertifizierungspfad kann mit diesem Format nicht gespeichert werden."


3.2 ByteArrays

Da beim Export- und Import von Zertifikaten viel mit ByteArrays gearbeitet wird, will ich hier etwas näher auf diesen Datentyp eingehen.

Sehr gut beschrieben sind ByteArrays in diesem Blog-Artikel:
Sans - Windows Security Blog:  PowerShell Byte Array And Hex Functions
In die Tiefe dieses Artikels werde ich hier bei Weitem nicht vorstoßen!


Manchmal muß man Dateien nicht Wort für Wort und Zeile für Zeile einlesen, sondern binär Byte für Byte. In meinem Fall benötige ich diese Funktionalität für den Umgang mit in Dateien gespeicherten Zertifikaten, wie im Kapitel  Zertifikate - Handling von Zertifikaten an Beispiel 1a: "Exportieren eines Zertifikats in eine pfx-Datei (Klasse X509ContentType)" gezeigt wird.

Aber auch für die genaue Analyse von Dateien kann ein byteweiser-Import hilfreich sein.

Beispiel 1: Drei Methoden eine Zertifikatsdatei in ein ByteArray einzulesen

$filepath="c:\mycerts\test.cer"

#Methode 1: get-content
[byte[]] $data = get-content -encoding byte -path $filepath
$data

#Methode 2: .Net-Klasse File
[byte[]] $data=[System.IO.File]::ReadAllBytes($filePath)
$data

#Methode 3: .Net-Klasse Filestream
$FileStream = New-Object System.IO.FileStream ($filePath,[System.IO.FileMode]::Open,[System.IO.FileAccess]::read)
[int]$size = [math]::truncate($filestream.Length)
[byte[]] $data = new-object byte[] $size
$filestream.Read($data, 0, $size)
$filestream.Close()
$data

#identische Ausgabe für alle Methoden
80
102
108
115
79
101
...

"[byte[]] $data" ist die gleichwertige Kurzform von "[system.byte[]] $data"

Zu Methode 1)
Das cmdlet "get-content" eignet sich für den Import kleinerer Dateien bis etwa 200 kb. Bei größeren Dateien sollte man aus Performancegründen auf die .Net Methoden ausweichen.

Zu Methode 2)
MSDN:  System.IO File Class

Zu Methode 3)
MSDN:  FileStream.FileStream(String, FileMode, FileAccess) Constructor
MSDN:  FileStream.Read Method


Beispiel 2: Ein Zertifikat aus dem My-Store in ein Bytearray exportieren und in einer Datei speichern

$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","Currentuser")
$store.Open("ReadOnly")
$Cert=($store.certificates)[0]
# identisch zu: $cert = (dir cert:\currentuser\my)[0]

$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::pfx
$pass = ConvertTo-SecureString "Hurra" -AsPlainText -Force
[system.byte[]] $data = $cert.export($type, $pass) #siehe Export-Methode unten
$data

[System.IO.File]::WriteAllBytes("c:\mycerts\file.pfx", $bytes)

#Ausgabe
48
130
6
170
2
...

- die Exportmethode der X509Certificate-Klasse exportiert ein Zertifikat in ein ByteArray siehe MSDN:  X509Certificate.Export Method (X509ContentType, SecureString)

- die möglichen Werte für X509ContentType findet man hier: MSDN:  X509ContentType Enumeration

- die Methode WriteAllBytes der Klasse "System.IO.File" schreibt alle Bytes in eine Datei  MSDN:  File.WriteAllBytes-Methode