« Security/Services/PKIWithManageCA » : différence entre les versions
Aucun résumé des modifications |
|||
| (2 versions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 42 : | Ligne 42 : | ||
manageCA est un script permettant de déployer et de gérer une PKI avec un certificat racine auto-signé. | manageCA est un script permettant de déployer et de gérer une PKI avec un certificat racine auto-signé. | ||
Il est disponible sur [https://github.com/didier13150/manageCA github] | |||
Comme on peut le voir en appelant l'option -h (help), on peut spécifier au démarrage du script le nom de la PKI, son emplacement, ainsi que le fichier de configuration du script. | Comme on peut le voir en appelant l'option -h (help), on peut spécifier au démarrage du script le nom de la PKI, son emplacement, ainsi que le fichier de configuration du script. | ||
| Ligne 138 : | Ligne 140 : | ||
On créera ensuite nos certificats (avec l'extension ocsp incluse): | On créera ensuite nos certificats (avec l'extension ocsp incluse): | ||
* un certificat server où le nom sera celui du nom d'hôte pleinement qualifiés (FQDN) | * un certificat server où le nom sera celui du nom d'hôte pleinement qualifiés (FQDN) pour le serveur Apache | ||
<pre> | <pre> | ||
----------------------------------------------------------------- | ----------------------------------------------------------------- | ||
| Ligne 200 : | Ligne 202 : | ||
</pre> | </pre> | ||
* un certificat ocsp où le nom sera ocspd | * un certificat ocsp où le nom sera ocspd (le démon qui fait tourner notre répondeur) | ||
<pre> | <pre> | ||
----------------------------------------------------------------- | ----------------------------------------------------------------- | ||
| Ligne 256 : | Ligne 258 : | ||
Press [enter] to continue | Press [enter] to continue | ||
</pre> | </pre> | ||
* un | * un ou plusieurs certificats client où le nom sera celui de l'utilisateur. | ||
<pre> | <pre> | ||
----------------------------------------------------------------- | ----------------------------------------------------------------- | ||
| Ligne 317 : | Ligne 319 : | ||
Press [enter] to continue | Press [enter] to continue | ||
</pre> | </pre> | ||
* un certificat web associé à | * un certificat web associé à chaque client | ||
<pre> | <pre> | ||
----------------------------------------------------------------- | ----------------------------------------------------------------- | ||
| Ligne 338 : | Ligne 340 : | ||
==== Configuration d'apache ==== | ==== Configuration d'apache ==== | ||
Dans le fichier ssl.conf | Dans le fichier ssl.conf, il faut | ||
<syntaxhighlight lang="apache"> | |||
SSLCertificateFile /etc/pki/httpd/certs/didier.b2pweb.com.crt | |||
SSLCertificateKeyFile /etc/pki/httpd/private/didier.b2pweb.com.key | |||
SSLCertificateChainFile /etc/pki/httpd/httpdca.crt | |||
SSLCACertificateFile /etc/pki/httpd/httpdca.crt | |||
SSLVerifyDepth 1 | |||
</syntaxhighlight> | |||
Ensuite au choix, on passe directement par la CRL | |||
<syntaxhighlight lang="apache"> | |||
# SSLCARevocationCheck can be | |||
# leaf: limits the checks to the end-entity cert | |||
# chain: CRL checks are applied to all certificates in the chain | |||
SSLCARevocationCheck chain | |||
SSLCARevocationPath /etc/pki/httpd/crl/ | |||
</syntaxhighlight> | |||
Ou par le répondeur OCSP | |||
<syntaxhighlight lang="apache"> | |||
SSLOCSPEnable on | |||
SSLOCSPDefaultResponder http://didier.b2pweb.com:2560 | |||
SSLOCSPOverrideResponder on | |||
#SSLOCSPResponderTimeout 10 | |||
</syntaxhighlight> | |||
La directive suivante est à ajouter pour obliger le client à présenter un certificat valide au serveur sous peine de ne pas avoir l'accès autorisé. | |||
< | elle peut-être mise à la définition de répertoire, de location, de vhost ou dans le fichier ssl.conf pour le faire d'une manière globale. | ||
<syntaxhighlight lang="apache"> | |||
SSLVerifyClient require | |||
</ | </syntaxhighlight> | ||
==== Installation du répondeur OCSP ==== | ==== Installation du répondeur OCSP ==== | ||
Voir la page dédiée au [[Services/OCSP| | Voir la page dédiée au [[Services/OCSP | Répondeur OCSP]] | ||
==== Tâche planifiée de régénération de la CRL ==== | |||
Dans le crontab de root | |||
# Regen CRL list | |||
15 0 * * * cd /etc/pki/httpd && openssl ca -gencrl -config ssl.cnf -out crl/httpdca.crl | |||
==== Intégration sur chaque poste client de son certificat web ==== | |||
== Utilisation de certificats avec du code PHP == | |||
Il n'est pas possible de rediriger une mauvaise connexion vers une erreur 403 d'Apache. On va donc la simuler. | |||
D'une manière générale, le login est récupérer par PHP dans la variable {{class|<nowiki>$_SERVER['PHP_AUTH_USER']</nowiki>}}, que ce soit par une authentification de type htacccess ou autre. | |||
Pour faire correspondre cette variable avec le CN du certificat client, Il faut rajouter dans la définition du répertoire/vhost/fichier | |||
<syntaxhighlight lang="apache"> | |||
SSLUserName SSL_CLIENT_S_DN_CN | |||
</syntaxhighlight> | |||
=== Code source === | |||
==== définition de l'alias pour Apache ==== | |||
<syntaxhighlight lang="apache"> | |||
Alias /testca /home/didier/public/www/testca | |||
<Directory /home/didier/public/www/testca/ > | |||
Options +MultiViews | |||
<IfModule mod_authz_core.c> | |||
# Apache 2.4 | |||
<RequireAny> | |||
Require ip 127.0.0.1 | |||
Require ip ::1 | |||
Require ip 192.168.0.0/24 | |||
Require ip 10.8.0.0/24 | |||
</RequireAny> | |||
</IfModule> | |||
<IfModule !mod_authz_core.c> | |||
# Apache 2.2 | |||
Order Deny,Allow | |||
Deny from All | |||
Allow from 127.0.0.1 | |||
Allow from ::1 | |||
Allow from 192.168.0.0/24 | |||
Allow from 10.8.0.0/24 | |||
</IfModule> | |||
AllowOverride None | |||
SSLVerifyClient optional | |||
# SSLOptions +ExportCertData | |||
SSLUserName SSL_CLIENT_S_DN_CN | |||
RewriteEngine On | |||
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f | |||
RewriteRule .*favicon\.ico$ /var/www/html/favicon.ico [L] | |||
RewriteRule .*robots\.txt$ /var/www/html/robots.txt [L] | |||
RewriteCond %{HTTPS} off | |||
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} | |||
</Directory> | |||
</syntaxhighlight > | |||
* Le certificat est optionnel pour se connecter au site. | |||
* Le champs '''SSL_CLIENT_S_DN_CN''' du certificat va correspondre à '''PHP_AUTH_USER''', qui est le champs login par défaut. | |||
* Le traffic HTTP est rediriger vers HTTPS | |||
==== Fichier index.php ==== | |||
<syntaxhighlight lang="php"> | |||
<?php | |||
function return_error() { | |||
header('HTTP/1.1 403 Forbidden'); | |||
include( "403.php" ); | |||
exit; | |||
} | |||
$certstatus = "critical"; | |||
if ( isset( $_SERVER['SSL_CLIENT_VERIFY'] ) && ! empty ( $_SERVER['SSL_CLIENT_VERIFY'] ) ) { | |||
$certverify = $_SERVER['SSL_CLIENT_VERIFY']; | |||
if ( $certverify == 'SUCCESS' ) { | |||
$certstatus = "ok"; | |||
} | |||
else { | |||
return_error(); | |||
} | |||
} | |||
else { | |||
return_error(); | |||
} | |||
?> | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<title>Test</title> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<style> | |||
th, td, table { | |||
border:1px black solid; | |||
border-collapse:collapse; | |||
padding:5px; | |||
text-align:left; | |||
} | |||
th { background-color:lightgrey;text-shadow: 0.1em 0.1em 0.2em white;} | |||
table{margin:10px 0;} | |||
.critical { color:red; } | |||
.warning { color:orange; } | |||
.ok { color: green; } | |||
.ok, .warning, .critical { font-weight:bold; } | |||
.hidden { display:none; } | |||
.button { | |||
padding:3px 10px; | |||
background-color:lightgrey; | |||
color:black; | |||
margin:15px 0; | |||
border:1px grey solid; | |||
border-radius:4px; | |||
text-shadow: 0.1em 0.1em 0.2em white; | |||
font-weight:bold; | |||
} | |||
.pre { | |||
white-space:pre; | |||
font-family: Monospace; | |||
border:1px black solid; | |||
padding:5px; | |||
margin:15px 0; | |||
} | |||
</style> | |||
<script> | |||
function toggleVisibility(id) { | |||
if (document.getElementById(id).style.display == "block") { | |||
document.getElementById(id).style.display = "none"; | |||
} | |||
else { | |||
document.getElementById(id).style.display = "block"; | |||
} | |||
} | |||
</script> | |||
</head> | |||
<body> | |||
<h1>Accès autorisé</h1> | |||
<?php if( isset ($_SERVER['PHP_AUTH_USER'] ) && ! empty ( $_SERVER['PHP_AUTH_USER'] ) ):?> | |||
<h2>Login: <?php echo $_SERVER['PHP_AUTH_USER'];?></td></h2> | |||
<?php endif;?> | |||
<table> | |||
<tr> | |||
<th>Clé de $_SERVER</th> | |||
<th>Valeur</th> | |||
<th>Commentaires</th> | |||
</tr> | |||
<tr> | |||
<td>SSL_CLIENT_VERIFY</td> | |||
<td><?php echo "<span class=\"$certstatus\">$certverify</span>";?></td> | |||
<td>Client utilisant un certificat valide si égal à SUCCESS</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_CLIENT_S_DN_CN</td> | |||
<td><?php echo $_SERVER['SSL_CLIENT_S_DN_CN'];?></td> | |||
<td>Utilisateur (CN)</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_CLIENT_S_DN_Email</td> | |||
<td><?php echo $_SERVER['SSL_CLIENT_S_DN_Email'];?></td> | |||
<td>Email</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_SERVER_S_DN_C</td> | |||
<td><?php echo $_SERVER['SSL_SERVER_S_DN_C'];?></td> | |||
<td>Code pays</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_SERVER_S_DN_ST</td> | |||
<td><?php echo $_SERVER['SSL_SERVER_S_DN_ST'];?></td> | |||
<td>Etat ou région</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_SERVER_S_DN_O</td> | |||
<td><?php echo $_SERVER['SSL_SERVER_S_DN_O'];?></td> | |||
<td>Organisation</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_CLIENT_V_START</td> | |||
<td><?php echo $_SERVER['SSL_CLIENT_V_START'];?></td> | |||
<td>Date de début de validité du certificat</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_CLIENT_V_END</td> | |||
<td><?php echo $_SERVER['SSL_CLIENT_V_END'];?></td> | |||
<td>Date de fin de validité du certificat</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_CLIENT_V_REMAIN</td> | |||
<td><?php echo $_SERVER['SSL_CLIENT_V_REMAIN'];?> jours</td> | |||
<td>Nombre de jours de validité restants</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_CIPHER</td> | |||
<td><?php echo $_SERVER['SSL_CIPHER'];?></td> | |||
<td>Cipher utilisé</td> | |||
</tr> | |||
<tr> | |||
<td>SSL_PROTOCOL</td> | |||
<td><?php echo $_SERVER['SSL_PROTOCOL'];?></td> | |||
<td>Protocole SSL</td> | |||
</tr> | |||
</table> | |||
<div><a href="#" onclick="javascript:toggleVisibility('debug');" class="button">Debug</a></div> | |||
<div id="debug" class="pre hidden"><?php var_dump( $_SERVER );?></div> | |||
</body> | |||
</html> | |||
</syntaxhighlight> | |||
==== Fichier 403.php ==== | |||
C'est celui qui émule une erreur 403 d'Apache. | |||
<syntaxhighlight lang="php"> | |||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> | |||
<html><head> | |||
<title>403 Forbidden</title> | |||
</head><body> | |||
<h1>Forbidden</h1> | |||
<p>You don't have permission to access <?php echo $_SERVER["REQUEST_URI"];?> | |||
on this server.</p> | |||
</body></html> | |||
</syntaxhighlight> | |||
Dernière version du 12 juillet 2013 à 09:16
Définition
Une infrastructure à clés publiques (Public Key Infrastructure in english), est un ensemble de composants physiques (des ordinateurs, des équipements cryptographiques logiciels ou matériel type Hardware Security Module (HSM) ou encore des cartes à puces), de procédures humaines (vérifications, validation) et de logiciels (système et application) en vue de gérer le cycle de vie des certificats numériques ou certificats électroniques.
Une infrastructure à clés publiques délivre un ensemble de services pour le compte de ses utilisateurs.
En résumé, ces services sont les suivants :
- enregistrement des utilisateurs (ou équipement informatique) ;
- génération de certificats ;
- renouvellement de certificats ;
- révocation de certificats ;
- publication de certificats ;
- publication des listes de révocation (comprenant la liste des certificats révoqués) ;
- identification et authentification des utilisateurs (administrateurs ou utilisateurs qui accèdent à la PKI) ;
- archivage, séquestre et recouvrement des certificats (option).
Description de l'infrastructure à clés publiques
Rôle d'une infrastructure à clés publiques
Une infrastructure à clés publiques (ICP) délivre des certificats numériques. Ces certificats permettent d'effectuer des opérations cryptographiques, comme le chiffrement et la signature numérique qui offrent les garanties suivantes lors des transactions électroniques :
- confidentialité : seul le destinataire (ou le possesseur) légitime d'un bloc de données ou d'un message pourra en avoir une vision intelligible ;
- authentification : lors de l'envoi d'un bloc de données ou d'un message ou lors de la connexion à un système, on connaît sûrement l'identité de l'émetteur ou l'identité de l'utilisateur qui s'est connecté ;
- intégrité : on a la garantie qu'un bloc de données ou un message expédié n'a pas été altéré, accidentellement ou intentionnellement ;
- non-répudiation : l'auteur d'un bloc de données ou d'un message ne peut pas renier son œuvre.
Les ICP permettent l'obtention de ces garanties par l'application de processus de vérification d'identité rigoureux et par la mise en œuvre de solutions cryptographiques fiables (éventuellement évaluées), conditions indispensables à la production et à la gestion des certificats électroniques.
Composants de l'infrastructure à clés publiques
Les PKI (comme définies par l'IETF) se scindent en 4 entités distinctes :
- L'autorité de certification (CA) qui a pour mission de signer les demandes de certificat: Certificate Signing Request (CSR) et de signer les listes de révocation (Certificate Revocation List: CRL). Cette autorité est la plus critique.
- L'autorité d'enregistrement (RA) qui a pour mission de générer les certificats, et d'effectuer les vérifications d'usage sur l'identité de l'utilisateur final (les certificats numériques sont nominatifs et uniques pour l'ensemble de la PKI).
- L'autorité de dépôt (Repository) qui a pour mission de stocker les certificats numériques ainsi que les listes de révocation (CRL).
- L'entité finale (End Entity EE). L’utilisateur ou le système qui est le sujet d’un certificat (En général, le terme « entité d’extrémité » (EE) est préféré au terme « sujet » afin d’éviter la confusion avec le champ Subject).
En complément, on pourra ajouter l'autorité de séquestre, qui n'est pas définie spécifiquement par l'IETF :
- L'autorité de séquestre (Key Escrow KE), cette entité a un rôle particulier, en effet lorsqu'on génère des certificats de chiffrement, on a l'obligation légale, en France de fournir aux autorités un moyen de déchiffrer les données chiffrées pour un utilisateur de la PKI. C'est là qu'intervient le séquestre, cette entité a pour mission de stocker de façon sécurisée les clés de chiffrement qui ont été générées par la PKI, pour pouvoir les restaurer le cas échéant.
Script manageCA
Présentation
manageCA est un script permettant de déployer et de gérer une PKI avec un certificat racine auto-signé.
Il est disponible sur github
Comme on peut le voir en appelant l'option -h (help), on peut spécifier au démarrage du script le nom de la PKI, son emplacement, ainsi que le fichier de configuration du script.
-c <NAME> Config File [/etc/manageCA.conf] -p <PATH> Path for PKI [/etc/pki] -n <NAME> CA Name [None]
Le fichier de configuration contient les éléments suivants:
- Le code pays
COUNTRYNAME="FR"
- L'état ou la région
STATE="PACA"
- La ville
CITY="Cavaillon"
- Le nom de la société
COMPANY="B2PWeb"
- L'URL permettant d’interroger le répondeur OCSP
OCSP_URL="http://didier.b2pweb.com"
- L'emplacement par défaut des PKI
PKI_PATH="/etc/pki"
Il peut être éditer à la main ou modifier directement depuis le script (options).
Utilisation
Première utilisation
A la première utilisation, on configurera les options en sélectionnant o dans le menu principal, si les options n'ont pas été définies à la main dans le fichier de configuration.
----------------------------------------------------------------- CA Options ----------------------------------------------------------------- 1) Country Name [FR] 2) State Name [PACA] 3) City Name [Cavaillon] 4) Company Name [B2PWeb] 5) OCSP URL [http://didier.b2pweb.com] s) Save Options p) Previous menu ==> Make your choice [none]:
On pourra éditer à loisir les options de notre PKI, puis enregistrer (dans le fichier <path>/etc/manageCA.conf</path>
Utilisation générale
=====================================================================
B2PWeb Certificate Management System
=====================================================================
1) Create a Client/Server/OCSP certificate
2) Create a Client Certificate for Web (PKCS#12)
3) Renew a Certificate
4) Revoke a Certificate
5) List Certificates
i) Initialize Root Certificate Authority (CA)
d) Delete CA
o) Show/Modify/Save CA Options
q) Quit
Options available before init
p) Change PKI default path [/etc/pki]
n) Change CA name [httpd]
==> Make your choice [none]:
On initialisera d'abord notre CA en sélectionnant i dans le menu principal
----------------------------------------------------------------- CA Initialisation ----------------------------------------------------------------- ==> Fully qualified Hostname [NONE]: didier.b2pweb.com ==> Admin email [NONE]: root@didier.b2pweb.com Using configuration from /etc/pki/httpd/ssl.cnf CA initialized Press [enter] to continue
On pourra ensuite, créer(1) un certificat, créer un certificat web(2) associé à un certificat existant, renouveler(3), révoquer(4), ou simplement afficher(5) les certificats.
Mise ne place d'une PKI pour Apache
Génération de notre PKI
On lance le script en spécifiant le nom de notre PKI
manageCA -n httpd
On créera ensuite nos certificats (avec l'extension ocsp incluse):
- un certificat server où le nom sera celui du nom d'hôte pleinement qualifiés (FQDN) pour le serveur Apache
-----------------------------------------------------------------
Create a client certificate
-----------------------------------------------------------------
==> User name [NONE]: didier.b2pweb.com
==> User email [NONE]: root@didier.b2pweb.com
==> Select Usage Key (server, client or ocsp) [client]: server
Add OCSP Extension to Certificate ? [Y/n]: y
Using configuration from /etc/pki/httpd/ssl2.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Jul 1 08:55:21 2013 GMT
Not After : Jul 1 08:55:21 2014 GMT
Subject:
countryName = FR
stateOrProvinceName = PACA
organizationName = B2PWeb
organizationalUnitName = User
commonName = didier.b2pweb.com
emailAddress = root@didier.b2pweb.com
X509v3 extensions:
Netscape Comment:
OpenSSL Generated Server Certificate
X509v3 Subject Key Identifier:
2D:A1:3A:DF:C1:E7:5F:BC:FC:E0:56:F4:A5:88:C8:D0:29:B0:03:C6
X509v3 Authority Key Identifier:
keyid:A8:14:AF:D0:20:45:E4:50:40:EC:5A:FB:71:26:32:EA:B6:CD:A3:DE
DirName:/C=FR/ST=PACA/L=Cavaillon/O=B2PWeb/OU=Admin/CN=didier.b2pweb.com/emailAddress=root@didier.b2pweb.com
serial:F2:FD:41:36:AC:97:18:54
X509v3 Issuer Alternative Name:
<EMPTY>
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
Netscape Cert Type:
SSL Server
X509v3 Extended Key Usage:
TLS Web Server Authentication
Authority Information Access:
OCSP - URI:http://didier.b2pweb.com
Certificate is to be certified until Jul 1 08:55:21 2014 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Press [enter] to continue
- un certificat ocsp où le nom sera ocspd (le démon qui fait tourner notre répondeur)
-----------------------------------------------------------------
Create a client certificate
-----------------------------------------------------------------
==> User name [NONE]: ocspd
==> User email [NONE]: root@didier.b2pweb.com
==> Select Usage Key (server, client or ocsp) [client]: ocsp
Using configuration from /etc/pki/httpd/ssl2.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 2 (0x2)
Validity
Not Before: Jul 1 08:56:47 2013 GMT
Not After : Jul 1 08:56:47 2014 GMT
Subject:
countryName = FR
stateOrProvinceName = PACA
organizationName = B2PWeb
organizationalUnitName = Admin
commonName = ocspd
emailAddress = root@didier.b2pweb.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature
X509v3 Extended Key Usage:
OCSP Signing
X509v3 Issuer Alternative Name:
<EMPTY>
X509v3 Subject Key Identifier:
5F:1D:88:93:04:8F:D9:C0:5A:71:56:48:15:82:2B:7A:94:0E:8F:C0
X509v3 Authority Key Identifier:
keyid:A8:14:AF:D0:20:45:E4:50:40:EC:5A:FB:71:26:32:EA:B6:CD:A3:DE
DirName:/C=FR/ST=PACA/L=Cavaillon/O=B2PWeb/OU=Admin/CN=didier.b2pweb.com/emailAddress=root@didier.b2pweb.com
serial:F2:FD:41:36:AC:97:18:54
Authority Information Access:
OCSP - URI:http://didier.b2pweb.com
Certificate is to be certified until Jul 1 08:56:47 2014 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Press [enter] to continue
- un ou plusieurs certificats client où le nom sera celui de l'utilisateur.
-----------------------------------------------------------------
Create a client certificate
-----------------------------------------------------------------
==> User name [NONE]: didier
==> User email [NONE]: didier@didier.b2pweb.com
==> Select Usage Key (server, client or ocsp) [client]: client
Add OCSP Extension to Certificate ? [Y/n]: y
Using configuration from /etc/pki/httpd/ssl2.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 3 (0x3)
Validity
Not Before: Jul 1 08:57:20 2013 GMT
Not After : Jul 1 08:57:20 2014 GMT
Subject:
countryName = FR
stateOrProvinceName = PACA
organizationName = B2PWeb
organizationalUnitName = Admin
commonName = didier
emailAddress = didier@didier.b2pweb.com
X509v3 extensions:
Netscape Comment:
OpenSSL Generated Client Certificate
X509v3 Subject Key Identifier:
C7:0B:2E:B3:B9:51:EB:84:E1:89:59:C2:5F:DE:EF:AD:79:36:12:C4
X509v3 Authority Key Identifier:
keyid:A8:14:AF:D0:20:45:E4:50:40:EC:5A:FB:71:26:32:EA:B6:CD:A3:DE
DirName:/C=FR/ST=PACA/L=Cavaillon/O=B2PWeb/OU=Admin/CN=didier.b2pweb.com/emailAddress=root@didier.b2pweb.com
serial:F2:FD:41:36:AC:97:18:54
X509v3 Issuer Alternative Name:
<EMPTY>
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation
Netscape Cert Type:
SSL Client
X509v3 Extended Key Usage:
TLS Web Client Authentication
Authority Information Access:
OCSP - URI:http://didier.b2pweb.com
Certificate is to be certified until Jul 1 08:57:20 2014 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Press [enter] to continue
- un certificat web associé à chaque client
----------------------------------------------------------------- Create a Client Certificate for Web ----------------------------------------------------------------- - didier.b2pweb.com - ocspd - didier ==> User name [NONE]: didier Enter Export Password: Verifying - Enter Export Password: Web certificate: /etc/pki/httpd/certs/didier_browser_cert.p12 Press [enter] to continue
Configuration d'apache
Dans le fichier ssl.conf, il faut
SSLCertificateFile /etc/pki/httpd/certs/didier.b2pweb.com.crt
SSLCertificateKeyFile /etc/pki/httpd/private/didier.b2pweb.com.key
SSLCertificateChainFile /etc/pki/httpd/httpdca.crt
SSLCACertificateFile /etc/pki/httpd/httpdca.crt
SSLVerifyDepth 1
Ensuite au choix, on passe directement par la CRL
# SSLCARevocationCheck can be
# leaf: limits the checks to the end-entity cert
# chain: CRL checks are applied to all certificates in the chain
SSLCARevocationCheck chain
SSLCARevocationPath /etc/pki/httpd/crl/
Ou par le répondeur OCSP
SSLOCSPEnable on
SSLOCSPDefaultResponder http://didier.b2pweb.com:2560
SSLOCSPOverrideResponder on
#SSLOCSPResponderTimeout 10
La directive suivante est à ajouter pour obliger le client à présenter un certificat valide au serveur sous peine de ne pas avoir l'accès autorisé.
elle peut-être mise à la définition de répertoire, de location, de vhost ou dans le fichier ssl.conf pour le faire d'une manière globale.
SSLVerifyClient require
Installation du répondeur OCSP
Voir la page dédiée au Répondeur OCSP
Tâche planifiée de régénération de la CRL
Dans le crontab de root
# Regen CRL list 15 0 * * * cd /etc/pki/httpd && openssl ca -gencrl -config ssl.cnf -out crl/httpdca.crl
Intégration sur chaque poste client de son certificat web
Utilisation de certificats avec du code PHP
Il n'est pas possible de rediriger une mauvaise connexion vers une erreur 403 d'Apache. On va donc la simuler.
D'une manière générale, le login est récupérer par PHP dans la variable $_SERVER['PHP_AUTH_USER'], que ce soit par une authentification de type htacccess ou autre.
Pour faire correspondre cette variable avec le CN du certificat client, Il faut rajouter dans la définition du répertoire/vhost/fichier
SSLUserName SSL_CLIENT_S_DN_CN
Code source
définition de l'alias pour Apache
Alias /testca /home/didier/public/www/testca
<Directory /home/didier/public/www/testca/ >
Options +MultiViews
<IfModule mod_authz_core.c>
# Apache 2.4
<RequireAny>
Require ip 127.0.0.1
Require ip ::1
Require ip 192.168.0.0/24
Require ip 10.8.0.0/24
</RequireAny>
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order Deny,Allow
Deny from All
Allow from 127.0.0.1
Allow from ::1
Allow from 192.168.0.0/24
Allow from 10.8.0.0/24
</IfModule>
AllowOverride None
SSLVerifyClient optional
# SSLOptions +ExportCertData
SSLUserName SSL_CLIENT_S_DN_CN
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule .*favicon\.ico$ /var/www/html/favicon.ico [L]
RewriteRule .*robots\.txt$ /var/www/html/robots.txt [L]
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Directory>
- Le certificat est optionnel pour se connecter au site.
- Le champs SSL_CLIENT_S_DN_CN du certificat va correspondre à PHP_AUTH_USER, qui est le champs login par défaut.
- Le traffic HTTP est rediriger vers HTTPS
Fichier index.php
<?php
function return_error() {
header('HTTP/1.1 403 Forbidden');
include( "403.php" );
exit;
}
$certstatus = "critical";
if ( isset( $_SERVER['SSL_CLIENT_VERIFY'] ) && ! empty ( $_SERVER['SSL_CLIENT_VERIFY'] ) ) {
$certverify = $_SERVER['SSL_CLIENT_VERIFY'];
if ( $certverify == 'SUCCESS' ) {
$certstatus = "ok";
}
else {
return_error();
}
}
else {
return_error();
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style>
th, td, table {
border:1px black solid;
border-collapse:collapse;
padding:5px;
text-align:left;
}
th { background-color:lightgrey;text-shadow: 0.1em 0.1em 0.2em white;}
table{margin:10px 0;}
.critical { color:red; }
.warning { color:orange; }
.ok { color: green; }
.ok, .warning, .critical { font-weight:bold; }
.hidden { display:none; }
.button {
padding:3px 10px;
background-color:lightgrey;
color:black;
margin:15px 0;
border:1px grey solid;
border-radius:4px;
text-shadow: 0.1em 0.1em 0.2em white;
font-weight:bold;
}
.pre {
white-space:pre;
font-family: Monospace;
border:1px black solid;
padding:5px;
margin:15px 0;
}
</style>
<script>
function toggleVisibility(id) {
if (document.getElementById(id).style.display == "block") {
document.getElementById(id).style.display = "none";
}
else {
document.getElementById(id).style.display = "block";
}
}
</script>
</head>
<body>
<h1>Accès autorisé</h1>
<?php if( isset ($_SERVER['PHP_AUTH_USER'] ) && ! empty ( $_SERVER['PHP_AUTH_USER'] ) ):?>
<h2>Login: <?php echo $_SERVER['PHP_AUTH_USER'];?></td></h2>
<?php endif;?>
<table>
<tr>
<th>Clé de $_SERVER</th>
<th>Valeur</th>
<th>Commentaires</th>
</tr>
<tr>
<td>SSL_CLIENT_VERIFY</td>
<td><?php echo "<span class=\"$certstatus\">$certverify</span>";?></td>
<td>Client utilisant un certificat valide si égal à SUCCESS</td>
</tr>
<tr>
<td>SSL_CLIENT_S_DN_CN</td>
<td><?php echo $_SERVER['SSL_CLIENT_S_DN_CN'];?></td>
<td>Utilisateur (CN)</td>
</tr>
<tr>
<td>SSL_CLIENT_S_DN_Email</td>
<td><?php echo $_SERVER['SSL_CLIENT_S_DN_Email'];?></td>
<td>Email</td>
</tr>
<tr>
<td>SSL_SERVER_S_DN_C</td>
<td><?php echo $_SERVER['SSL_SERVER_S_DN_C'];?></td>
<td>Code pays</td>
</tr>
<tr>
<td>SSL_SERVER_S_DN_ST</td>
<td><?php echo $_SERVER['SSL_SERVER_S_DN_ST'];?></td>
<td>Etat ou région</td>
</tr>
<tr>
<td>SSL_SERVER_S_DN_O</td>
<td><?php echo $_SERVER['SSL_SERVER_S_DN_O'];?></td>
<td>Organisation</td>
</tr>
<tr>
<td>SSL_CLIENT_V_START</td>
<td><?php echo $_SERVER['SSL_CLIENT_V_START'];?></td>
<td>Date de début de validité du certificat</td>
</tr>
<tr>
<td>SSL_CLIENT_V_END</td>
<td><?php echo $_SERVER['SSL_CLIENT_V_END'];?></td>
<td>Date de fin de validité du certificat</td>
</tr>
<tr>
<td>SSL_CLIENT_V_REMAIN</td>
<td><?php echo $_SERVER['SSL_CLIENT_V_REMAIN'];?> jours</td>
<td>Nombre de jours de validité restants</td>
</tr>
<tr>
<td>SSL_CIPHER</td>
<td><?php echo $_SERVER['SSL_CIPHER'];?></td>
<td>Cipher utilisé</td>
</tr>
<tr>
<td>SSL_PROTOCOL</td>
<td><?php echo $_SERVER['SSL_PROTOCOL'];?></td>
<td>Protocole SSL</td>
</tr>
</table>
<div><a href="#" onclick="javascript:toggleVisibility('debug');" class="button">Debug</a></div>
<div id="debug" class="pre hidden"><?php var_dump( $_SERVER );?></div>
</body>
</html>
Fichier 403.php
C'est celui qui émule une erreur 403 d'Apache.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access <?php echo $_SERVER["REQUEST_URI"];?>
on this server.</p>
</body></html>