Newsgroup: it.comp.java
Titolo: Scambio cedrtificati Server/Client

Salve, qualcuno può spiegarmi come avviene esattamentelo
scambiodelcertificato dakl server al client, e comeilclient può
accettare questo e verificare che sia valido. Ho letto dalla
documentazione java il protocollo handshake (
http://java.sun.com/j2se/
1.4.2/docs/guide/security/jsse/JSSERefGuide.html#Introduction) ma non
ho capito bene come funzioni il tutto.
Grazie per l'aiuto.

 Grazie per l'aiuto.
Non ci sono risposte semplici perch� molto varia da sistema a sistema e 
dipende dagli strumenti di cofigurazione ma in sostanza un certificato 
fornito al cliente da un server viene verificato con una "terza parte" che 
si chiama certification autority che lo ha rilasciato (a pagamento).... 
tipicamente nelle applicazioni "casalinghe" non si spendono questi soldi e 
bisogna quindi bypassare questi controlli di sicurezza (...vedi il browser 
che ti avverte che il sito non � sicuro...).
Un modo per farlo � importare il certificato ed inserirlo nel repository del 
browser per dirgli che quel certificato � "cosa nostra".
 

Esistono due modalità di autenticazione: autenticazione del solo
server, quella usata nella stragrande maggioranza di casi (vedi siti
di commercio elettronico),, che serve a garantire il client (ovvero
l'utente remoto) dell'identità (e quindi dell'affidabilità) del
server; e la mutua autenticazione, in cui client e server si
autenticano reciprocamente, e la transazione può avvenire solo se
entrambi,al termine della fase di autenticazione (handshake) sono
"soddisfatti" dell'identità dell'altra parte. Il protocollo adottato
va sotto il nome di SSL (Secure Socket Layer) e prevede una cifratura
dei dati scambiati tra le due parti. La cifratura è fatta con
algoritmi simmetrici, la chiave di cifra è generata durante la fase di
handshake.
Per tornare all'autenticazione,questa viene fatta adottando i principi
della crittografia asimmetrica, che permette oltre alla
confidenzialità delle informazioni, anche il controllo dell'identità.
Per inciso questo meccanismo è alla base della firma digitale.
In pochissime parole, tanto per dare il senso dell'andamento delle
cose: la crittografia asimmetrica prevede che la cifratura e
decifratura vengano effettuate tramite due chiavi: con una chiave si
cifra (non importra quale delle due), con l'altra si decifra. Non è
possibile decifrare con la stessa chiave con cui si è cifrato, e non è
possibile ricostruire una chiave a partire dall'altra. Quando si vuole
adottare un sistema del genere, tutti i partecipanti hanno a
disposizione una coppia di chiavi, di cui una resta privata e nota al
solo proprietario, e l'altra è pubblica disponibile a tutti (in genere
disponibile su appositi server pubblici). In questo modo:
1. se io voglio spedirti un messaggio cifrato che solo tu possa
leggere, recupero la tua chiave pubblica e cifro il messaggio (non è
esattamente così, perché computazionalmente sarebbe troppo oneroso, ma
per semplificare diciamo che è esattamente così, la sostanza non
cambia poi molto), che a questo punto solo tu sarai in grado di
decifrare;
2. se io voglio spedirti un messaggio a darti la garanzia che sono
proprio io l'autore, cifro il mio messaggio con la mia chiave privata
e te lo spedisco. Tu sarai in grado di decifrarlo solo usando la mia
chiave pubblica, e questo ti darà la garanzia matematica (nel vero
senso della parola) che io sono l'autore, perché nessuno al di fuori
di me potrebbe aver cifrato il messaggio che tu hai potuto decifrare
con lamia chiave pubblica (a meno che qualcuno non mi abbia rubato la
chiave privata).
A ciascuna coppia di chiavi si usa associare una struttura dati
chiamata "certificato". Si tratta di un oggetto che contiene la chiave
pubblica,e alcune informazioni sull'identià del proprietario, e infine
una sezione detta "firma". Si tratta di una firma digitale,ovvero di
una cifratura fatta con una chiave privata delle struttura suddetta.
Se lafirmaè fatta con la chiave privata associata alla pubblica
contenuta nel certificato, parliamo di certificato "self-signed", Se
invece la firma è fatta da una terza parte, allora parliamo di
certificato firmata da una terza parte. Questa terza parte si chiama
Certification Authority, citata da Legione. In pratica una
Certification Authority è un'entità (costituita da un insieme di
hardware e software) che emette e firma, in maniera affidabile,
coppie di chiavi per utenti finali.
Un certificato firmato da una Certification Authority forma una catena
di certificazione: la coppia di chiavi risultata certificata da un
certificato, a sua volta certificato da una certification authority.
Se vai su un sito in https e dai uno sguardo al certificato che ti
viene proposto, troverai la catena di cui ti dicevo: vedrai un
certificato di Certification Authority (o anche più di uno: a volte le
Certification Authority sono certificate da altre Certification
Authority, e così via) su una catena,in cui l'elemento foglia è il
certificato del server.
Nell'autenticazione semplice, quando è il solo client che si assicura
del'identità del server, il controllo di affidabilità che il browser
fa quandosi connette ad un sito sicuro è proprio questo: verifica che
la firma sul certificato server sia stata apposta da una Certification
Authority sicura. La verifica della firma la fa molto semplicemente
recuperando la chiave pubblica del certificato di CA (Certification
Authority) e provando a "decifrare" la firma sul certificato server.
Tutti i browser in circolazione hanno un proprio database di
certificati di Certification Authority, necessari per questi compiti
(tali certificati possono anche essere scaricati da server pubblici,
in ogni caso, e installati nel proprio browser). Periodicamente questi
database vengono aggiornati tramite gli aggiornamentiai browser o al
sistema operativo (vedi il caso di Microsoft, che tra gli
aggiornamenti periodici propone anche quello dei "Certificati
Principali".
Quando lavori in Java, su un applicazione web, in cui non devi
preoccuparti della realizzazione del client, inteso com http user-
agent, e non devi fare particolari controlli sui vari certificati (ce
ne sono altri oltre quelli che ti ho detto che hanno a che fare con la
validità del certificato, basata su speciali strutture di controllo
delle Certificate Revocation Lists - CRL, ma anche altri controlli
aggiuntivi basati sull'identità stessa del server o del client), non
hai bisogno di scrivere codice, ti basta semplicemente configurare il
tuo servlet container o applicaiton server, o anche il solo server
http che ti fa da frontend verso il servlet container/applciaiton
server. La web application in linea di principio può essere del tutto
inconsapevole di trovarsi in esecuzione in un ambiente protetto omeno.
Ciao
Daniele

 dei dati scambiati tra le due parti. [CUT]
Penso che tu intenda "il protocollo adottato in entrambi i casi va sotto 
il nome di...", o sbaglio?
In ogni caso, a me interessa (se non ho capito male) il primo caso: 
applicazione server che deve scambiare dati con un'applet presente in 
una pagina web (quindi, accessibile a tutti). Non ho nessun bisogno di 
autenticare il client; tuttavia client e server devono scambiarsi dei 
dati in modo protetto (non intercettabile), per cui ho pensato subito a 
qualcosa come (sul server)
  SSLServerSocketFactory 
sslserversocketfactory=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
SSLServerSocket 
SSLserver=(SSLServerSocket)sslserversocketfactory.createServerSocket(/*int*/numeroPorta);
  do {
  SSLSocket client=(SSLSocket)SSLserver.accept();
//...
e analogamente sul client:
SSLSocketFactory 
sslsocketfactory=(SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket 
client=(SSLSocket)sslsocketfactory.createSocket(/*String*/IP,/*int*/numeroPorta);
//...
Il problema nasce dal fatto che (almeno con certificati "self-signed" 
con cui ho fatto i test) devo utilizzare una unica password per creare i 
due certificati per il client e per il server:
keytool -genkey -alias marco -keystore serverkeystore.jks -keyalg RSA 
-storepass "unicapassword" -keypass "unicapassword"
#creato certificato (serverkeystore.jks)
keytool -export -keystore serverkeystore.jks -alias marco -rfc -file 
certificato.cer -storepass "unicapassword"
#esportato certificato (certificato.cer)
keytool -import -alias marco -file certificato.cer -keystore 
clienttruststore.jks -storepass "unicapassword"
#importato certificato (clienttruststore.jsk)
Io pensavo che storepass e keypass fossero la chiave privata e quella 
pubblica, ma se sono diverse i certificati vengono creati, ma la 
connessione fallisce regolarmente (e, in effetti, tutti gli esempi che 
ho trovato in rete riportano la stessa password per storepass e keypass).
Risultato: se il client non conosce "unicapassword", l'applet non 
funziona: Quindi sono costretto ad inserirla nell'applet, il che 
significa che, in teoria, chiunque potrebbe facilmente, decompilando il 
codice, leggerla in chiaro.
Che tipo di sicurezza ottengo rendendo pubblica "unicapassword"? dovendo 
esserci una chiave pubblica ed una privata, non capisco quale sia quella 
privata. Forse viene generata automaticamente nel file 
serverkeystore.jks, senza che io debba digitarla? Oppure, in modo 
casuale, ad ogni tentativo di connessione? Oppure "unicapassword" � 
proprio la chiave privata, e quindi rendendola pubblica viene inficiata 
la sicurezza? Ed in quest'ultimo caso, quale sarebbe la strada corretta 
da seguire?
Ciao
Marco

 codice, leggerla in chiaro.
Qui c'è in realtà un problema di distribuzione dell'applicazione:
sulle macchine client, in cui dovrebbe andare in esecuzione l'applet,
occorre installare un truststore contenente il certificato self-signed
del server, per poterne validare l'identità. A meno che il certificato
server non sia stato emesso da una CA presente tra quelle disponibili
in cacerts (e qui dovresti pagare :-): in questo caso non hai bisogno
di nient'altro. Ad essere precisi, una cosa occorrerebbe farla:
modificare la password di default del truststore, altrimenti un
attaccante che avesse accesso alla macchina client potrebbe inserire
in cacerts un certificato di CA fasullo, o un certificato self-signed,
e ogni qual volta l'utente si connette ai server dell'attaccante, la
JVM non protesta ;-)
Ai link seguenti trovi svariati esempi di codice per architetture java
client-server che si scambiano dati con protocollo SSL:
http://stilius.net/java/java_ssl.php
http://www.exampledepot.com/egs/javax.net.ssl/GetCert.html?l=rel
http://www.jguru.com/faq/view.jsp?EID=32388
http://www.herongyang.com/JDK/SSL-Socket-Client-Example-SslSocketClient.html
Ma, ripeto, si tratta di esempi generali client-server, da cui puoi
prendere un po' di informazioni aggiuntive sul mondo ssl in java.
Ciao
Daniele

 
http://stilius.net/java/java_ssl.php
Partiamo da qui, visto che uso proprio questa strada. Per eseguire il 
file EchoServer.java (che allego in calce), devo creare il certificato 
per il server, e poi quello per il client. Questo avviene con l'istruzione:
STOREPASS="123456"
KEYPASS=$STOREPASS
keytool -genkey -alias marco -keystore serverkeystore.jks -dname 
"CN=prova" -keyalg RSA -storepass "$STOREPASS" -keypass "$KEYPASS"
Ora, la password immessa (123456), DEVE essere nota al client (che deve 
poter eseguire ava -Djavax.net.ssl.trustStore=clienttruststore.jks 
-Djavax.net.ssl.trustStorePassword=$STOREPASS EchoClient). Quindi, 
l'applet presente in una pagina web accessibile a tutti deve contentere 
la password, che quindi pu� facilmente essere letta da eventuali 
attaccanti che, se avessero accesso ad una macchina client, potrebbero 
fare cose poco simpatiche.
Ma, se  creo i certificati con
STOREPASS="123456"
KEYPASS="abcdef"
keytool -genkey -alias marco -keystore serverkeystore.jks -dname 
"CN=prova" -keyalg RSA -storepass "$STOREPASS" -keypass "$KEYPASS"
i certificati vengono creati regolarmente, ma eseguendo
java -Djavax.net.ssl.keyStore=serverkeystore.jks 
-Djavax.net.ssl.keyStorePassword=$STOREPASS EchoServer
ottengo l'eccezione
java.net.SocketException: java.security.NoSuchAlgorithmException: Error 
constructing implementation (algorithm: Default, provider: SunJSSE, 
class: sun.security.ssl.DefaultSSLContextImpl)
	at 
javax.net.ssl.DefaultSSLServerSocketFactory.throwException(SSLServerSocketFactory.java:159)
	at 
javax.net.ssl.DefaultSSLServerSocketFactory.createServerSocket(SSLServerSocketFactory.java:171)
	at EchoServer.main(EchoServer.java:15)
Caused by: java.security.NoSuchAlgorithmException: Error constructing 
implementation (algorithm: Default, provider: SunJSSE, class: 
sun.security.ssl.DefaultSSLContextImpl)
	at java.security.Provider$Service.newInstance(Provider.java:1262)
	at sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
	at sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
	at javax.net.ssl.SSLContext.getInstance(SSLContext.java:142)
	at javax.net.ssl.SSLContext.getDefault(SSLContext.java:85)
	at 
javax.net.ssl.SSLServerSocketFactory.getDefault(SSLServerSocketFactory.java:113)
	at EchoServer.main(EchoServer.java:14)
Caused by: java.io.IOException: Keystore was tampered with, or password 
was incorrect
	at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:788)
	at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
	at java.security.KeyStore.load(KeyStore.java:1201)
	at 
sun.security.ssl.DefaultSSLContextImpl.getDefaultKeyManager(DefaultSSLContextImpl.java:167)
	at 
sun.security.ssl.DefaultSSLContextImpl.<init>(DefaultSSLContextImpl.java:57)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at 
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at 
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
	at java.lang.Class.newInstance0(Class.java:372)
	at java.lang.Class.newInstance(Class.java:325)
	at java.security.Provider$Service.newInstance(Provider.java:1238)
	... 6 more
Caused by: java.security.UnrecoverableKeyException: Password 
verification failed
	at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:786)
	... 17 more
Quindi, il mio problema � il seguente: tu dici che dovrei cambiare la 
password di default del truststore, ma io riesco solo a cambiare 
storepass e keypass, purch� siano uguali, e non posso fare a meno di 
rendere pubblica tale password. Come si fa a rendere privata una delle 
due, senza pregiudicare la funzionalit� dell'applicazione, ma impedendo 
ad eventuali malintenzionati di creare certificati a mio nome?
Ti ringrazio tantissimo della risposta, che mi ha chiarito alcune cose 
che non avevo capito, e spero che tu sappia illuminarmi su questa, che 
per me � la questione centrale.
Ciao
Marco
--------------------------------------------------------
Allego testo del file EchoServer.java:
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class EchoServer
  {
   public static void main(String[]args)
    {
     try
      {
       SSLServerSocketFactory 
sslserversocketfactory=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
       SSLServerSocket sslserversocket=(SSLServerSocket) 
sslserversocketfactory.createServerSocket(9999);
       SSLSocket sslsocket=(SSLSocket)sslserversocket.accept();
       InputStream inputstream=sslsocket.getInputStream();
       InputStreamReader inputstreamreader=new 
InputStreamReader(inputstream);
       BufferedReader bufferedreader=new BufferedReader(inputstreamreader);
       String string=null;
       while ((string=bufferedreader.readLine())!=null)
        {
         System.out.println(string);
         System.out.flush();
        }
      }
     catch (Exception exception)
      {exception.printStackTrace();}
    }
  }

         at
[CUT]
Questo è un altro problema, segnalato da quel
"NoSuchAlgorithmException". L'implementazione di default della SUN
della parte crittografica non contiene tutto. SUN offre delle
interfacce, che poi devono essere implementate, un po' come accade per
JDBC. Si parla in questo caso di "Provider Crittografici", che offrono
l'implementazione richiesta. In circolazione c'è l'ottimo Bouncy
Castle (
http://www.bouncycastle.org/
), progetto Open Source che offre
l'implementazione di cui tu hai bisogno (e anche molto altro). Per
utilizzarlo, la via più breve è impostarlo come Provider crittografico
di default: in testa al tuo codice (sia client che server) devi avere
l'istruzione
Security.addProvider(new BouncyCastleProvider());
Questo risolve il tuo NoSuchAlgorithmException.
Come puoi immaginare, anche questa cosa pone un problema di
distribuzione: nella JVM client occorre avere nel classpath anche
Bouncy Castle (la via rapida è metterlo nella directory jre/lib/ext,
dove trovi anche l'implementazione di default del crypto provider
fatta da SUN. Un altra possibilità è impacchettarlo con l'applet, ma
questo fa aumentare notevolmente le dimensioni dell'applet stessa: il
file bcprov-jdkxxx.jar, che contiene l'implementazione richiesta,
"pesa" circa 1,5 MB .Nella mia esperienza lavorativa ho sviluppato
applet che effettuavano operazioni crittografiche (interagivano con
smartcard per firmare digitalmente informazioni che venivano poi
spedite al server), e mi rendo conto che si tratta di una bella rogna:
nel mio caso il provider crittografico che utilizzavo (era IAIK, a
pagamento) forniva una libreria alleggerita per applet, che conteneva
lo stretto necessario, proprio per evitare di dover intervenire sulle
macchine client, copiando nella JVM il provider crittografico.
L'applet conteneva ance il provider crittografico, che veniva
scaricato ogni volta sulla macchina client assieme all'applet. In ogni
caso le dimensioni erano comunque ragguardevoli, ma non c'era altra
possibilità, l'applet veniva distribuita ad un elevato numero di
utenti, sulle cui macchine non avevamo alcun controllo).
Nel pacchetto scaricato da Bouncy Castle trovi nella cartella dei
sorgenti anche numerosissimi esempi di utilizzo del provider
crittografico negli ambiti più svariati.
Spero che questo possa aiutarti a venirne fuori.
Ciao
Daniele

 Spero che questo possa aiutarti a venirne fuori.
A venire fuori, per il momento, direi proprio di no. Mi fa solo capire 
che la strada che seguivo, come sospettavo, � sbagliata. Io dovrei 
scambiare questi benedetti dati (almeno nome utente e password) tramite 
connessione criptata, senza che l'utente debba installare nulla sul PC 
(oltre a java), senza pregiudicare la sicurezza, e senza dover usare il 
protocollo http. Non devo creare pagine web, e ho gi� definito e 
sviluppato il protocollo di comunicazione (cosa inviare, cosa 
rispondere, e in che ordine). Mi rimane quest'ultimo piccolo (si fa per 
dire) dettaglio che manda a carte 48 tutto il resto... la sicurezza!!!
Ma scusa, quando accedo ad una pagina https, non credo che il browser mi 
comunichi la password con cui il certificato � stato creato, eppure la 
connessione criptata si fa. Possibile che non ci sia proprio modo, in 
java, di ottenere una connessione criptata senza dover comunicare al 
client la password con cui il certificato � stato creato????
Grazie delle tue risposte, che mi hanno aiutato a chiarire i miei dubbi 
(anche se ora non so proprio che pesci pigliare).
Marco

 client la password con cui il certificato è stato creato????
Purtroppo, togliendo di mezzo lo user agent (il browser), ti tocca
fare in modo che la tua applet implementi quell'insieme minimo di
funzionalità che lo user agent offre quando stabilisce connessioni
sicure. Il browser ha il suo repository di certificati, e il suo
strato crittografico per stabilire connessioni SSL. Se hai bisogno di
fare la stessa cosa, purtroppo ti tocca sviluppare la parte mancante.
Aggiungere uno strato di sicurezza ad una connessione tra applet e un
server che si parlano via stream (immagino avrai un tuo protocollo di
oggetti serializzabili che rappresentano le informazioni scambiate)
purtroppo non è una cosa banale.
In ogni caso ho fatto qualche ricerca sul web, e ho trovato un thread
interessante sui forum di SUN:
http://forums.sun.com/thread.jspa?forumID=2&threadID=479169
Uno degli ultimi interventi, a proposito della distribuzione del
truststore di cui parlavamo più sopra, prevede che il truststore
stesso sia presente nel jar dell'applet, e da lì acceduto.
Considera in ogni caso che per rendere effettivamente sicura una
soluzione di questo tipo, l'url da cui scaricare l'applet deve essere
a sua volta protetta da SSL: questo vale in generale, sia che tu metta
o non metta il truststore nel jar. In attacca man-in-the-middle
potrebbe sostituire la tua applet con un'altra e allora tutti i
discorsi di sicurezza andrebbero ma farsi benedire.
Fortunatamente per questa seconda cosa non devi implementare nulla, ti
occorre solo mettere l'ssl sulla pagina da cui scarichi l'applet.
Ciao
Daniele

 per te accettabile.
Un attimo, mi sorge un dubbio: vuoi dire che se usassi un certificato a 
pagamento (tipo Verisign), SSLServer funzionerebbe senza dover 
comunicare la password al client? Perch� io per la fase operativa 
prevedo di usare certificati "seri", solo che ancora sono in fase di test.
Supponiamo che il certificato server sia certificato da Verisign o 
affini, e che l'applicazione server e l'applet seguano una strada tipo 
http://stilius.net/java/java_ssl.php
 .
Vuoi dire che in questo caso il client riuscirebbe a stabilire la 
connessione SSL senza dover digitare
java -Djavax.net.ssl.trustStore=mySrvKeystore 
-Djavax.net.ssl.trustStorePassword=123456 EchoClient
ma solo
java EchoClient
...senza, quindi, dover conoscere la password con cui il certificato � 
stato creato perch� SSL funzioni?
Grazie mille di tutte le tue spiegazioni
Marco

 stato creato perché SSL funzioni?
Esatto: e se vuoi fare delle prove adesso, è sufficiente che tu
inserisca il tuo certificato self-signed in cacaerts (la password di
default è 'changeit').
Qui interviene un altro discorso di sicurezza: la password di default
per cacerts è changeit, chiaro riferimento al fatto che tale password
debba essere cambiata, altrimenti chiunque abbia accesso alla macchina
client può alterare il contenuto di cacerts inserendovi un proprio
certificato self-signed.
Se però decidi di cambiarla, poi occorre al solito operare sulla JVM
client per dare come parametro di avvio delle JVM la nuova password.
Al solito, qui si tratta di fare compromessi: quanto è preziosa la
"merce" scambiata (intesa come "informazioni scambiate")?
Un attacco man-in-the-middle senza compromettere la macchina client
(senza dover alterare il contenuto di cacerts) è sicuramente più
semplice di un attacco man-in-the-middle che richiede invece
l'alterazione di cacerts: se non altro, nel secondo caso l'attaccante
deve trovare il modo di entrare nelle macchine client e fare le sue
modifiche.
La cosa importante è che l'applet stessa sia scaricata da una url
protetta da SSL, per il discorso che ti facevo in precedenza, che un
attaccante, su una url in chiaro, potrebbe sostituire l'applet
originale con una maligna.
Per cui, lasciando la password di default, in ogni caso hai che il
traffico viene cifrato, non passa in chiaro. Ricordati che il traffico
è cifrato con chiavi di sessione, generate al momento dell'handshake
ssl, e che tali chiavi sono generate a partire da informazione
cirfrata con chiave pubblica che client e server si scambiano. Un
attaccante che sappia che la password dei truststore cacerts sui
client è changeit, non se ne fa nulla, se poi non riesce ad accedere
alle macchine client per alterarne fisicamente il cacerts.
Mi è venuto in mente che esistono un paio di software open source che
ti permettono di lavorare agevolmente con una GUI con chiavi,
keystore, certificati & C: si tratta di Portecle (http://
portecle.sourceforge.net/
, download all'url 
http://sourceforge.net/projects/portecle/
)
e di KeytoolUI (
http://yellowcat1.free.fr/index_ktl.html
).
Ciao
Daniele