Authentisierung mit Clientzertifikaten

From
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Ziel des Seminarbeitrags war es, den Nutzen und die Nutzbarkeit von Clientzertifikaten zu untersuchen. Ferner sollte geprüft werden, ob und in welchem Rahmen sich Clientzertifikate am Modell der universitätsinstitutsübergreifenden Accountverwaltung verwenden lassen.

Passwörter

Das Konzept der Authentifizierung einer Person über geheimes Wissen (Passwort, PIN), das in der Erinnerung selbiger gespeichert ist, ist etabliert und durch verschiedene Ideen zur Wahl sicherer Passwörter verbessert worden. Nichtsdestotrotz gelangt das menschliche Gedächtnis aufgrund der Vielzahl von Zugangskonten, die eine Person heutzutage nutzt, sowie deren jeweils - im Idealfall - unterschiedlich gewählten Zugangsdaten, die durch die Gefahr eines Wörterbuchangriffs mittels schnellerer Rechentechnik eine immer größere Länge mit sich bringen müssen, an die Grenzen seiner Leistungsfähigkeit.

Aus diesem Grund ist es notwendig ein Medium größerer und konsistenterer Kapazität für die sichere Verwahrung von Identifikatoren zu verwenden.

Zertifikate

Zertifikate sind digitale Nachweise spezifischer Eigenschaften von Subjekten, welche vom Aussteller des Zertifikates beglaubigt werden. Überprüft werden kann nur die Integrität, d.h. die Korrektheit des Zertifikates im Sinne der Nicht-Modifizierung selbigens und die Authentizität, also die Echtheit des Urhebers, sofern man dessen Identität bereits verifiziert hat. Den De-facto-Standard in der heutigen Kommunikationswelt stellen hierfür Zertifikate nach X.509, deren Funktionsweise mittels einer Public-Key-Infrastruktur sichergestellt wird.

Client-Zertifikate

TLS-Handshake, Quelle: Wikipedia

Certificate Revocation List (CRL)

Um ungültige oder abgelaufene Zertifikate sicher ausschließen zu können, werden Certificate Revocation Lists geführt. Diese werden von der ausstellenden Certificate Authority betreut und signiert, so dass eine überprüfbare Sperrliste entsteht. Die CRL ist jeweils nur für einen bestimmten Zeitraum gültig und wird in festen Zeitabständen aktualisiert, dies soll vor Angriffen bei denen, z.B. dem Überprüfenden eine veraltete CRL untergeschoben wird, schützen.

Es ist jedoch zu beachten, dass eine CRL keine Aussage über die Gültigkeit sondern nur über die Ungültigkeit eines Zertifikates treffen kann.

Beispielimplementierung

In der Implementierung wurde eine Root Certificate Authority simuliert, welche Zertifikate an Intermediate-CAs ausstellt, welche daraufhin Benutzern mit den gewünschten Clientzertifikaten versorgen können. Der Nutzer muss lediglich das Zertifikat der RootCA und der clientzertifikataustellenden Intermediate-CA im Browser importiert haben, es muss also kein direktes Vertrauensverhältnis zwischen dem Client und anderen Intermediate-CAs bestehen, da diese anhand der Zertifikatskette die Authentizität des Clients verfizieren können.

Um die Funktion des Clientzertifikates zu überprüfen, wird für jeden Nutzer ein privater Ordner erstellt, auf den nur er mittels Authentisierung durch sein Zertifikat Zugriff besitzt.

Natürlich ist uns bewusst, dass jede signierende CA, die Vertrauen des Nutzers genießen soll, um einiges besser abgesichert werden muss, als es in dieser Implementierung der Fall ist. Es existieren diverse Frameworks für eine PKI auf dem Markt; leider ist nach der Recherche im Rahmen des Workshops keines davon kurzfristig für unsere Zwecke geeignet gewesen, womit wir auf eine Eigenimplementierung zurückgreifen mussten.

Serverkonfiguration

  • Apache mit PHP 5.x- und SSL-Modul
  • /etc/apache2/vhosts.d/00_default_ssl_vhost.conf
    • SSLCACertificateFile und SSLCARevocationPath auf das selbsterstelle Rootzertifikat und den Ordner, in welchem die Revocation Lists gespeichert werden, setzen
    • Wichtig: Apache muss mittels '/etc/init.d/apache2 restart' neugestartet werden

Um bei Zugriff auf einen Ordner eine Zugangskontrolle mittels Clientzertifikat zu erreichen, genügt es eine .htaccess-Datei mit folgendem Inhalt zu erstellen:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

SSLVerifyClient require
SSLVerifyDepth 10
SSLOptions +ExportCertData +StdEnvVars

Hierbei werden die übermittelten Zertifikatsdaten an das aufgerufene PHP-Skript als Server-Variable weitergereicht, womit man diese dann verifizieren und den Zugriff erlauben kann.

Erstelllung einer CA

Beispielhaftes Formular zur Erstellung einer Root-CA
Beispielhaftes Formular zur Erstellung einer Intermediate-CA

Für viele der Befehle, die zur Erstellung notwendig sind, kann das OpenSSL-PHP-Modul verwendet werden. Jedoch bietet das Modul u.a. für die Erstellung von CAs keine Schnittstelle, weshalb wir in diesen Fällen auf Shell-Befehle zurückgegriffen haben, welche wir aus PHP heraus mit shell_exec() aufrufen.

Jedes signierte Zertifikat einer CA hat seine eigene Seriennummer und wird ein Zertifikat zurückgerufen, dann wird ein Counter hochgezählt. Dafür und für das Signieren von Clientzertifikaten sind im Ordner der CA (oder wie in der openssl.cnf festgelegt) die folgende Dateien und Ordner notwendig:

mkdir(__CA_DIR.'/certs');
mkdir(__CA_DIR.'/keys');
mkdir(__CA_DIR.'/crl');
file_put_contents(__CA_DIR.'/serial', '00');
file_put_contents(__CA_DIR.'/crlnumber', '00');

Die meisten PHP-OpenSSL-Befehle benötigen als einen Parameter ein Array, in welchem diverse Einstellungen vorgegeben sind. In den Ausschnitten, die wir hier zeigen, heißt dieses Array $configargs und setzt sich wie folgt zusammen:

$configargs = array(
	'digest_alg' => $digest_alg,
	'x509_extensions' => $x509_extension,
	'req_extensions'   => $req_extension,
	'private_key_bits' => (int) $private_key_bits,
	'private_key_type' => OPENSSL_KEYTYPE_RSA, // currently only RSA works
	'encrypt_key' => true,
	'encrypt_key_cipher' => (int) $encrypt_key_cipher,
	'config' => $config
);

Informationen zur genauen Bedeutung der Optionen können in der PHP-Dokumentation einzelner Befehle nachgelesen werden.

Zuerst muss für die CA ein Schlüsselpaar erstellt werden. Dazu wird mit openssl_pkey_new ein privater Schlüssel generiert und anschließend via openssl_pkey_export mit einem Passwort versehen. Der öffentliche Schlüssel kann separat mit openssl_pkey_get_details oder mit openssl_pkey_get_public einfach ausgelesen werden.

// Create the keypair
$reqKey = openssl_pkey_new($configargs);

// Get private key (and encrypt it if the password is != NULL)
openssl_pkey_export($reqKey, $privateKey, $password, $configargs);

// save private key
file_put_contents($dir.'/ca.key', $privateKey);

// Get public key
$publicKey = openssl_pkey_get_details($reqKey);
$publicKey = $publicKey["key"];

Mit dem Schlüsselpaar ($reqKey) und den Informationen aus dem Formular (das Array $dn) kann nun ein CSR erstellt (openssl_csr_new) und abgespeichert werden (openssl_csr_export).

// create new CSR
$reqCSR = openssl_csr_new($dn, $reqKey, $configargs);

// save CSR
openssl_csr_export($reqCSR, $csr);
file_put_contents($dir.'/ca.csr', $csr);


Erstellung der Root-CA

Zum Generieren des Root-CA-Zertifikats wird der Befehl openssl_csr_sign verwendet. Als zweiten Parameter erwartet die Funktion ein CA-Zertifikat, wird jedoch NULL übergeben, wird ein selbstsigniertes Zertifikat erstellt. Als dritter Parameter muss der zum CA-Zertifikat des zweiten Parameters passende private Schlüssel übergeben werden, was in diesem Fall der neu generierte Schlüssel der Root-CA ist. Mit openssl_x509_export exportiert und anschließend gespeichert werden.

// sign certificate
$reqCert = openssl_csr_sign($reqCSR, NULL, $reqKey, $days, $configargs, $serial);

// save certificate
openssl_x509_export($reqCert, $cert);
file_put_contents($dir.'/ca.crt', $cert);

Erstellung der Intermediate-CAs

Das so signierte Zertifikat wird im "certs"-Ordner der Root-CA unter der Seriennummer abgelegt, weshalb die Seriennummer vor dem Signieren ausgelesen und in einer Variable abgespeichert wird.

// save the serial because the crt will be named based on it
$serial = str_replace("\n", '', file_get_contents('rootCA/serial'));

Mit folgendem Shell-Befehl wird der CSR, welcher sich in "$dir/ca.csr" befindet von der Root-CA signiert.

$command = "/usr/bin/openssl ca -config 'rootCA/openssl.cnf' -days ".$days." -notext -batch -key '".$password."' -in ".$dir.'/ca.csr';
$output = shell_exec($command);

Dabei ist $password das Passwort womit der private Schlüssel der Root-CA gesichert ist und $days die Anzahl der Tage, welche das signierte Zertifikat gültig sein soll.

Das signierte Zertifikat kann nun in den Ordner der Intermediate-CA kopiert werden.

// cp the crt to the intermediate CA's folder
file_put_contents($dir.'/ca.crt', file_get_contents('rootCA/certs/'.$serial.'.pem'));

// add certificate chain
file_put_contents($dir.'/ca.crt', file_get_contents('rootCA/ca.crt'), FILE_APPEND);

Für die Erstellung der Zertifikatskette reicht es, wenn man das Root-CA-Zertifikat an das Intermediate-CA-Zertifikat anhängt.

Erstellung eines Clientzertifikats

Beispielhaftes Formular zur Erstellung eines SPKAC unter der Verwendung des <keygen>-Tags in Opera

Certificate Signing Request (CSR)

Damit ein Clientzertifikat von einer CA erstellt und signiert werden kann, muss der Nutzer einen Certificate Signing Request an die CA schicken, welche dann – nach Überprüfung der Angaben und Authentizität – dem Nutzer ein signiertes Zertifikat aushändigen kann.

Für einen CSR muss der Nutzer typischerweise die Informationen:

  • Allgemeiner Name (CN)
  • Organisation (O)
  • Organisationseinheit (OU)
  • Email-Adresse (E)
  • Ort (L)
  • Staat/Bundesland (ST)
  • Land (C) angeben.

Signed Public Key and Challenge (SPKAC)

SPKAC ist ein von vielen Browsern unterstütztes Format um einen CSR und einen öffentlichen Schlüssel zu übermitteln. Hierbei wird der <keygen>-Tag verwendet, um clientseitig das Schlüsselpaar zu generieren. Die CA kann nun mit den Daten und dem öffentlichen Schlüssel des Nutzers eine .spkac-Datei erstellen welche folgendes Format hat:

  SPKAC=Schlüssel
  CN=Allgemeiner Name
  emailAddress=Email-Adresse
  0.OU=Organisationseinheit
  organizationName=Organisation
  countryName=Land
  stateOrProvinceName=Staat/Bundesland
  localityName=Ort

Dieser SPKAC kann dann mit folgendem Befehl von der CA signiert werden:

  $command = "/usr/bin/openssl ca -config '".$dir."/openssl.cnf'";
  $command .= " -days ".$row['VALIDDAYS'];
  $command .= " -notext -batch -key '".$password."'";
  $command .= " -spkac ".$dir.'/spkacs/'.$RID.'.spkac';
  $output = shell_exec($command);

Probleme

Fehlende Benutzerakzeptanz

Mögen Clientzertifikate einmal eingerichtet an einem Rechner funktionieren, so ist der effektive Nutzen in einer Welt, in der Ubiquitous Computing immer mehr zur Realität wird, geringer. Nutzer besitzen diverse Plattformen, Konten und Devices, die je eine eigene Konfiguration benötigen. Während eine Passwort-Authentifizierung mittels Gehirn oder einem Post-It unter der Tastatur portabel ist, benötigt man für den Transport des Zertifikats ein elektronisches Medium, welches besonders gesichert sein muss. Sogenannte Smartcards lösen dieses Problem, sind allerdings leider auch mangels Lesegeräten noch wenig verbreitet.

Handhabungsweise verschiedener Browser

Im Test hat sich gezeigt, dass verschiedene Browser unterschiedlich ausführliche Informationen an den Server übermitteln. So hat Firefox nur das erste Glied der Zertifikatskette übertragen, wohingegen Opera dem Server die komplette Kette bereitstellt. Dies ist dahingehend ein Problem, dass in unserem Beispiel-Setup mit Firefox nicht auf das Wurzelzertifikat überprüft werden konnte. In dem möglichen Anwendungsszenario müsste in dem Fall die Zertifizierungsstelle eines Instituts direkt den Zertifizierungsstellen anderer Institute vertrauen, sollte sich ein Benutzer mit einem Clientzertifikat authentifizieren wollen. Bei den von Opera übertragenen Daten hingegen würde eine Überprüfung auf die Wurzelzertifizierungsstelle der HU ausreichen.

Quellen

RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2

RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile

[1] Verwendung des <keygen>-Tags mit PHP