ESP32 (21) – Mutua autenticazione

luca 25/08/2017 0

Dopo aver pubblicato l’articolo su come realizzare un webserver con il chip esp32, alcuni utenti mi hanno scritto segnalandomi giustamente che chiunque, una volta collegato alla rete wifi, potrebbe comandare il relay e chiedendomi come poter controllare l’accesso al sito.

Una soluzione classica (utilizzata anche in questo mio tutorial) è quella di richiedere l’inserimento di una password. Tale soluzione è molto semplice da implementare ma ha come aspetto negativo la necessità di dover digitare la password ogni volta che si desidera comandare il relay.

Per evitare la richiesta della password ad ogni accesso, è possibile implementare una maschera di login e mantenere l’accesso tramite cookie di sessione; lo vedremo in un prossimo tutorial!

Oggi voglio mostrarvi come proteggere il vostro sito web tramite una funzionalità del protocollo SSL/TLS, la mutua autenticazione.

Mutua autenticazione

Ogni volta che ci colleghiamo ad un sito con il protocollo https, il server che ospita il sito ci invia il certificato SSL di tale sito. Grazie a questo certificato possiamo verificare la identità del server e stabilire con esso una connessione protetta:

ssl-02

Il protocollo TLS include anche la possibilità che il server richieda al client un certificato di autenticazione: in tal modo è possibile una two-way authentication, ovvero il server e il client si autenticano l’un l’altro tramite appunto certificati SSL:

ssl-01

Utilizzando questa modalità di autenticazione, l’utente dovrà soltanto installare sul proprio dispositivo il certificato client (e la relativa chiave privata) ed eventualmente scegliere quale certificato inviare al server se sul proprio dispositivo ne sono installati più di uno:

ssl-03

L’autenticazione tramite certificati SSL si basa quindi sul principio di qualcosa che possiedo (come ad esempio una chiave) e non di qualcosa che conosco (come ad esempio una password).

Certificati

In generale i certificati SSL possono essere di due tipi:

  • self-signed (auto-firmati)
  • emessi da una Certification Authority

I primi vanno bene per usi interni o di test, mentre i secondi, emessi normalmente da CA fidate, sono largamente usati in ambiente di produzione o su Internet. Vi sarà probabilmente capitato questo messaggio di avviso:

ssl-04

che indica proprio che il vostro browser non riconosce come valido il certificato inviato dal server proprio perché firmato da una CA non fidata.

Per l’esempio di oggi, utilizzeremo OpenSSL come certification authority per creare i certificati che ci servono. Se state utilizzando la toolchain fornita da Espressif, non è necessario installare nulla visto che OpenSSL è già incluso.

Iniziamo creando una cartella che conterrà tutti i files necessari per la CA all’interno della nostra home directory:

cd 
mkdir myCA

Spostiamoci all’interno di tale cartella e creiamo alcuni files e cartelle vuoti:

cd myCA
mkdir csr certs crl newcerts private
touch index.txt
echo 1000 > serial

sslca-01

Copiamo il file di configurazione della certification authority (openssl.cnf) dal mio repository Github alla cartella myCA. Apriamo il file e modifichiamo il path principale:

sslca-02

Dobbiamo ora generare la chiave privata e il certificato della nostra CA. Iniziamo con la chiave (sarà lunga 2048 bit, dimensione sufficiente per garantire una buona sicurezza):

winpty openssl genrsa -aes256 -out private/ca.key 2048

(i comandi devono esseere preceduti da winpty solo sotto Windows!)

Dobbiamo scegliere una password; è importante ricordarla perché ci verrà richiesta ogni volta che vorremo utilizzare la CA:

sslca-03

Generiamo ora il certificato della CA (durata 3650 giorni, ovvero 10 anni):

winpty openssl req -config openssl.cnf -key private/ca.key -new -x509 -days 3650 -sha256 -extensions ca_cert -out certs/ca.cer

Dobbiamo indicare alcune informazioni… l’unica obbligatoria è il common name che identificherà il nome della CA sui vari certificati. Al termine del processo possiamo aprire il certificato generato (file ca.cer) e verificare il nome e la scadenza:

sslca-04

Passiamo ora alla generazione dei certificati serverclient. Il procedimento è il medesimo:

  • genero una nuova chiave privata – openssl genrsa
  • genero il file CSR (Certificate Signing Request – richiesta di certificato) – openssl req
  • firmo il file CSR con la CA in modo da ottenere il certificato – openssl ca

Certificato server:

winpty openssl genrsa -out private/esp-server.key 2048
winpty openssl req -config openssl.cnf -key private/esp-server.key -new -sha256 -out csr/esp-server.csr
winpty openssl ca -config openssl.cnf -extensions server_cert -days 365 -notext -md sha256 -in csr/esp-server.csr -out certs/esp-server.cer

Certificato client:

winpty openssl genrsa -out private/esp-user.key 2048
winpty openssl req -config openssl.cnf -key private/esp-user.key -new -sha256 -out csr/esp-user.csr
winpty openssl ca -config openssl.cnf -extensions usr_cert -days 365 -notext -md sha256 -in csr/esp-user.csr -out certs/esp-user.cer

Come spiegato sopra, il dispositivo client deve possedere sia il certificato client che la relativa chiave privata. Possiamo unire certificato e chiave in un unico file p12 (o pfx) con il comando:

winpty openssl pkcs12 -export -out esp-user.pfx -inkey private/esp-user.key -in certs/esp-user.cer

La procedura di installazione del file pfx dipende dalla piattaforma: su Windows è sufficiente un doppio-click sul file e seguire il wizard di importazione.

SSL webserver

Il codice sorgente del programma in esecuzione sul chip esp32 è disponibile nel mio repository Github.

Per prima cosa dobbiamo copiare nella cartella di progetto i certificati (CA e server) e la chiave privata (server) e – includerli come text data nel programma (vi ho già mostrato come fare per le immagini del precedente esempio):

esp-ssl01

Per la gestione del protocollo SSL utilizziamo la libreria mbedTLS, già inclusa nel framework.

Includiamo tutti gli headers necessari:

#include "mbedtls/platform.h"
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#include "mbedtls/error.h"

Prima di poter accettare connessioni SSL, è necessario definireinizializzare le diverse variabili che andremo a utilizzare:

// mbed TLS variables
mbedtls_ssl_config conf;
mbedtls_ssl_context ssl;
mbedtls_net_context listen_fd, client_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_x509_crt srvcert;
mbedtls_x509_crt cachain;
mbedtls_pk_context pkey;
 
[...]
 
// initialize mbedTLS components
mbedtls_net_init(&listen_fd);
mbedtls_net_init(&client_fd);
mbedtls_ssl_config_init(&conf);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);	
mbedtls_x509_crt_init(&srvcert);
mbedtls_x509_crt_init(&cachain);
mbedtls_pk_init(&pkey);

Carichiamo i certificati e la chiave privata nelle variabili della libreria:

mbedtls_x509_crt_parse(&cachain, ca_cer_start, ca_cer_end - ca_cer_start);
mbedtls_x509_crt_parse(&srvcert, espserver_cer_start, espserver_cer_end - espserver_cer_start);
mbedtls_pk_parse_key(&pkey, espserver_key_start, espserver_key_end - espserver_key_start, NULL, 0);

Indichiamo ora alla libreria quali variabili utilizzare e richiediamo la mutua autenticazione (MBEDTLS_SSL_VERIFY_REQUIRED):

mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL);
mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey);
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);

Dopo aver configurato gli altri aspetti della libreria (random number generator e funzione di debug) possiamo associarla alla porta standard per il protocollo https (443) e accettare le connessioni in ingresso:

mbedtls_net_bind(&listen_fd, NULL, "443", MBEDTLS_NET_PROTO_TCP);
mbedtls_net_accept(&listen_fd, &client_fd, NULL, 0, NULL);

Una volta accettata la connessione, è sufficiente chiamare la funzione:

mbedtls_ssl_handshake(&ssl);

perché la libreria invii al client il proprio certificato SSL server e richieda il certificato client, effettuandone poi la verifica: la mutua autenticazione è così garantita!

Il resto del programma ricalca l’esempio precedente, utilizzando le funzioni di invio/ricezione della libreria mbedTLS (mbedtls_ssl_read e mbedtls_ssl_write).

Test

(sottotitoli in italiano disponibili)

Leave A Response »

Questo sito usa i cookie per poterti offrire una migliore esperienza di navigazione maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi