« Security/Services/PKIWithManageCA » : différence entre les versions

De TartareFR
Aller à la navigation Aller à la recherche
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 certificat client où le nom sera celui de l'utilisateur.
* 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é à notre client
* 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é.


<pre>
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.
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
<syntaxhighlight lang="apache">
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLVerifyClient require
</pre>
</syntaxhighlight>


==== Installation du répondeur OCSP ====
==== Installation du répondeur OCSP ====


Voir la page dédiée au [[Services/OCSP| répondeur 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&egrave;s autoris&eacute;</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&eacute; 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 &eacute;gal &agrave; 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&eacute;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&eacute;but de validit&eacute; 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&eacute; 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&eacute; restants</td>
        </tr>
        <tr>
            <td>SSL_CIPHER</td>
            <td><?php echo $_SERVER['SSL_CIPHER'];?></td>
            <td>Cipher utilis&eacute;</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).

Important.png
Les options doivent être renseignés avant d'initialiser l'autorité de certification.

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&egrave;s autoris&eacute;</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&eacute; 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 &eacute;gal &agrave; 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&eacute;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&eacute;but de validit&eacute; 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&eacute; 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&eacute; restants</td>
        </tr>
        <tr>
            <td>SSL_CIPHER</td>
            <td><?php echo $_SERVER['SSL_CIPHER'];?></td>
            <td>Cipher utilis&eacute;</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>