MokaByte 92 - Gennaio 2005
IIOP over SSL
II parte: la pratica
di

S. Rossini
A. D'Angeli

Nel precedente articolo si è parlato di SSLIOP, ovvero del protocollo IIOP over SSL (vedere [MOKA_SSLIOP1]). In questo articolo vedremo alcuni esempi pratici per utilizzare il trasporto sicuro SSL espo-nendo un EJB con l'Application Server JBoss Come abbiamo spiegato nel precedente articolo, è possibile abilitare il trasporto SSL per ot-tenere il duplice scopo di autenticare le controparti nella comunicazione e proteggere i dati trasmessi. Così facendo, la trasmissione dei dati, prima di essere inoltrata mediante socket TCP, viene codificata secondo un opportuno algoritmo. Metteremo in pratica quanto visto nel numero scorso, e prenderemo in esame due scenari di interazione: trust in target (autenticazione solo del server) e mutual authentication (autenti-cazione sia del server che del client). Per entrambe le prove procederemo prima generando le chiavi necessarie, poi mostrando come impostare il server (ovvero un EJB deployato su JBoss) e quindi impostando e lanciando un client standalone.


Esempio Trust In Target: Generazione delle chiavi
Ricordiamo dal numero precedente che uno dei capisaldi del protocollo SSL è la infrastruttura a chiave pubblica (o asimmetrica). Dovremo quindi per prima cosa generare una coppia di chiavi, una pubblica ed una privata. Abbiamo bisogno di una sola coppia di chiavi perché in questo scenario vogliamo che venga verificata soltanto l'identità del target (cioè del server). Le chiavi che dovremo generare saranno quindi la chiave privata del server e la sua corrispondente chiave pubblica. Il server userà la propria chiave privata per asserire la propria identità ed il client userà la chiave pubblica corrispondente per verificarla. Ricordiamo inoltre che pur avendosi una sola coppia di chiavi, la cifratura della comunicazione avviene comunque in entrambi i sensi, perché le chiavi asimmetriche verranno usate per scambiarsi una chiave segreta temporanea che verrà impiegata per cifrare i dati scambiati durante la sessione di comunicazione.
Per creare la coppia di chiavi pubblica e privata necessarie a garantire l'autenticità della controparte e la riservatezza della comunicazione tra client è server è possibile utilizzare il programma keytool del JDK.
Specificando l'opzione -genkey il keytool crea una chiave privata e la sua corrispettiva chiave pubblica in un file criptato denominato keystore che viene generato nella directory dalla quale è stato lanciato il comando. La chiave pubblica viene inclusa in un certificato self signed all'interno del file prodotto. Ricordiamo dal numero precedente che un certificato non è altro che un'attestazione firmata da una certification authority (entità issuer) che assicura la bontà della chiave pubblica di un subject. Un certificato self-signed è semplicemente quello in cui issuer e subject sono la stessa entità.
Il principale inconveniente dei certificati self signed è appunto il fatto che non prevedono la firma da parte di una well-known Certification Authority (CA) che faccia da garante della validità e bontà del certificato. In questo modo i certificati self signed possono essere facile oggetto di attacchi ad esempio di tipo Man In The Middle (vedere[MITMA] e [TSSLC]).
Quindi un certificato self signed è molto utile per casi di prova (come il nostro) e/o di test per applicazioni che devono comunicare con SSL; nei casi reali sarà più opportuno ottenere un certificato rilasciato da una Certification Authority.
Il formato dei certificato utilizzato da SSL è quello dettato dalla specifica X.509 (vedere [RFC_X509]).
Nel nostro caso si provvede a creare un keystore di nome mokastore.ks, identificato dall'alias mokalias e "protetto" da una password 'alberto' che permette la verifica dell'integrità del keystore. Con l'opzione -dname si specificano i dati di identificazione dell'intestatario del certificato in formato Distinguished Name X.500 (lo stesso usato, ad esempio, nei server LDAP).

%JAVA_HOME%\bin\keytool -genkey -alias "mokalias" -keystore "mokakeystore.ks" -dname "CN=Alberto, OU=Redazione, O=Mokabyte, L=Mi, S=IT, C=IT" -storepass "alberto"

Si noti che per facilitare la lettura, assoceremo in modo consistente in questo articolo il nome 'Alberto' al server ed il nome 'Stefano' al client, sia come Distinguished Name del subject che come password.
Per distribuire la chiave pubblica (nel nostro caso al client) è necessario separarla dal file di keystore. Tale procedura si compone di due passi: dapprima si esegue l'export del certificato self-signed, ottenendo un file .cer:

%JAVA_HOME%\bin\keytool -export -keystore "mokakeystore.ks" -alias "mokalias" -file "mokastorepass.cer" -storepass "alberto"

Alcune applicazioni (ad esempio i browser) sono in grado di gestire direttamente le chiavi pubbliche attraverso i file .cer. Viceversa, per poter utilizzare una chiave pubblica in modo programmatico attraverso le API Java (come è il nostro caso) dovremo importare il certificato in un file di formato JKS (lo stesso formato del keystore precedentemente generato). Come abbiamo accennato nello scorso articolo, un file di chiavi contenente solo certificati (e non anche la chiave privata, come avviene per il keystore) viene chiamato trustStore.
Per importare il certificato in un trustStore destinato al client è possibile utilizzare l'utility di import specificando il .cer che si vuole importare e il nome del trustStore che si vuole creare.

%JAVA_HOME%\bin\keytool -import -keystore "pub_mokakeystore.ks" -alias "mokalias" -file "mokastorepass.cer" -storepass "alberto"

Come terminologia, useremo in modo consistente la denominazione pub_xyz.ks per indicare il trustStore associato al keystore xyz.ks. Il file così ottenuto è pronto per essere distribuito alle postazioni client.

 

Abilitazione di IIOP/SSL su JBoss

Vediamo quindi quali sono i passi necessari per abilitare il trasporto sicuro SSL nell'esposizione di un EJB in JBoss. Ovviamente, si farà riferimento alla Server Configuration 'all' di JBoss che è quella che contiene il supporto per l'esposizione attraverso IIOP e quindi i necessari file di configurazione per poter abilitare anche il supporto a IIOP/SSL (vedere [MOKA_INT_3]). Si raccomanda inoltre di utilizzare una versione di JBoss almeno pari 3.2.5.

Innanizitutto è bene precisare che le operazioni necessarie per abilitare l'SSL non richiedono nessuna modifica a livello di sorgente Java.
Come primo passo bisonga editare il file <<JBOSS_HOME>>/server/all/deploy/iiop-service.xml e scommentare le sezioni specificate all'inizio del file per abilitare il supporto SSL: si tratta innanzitutto di scommentare l'MBean JaasSecurityDomain

<!-- (uncomment to use IIOP over SSL)
-->
<mbean code="org.jboss.security.plugins.JaasSecurityDomain"
name="jboss.security:service=JaasSecurityDomain,domain=IIOP+SSL">
<constructor>
<arg type="java.lang.String" value="IIOP+SSL"/>
</constructor>
<attribute name="KeyStoreURL">YOURKEYSTORE</attribute>
<attribute name="KeyStorePass">YOURKEYSTOREPASS</attribute>
</mbean>

Al posto delle stringhe YOURKEYSTORE, YOURKEYSTOREPASS, dovrete inserire rispettivamente un URL che punti al file di keystore che il server dovrà utilizzare e la relativa password.

Ottenuto il keystore di nome mokakeystore.ks come descritto al paragrafo precedente, al posto di YOURKEYSTORE dovrete scrivere:

file://C:/mokabyte/moka_iiop_over_ssl/cert/trust_in_target/mokakeystore.ks

e al posto di YOURKEYSTOREPASS scriverete 'alberto'. Oltre a questo, si deve procedere a scommentare l'attributo 'SecurityDomain' ed il relativo elemento innestato 'depends' presente nel MBean CorbaORBService nello stesso file

<mbean code="org.jboss.iiop.CorbaORBService"
name="jboss:service=CorbaORB">
<attribute name="ORBClass">org.jacorb.orb.ORB</attribute>
<attribute name="ORBSingletonClass">org.jboss.system.ORBSingleton</attribute>
<attribute name="ORBSingletonDelegate">org.jacorb.orb.ORBSingleton</attribute>
<attribute name="ORBPropertiesFileName">jacorb.properties</attribute>
<attribute name="PortableInterceptorInitializers">
<interceptor-initializers>
<initializer>org.jboss.iiop.codebase.CodebaseInterceptorInitializer</initializer>
</interceptor-initializers>
</attribute>
<!-- (uncomment to use IIOP over SSL)
-->
<attribute name="SecurityDomain">java:/jaas/IIOP+SSL</attribute>
<depends>jboss.security:service=JaasSecurityDomain,domain=IIOP+SSL</depends>
</mbean>

Come secondo passo bisogna editare il file <<JBOSS_HOME>>/server/all/conf/jacorb.properties che contiene i settaggi dell'ORB Jacorb integrato in JBoss.
Dovrete anzitutto impostare la property:

jacorb.security.support_ssl=on (per default è impostata a off)

Poi bisognerà impostare le property seguenti:

  • jacorb.security.ssl.client.supported_options=20
  • jacorb.security.ssl.client.required_options=0
  • jacorb.security.ssl.server.supported_options=20
  • jacorb.security.ssl.server.required_options=20

Il valore numerico 20 (esadecimale) impostato corrisponde all'opzione 'Trust in Target', come definito nella specifica CSIv2 (vedere [CORBA3.02_SPEC] al paragrafo 24.9.3). Le quattro proprietà così impostate indicano che l'ORB integrato in JBoss richiede in modo mandatorio l'impiego della feature 'Trust in Target' e cioè la verifica dell'identità dell'oggetto chiamato, quando l'ORB ha il ruolo di server, mentre la supporta senza richiederla obbligatoriamente quando è usato nel ruolo di client.
Si osservi che non si è impostata la seconda proprietà 'client.required_options' al valore 20, cosa che avrebbe reso la feature trustInTarget obbligatoriamente richiesta nell'handshake dall'ORB di JBoss anche nel suo ruolo client.
Il motivo di questa scelta è purtroppo un bug presente in Jacorb versione 2.1 (vedere [JCO_BG]), che è la versione integrata in JBoss almeno fino alla versione 3.2.6, che fa sì che quasi tutti i valori forniti alla property jacorb.security.ssl.client.required_options causino erroneamente la seguente eccezione:
NO_PERMISSION: Client-side policy requires TLS but server doesn't support it

Per le prove che faremo la proprietà jacorb.security.ssl.client.required_options verrà quindi settata sempre al valore 0. Si noti che la versione di Jacorb 2.2 standalone (ossia non integrata in JBoss) non presenta questo problema.

Se vi fermate a quanto detto finora e tentate di avviare JBoss e deployare un EJB esposto tramite RMI/IIOP, l'effetto che avrete sarà un'eccezione del tipo:

SSLHandshakeException:…. no trusted certificate found.

Cosa è successo? il fatto è che le impostazioni ora eseguite si applicano ad ogni server CORBA presente in JBoss e quindi anche al Naming Server. Il problema si manifesta infatti nel momento in cui JBoss all'atto del deploy tenta di registrare il nome del nuovo EJB al proprio Naming Server. In effetti bisogna considerare che adesso tale Naming Server è 'blindato' e utilizza anch'esso SSL in tutte le interazioni, anche quelle che sono originate dall'interno dello stesso JBoss.



Figura 1: Fallimento comunicazione tra JBoss Server e JNDI Server


Per superare questo "ostacolo", bisogna rendere noto a JBoss il certificato corrispondente alla private key che si è impostata nel primo passo.
Per rendere noto tale certificato a JBoss quando agisce come client, è sufficiente specificare come proprietà di sistema di JBoss quanto segue:

-Djavax.net.ssl.trustStore=
C:/mokabyte/moka_iiop_over_ssl/cert/trust_in_target/pub_mokakeystore.ks

Per specificare tale property potete ad esempio modificare lo script di lancio di JBoss (run.bat / run.sh) e specificare il settaggio come JAVA_ARGS.


Figura 2
: Comunicazione "sicura" tra JBoss Server e JNDI Server


Esecuzione del Client
Proviamo per prima cosa a vedere se un client Java riesce a collegarsi all'Application Server che ha l'SSL abilitato, senza utilizzare SSL.
Nel build.xml allegato agli esempi di questo articolo abbiamo incluso a tale scopo i due target 'run_iiop_sun' e 'run_iiop_jacorb'. Questi hanno lo scopo di avviare un semplice programma client che tenta di connettersi all'EJB Calculator, usando rispettivamente l'ORB SUN e quello Jacorb, ma in entrambi i casi senza utilizzare nessuna impostazione riguardo a SSL e in particolare senza possedere alcun certificato.

L'operazione giustamente fallisce in ambedue i casi perché il server forza l'utilizzo di SSL e all'atto dell'handshake trasmette al client il proprio certificato che però il client non riconosce come fidato, in quanto esso non è presente nel trustStore. Si ricorda infatti che se non viene specificato diversamente, il trustStore di un'applicazione Java è il file %JAVA_HOME%\jre\lib\security\cacerts che contiene soltanto i certificati delle CA principali.
L'errore che si ottiene è: org.omg.CORBA.NO_PERMISSION: vmcid: 0x0 minor code: 3 completed: No (vedere [MOKA_SECIOP_1]).
Vediamo quindi di far sì che il client riconosca ed autentichi il target invocato. Per far questo, bisogna indicare al client di utilizzare in luogo del trustStore di default il file pub_mokakeystore.ks contenente il certificato con la chiave pubblica del server, mediante le proprietà

-Djavax.net.ssl.trustStore=
C:/mokabyte/moka_iiop_over_ssl/cert/trust_in_target/pub_mokakeystore.ks

Oltre a questo, bisogna specificare ulteriori proprietà specifiche ad SSL e utilizzando Jacorb questo può essere fatto fornendo un file di property come quello incluso nello zip di esempi col nome jsse_client_props.

In questo file sono state impostate le property

  • jacorb.security.ssl.client.supported_options=20
  • jacorb.security.ssl.client.required_options=0

Non sono presenti le property relative al server in quanto questo è un puro client. E' inoltre necessario specificare un qualunque file di keystore, tramite la property jacorb.security.keystore, altrimenti Jacorb genera un eccezione, ma in questo caso può anche essere un keystore fasullo, perché il server non è impostato per autenticare il client.
Lanciando il client otteniamo che la comunicazione avviene con successo visto che il client riconosce correttamente il server.


Figura 3
: Trust in Target: Comunicazione sicura tra client e server


Per eseguire questa prova vi suggeriamo di lanciare il target ANT run_iiop_ssl_jacorb presente nel build.xml degli esempi.

Una cosa importante da notare nelle opzioni di lancio del client con SSL è l'URL che bisogna fornire come bootstrap per inizializzare il JNDI Context del Client. Si ricorderà che in assenza di SSL bisognava utilizzare un URL CORBA del tipo:
corbaloc:iiop:<<SERVER>>:3528/JBoss/Naming/root


Figura 4
: Comunicazione IIOP tra client e server


Utilizzando SSL (con Jacorb) l'Url da utilizzare sarà invece del tipo:

corbaloc:ssliop:<<SERVER>>:3529/JBoss/Naming/root


Figura 5: Comunicazione SSL IIOP tra client e server


Si notino le due differenze: la più elementare è il fatto che viene utilizzata la porta 3529 in luogo di 3528 perché questa è la porta usata per default dall'ORB in JBoss quando è attivo SSL (similmente a quanto avviene con il passaggio dalla porta 80 alla porta 443 quando si impiega HTTPS). L'altra differenza è che viene specificata la stringa ssliop invece che iiop. Questo serve a informare il client ORB che l'Oggetto Corba da usare per il bootstrap è esposto con SSLIOP. Si noti che questo formato di Url Corba 'ssliop' ad oggi non è ancora stato standardizzato dall'OMG benché sia la scelta impiegata da diversi vendor tra cui Jacorb.
Può essere molto istruttivo impostare nel client la system property

-Djavax.net.debug=ssl

con cui si fa sì che vengano tracciati tutti i messaggi scambiati tra il client ed il server per portare a termine la fase di handshake che è stata descritta nel numero precedente.

 

Esempio di autenticazione
Mentre l'autenticazione del target permette di essere certi che quando si invoca un Server Remoto (il Target) chi ci risponde sia effettivamente quello che ci aspettiamo, l'autenticazione mutua permette di accertarsi che anche il client che richiede un certo servizio da un Server remoto sia riconosciuto da questo come un'entità autorizzata a fruirne.
In uno scenario di comunicazioni diretta fra oggetti (B2B) può essere rilevante sia l'autenticazione del target che del client: cioè, la mutua autenticazione.

 

Generazione delle chiavi
Oltre ai certificati mokakeystore.ks e pub_mokakeystore.ks utilizzati nel precedente esempio dobbiamo creare una nuova coppia di certificati.
Creiamo quindi il keystore client_mokakeystore.ks associato a Stefano

%JAVA_HOME%\bin\keytool -genkey -alias "client_mokalias" -keystore "client_mokakeystore.ks" -dname "CN=Stefano, OU=Redazione, O=Mokabyte, L=Mi, S=IT, C=IT" -storepass "stefano"

e provvediamo ad esportarlo e ad importarlo in un file di nome pub_client_mokakeystore.ks:

%JAVA_HOME%\bin\keytool -export -keystore "client_mokakeystore.ks" -alias "client_mokalias" -file "client_mokastorepass.cer" -storepass "stefano"

%JAVA_HOME%\bin\keytool -import -keystore "pub_client_mokakeystore.ks" -alias "clent_mokalias" -file "client_mokastorepass.cer" -storepass "stefano"

E' ora necessaria un'ulteriore operazione: in questo scenario il server JBoss dovrà possedere il certificato del client (per poterlo autenticare) ma anche il certificato del server stesso (per poter autenticare il Naming Server al momento del deploy). Per ottenere questo, bisogna aggiungere al file pub_client_mokakeystore.ks anche il certificato del server:

%JAVA_HOME%\bin\keytool -import -keystore "pub_client_mokakeystore.ks" -alias "mokalias" -file "../trust_in_target/mokastorepass.cer" -storepass "stefano"

 

Abilitazione di IIOP/SSL su JBoss
Le impostazioni da fare per questo scenario sono molto simili a quelle del caso precedente: in particolare, il file iiop-service.xml dovrà essere impostato esattamente come fatto prima, infatti il server JBoss dovrà referenziare anche in questo caso la propria chiave privata collocata in: C:/mokabyte/moka_iiop_over_ssl/cert/trust_in_target/mokakeystore.ks

Il file jacorb.properties invece dovrà essere leggermente variato: in questo caso infatti dovremo impostare

jacorb.security.ssl.client.supported_options=60
jacorb.security.ssl.client.required_options=0

jacorb.security.ssl.server.supported_options=60
jacorb.security.ssl.server.required_options=60

Il valore 60 è il codice associato alla feature di mutua autenticazione; anche in questo caso bisogna lasciare a zero la property client.required_options a causa del bug sopra menzionato.
Infine, bisognerà avviare JBoss fornendo la system property

-Djavax.net.ssl.trustStore=
C:/mokabyte/moka_iiop_over_ssl/cert/mutual_authentication/pub_client_mokakeystore.ks

in modo che il server JBoss sia in grado di autenticare l'identità del proprio Naming Server e del client remoto. All'avvio di JBoss con queste impostazioni potrete notare il seguente messaggio addizionale nei log:

20:04:22,261 INFO [SSLServerSocketFactory] Will create SSL sockets that require client authentication

 

Esecuzione del client
Per completare questo passo è solo necessaria qualche lieve modifica al file contenente le property relative a ssl che abbiamo chiamato in questo caso jsse_client_props_mutual. Dovremo infatti impostare le property nel seguente modo:

jacorb.security.ssl.client.supported_options=60
jacorb.security.ssl.client.required_options=0

Inoltre in questo caso il keystore specificato mediante jacorb.security.keystore dovrà obbligatoriamente contenere un chiave privata che corrisponda ad uno dei certificati presenti nel trustStore di JBoss, perché in questo caso l'identità del client verrà validata.
Queste impostazioni sono collocate nel file jsse_client_props_mutual. Per eseguire un client in tale modalità, potrete sfruttare il task ant incluso negli esempi denominato 'run_iiop_ssl_jacorb_mutual'.
Per quanto riguarda invece il trustStore da impostare sul client attraverso la property javax.net.ssl.trustStore, questo può essere lasciato invariato rispetto al caso precedente, in quanto il client ha ancora necessità di conoscere il certificato con la chiave pubblica del server.


Figura 6
: Mutua Autenticazione: Comunicazione sicura tra client e server

 

Conclusioni
In questo articolo si sono presentati degli esempi al fine di esemplificare quanto introdotto in [MOKA_SSLIOP_1].
Per comodità del lettore abbiamo incluso nella directory degli esempi anche i file di configurazione per JBoss impostati come descritto nell'articolo.

Allegati
Scarica gli esempi allegati all'articolo

 

Bibliografia
[MOKA_SSLIOP_1] S.Rossini, A D'Angeli: IIOP over SSL (I): La teoria, MokabyteN.91-
Dicembre 2004
[RFC_X509] RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile
[MITMA] http://en.wikipedia.org/wiki/Man_in_the_middle
[TSSLC] http://www.apachefrance.com/Manuels/Tomcat_3.0/tomcat-ssl-howto.html
[JCO_BG] http://www.jacorb.org/cgibin/bugzilla/show_bug.cgi?id=464
[JBOSS] http://www.jboss.org
[JACORB] http:// www.jacorb.org
[CORBA3.02_SPEC] http://www.omg.org/technology/documents/corba_spec_catalog.htm

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it