[howto] Apache 2 e SSL – verifica del client attraverso l’uso dei certificati
Il presente howto è un semplice adattamenteo dell’articolo Apache 2 e SSL pubblicato sul sito http://www.techplus.it/ di Ermanno Gnan
Apache 2 può essere configurato in modo da ottenere una connessione sicura tramite SSL oppure richiedere informazioni al client prima di attivare una connessione sicura. Questo processo avviene attraverso lo scambio di certificati.
Un certificato è un documento pubblico che può essere tranquillamente diffuso.
I suoi utilizzi sono molteplici: può servire a contrattare una connessione sicura, fornire informazioni generali riguardanti il possessore del certificato ecc.
L’implementazione dei certificati su Debian verrà qui gestita con OpenSSL ma prima di entrare nel dettaglio sono qui riportate alcune terminologie che è opportuno padroneggiare:
- CA: Certification Authority (L’autorità che valida i certificati).
- I: Issuer (l’emittente del certificato).
- S: Subject (Il proprietario del certificato).
- L: Locality (Località o Città).
- SP: State Province (Stato di provincia usato solo in USA).
- C: Country (Paese
- CN: Common Name (Nome Comune).
- O: Organization (Organizzazione).
- OU: Organization Unit (Unità Organizzativa).
- DN: Campo contenente tutti i campi separati da uno slash (“/”).
- RSA: Algoritmo di crittografia usato per i certificati
- MD5: è un check-sum usato per controllare che messaggi crittografati non vengano contraffatti.
Come precedentemente accennato, il certificato può avere molteplici funzioni:
- fornire dei dati riguardanti il proprietario del certificato e dell’ente fornitore;
- dare una chiave pubblica con il quale è possibile decodificare documenti criptati tramite una chiave privata posseduta in modo esclusivo dal proprietario;
- permettere a chi è in possesso del certificato di criptare con una chiave contenuta in esso un’informazione che potrà solo essere decriptata dal possessore della chiave.
La sicurezza dei certificati sta nel fatto che pur possedendo queste due chiavi (l’impronta e la firma) pubbliche non ci sia la possibilità di risalire alla chiave privata alla quale è abbinato il certificato.
Per approfondimenti sugli usi a livello utente e al valore legale del certificato: http://it.wikipedia.org/wiki/Firma_digitale.
A questo punto parlando di certificato dovremo tenere a mente che da qualche parte per ogni certificato esista una chiave privata con la quale il certificato è stato creato.
Il processo di creazione di un certificato non è eccessivamente complicato e qualsiasi ente (anche fittizio) ha la possibilità di produrne uno o più.
Chiunque può quindi creare un certificato funzionante a tutti gli effetti con OpenSSL ma la “rete di fiducia” (Web of Trust) che accompagna il loro utilizzo fa in modo che si possa verificare la provenienza e la validità di un certificato.
Esistono infatti le CA (Certification Authority) che validano i certificati emessi dagli enti.
Per creare un certificato bisogna fare una richiesta tramite un certificato intermedio (CSR) che deve essere validato dalla CA che è inserita in una rete di fiducia.
L’elenco dei certificati rilasciati da una CA deve essere di dominio pubblico cosicché chiunque possa confrontare un certificato con la sua copia originale.
In seguito seguirà una guida che illustrerà passo passo come creare dei certificati validi per stabilire una connessione SSL con Apache.
Configurazione di OpenSSL e creazione dei certificati
Prima di iniziare è opportuno riassumere i passi-base per la creazione del certificato:
- Creazione di una propria CA: creare una chiave per l’ente certificatore che deve esser usata per creare una richiesta che (solo in questo primo passaggio) deve essere auto-validata dalla richiesta stessa.
- Creazione di un certificato per il server: creare una chiave per il server, creare una richiesta per la CA da validare con la nuova chiave, validare la richiesta con la CA e la chiave della CA.
- Creazione di un certificato per il client: procedimento analogo a quello del server.
Prima di tutto, occorre configurare il file /usr/lib/ssl/openssl.conf in questo modo:
HOME = .
RANDFILE = $ENV::HOME/.rnd
oid_section = new_oids
[ new_oids ]
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = /var/CA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/CA/ca.crt # The CA certificate
serial = $dir/serial # The current serial number
crl = $dir/server.crl # The current CRL
private_key = $dir/CA/ca.KEY# The private key
RANDFILE = $dir/private/.urand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = md5 # which md to use.
preserve = no # keep passed DN ordering
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
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 # The extentions to add to the self signed cert
string_mask = nombstr
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IT
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Some-State
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Internet Widgits Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, YOUR name)
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_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
[ crl_ext ]
authorityKeyIdentifier = keyid:always,issuer:always
Creazione delle cartelle per la factory dei certificati
cd /var/
mkdir CA
cd CA/
Creazione delle sottocartelle necessarie come configurato precedentemente in openssl.conf
mkdir certs
mkdir crl
touch index.txt
echo 100001 > serial
mkdir newcerts
mkdir CA
Nella cartella CA creo la factory della mia CA. Prima di tutto creo la chiave:
cd CA
openssl genrsa -out ca.KEY
quindi va creata la richiesta di certificato:
openssl req -new -key ca.KEY -out ca.CSR
infine, va abbinata la richiesta di certificato alla chiave
openssl x509 -req -days 3650 -in ca.CSR -out ca.CRT -signkey ca.KEY
Al termine, dovrebbero risultare i tre file ca.CRT ca.CSR ca.KEY.
Il passo successivo sarà creare le cartelle per il server
cd ..
mkdir server
cd server/
mkdir certificates
mkdir requests
mkdir keys
e le directory per l’utente
cd ..
mkdir user
cd user/
mkdir certificates
mkdir requests
mkdir keys
A questo punto, verranno creati i certificati per il lato server nell’apposita cartella
cd ../server/keys
generazione della chiave
openssl genrsa -des3 -out server.KEY
creazione della richiesta du certificato nell’apposita directory
cd ../requests/
openssl req -new -key ../keys/server.KEY -out server.CSR
viene abbinata la richiesta di certificato alla chiave
cd ../certificates/
openssl ca -in ../requests/server.CSR -cert ../../CA/ca.CRT -keyfile ../../CA/ca.KEY -out server.CRT
Creiamo un archivio tar.gz che conservi i permessi e le posizioni in directory dei tre certificati di cui ho bisogno:
cd /var/
tar czpvf certificati.tar.gz CA/server/certificates/server.CRT CA/server/keys/server.KEY CA/CA/ca.CRT
cp certificati.tar.gz /etc/apache2/
Dopo esserci riposizionati nella cartella di Apache 2, scompattiamo il file e collochiamo i certificati rinominando la cartella CA in certs
cd /etc/apache2/
tar -xzf certificati.tar.gz
mv techplusleCA/ certs
Ultimo passo per consentire la verifica del client che stabilisce una connessione sicura via SSL, è la creazione dei certificati per gli utenti
cd /var/CA/user/keys
generazione della chiave
openssl genrsa -des3 -out user.KEY 1024
creazione della richiesta di certificato
cd ../requests/
compilazione della richiesta
openssl req -new -key ../keys/user.KEY -out user.CSR
creazione del certificato ed esportazione per l’utente
combina la richiesta con la certification autority
cd ../certificates/
openssl ca -in ../requests/user.CSR -cert ../../CA/ca.CRT -keyfile ../../CA/ca.KEY -out user.CRT
il certificato va convertito per l’utente in modo che venga accettato dal browser
N.B. durante la creazione non va lasciata la password vuota!
openssl pkcs12 -export -clcerts -in user.CRT -inkey ../keys/user.KEY -out user.P12
Negoziazione di un certificato per aprire una connessione
Il caso più semplice è quello di uno scambio di chiavi simmetriche tramite certificato (che utilizza chivi asimmetriche).
I primi problemi che si presentano al momento in cui si voglia iniziare una connessione sicura sono lo scambio di una chiave che permetta ai due interlocutori (client e server) di comprendersi e il problema del gravoso numero di operazioni che serve a decifrare informazioni criptate con chiavi asimmetriche.
Quando si decide di accettare una connessione sicura con un server, la prima cosa che verrà inviata dal server al client è un certificato pubblico di cui il client dovrà fidarsi. Naturalmente il certificato pubblico del server deve esser stato rilasciato da una CA (la lista delle maggiori CA è già fornita dalla maggior parte dei browser) e può quindi essere confrontato con quello originale detenuto nel database pubblico CA. Fatto ciò il client è sicuro che il certificato appartenga a quel server per cui farà una richiesta di connessione criptata utilizzando la chiave pubblica presente nel certificato e solamente il server in possesso della chiave privata abbinata al certificato sarà in grado di capire il messaggio e di rispondere in modo adeguato al client.
Facendo un piccolo passo indietro, al momento in cui accetta il certificato, il client invia al server in modo criptato una chiave simmetrica criptata secondo la chiave pubblica contenuta nel certificato del server che verrà successivamente usata dai due interlocutori in modo da velocizzare lo scambio di informazioni.
Infine il server con la propria chiave privata decodifica la chiave simmetrica criptata dal client.
In questo modo si è completamente sicuri che la chiave simmetrica non possa essere rubata poiché solo il client che l’ha generata e il server che può codificarla la possiedono.
Questo discorso vale anche alla rovescia: il certificato può essere mandato dal client al server (il client deve però possedere un certificato proprio).
La situazione, in questa seconda opzione, si complica leggermente poiché il server deve possedere un elenco delle CA accettate (quelle che marchiano i certificati dei client) oltre ad una seconda configurazione che deve scremare fra i certificati posseduti dal client quello da lui desiderato.
Tutto ciò è dovuto al fatto per cui un client può possedere più certificati che gli permettono di creare connessioni differenti di tipo SSL con più server mentre nel caso in cui un server mandi il proprio certificato al client non esiste alcuna ambiguità.
Configurazione del VirtualHost di Apache2 per l’uso di SSL
Per far ciò, è succiente aggiungere alcune direttive nella sezione
SSLEngine On
SSLCertificateFile /etc/apache2/certs/server/certificates/server.CRT
SSLCertificateKeyFile /etc/apache2/certs/server/keys/server.KEY
SSLCACertificateFile /etc/apache2/certs/CA/ca.CRT
SSLCACertificatePath /etc/apache2/certs/authCA/
SSLVerifyClient require
Si noti come la direttiva SSLVerifyClient impone l’invio da parte del client di un certificato valido per la connessione.
Revoca di un certificato
Un certificato revocato viene incluso in una lista definita CRL (Certificate Revocation List). La creazione di questa lista avviene tramite questo comando:
cd /var/CA
openssl ca -gencrl -out server.crl
La revoca viene invece affidata al seguente comando:
cd /var/CA
openssl ca -revoke newcerts/certificato_compromesso.pem
Per ottenere il nome del certificato, è possibile consultare il file index.txt nella directory principale della CA. I file pem sono conservati nella sottodirectory newcerts. Una volta revocato un certificato, è necessario ricompilare la CRL, utilizzando lo stesso comando con cui in precedenza l’avevamo creata:
cd /var/CA
openssl ca -gencrl -out server.crl
Configurazione di Apache2 per gestire la revoca di un certificato
Prima di tutto, occorre copiare la CRL all’interno della cartella certs di Apache:
mkdir /etc/apache2/certs/crl
cp /var/CA/server.crl /etc/apache2/certs/crl
Occorre poi modificare la configurazione del virtual host, aggiungendo queste due direttive:
SSLCARevocationFile /etc/apache2/certs/crl/server.crl
SSLCARevocationPath /etc/apache2/certs/crl/
Evitare la richiesta della passphrase del certificato server *
Per rimuovere la richiesta della passphrase durante l’avvio di Apache, è sufficiente procedere così:
cd /var/CA/server/keys
cp server.key server.key.encripted
openssl rsa -in server.key.encripted -out server.key
cp server.key /etc/apache/certs/server/key/server.key
chmod 600 /etc/apache/certs/server/key/server.key
* Dal post Creare e installare un certificato SSL, Apache sicuro con https:// di Michele Menciassi