Sono stato incaricato di implementare un server Web Java personalizzato/autonomo in grado di elaborare messaggi SSL e non SSL sulla stessa porta.Handshaking SSL utilizzando certificati autofirmati e SSLEngine (JSSE)
Ho implementato un server NIO e funziona abbastanza bene per richieste non SSL. Sto avendo un pò di tempo con il pezzo SSL e potrei davvero usare qualche consiglio.
Ecco cosa ho fatto finora.
Per distinguere tra messaggi SSL e non SSL, controllo il primo byte della richiesta in ingresso per verificare se si tratta di un messaggio SSL/TLS. Esempio:
byte a = read(buf);
if (totalBytesRead==1 && (a>19 && a<25)){
parseTLS(buf);
}
Nelle parseTLS() metodo che istanziare uno SSLEngine simili:
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
java.security.KeyStore ts = java.security.KeyStore.getInstance("JKS");
ks.load(new java.io.FileInputStream(keyStoreFile), passphrase);
ts.load(new java.io.FileInputStream(trustStoreFile), passphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLEngine serverEngine = sslc.createSSLEngine();
serverEngine.setUseClientMode(false);
serverEngine.setEnableSessionCreation(true);
serverEngine.setWantClientAuth(true);
volta che lo SSLEngine viene istanziata, ho elaborare i dati in ingresso utilizzando i metodi di decifratura/involucro utilizzando il codice direttamente del funzionario JSSE Samples:
log("----");
serverResult = serverEngine.unwrap(inNetData, inAppData);
log("server unwrap: ", serverResult);
runDelegatedTasks(serverResult, serverEngine);
log("----");
serverResult = serverEngine.wrap(outAppData, outNetData);
log("server wrap: ", serverResult);
runDelegatedTasks(serverResult, serverEngine);
la prima parte della stretta di mano sembra funzionare bene. Il client invia un messaggio stretta di mano e il server risponde con un messaggio con 4 record:
handshake (22)
- server_hello (2)
- certificate (11)
- server_key_exchange (12)
- certificate_request (13)
- server_hello_done (14)
Avanti, il client invia un messaggio con tre parti:
handshake (22)
- certificate (11)
- client_key_exchange (16)
change_cipher_spec (20)
- client_hello (1)
handshake (22)
*** Encrypted Message ****
Lo SSLEngine scarta la richiesta del client e analizza i record ma il metodo wrap produce 0 byte con uno stato di handshake di OK/NEED_UNWRAP. In altre parole, non c'è niente da restituire al cliente e la stretta di mano arriva a una brusca frenata.
Questo è il punto in cui sono bloccato.
Nel debugger, posso vedere che SSLEngine, in particolare ServerHandshaker, non trova alcun peer certs. Questo è piuttosto ovvio quando guardo il record del certificato dal client che è lungo 0 byte. Ma perché?
Posso solo supporre che ci sia qualcosa di sbagliato nella risposta di HelloServer ma non riesco a metterci il dito sopra. Il server sembra inviare un certificato valido ma il client non sta inviando nulla indietro. C'è un problema con il mio keystore? O è il truststore? O ha qualcosa a che fare con il modo in cui sto istanziando SSLEngine? Sono perplesso.
paio di altri punti:
- L'archivio chiavi e truststore si fa riferimento nel codice snippit sopra sono stati creati utilizzando il seguente tutorial: http://www.techbrainwave.com/?p=953
- sto usando Firefox 10 e IE 9 come il client di prova il server. Stessi risultati per entrambi i client web.
- Utilizzo Sun/Oracle JDK 6 e Java Secure Socket Extension (JSSE) fornito in dotazione.
Non vedo l'ora di avere una guida che potreste avere, ma per favore non dirmi che sono pazzo o di usare Netty o Grizzly o qualche altra soluzione esistente. Non è un'opzione in questo momento. Voglio solo capire cosa sto facendo male.
Grazie in anticipo!
Solo una domanda stupida: hai generato e installato certificati client in es. Firefox quando ti connetti al tuo web-server tramite HTTPS? – Robert
Sì. FF mi ha chiesto di accettare/rifiutare il certificato. Ho cliccato su "Accetto i rischi tecnici" e posso vedere il certificato in Strumenti-> Opzioni-> Avanzate-> Crittografia-> Visualizza certificati-> Server. Infatti, FF non invierà il secondo messaggio di handshake senza questo. – Peter
Non è quello che stavo chiedendo. Stavo chiedendo il certificato del cliente. L'autenticazione del client SSL è facoltativa e utilizzata principalmente in ambienti aziendali, spesso in combinazione con chip-card. Se il client non ha un certificato installato (sezione "Il tuo certificato" di Firefox) non ne invierà uno. – Robert