2012-03-09 20 views
5

Sto provando a scrivere un client (un middleware in effetti, che è un client per un'entità, ma che funge anche da server per gli altri). Nella sua capacità di client dovrebbe parlare con un altro server (VirtualCenter di VMware) e chiedergli di fare cose per suo conto.Forzare il socket client SSL per inviare il certificato

Per offrire più contesto, VirtualCenter consente a un'applicazione di registrarsi come un'estensione. Tale domanda potrebbe registrare il suo certificato al momento della registrazione (setCertificate). Successivamente, l'applicazione può accedere a VirtualCenter utilizzando il suo certificato (metodo loginExtensionByCertificate()) e quindi non è necessario memorizzare nome utente e password. Tuttavia, affinché funzioni, il client (la mia app) deve inviare un certificato come parte della sua connessione SSL, anche se il server (VirtualCenter) non lo richiede in particolare.

Sto scrivendo la mia app con Java. Ho creato il mio gestore di chiavi, l'ho collegato al mio keystore e specificato l'alias da usare. Quindi inizializzato il mio contesto ssl per usare quel gestore di chiavi. Nei socket creati, vedo che il loro SSLContext ha il mio key manager in loro. Tuttavia, non vedo che il gestore di chiavi sia mai stato chiamato per ottenere il certificato. Per qualche motivo, il socket non ritiene necessario inviare un certificato.

Capisco che il server possa chiedere al cliente di presentare il suo certificato. In questo caso, non succede. Quello che mi chiedo se ci sia un modo per forzare il socket creato a presentare un certificato indipendentemente dal fatto che il server lo richieda.

+0

Suggerisco di eseguire il debug dell'handshake utilizzando '-Djavax.net.debug = ssl' o almeno' Djavax.net.debug = ssl: handshake' per vedere se si ottiene un 'CertificateRequest' e controllare l'elenco' certificate_authorities' contiene. – Bruno

risposta

2

Tuttavia, per far funzionare tutto questo, il cliente (la mia app) deve inviare un certificato come parte della sua connessione SSL, anche se il server (VirtualCenter) non chiede particolarmente

per funzionare, il server deve chiedere per essa. Ecco come viene definito il protocollo SSL. Se si può fare in modo che il client lo invii non richiesto, cosa che non si può fare, il server sarebbe obbligato a interrompere la connessione.

La soluzione è al server. Sei sicuro al 100% che non stia chiedendo? Forse sta chiedendo ma il tuo cliente non sta inviando? ad esempio, poiché il certificato non è firmato da una CA che il server considera attendibile.

+0

Sei sicuro della "caduta della connessione"? AFAIK IIS può essere impostato per ignorare i certificati client. –

+0

@desaivv RFC 4346 'Questo messaggio viene inviato solo se il server richiede un certificato' sembra abbastanza chiaro; forse non è obbligato a disconnettere la connessione, ma JSSE di certo non invierà un certificato se non richiesto. Non so nulla di IIS. – EJP

+1

La sezione 7.4 dice anche "* I messaggi del protocollo di handshake sono presentati di seguito nell'ordine in cui DEVONO essere inviati, l'invio di messaggi di handshake in un ordine inaspettato causa un errore fatale *". Prenderò in considerazione l'invio di un messaggio 'ClientCertificate' non richiesto come" ordine inatteso "(quindi questo interromperà la connessione). @desaivv, cosa intendi con "IIS può essere impostato per ignorare i certificati client"? (Qualsiasi doc/puntatore?) Non sta "ignorando" qui solo per non utilizzarli per l'autenticazione/l'autorizzazione dell'applicazione seduta dietro? – Bruno

4

I certificati client possono essere inviati solo se il server lo richiede. Vedere TLS Spec. - Client Certificate message (RFC 4346, Section 7.4.6):

Questo è il primo messaggio il cliente può inviare, dopo aver ricevuto un server di ciao messaggio fatto. Questo messaggio viene inviato solo se il server richiede un certificato.

Non è possibile forzare il client a inviare un certificato client se il server non ne ha richiesto uno.

MODIFICA: Ovviamente, è anche necessario assicurarsi che il keymanager/keystore sia impostato correttamente. Si potrebbe affrontare problemi simili a quelli descritti in why doesn't java send the client certificate during SSL handshake?

0

VMware VC richiede sempre il certificato SSL del client, poiché questo è il numero di estensioni autenticate che si registrano in VC. Quindi, sei sulla strada giusta.

Sospetto che stiate solo avendo problemi con le interazioni SSL/Java, e non è un problema specifico di VMware (anche se è sempre difficile dirlo con SSL ...).

Penso che si desidera di seguire i suggerimenti qui: Java client certificates over HTTPS/SSL

0

Infine, ha risolto il problema. Sembra che VMware abbia un percorso molto diverso. La domanda è stata fraintesa.

Innanzitutto, ho tracciato la connessione tramite WireShark e in nessun punto il server richiede (necessita o desidera) un certificato. Tuttavia, VirtualCenter (VC) fornisce un modo per registrare un certificato come parte di una connessione e quindi utilizzare tale certificato per autenticare. Perché funzioni, forniscono un modo per connessioni tunnel.

La sequenza che ho usato è:

  • prima specificare l'URL per la connessione a come https: //: (notare che il protocollo è sicuro, ma la porta non è).

  • Il socket iniziale verrà aperto sulla porta di testo in chiaro. Ma avendo https come il protocollo costringerà a chiamare il mio SSLSocketFactory. Nella mia fabbrica di prese, ricevo una chiamata al mio metodo public Socket createSocket(Socket s, String host, int port, boolean autoClose), che mi consente di convertire il mio socket in SSLSocket a mio piacimento.

mio codice è essenzialmente simile:

@Override 
public Socket createSocket(Socket s, String host, int port, boolean autoClose) 
    throws IOException { 
    s.setKeepAlive(true); 
    String connectReq = "CONNECT /sdkTunnel HTTP/1.1\r\n\r\n"; 
    OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream()); 
    writer.write(connectReq, 0, connectReq.length()); 
    writer.flush(); 
    // In this initial response, all that matters is the http code. If 
    // it is 200, the rest can be ignored. 
    READ_AND_VERIFY_INITIAL_RESPONSE(); 
    SSLSocket sock = (SSLSocket) origSslSockFactory 
     .createSocket(s, s.getInetAddress().getHostName(), s.getPort(), true); 
    // Depending on whether the caller actually does the handshake 
    // or not, you may need to call handshake here. In my case, I 
    // did not need to, since HTTPClient I am using calls the 
    // handshake. Axis does not call, so you may have to in that 
    // case. 

    // sock.startHandshake(); 
    return sock; 
} 

Nel blocco di cui sopra, è l'origSslSockFactory SSLSocketFactory che ha ottenuto sostituito da l'implementazione. Nel mio caso era un'istanza di sun.security.ssl.SSLSocketFactoryImpl.

Dopo questa procedura, chiamare ExtensionManager.setExtensionCertificate() ha esito positivo. E successivamente, tutte le chiamate a SessionManager.loginExtensionByCertificate() hanno esito positivo.

Ho voluto postare questo perché sembrano esserci molte domande a riguardo.

0

Quando vCenter è installato, utilizza un proxy inverso sulla porta 443 che inoltra le richieste su HTTP al servizio effettivo. Il proxy non richiede mai il certificato client né sarebbe in grado di inoltrarlo.

Cercare di trovare la porta effettiva su cui è in esecuzione il servizio e connettersi.

Problemi correlati