« Security/sevices/SSLCertificate/Apache » : différence entre les versions

De TartareFR
Aller à la navigation Aller à la recherche
 
(25 versions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
== Introduction ==
Cette page explique les opérations nécessaires pour la configuration d'un serveur Apache v2 utilisant des certificats utilisateurs. Ces certificats pourront être révoqués facilement.
== Pré-requis ==
*Le module ssl doit être activé dans la configuration d'Apache et la configuration ssl est incluse :
:* Le module est chargé :<pre>LoadModule ssl_module modules/mod_ssl.so</pre>
:* La configuration ssl est incluse :<pre>Include conf.d/ssl.conf</pre>
* Le firewall est ouvert pour une connection '''https''' sur le port '''443''' en '''TCP'''<pre>iptables -I INPUT -p tcp --dport 443 -j ACCEPT</pre><pre>iptables -I OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT</pre>
== Préparation ==
== Préparation ==


Ligne 12 : Ligne 22 :


<pre>
<pre>
HOME                    = .                                                                                                                                 
HOME                    = /etc/pki/httpd
RANDFILE                = .rand                                                                                                                            
RANDFILE                = /etc/pki/httpd/.rand
                                                                                                                                                           
 
[ca]                                                                                                                                                        
[ca]  
default_ca              = ca_default                                                                                                                        
default_ca              = ca_default
                                                                                                                                                           
 
[ca_default]                                                                                                                                                
[ca_default]  
dir                    = .                                                                                                                                 
dir                    = /etc/pki/httpd
certs                  = $dir/certs                                                                                                                        
certs                  = $dir/certs
crl_dir                = $dir/crl                                                                                                                          
crl_dir                = $dir/crl
database                = $dir/index.txt                                                                                                                    
database                = $dir/index.txt
new_certs_dir          = $dir/newcerts                                                                                                                    
new_certs_dir          = $dir/newcerts
certificate            = $dir/httpd_ca.crt                                                                                                                
certificate            = $dir/httpd_ca.crt
private_key            = $dir/private/httpd_ca.key                                                                                                        
private_key            = $dir/private/httpd_ca.key
serial                  = $dir/serial                                                                                                                      
serial                  = $dir/serial
crl                    = $dir/crl.pem                                                                                                                     
crl                    = $dir/ca.crl
crlnumber              = $dir/crlnumber                                                                                                                    
crlnumber              = $dir/crlnumber
crl_extensions          = crl_ext                                                                                                                          
crl_extensions          = crl_ext
x509_extensions        = usr_cert                                                                                                                          
x509_extensions        = usr_cert
name_opt                = ca_default
name_opt                = ca_default
cert_opt                = ca_default
cert_opt                = ca_default
Ligne 52 : Ligne 62 :
distinguished_name      = req_distinguished_name
distinguished_name      = req_distinguished_name
attributes              = req_attributes
attributes              = req_attributes
x509_extensions        = v3_ca # The extentions to add to the self signed cert
x509_extensions        = v3_ca
string_mask            = MASK:0x2002
string_mask            = MASK:0x2002


Ligne 89 : Ligne 99 :
basicConstraints                = CA:true
basicConstraints                = CA:true


[ crl_ext ]
[crl_ext]
authorityKeyIdentifier=keyid:always,issuer:always


# issuerAltName=issuer:copy
[OCSP]
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints        = CA:FALSE
keyUsage                = digitalSignature
extendedKeyUsage        = OCSPSigning
issuerAltName           = issuer:copy
subjectKeyIdentifier    = hash
authorityKeyIdentifier = keyid:always,issuer:always
authorityInfoAccess    = OCSP;URI:http://didier.domicile.org/
[OCSP_SERVER]
nsComment                      = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                  = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation, keyEncipherment
nsCertType                      = server
extendedKeyUsage                = serverAuth
authorityInfoAccess            = OCSP;URI:http://didier.domicile.org/
[OCSP_CLIENT]
nsComment                      = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                  = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation
nsCertType                      = client
extendedKeyUsage                = clientAuth
authorityInfoAccess            = OCSP;URI:http://didier.domicile.org/


</pre>
</pre>
Ligne 147 : Ligne 186 :
echo "Generate web certificates for \"${user}\""
echo "Generate web certificates for \"${user}\""


openssl pkcs12 -export -inkey certs/${user}.key -in certs/${user}.crt -CAfile ${caname}_ca.crt \
openssl pkcs12 -export -inkey certs/${user}.key -in certs/${user}.crt \
         -out certs/${user}_browser_cert.p12
         -out certs/${user}_browser_cert.p12


Ligne 179 : Ligne 218 :


# Regen CRL list
# Regen CRL list
openssl ca -gencrl -config ssl.cnf -out crl.pem
openssl ca -gencrl -config ssl.cnf -out ca.crl


</syntaxhighlight>
</syntaxhighlight>
Ligne 238 : Ligne 277 :
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
cd /etc/pki/httpd/
cd /etc/pki/httpd/
ln crl.pem crl/
ln ca.crl crl/
cd crl
cd crl
ln -s crl.pem `openssl crl -hash -noout -in crl.pem`.r0
ln -s ca.crl `openssl crl -hash -noout -in ca.crl`.r0
</syntaxhighlight>
</syntaxhighlight>


Ligne 277 : Ligne 316 :
      
      
     SSLEngine on
     SSLEngine on
   
     SSLProtocol all -SSLv2
     SSLProtocol all -SSLv2
   
     SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
     SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
   
     SSLHonorCipherOrder on
     SSLHonorCipherOrder on  
   
     SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
     SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
   
     SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
     SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
   
     SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
     SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
     SSLCARevocationPath /etc/pki/httpd/crl/
     SSLCARevocationPath /etc/pki/httpd/crl/
   
     SSLVerifyClient require
     SSLVerifyClient require
     SSLVerifyDepth  2
     SSLVerifyDepth  2
Ligne 311 : Ligne 342 :
</VirtualHost>
</VirtualHost>
</syntaxhighlight>
</syntaxhighlight>
{{Admon/warning|Redémarrage du service web|Il faut redémarrer Apache pour que les nouveaux paramètres soient pris en compte.
{{Admon/important|Redémarrage du service web|Il faut redémarrer Apache pour que les nouveaux paramètres soient pris en compte.
Avec '''sysVinit'''
Avec '''sysVinit'''
<pre>service httpd restart</pre>
<pre>service httpd restart</pre>
Ligne 376 : Ligne 407 :
     TransferLog logs/ssl_access_log
     TransferLog logs/ssl_access_log
     LogLevel warn
     LogLevel warn
   
 
     SSLEngine on
     SSLEngine on
   
     SSLProtocol all -SSLv2
     SSLProtocol all -SSLv2
   
     SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
     SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
   
     SSLHonorCipherOrder on
     SSLHonorCipherOrder on  
   
     SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
     SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
   
     SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
     SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
   
     SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
     SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
     SSLCARevocationPath /etc/pki/httpd/crl/
     SSLCARevocationPath /etc/pki/httpd/crl/
   
     SSLVerifyClient require
     SSLVerifyClient require
     SSLVerifyDepth  2
     SSLVerifyDepth  2
Ligne 411 : Ligne 434 :


</VirtualHost>
</VirtualHost>
NameVirtualHost 192.168.0.100:443


<VirtualHost 192.168.0.100:443>     
<VirtualHost 192.168.0.100:443>     
Ligne 441 : Ligne 466 :
</VirtualHost>
</VirtualHost>
</syntaxhighlight>
</syntaxhighlight>
== Répartition de charge ==
Il sera de la responsabilité de l'administrateur de recopier ( ou de mettre en place une réplication Raid sur IP, une tâche {{app|cron}} ) le répertoire <path>/etc/pki/httpd</path> sur tous les noeuds du cluster à chaque modification ( ajout, révocation, renouvellement, etc... )
Exemple d'ajout d'une grappe à un cluster ( ipvsadm ) dont l'IP WAN est 1.2.3.4:
ipvsadm -A -t 1.2.3.4:443 -s lc
ipvsadm -a -t 1.2.3.4:443 -r 192.168.0.1:443 -m
ipvsadm -a -t 1.2.3.4:443 -r 192.168.0.2:443 -m
ipvsadm -a -t 1.2.3.4:443 -r 192.168.0.3:443 -m
Destruction du cluster
ipvsadm -d -t 1.2.3.4:443 -r 192.168.0.1:443 -m
ipvsadm -d -t 1.2.3.4:443 -r 192.168.0.2:443 -m
ipvsadm -d -t 1.2.3.4:443 -r 192.168.0.3:443 -m
ipvsadm -D -t 1.2.3.4:443 -s lc


== Utilisation avec PHP ==
== Utilisation avec PHP ==
Ligne 465 : Ligne 506 :


Dans le cas qui nous intéresse, on vérifie le nom en lisant la varible '''SSL_CLIENT_S_DN_CN''' et l'email associé avec '''SSL_CLIENT_S_DN_Email'''.
Dans le cas qui nous intéresse, on vérifie le nom en lisant la varible '''SSL_CLIENT_S_DN_CN''' et l'email associé avec '''SSL_CLIENT_S_DN_Email'''.
Exemple de script PHP affichant le tableau suivant
{| class="wikitable"
! Clé de $_SERVER
! Valeur
! Commentaires
|-
| SSL_CLIENT_VERIFY
| SUCCESS
| Client utilisant un certificat valide si égal à SUCCESS
|-
| SSL_CLIENT_S_DN_CN
| didier
| Utilisateur (CN)
|-
| SSL_CLIENT_S_DN_Email
| didier@localhost
| Email
|-
| SSL_SERVER_S_DN_C
| FR
| Code pays
|-
| SSL_SERVER_S_DN_ST
| Languedoc-Roussillon
| Etat ou région
|-
| SSL_SERVER_S_DN_O
| Home
| Organisation
|}
<syntaxhighlight lang="html4strict">
<!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;}
    </style>
  </head>
<body>
    <table>
        <tr>
            <th>Cl&eacute; de $_SERVER</th>
            <th>Valeur</th>
            <th>Commentaires</th>
        </tr>
        <tr>
            <td>SSL_CLIENT_VERIFY</td>
            <td><?php echo $_SERVER['SSL_CLIENT_VERIFY'];?></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>
    </table>
</body>
</html>
</syntaxhighlight>
== All in one script ==
[[Scripts/manageCA| manageCA Script]]
{{:Scripts/manageCA}}


== Références ==
== Références ==
<references/>
<references/>

Dernière version du 7 janvier 2013 à 17:52

Introduction

Cette page explique les opérations nécessaires pour la configuration d'un serveur Apache v2 utilisant des certificats utilisateurs. Ces certificats pourront être révoqués facilement.

Pré-requis

  • Le module ssl doit être activé dans la configuration d'Apache et la configuration ssl est incluse :
  • Le module est chargé :
    LoadModule ssl_module modules/mod_ssl.so
  • La configuration ssl est incluse :
    Include conf.d/ssl.conf
  • Le firewall est ouvert pour une connection https sur le port 443 en TCP
    iptables -I INPUT -p tcp --dport 443 -j ACCEPT
    iptables -I OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT

Préparation

Création du répertoire des certificats

 mkdir /etc/pki/httpd && cd /etc/pki/httpd

Création du fichier de configuration de nos futurs certificats

On créer le fichier <path>/etc/pki/httpd/ssl.cnf</path>

HOME                    = /etc/pki/httpd
RANDFILE                = /etc/pki/httpd/.rand

[ca] 
default_ca              = ca_default

[ca_default] 
dir                     = /etc/pki/httpd
certs                   = $dir/certs
crl_dir                 = $dir/crl
database                = $dir/index.txt
new_certs_dir           = $dir/newcerts
certificate             = $dir/httpd_ca.crt
private_key             = $dir/private/httpd_ca.key
serial                  = $dir/serial
crl                     = $dir/ca.crl
crlnumber               = $dir/crlnumber
crl_extensions          = crl_ext
x509_extensions         = usr_cert
name_opt                = ca_default
cert_opt                = ca_default
default_days            = 365
default_crl_days        = 30
default_md              = md5
preserve                = no
policy                  = policy_match

[policy_match] 
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[req] 
default_bits            = 1024
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions         = v3_ca
string_mask             = MASK:0x2002

[req_distinguished_name] 
countryName                     = Country Name (2 letter code)
countryName_default             = FR
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Languedoc-Roussillon
localityName                    = Locality Name (eg, city)
localityName_default            = Beaucaire
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Home
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (eg, your name or your server\'s hostname)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64

[req_attributes] 
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20
unstructuredName                = An optional company name

[usr_cert] 
basicConstraints                = CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always

[v3_ca] 
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid:always,issuer:always
basicConstraints                = CA:true

[crl_ext]
authorityKeyIdentifier=keyid:always,issuer:always

[OCSP]
basicConstraints        = CA:FALSE
keyUsage                = digitalSignature
extendedKeyUsage        = OCSPSigning
issuerAltName           = issuer:copy
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
authorityInfoAccess     = OCSP;URI:http://didier.domicile.org/
 
[OCSP_SERVER]
nsComment                       = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                   = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation, keyEncipherment
nsCertType                      = server
extendedKeyUsage                = serverAuth
authorityInfoAccess             = OCSP;URI:http://didier.domicile.org/
 
[OCSP_CLIENT]
nsComment                       = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                   = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation
nsCertType                      = client
extendedKeyUsage                = clientAuth
authorityInfoAccess             = OCSP;URI:http://didier.domicile.org/

Note.png
Modification du fichier ssl.cnf
Bien que cela ne soit pas obligatoire, il est recommandé d'éditer les champs suffixés par _default dans la section [req_distinguished_name], afin de coller aux informations du serveur en cours d'installation
Cela vous permettra d'accepter directement les valeurs proposées par défaut à la génération des certificats.
Les autres sections n'ont pas besoin d'être éditées.

Création des scripts de gestion de certificats

Par simplicité, on va se servir de ces scripts pour générer les certificats des utilisateurs.

Script de génération des certificats

Fichier <path>/etc/pki/httpd/generate-certificate.sh</path>

#!/bin/bash

# user is equal to parameter one or the first argument when you actually run the script
user=$1

if [[ "$user" == "" ]]
then
        echo "Usage: $(basename $0) USER"
        exit
fi

echo "Generate certificates for \"${user}\""

openssl genrsa -out certs/${user}.key 2048

cat ssl.cnf | sed 's/insert_hostname/'${user}'/'> ssl2.cnf

openssl req -config ssl2.cnf -new -nodes -out certs/${user}.csr -key certs/${user}.key

openssl ca -config ssl2.cnf \
        -out certs/${user}.crt -outdir certs -infiles certs/${user}.csr

cat certs/${user}.crt certs/${user}.key > pem/${user}.pem

mv ssl2.cnf confs/${user}-ssl.cnf

Script de génération des certificats pour les navigateurs Web

Fichier <path>/etc/pki/httpd/generate-web-certificate.sh</path>

#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1
 
if [[ "$user" == "" ]]
then    
        echo "Usage: $(basename $0) USER"
        exit
fi

echo "Generate web certificates for \"${user}\""

openssl pkcs12 -export -inkey certs/${user}.key -in certs/${user}.crt \
        -out certs/${user}_browser_cert.p12

Script de revocation de certificats

Fichier <path>/etc/pki/httpd/revoke-certificate.sh</path>

#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1
        
if [[ "$user" == "" ]]
then
        echo "Usage: $(basename $0) USER"
        exit
fi
 
echo "Revoke certificates for \"${user}\""
        
openssl ca -revoke certs/${user}.crt -config ssl.cnf

# Save old certificate
x=1
while [ -f "certs/${user}.revoked.$x.crt" ]
do
	x=$(( $x + 1 ))
done

mv certs/${user}.crt certs/${user}.revoked.$x.crt

# Regen CRL list
openssl ca -gencrl -config ssl.cnf -out ca.crl

Script de renouvellement de certificats

Fichier <path>/etc/pki/httpd/renew-certificate.sh</path>

Il faut révoquer l'ancien certificat et signer la demande de certificat créée initialement, basée sur sa clef privée.

L'ancien certificat se retrouve en cherchant dans le fichier index.txt le nom qualifié (DN) qui correspond à la requête. La procédure de révocation s'effectue ensuite avec le numéro de série <xx> et le fichier de certificat cert/<xx>.pem.

La signature de la nouvelle requête peut être manuelle pour s'assurer que les dates de validité du certificat seront correctes.

#!/bin/bash
# user is equal to parameter one or the first argument when you actually run the script
user=$1 
        
if [[ "$user" == "" ]]
then
        echo "Usage: $(basename $0) USER"
        exit
fi
 
echo "Renew certificates for \"${user}\""

./revoke-certificate.sh ${user}
openssl ca -config confs/${user}-ssl.cnf \
        -out certs/${user}.crt -outdir certs -infiles certs/${user}.csr
 
cat certs/${user}.crt certs/${user}.key > ${user}.pem

Mise en place

Génération de l'autorité de certification

Toujours depuis le répertoire /etc/pki/httpd, on initialise notre générateur et on génère l’autorité de certification. Celle-ci se compose d'une paire clé/certificat qui servira à signer tous les autres certificats.

Ici, le CN sera obligatoirement le nom d'hôte du serveur (FQDN), les autres renseignements ne sont pas bloquants pour la suite.

cd /etc/pki/httpd/
mkdir {certs,newcerts,private,confs,crl,pem}
touch index.txt
echo 01 > serial
echo 01 > crlnumber
openssl genrsa -out private/httpd_ca.key 2048
openssl req -config ssl.cnf -new -x509 -days 3650 -key private/httpd_ca.key \
-out httpd_ca.crt -extensions v3_ca

Activation de la Liste des certificats révoqués : Certificate Revocation Lists (CRL)

On active la CRL en deux temps [1]

  • création d'un lien en dur ( ou copie ) du fichier crl dans le répertoire crl
  • création d'un lien symbolique de celui-ci en le nommant avec un hash ( donné par openssl )
cd /etc/pki/httpd/
ln ca.crl crl/
cd crl
ln -s ca.crl `openssl crl -hash -noout -in ca.crl`.r0

Génération du certificat pour Apache

Il faut créer un certificat valide pour le serveur

cd /etc/pki/httpd/
./generate-certificate.sh httpd

Configuration d'Apache

Fichier <path>/etc/httpd/conf.d/ssl.conf</path>

LoadModule ssl_module modules/mod_ssl.so

Listen 443

SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog

SSLSessionCache         shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout  300

SSLMutex default

SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin

SSLCryptoDevice builtin
<VirtualHost _default_:443>
    
    ErrorLog logs/ssl_error_log
    TransferLog logs/ssl_access_log
    LogLevel warn
    
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
    SSLHonorCipherOrder on
    SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
    SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
    SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
    SSLCARevocationPath /etc/pki/httpd/crl/
    SSLVerifyClient require
    SSLVerifyDepth  2
    
    <Files ~ "\.(cgi|shtml|phtml|php3?)$">
        SSLOptions +StdEnvVars +ExportCertData
    </Files>
    <Directory "/var/www/cgi-bin">
        SSLOptions +StdEnvVars +ExportCertData
    </Directory>
    
    SetEnvIf User-Agent ".*MSIE.*" \
             nokeepalive ssl-unclean-shutdown \
             downgrade-1.0 force-response-1.0
    
    CustomLog logs/ssl_request_log \
              "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>
Important.png
Redémarrage du service web
Il faut redémarrer Apache pour que les nouveaux paramètres soient pris en compte.

Avec sysVinit

service httpd restart

Avec systemctl

systemctl restart httpd.service

Gérer les certificats des utilisateurs

Cette partie est la seule qui peut être exécuter plusieurs fois. Elle est très amplement facilitée par les scripts de gestion édités auparavant.

Ajout d'un utilisateur

L'autorisation d'accès d'un utilisateur est conditionné par un certificat web qui doit être importer dans le navigateur de celui-ci. Ce certificat web est une simple traduction du certificat openssl à qui il est étroitement associé. Le certificat web ne peut exister sans lui.

Généreration des certificats

cd /etc/pki/httpd/
./generate-certificate.sh <USER>
./generate-web-certificate.sh <USER>

Il ne reste plus qu'à donner de manière sécurisée le certificat web à l'utilisateur le fichier <path>/etc/pki/httpd/certs/<USER>_browser_cert.p12</path>, ainsi que le mot de passe associé.

Celui-ci devra l'importer dans son navigateur :

Révocation d'utilisateur

On révoque son certificat et celui-ci ne peut plus accéder au site.

cd /etc/pki/httpd/
./revoke-certificate.sh <USER>

Virtualhosts

Apache ne supporte pas le multi virtualhost de but en blanc sur une connection https, mais cela est toutefois possible sous certaines conditions :

  • Les certificats et les clés sont partagées par tous les virtualhosts ( y compris le default ) et ceux-ci doivent être recopiés à chaque définition de virtualhost. De plus celles-ci doivent comporter le port :
    <VirtualHost 192.168.0.100:443>
  • Utilisation de la directive NameVirtualHost avec spécification du port :
    NameVirtualHost 192.168.0.100:443
  • Les autres définitions des virtualhosts accessibles en http doivent mentionner le port ( httpd-vhosts.conf ) :
    <VirtualHost 192.168.0.100:80>

Fichier <path>/etc/httpd/conf.d/ssl.conf</path>

LoadModule ssl_module modules/mod_ssl.so

Listen 443

SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog

SSLSessionCache         shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout  300

SSLMutex default

SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin

SSLCryptoDevice builtin
<VirtualHost _default_:443>
    
    ErrorLog logs/ssl_error_log
    TransferLog logs/ssl_access_log
    LogLevel warn

    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
    SSLHonorCipherOrder on
    SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
    SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
    SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
    SSLCARevocationPath /etc/pki/httpd/crl/
    SSLVerifyClient require
    SSLVerifyDepth  2
    
    <Files ~ "\.(cgi|shtml|phtml|php3?)$">
        SSLOptions +StdEnvVars +ExportCertData
    </Files>
    <Directory "/var/www/cgi-bin">
        SSLOptions +StdEnvVars +ExportCertData
    </Directory>
    
    SetEnvIf User-Agent ".*MSIE.*" \
             nokeepalive ssl-unclean-shutdown \
             downgrade-1.0 force-response-1.0
    
    CustomLog logs/ssl_request_log \
              "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>

NameVirtualHost 192.168.0.100:443

<VirtualHost 192.168.0.100:443>    
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite RC4-SHA:AES128-SHA:ALL:!ADH:!EXP:!LOW:!MD5:!SSLV2:!NULL
    SSLHonorCipherOrder on 
    SSLCertificateFile /etc/pki/httpd/certs/httpd.crt
    SSLCertificateKeyFile /etc/pki/httpd/certs/httpd.key
    SSLCACertificateFile /etc/pki/httpd/httpd_ca.crt
    SSLCARevocationPath /etc/pki/httpd/crl/
    SSLVerifyClient require 
    SSLVerifyDepth  2

    ServerAdmin root@localhost
    DocumentRoot "/home/ssl-vhost" 
    ServerName ssl-vhost.localdomain

    <Directory "/home/ssl-vhost">
        AllowOverride none
        Allow from all
        Order allow,deny
    </Directory>

    LogLevel warn
    ErrorLog "logs/ssl-vhost-error.log" 
    CustomLog "logs/ssl-vhost-access.log" common
    TransferLog logs/ssl-vhost-access.log

</VirtualHost>

Répartition de charge

Il sera de la responsabilité de l'administrateur de recopier ( ou de mettre en place une réplication Raid sur IP, une tâche cron ) le répertoire <path>/etc/pki/httpd</path> sur tous les noeuds du cluster à chaque modification ( ajout, révocation, renouvellement, etc... )

Exemple d'ajout d'une grappe à un cluster ( ipvsadm ) dont l'IP WAN est 1.2.3.4:

ipvsadm -A -t 1.2.3.4:443 -s lc
ipvsadm -a -t 1.2.3.4:443 -r 192.168.0.1:443 -m
ipvsadm -a -t 1.2.3.4:443 -r 192.168.0.2:443 -m
ipvsadm -a -t 1.2.3.4:443 -r 192.168.0.3:443 -m

Destruction du cluster

ipvsadm -d -t 1.2.3.4:443 -r 192.168.0.1:443 -m
ipvsadm -d -t 1.2.3.4:443 -r 192.168.0.2:443 -m
ipvsadm -d -t 1.2.3.4:443 -r 192.168.0.3:443 -m
ipvsadm -D -t 1.2.3.4:443 -s lc

Utilisation avec PHP

Il faut activer la passation des paramètres SSL à PHP en rajoutant l'option ExportCertData[2]

Fichier <path>/etc/httpd/conf.d/ssl.conf</path>

<Files ~ "\.(cgi|shtml|phtml|php3?)$">
    SSLOptions +StdEnvVars +ExportCertData
</Files>
<Directory "/var/www/cgi-bin">
    SSLOptions +StdEnvVars +ExportCertData
</Directory>

Quand un certificat d'un client est disponible, la variable globale $_SERVER contient beaucoup plus d'information, toutes préfixées avec SSL_CLIENT_.

  • SSL_CLIENT_VERIFY est très importante et les information du certificat ne doivent pas être utilisées si cette variable n'est pas égale à SUCCESS. Cette variable est passée à NONE si il n'y a pas de certificat.
  • SSL_CLIENT_M_SERIAL contient le numéro de série qui identifie le certificat unique associé depuis l'autorité de certification.
  • Toutes les variables SSL_CLIENT_I_* sont à propos de l'autorité de certification.
  • Toutes les variables SSL_CLIENT_S_* sont à propos de l'utilisateur.

Dans le cas qui nous intéresse, on vérifie le nom en lisant la varible SSL_CLIENT_S_DN_CN et l'email associé avec SSL_CLIENT_S_DN_Email.

Exemple de script PHP affichant le tableau suivant

Clé de $_SERVER Valeur Commentaires
SSL_CLIENT_VERIFY SUCCESS Client utilisant un certificat valide si égal à SUCCESS
SSL_CLIENT_S_DN_CN didier Utilisateur (CN)
SSL_CLIENT_S_DN_Email didier@localhost Email
SSL_SERVER_S_DN_C FR Code pays
SSL_SERVER_S_DN_ST Languedoc-Roussillon Etat ou région
SSL_SERVER_S_DN_O Home Organisation
<!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;}
    </style>
  </head>
<body>
    <table>
        <tr>
            <th>Cl&eacute; de $_SERVER</th>
            <th>Valeur</th>
            <th>Commentaires</th>
        </tr>
        <tr>
            <td>SSL_CLIENT_VERIFY</td>
            <td><?php echo $_SERVER['SSL_CLIENT_VERIFY'];?></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>
    </table>
</body>
</html>

All in one script

manageCA Script

Version potentiellement plus à jour sur https://github.com/didier13150/manageCA

#!/bin/bash
################################################################################
# Author: Didier Fabert
# Rev 0.4
################################################################################
COUNTRYNAME="FR"
STATE="Languedoc-Roussillon"
CITY="Beaucaire"
COMPANY="Home"
OCSP_URL="http://didier.domicile.org/"

PKI_PATH="/etc/pki"
NAME=""
CFG_FILE="/etc/manageCA.conf"

function printUsage() {
	echo "$(basename $0)"
}

function printHelp() {
	echo
	echo "Options:"
	echo -e "\t-c <NAME>     Config File [${CFG_FILE}]"
	echo -e "\t-p <PATH>     Path for PKI [/etc/pki]"
	echo -e "\t-n <NAME>     CA Name [None]"
}

function printMenu() {
	clear
	echo "====================================================================="
	echo "             ${COMPANY} Certificate Management System"
	echo "====================================================================="
	echo
	echo "   1) Create a Client/Server/OCSP certificate"
	echo "   2) Create a Client Certificate for Web (PKCS#12)"
	echo "   3) Renew a Certificate"
	echo "   4) Revoke a Certificate"
	echo "   5) List Certificates"
	echo
	echo "   i) Initialize Root Certificate Authority (CA)"
	echo "   d) Delete CA"
	echo "   o) Show/Modify/Save CA Options"
	echo "   q) Quit"
	echo
	echo "   Options available before init"
	echo "   p) Change PKI default path [${PKI_PATH}]"
	echo "   n) Change CA name [${NAME}]"
	echo
}

function printSubMenu {
        clear
        echo "-----------------------------------------------------------------"
        echo ${1}
        echo "-----------------------------------------------------------------"
        echo
}

function manageOptions() {
	local buffer
	while true;
	do
		printSubMenu "CA Options"
		echo "   1) Country Name [${COUNTRYNAME}]"
		echo "   2) State Name [${STATE}]"
		echo "   3) City Name [${CITY}]"
		echo "   4) Company Name [${COMPANY}]"
		echo "   5) OCSP URL [${OCSP_URL}]"
		echo
		echo "   s) Save Options"
		echo "   p) Previous menu"
		echo
		read -p " ==> Make your choice [none]: " -n 1 CHOICE
		echo
		echo
		case ${CHOICE} in
			1)
				read -p " ==> New Country Name [${COUNTRYNAME}]: " buffer
				[ ! -z ${buffer} ] && COUNTRYNAME=${buffer}
				;;
			2)
				read -p " ==> New State Name [${STATE}]: " buffer
				[ ! -z ${buffer} ] && STATE=${buffer}
				;;
			3)
				read -p " ==> New City Name [${CITY}]: " buffer
				[ ! -z ${buffer} ] && CITY=${buffer}
				;;
			4)
				read -p " ==> New Company Name [${COMPANY}]: " buffer
				[ ! -z ${buffer} ] && COMPANY=${buffer}
				;;
			5)
				read -p " ==> New OCSP URL [${OCSP_URL}]: " buffer
				[ ! -z ${buffer} ] && OCSP_URL=${buffer}
				;;
			s)
				saveCfg
				;;
			p)
				return
				;;
		esac
	done
}

function saveCfg() {
	local buffer=$1
	if [ -z ${buffer} ]
	then
		echo
		read -p " ==> File to save [${CFG_FILE}]: " buffer
		[ ! -z ${buffer} ] && CFG_FILE=${buffer}
	fi
	touch ${CFG_FILE}
	
	if [ -w ${CFG_FILE} ]
	then
		echo "## Configuration file for manageCA.sh script" > ${CFG_FILE}
		echo >> ${CFG_FILE}
		echo "# Country Code for certificate" >> ${CFG_FILE}
		echo "COUNTRYNAME=\"${COUNTRYNAME}\"" >> ${CFG_FILE}
		echo >> ${CFG_FILE}
		echo "# State Name for certificate" >> ${CFG_FILE}
		echo "STATE=\"${STATE}\"" >> ${CFG_FILE}
		echo >> ${CFG_FILE}
		echo "# City Name for certificate" >> ${CFG_FILE}
		echo "CITY=\"${CITY}\"" >> ${CFG_FILE}
		echo >> ${CFG_FILE}
		echo "# Company Name for certificate" >> ${CFG_FILE}
		echo "COMPANY=\"${COMPANY}\"" >> ${CFG_FILE}
		echo >> ${CFG_FILE}
		echo "# OCSP URL for certificate" >> ${CFG_FILE}
		echo "OCSP_URL=\"${OCSP_URL}\"" >> ${CFG_FILE}
		echo >> ${CFG_FILE}
		echo "# PKI Default Path" >> ${CFG_FILE}
		echo "PKI_PATH=\"${PKI_PATH}\"" >> ${CFG_FILE}
		echo >> ${CFG_FILE}
	else
		echo
		echo "Error: ${CFG_FILE} is not writable for you"
		read -p "Press [enter] to continue" DUMMY
	fi
}

function addUser() {
	local user
	local email
	local usage="client"
	local buffer
	local userdata
	printSubMenu "Create a client certificate"
	read -p " ==> User name [NONE]: " user
	if [[ "${user}" == "" ]]
	then
		return
	fi
	echo
	read -p " ==> User email [NONE]: " email
	if [[ "${email}" == "" ]]
	then
		return
	fi
	echo
	
	read -p " ==> Select Usage Key (server, client or ocsp) [client]: " buffer
	[ -z ${buffer} ] || usage=${buffer}
	echo
	
	if [[ "${usage}" == "ocsp" ]]
	then
			extension="-extensions OCSP"
	else
		read -p "Add OCSP Extension to Certificate ? [Y/n]: " buffer
		[ -z ${buffer} ] && buffer="y"
		if [[ "${buffer}" == "y" ]]
		then
			if [[ "${usage}" == "server" ]]
			then
				extension="-extensions OCSP_SERVER"
			else
				extension="-extensions OCSP_CLIENT"
			fi
		else
			extension=""
		fi
	fi
	
	openssl genrsa -out ${PKI_PATH}/${NAME}/certs/${user}.key 2048 \
		1>/dev/null 2>&1
	if [[ "${usage}" == "server" ]]
	then
		userdata="organizationalUnitName_default  = User\n"
	else
		userdata="organizationalUnitName_default  = Admin\n"
	fi
	userdata="${userdata}commonName_default              = ${user}\n"
	userdata="${userdata}emailAddress_default            = ${email}"
	cat ${PKI_PATH}/${NAME}/ssl.cnf | tr -d '#' | \
		sed -e "s/@USERDATA@/${userdata}/" \
		> ${PKI_PATH}/${NAME}/ssl2.cnf
	openssl req -config ${PKI_PATH}/${NAME}/ssl2.cnf -new -nodes -batch \
		-out ${PKI_PATH}/${NAME}/certs/${user}.csr \
		-key ${PKI_PATH}/${NAME}/certs/${user}.key
	openssl ca -config ${PKI_PATH}/${NAME}/ssl2.cnf \
		-cert ${PKI_PATH}/${NAME}/${NAME}_ca.crt ${extension} \
		-out ${PKI_PATH}/${NAME}/certs/${user}.crt \
		-outdir ${PKI_PATH}/${NAME}/certs \
		-infiles ${PKI_PATH}/${NAME}/certs/${user}.csr
	cat ${PKI_PATH}/${NAME}/certs/${user}.crt \
		${PKI_PATH}/${NAME}/certs/${user}.key \
			> ${PKI_PATH}/${NAME}/pem/${user}.pem
	mv ${PKI_PATH}/${NAME}/ssl2.cnf ${PKI_PATH}/${NAME}/confs/${user}-ssl.cnf
	read -p "Press [enter] to continue" DUMMY
}

function webUser() {
	local user
	printSubMenu "Create a Client Certificate for Web"
	printUserList
	read -p " ==> User name [NONE]: " user
	if [[ "${user}" == "" ]]
	then
		return
	fi
	echo
	if [ -f ${PKI_PATH}/${NAME}/certs/${user}.crt ]
	then
		openssl pkcs12 -export -inkey ${PKI_PATH}/${NAME}/certs/${user}.key \
			-in ${PKI_PATH}/${NAME}/certs/${user}.crt \
			-CAfile ${PKI_PATH}/${NAME}/${NAME}_ca.crt \
			-out ${PKI_PATH}/${NAME}/certs/${user}_browser_cert.p12
	fi
	echo
	[ -f ${PKI_PATH}/${NAME}/certs/${user}_browser_cert.p12 ] \
		&& echo "Web certificate: ${PKI_PATH}/${NAME}/certs/${user}_browser_cert.p12" \
		|| echo "Error encoured"
	echo
	read -p "Press [enter] to continue" DUMMY
}

function renewUser() {
	local user
	printSubMenu "Renew a Server Certificate"
	printUserList
	read -p " ==> User name [NONE]: " user
	if [[ "${user}" == "" ]]
	then
		echo "Error: Name cannot be empty"
		read -p "Press [enter] to continue" DUMMY
		return
	fi
	revokeUser ${user}
	openssl ca -config ${PKI_PATH}/${NAME}/confs/${user}-ssl.cnf \
        -out ${PKI_PATH}/${NAME}/certs/${user}.crt \
        -outdir ${PKI_PATH}/${NAME}/certs \
        -infiles ${PKI_PATH}/${NAME}/certs/${user}.csr
	cat ${PKI_PATH}/${NAME}/certs/${user}.crt \
		${PKI_PATH}/${NAME}/certs/${user}.key \
			> ${PKI_PATH}/${NAME}/pem/${user}.pem
	echo
	read -p "Press [enter] to continue" DUMMY
}

function revokeUser() {
	local user=$1
	printSubMenu "Revoke a Client Certificate"
	printUserList
	[ -z ${user} ] && read -p " ==> User name [NONE]: " user
	if [[ "${user}" == "" ]]
	then
		return
	fi
	openssl ca -revoke ${PKI_PATH}/${NAME}/certs/${user}.crt \
		-config ${PKI_PATH}/${NAME}/ssl.cnf
	# Save old certificate
	x=1
	while [ -f "${PKI_PATH}/${NAME}/certs/${user}.revoked.$x.crt" ]
	do
		x=$(( $x + 1 ))
	done
		mv ${PKI_PATH}/${NAME}/certs/${user}.crt ${PKI_PATH}/${NAME}/certs/${user}.revoked.$x.crt
	
	x=1
	while [ -f "${PKI_PATH}/${NAME}/pem/${user}.revoked.$x.pem" ]
	do
		x=$(( $x + 1 ))
	done
	mv ${PKI_PATH}/${NAME}/pem/${user}.pem ${PKI_PATH}/${NAME}/pem/${user}.revoked.$x.pem
	# Regen CRL
	openssl ca -gencrl -config ${PKI_PATH}/${NAME}/ssl.cnf \
		-out ${PKI_PATH}/${NAME}/${NAME}_ca.crl
	echo
	echo "Don't forget to reload Apache"
	echo
	[ -z ${1} ] read -p "Press [enter] to continue" DUMMY
}

function listUser() {
	printSubMenu "List Client Certificates"
	while [ 1 ]
	do
	   read LINE || break
	   LISTNUM=`echo ${LINE} | grep -v "^R" | awk '{ print $3 }'`
	   LISTCN=`echo ${LINE} | grep -v "^R" | awk -F CN= '{ print $2 }' | cut -d '/' -f1`
	   [ -z ${LISTNUM} ] || echo " ${LISTNUM} ${LISTCN}"
	done < ${PKI_PATH}/${NAME}/index.txt
	echo
	read -p "Press [enter] to continue" DUMMY
}

function printUserList() {
	while [ 1 ]
	do
	   read LINE || break
	   LISTCN=`echo ${LINE} | grep -v "^R" | awk -F CN= '{ print $2 }' | cut -d '/' -f1`
	   [ -z ${LISTCN} ] || echo "- ${LISTCN}"
	done < ${PKI_PATH}/${NAME}/index.txt
}

function changeDefaultPath() {
	local buffer
	read -p " ==> Select New path for CA [${PKI_PATH}]: " buffer
	if [ ! -z ${buffer} ]; then PKI_PATH=${buffer} ; fi
}

function changeName() {
	read -p " ==> Select New CA name [NONE]: " NAME
}

function initCA() {
	printSubMenu "CA Initialisation"
	if [ -f ${PKI_PATH}/${NAME}/ssl.cnf ]
	then
		read -p "!!! Already initalized !!!"
		return
	fi
	read -p " ==> Fully qualified Hostname [NONE]: " hostname
	if [[ "$hostname" == "" ]]
	then
		echo "Error: Fully qualified Hostname cannot be empty"
		read -p "Press [enter] to continue" DUMMY
		return
	fi
	echo
	read -p " ==> Admin email [NONE]: " email
	if [[ "$email" == "" ]]
	then
		echo "Error: email cannot be empty"
		read -p "Press [enter] to continue" DUMMY
		return
	fi
	
	mkdir -p ${PKI_PATH}/${NAME}/{certs,newcerts,private,confs,crl,pem}
	initConfig
	touch ${PKI_PATH}/${NAME}/index.txt
	[ -f ${PKI_PATH}/${NAME}/serial ] || echo 01 > ${PKI_PATH}/${NAME}/serial
	[ -f ${PKI_PATH}/${NAME}/crlnumber ] || echo 01 > ${PKI_PATH}/${NAME}/crlnumber
	[ -f ${PKI_PATH}/${NAME}/private/${NAME}_ca.key ] || \
		openssl genrsa -out ${PKI_PATH}/${NAME}/private/${NAME}_ca.key 2048 \
		1>/dev/null 2>&1
	local userdata="organizationalUnitName_default  = Admin\n"
	userdata="${userdata}commonName_default              = ${hostname}\n"
	userdata="${userdata}emailAddress_default            = ${email}"
	cat ${PKI_PATH}/${NAME}/ssl.cnf | tr -d '#' | \
		sed -e "s/@USERDATA@/${userdata}/" \
		> ${PKI_PATH}/${NAME}/ssl2.cnf
	openssl req -config ${PKI_PATH}/${NAME}/ssl2.cnf -new -x509 -days 3650 -batch \
		-key ${PKI_PATH}/${NAME}/private/${NAME}_ca.key \
		-out ${PKI_PATH}/${NAME}/${NAME}_ca.crt -extensions v3_ca
	mv ${PKI_PATH}/${NAME}/ssl2.cnf ${PKI_PATH}/${NAME}/confs/ca.cnf
	[ -f ${PKI_PATH}/${NAME}/${NAME}_ca.crl ] || openssl ca -gencrl \
		-config ${PKI_PATH}/${NAME}/ssl.cnf -out ${PKI_PATH}/${NAME}/${NAME}_ca.crl
	ln ${PKI_PATH}/${NAME}/${NAME}_ca.crl ${PKI_PATH}/${NAME}/crl/
	local hash=`openssl crl -hash -noout -in ${PKI_PATH}/${NAME}/crl/${NAME}_ca.crl`
	ln -s ${PKI_PATH}/${NAME}/crl/${NAME}_ca.crl ${PKI_PATH}/${NAME}/crl/$hash.r0
	echo
	echo "CA initialized"
	echo
	read -p "Press [enter] to continue" DUMMY
}

function deleteCA() {
	printSubMenu "Deleting CA"
	read -p " ==> Are you sure ? Type uppercase YES to confirm: " CONFIRM
	if [[ "${CONFIRM}" == "YES" ]]
	then
		rm -rf ${PKI_PATH}/${NAME}
		echo
		echo "CA completely deleted"
		echo
		read -p "Press [enter] to continue" DUMMY
	fi
}

function initConfig() {
	cat << 'EOF' > ${PKI_PATH}/${NAME}/ssl.cnf
HOME                    = @HOME@
RANDFILE                = @HOME@/.rand

[ca] 
default_ca              = ca_default

[ca_default] 
dir                     = @HOME@
certs                   = $dir/certs
crl_dir                 = $dir/crl
database                = $dir/index.txt
new_certs_dir           = $dir/newcerts
certificate             = $dir/@NAME@_ca.crt
private_key             = $dir/private/@NAME@_ca.key
serial                  = $dir/serial
crl                     = $dir/@NAME@_ca.crl
crlnumber               = $dir/crlnumber
crl_extensions          = crl_ext
x509_extensions         = usr_cert
name_opt                = ca_default
cert_opt                = ca_default
default_days            = 365
default_crl_days        = 30
default_md              = md5
preserve                = no
policy                  = policy_match

[policy_match] 
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[req] 
default_bits            = 1024
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions         = v3_ca
string_mask             = MASK:0x2002

[req_distinguished_name] 
countryName                     = Country Name (2 letter code)
countryName_default             = @COUNTRYNAME@
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = @STATE@
localityName                    = Locality Name (eg, city)
localityName_default            = @CITY@
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = @ORGANISATION@
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (eg, your name or your server\'s hostname)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64
##@USERDATA@

[req_attributes] 
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20
unstructuredName                = An optional company name

[usr_cert] 
basicConstraints                = CA:FALSE
nsComment                       = "OpenSSL Generated Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always

[v3_ca] 
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid:always,issuer:always
basicConstraints                = CA:true

[crl_ext]
authorityKeyIdentifier=keyid:always,issuer:always

[OCSP]
basicConstraints        = CA:FALSE
keyUsage                = digitalSignature
extendedKeyUsage        = OCSPSigning
issuerAltName           = issuer:copy
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
authorityInfoAccess     = OCSP;URI:@OCSPURL@
 
[OCSP_SERVER]
nsComment                       = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                   = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation, keyEncipherment
nsCertType                      = server
extendedKeyUsage                = serverAuth
authorityInfoAccess             = OCSP;URI:@OCSPURL@
 
[OCSP_CLIENT]
nsComment                       = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier            = hash
authorityKeyIdentifier          = keyid,issuer:always
issuerAltName                   = issuer:copy
basicConstraints                = critical,CA:FALSE
keyUsage                        = digitalSignature, nonRepudiation
nsCertType                      = client
extendedKeyUsage                = clientAuth
authorityInfoAccess             = OCSP;URI:@OCSPURL@

EOF
	sed -i \
		-e "s#@HOME@#${PKI_PATH}/${NAME}#g" \
		-e "s#@NAME@#${NAME}#g" \
		-e "s#@COUNTRYNAME@#${COUNTRYNAME}#g" \
		-e "s#@STATE@#${STATE}#g" \
		-e "s#@CITY@#${CITY}#g" \
		-e "s#@ORGANISATION@#${COMPANY}#g" \
		-e "s#@OCSPURL@#${OCSP_URL}#g" \
		${PKI_PATH}/${NAME}/ssl.cnf
}

#Main program


# process command line arguments
while getopts "?hup:n:c:" opt
do
	case "${opt}" in
		u)
			printUsage
			exit 0
			;;
		h|\?)
			printUsage
			printHelp
			exit 0
			;;
		c)
			CFG_FILE=$OPTARG
			;;
		p)
			PKI_PATH=$OPTARG
			;;
		n)
			NAME=$OPTARG
			;;
	esac
done

# Load config
[ -f ${CFG_FILE} ] && source ${CFG_FILE} || saveCfg ${CFG_FILE}

clear
[ -z ${NAME} ] && changeName
while true;
do
	printMenu
#	CheckOpenSSLConfig
	read -p " ==> Make your choice [none]: " -n 1 CHOICE
	case ${CHOICE} in
		1)
			addUser
			;;
		2)
			webUser
			;;
		3)
			renewUser
			;;
		4)
			revokeUser
			;;
		5)
			listUser
			;;
		I|i)
			initCA
			;;
		Q|q)
			echo
			break
			;;
		P|p)
			echo
			changeDefaultPath
			;;
		N|n)
			echo
			changeName
			;;
		D|d)
			deleteCA
			;;
		O|o)
			manageOptions
			;;
	esac
done

Références