Accetta il certificato SSL autofirmato del server nel client Java


220

Sembra una domanda standard, ma non sono riuscito a trovare indicazioni chiare da nessuna parte.

Ho un codice Java che cerca di connettermi a un server con un certificato probabilmente autofirmato (o scaduto). Il codice segnala il seguente errore:

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

A quanto ho capito, devo usare keytool e dire a java che va bene consentire questa connessione.

Tutte le istruzioni per risolvere questo problema presumono che io sia completamente esperto con keytool, come

generare la chiave privata per il server e importarla nel keystore

C'è qualcuno che potrebbe pubblicare istruzioni dettagliate?

Sto eseguendo unix, quindi lo script bash sarebbe il migliore.

Non sono sicuro che sia importante, ma il codice viene eseguito in jboss.


2
Vedi Come si accetta un certificato autofirmato con una connessione Java HttpsURLC? . Ovviamente, sarebbe meglio se puoi far usare al sito un certificato valido.
Matthew Flaschen

2
Grazie per il link, non l'ho visto durante la ricerca. Ma entrambe le soluzioni implicano un codice speciale per inviare una richiesta e sto usando il codice esistente (client Amazon WS per Java). Rispettivamente, è il loro sito che mi sto collegando e non riesco a risolvere i suoi problemi di certificato.
Nikita Rybak

2
@MatthewFlaschen - "Ovviamente, sarebbe meglio se puoi far usare al sito un certificato valido ..." - Un certificato autofirmato è un certificato valido se il client si fida di esso. Molti pensano che conferire fiducia al cartello CA / Browser sia un difetto di sicurezza.
jww

3
Correlato, vedere Il codice più pericoloso al mondo: convalida dei certificati SSL in software non browser . (Il collegamento viene fornito poiché sembra che tu stia ottenendo quelle risposte di spam che disabilitano la convalida).
jww

Risposte:


312

Hai fondamentalmente due opzioni qui: aggiungi il certificato autofirmato al tuo truststore JVM o configura il tuo client per

opzione 1

Esporta il certificato dal tuo browser e importalo nel tuo truststore JVM (per stabilire una catena di fiducia):

<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

opzione 2

Disabilita la convalida del certificato:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {     
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        } 
        public void checkClientTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
            } 
        public void checkServerTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    } 
}; 

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

Nota che non consiglio affatto l'opzione n. 2 . Disabilitare il gestore di fiducia sconfigge alcune parti di SSL e ti rende vulnerabile agli attacchi man in the middle. Preferire l'opzione n. 1 o, ancora meglio, fare in modo che il server utilizzi un certificato "reale" firmato da una CA nota.


7
Non solo l'attacco MIM. Ti rende vulnerabile alla connessione al sito sbagliato. È completamente insicuro. Vedi RFC 2246. Sono contrario a pubblicare questo TrustManager in ogni momento. Non è nemmeno corretto rispetto alle sue specifiche.
Marchese di Lorne

10
@EJP Non sto davvero raccomandando la seconda opzione (ho aggiornato la mia risposta per renderlo chiaro). Tuttavia, non pubblicarlo non risolverà nulla (questa è un'informazione pubblica) e IMHO non merita un voto negativo.
Pascal Thivent

140
@EJP È insegnando alle persone che le istruisci, non nascondendo le cose. Quindi mantenere le cose segrete o nell'oscurità non è affatto una soluzione. Questo codice è pubblico, l'API Java è pubblica, è meglio parlarne che ignorarlo. Ma posso vivere con te che non sei d'accordo.
Pascal Thivent

10
L'altra opzione, quella che non menziona, è quella di far riparare il certificato del server riparandolo da solo o chiamando le persone di supporto pertinenti. I certificati per host singolo sono davvero molto economici; scherzare con roba autografata è sciocco da un centesimo (cioè, per chi non ha familiarità con quell'idioma inglese, un insieme di priorità totalmente stupido che costa molto per risparmiare quasi nulla).
Donal Fellows

2
@Rich, 6 anni di ritardo, ma puoi anche ottenere il certificato del server in Firefox facendo clic sull'icona del lucchetto -> maggiori informazioni -> Visualizza certificato -> scheda Dettagli -> Esporta ... È ben nascosto.
Siddhartha

9

Ho inseguito questo problema a un provider di certificati che non fa parte degli host attendibili JVM predefiniti a partire da JDK 8u74. Il provider è www.identrust.com , ma non era il dominio a cui stavo cercando di connettermi. Quel dominio aveva ottenuto il suo certificato da questo provider. Vedere La copertura della radice incrociata si fida dell'elenco predefinito in JDK / JRE? - leggi un paio di voci. Vedi anche Quali browser e sistemi operativi supportano Let's Encrypt .

Quindi, per connettermi al dominio che mi interessava, che aveva un certificato rilasciato da, identrust.comho fatto i seguenti passaggi. Fondamentalmente, ho dovuto ottenere il DST Root CA X3certificato identrust.com ( ) per essere considerato attendibile dalla JVM. Sono stato in grado di farlo utilizzando Apache HttpComponents 4.5 in questo modo:

1: ottenere il certificato da indettrust in Istruzioni per il download della catena di certificati . Fare clic sul collegamento DST Root CA X3 .

2: Salva la stringa in un file denominato "DST Root CA X3.pem". Assicurati di aggiungere le righe "----- BEGIN CERTIFICATE -----" e "----- END CERTIFICATE -----" nel file all'inizio e alla fine.

3: Crea un file keystore java, cacerts.jks con il seguente comando:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4: Copia il keystore cacerts.jks risultante nella directory delle risorse della tua applicazione java / (maven).

5: utilizzare il codice seguente per caricare questo file e allegarlo a Apache 4.5 HttpClient. Questo risolverà il problema per tutti i domini che hanno certificati emessi da indetrust.comutil oracle che include il certificato nell'archivio chiavi predefinito JRE.

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

Quando il progetto viene compilato, cacerts.jks verrà copiato nel classpath e caricato da lì. A questo punto non ho provato con altri siti SSL, ma se il codice sopra "concatena" in questo certificato allora funzionerà anche loro, ma ancora una volta, non lo so.

Riferimento: contesto SSL personalizzato e come si accetta un certificato autofirmato con una connessione Java HttpsURLC?


La domanda riguarda un certificato autofirmato. Questa risposta non lo è.
Marchese di Lorne

4
Leggi la domanda (e rispondi) un po 'più da vicino.
K.Nicholas

9

Apache HttpClient 4.5 supporta l'accettazione di certificati autofirmati:

SSLContext sslContext = SSLContexts.custom()
    .loadTrustMaterial(new TrustSelfSignedStrategy())
    .build();
SSLConnectionSocketFactory socketFactory =
    new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> reg =
    RegistryBuilder.<ConnectionSocketFactory>create()
    .register("https", socketFactory)
    .build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);        
CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);

Questo crea una fabbrica di socket SSL che utilizzerà il TrustSelfSignedStrategy, lo registra con un gestore di connessione personalizzato quindi esegue un HTTP GET utilizzando quel gestore di connessione.

Sono d'accordo con coloro che recitano "non farlo in produzione", tuttavia ci sono casi d'uso per accettare certificati autofirmati al di fuori della produzione; li usiamo nei test di integrazione automatizzati, in modo da utilizzare SSL (come in produzione) anche quando non siamo in esecuzione sull'hardware di produzione.


6

Piuttosto che impostare il socket factory predefinito (che IMO è una cosa negativa), ciò influenzerà solo la connessione corrente piuttosto che ogni connessione SSL che provi ad aprire:

URLConnection connection = url.openConnection();
    // JMD - this is a better way to do it that doesn't override the default SSL factory.
    if (connection instanceof HttpsURLConnection)
    {
        HttpsURLConnection conHttps = (HttpsURLConnection) connection;
        // Set up a Trust all manager
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
        {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }

            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }

            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }
        } };

        // Get a new SSL context
        SSLContext sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        // Set our connection to use this SSL context, with the "Trust all" manager in place.
        conHttps.setSSLSocketFactory(sc.getSocketFactory());
        // Also force it to trust all hosts
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        // and set the hostname verifier.
        conHttps.setHostnameVerifier(allHostsValid);
    }
InputStream stream = connection.getInputStream();

2
Il tuo checkServerTrustednon implementa la logica necessaria per confidare in realtà il certificato e garantiscono i certificati non attendibili vengono respinte. Questo potrebbe fare una buona lettura: Il codice più pericoloso al mondo: convalida dei certificati SSL in software non browser .
jww

1
Il tuo getAcceptedIssuers()metodo non è conforme alle specifiche e questa "soluzione" rimane radicalmente insicura.
Marchese di Lorne

6

Esiste un'alternativa migliore all'affidabilità di tutti i certificati: creare un certificato TrustStoreche si fidi specificamente di un determinato certificato e usarlo per creare un SSLContextda cui ottenere il SSLSocketFactoryset su HttpsURLConnection. Ecco il codice completo:

File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

In alternativa è possibile caricare KeyStoredirettamente da un file o recuperare il certificato X.509 da qualsiasi fonte attendibile.

Notare che con questo codice, i certificati in cacertsnon verranno utilizzati. Questo particolare HttpsURLConnectionsi fiderà solo di questo certificato specifico.


La [documentazione Android] ( developer.android.com/training/articles/security-ssl#SelfSigned ) fornisce fondamentalmente la tua spiegazione. Fornisce solo un po 'più di spiegazioni, codice e avvertimenti.
Daniel

Secondo me questa dovrebbe essere la risposta accettata! Il vantaggio di questo metodo è che si fa tutto in modo programmatico e si mantiene comunque la sicurezza e non si modifica il truststore di JRE. L'opzione # 2 dalla risposta accettata è completamente sbagliata per motivi di sicurezza. Grazie per aver fornito questa soluzione!
actunderdc

1

Considera attendibili tutti i certificati SSL: - Puoi bypassare SSL se desideri eseguire il test sul server di prova. Ma non utilizzare questo codice per la produzione.

public static class NukeSSLCerts {
protected static final String TAG = "NukeSSLCerts";

public static void nuke() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] { 
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    X509Certificate[] myTrustedAnchors = new X509Certificate[0];  
                    return myTrustedAnchors;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {}

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {}
            }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
    } catch (Exception e) { 
    }
}

}

Chiamare questa funzione nella funzione onCreate () in Activity o nella classe dell'applicazione.

NukeSSLCerts.nuke();

Questo può essere utilizzato per Volley in Android.


Non sono del tutto sicuro del motivo per cui sei stato votato, a meno che il codice non funzioni. Forse è il presupposto che Android sia in qualche modo coinvolto quando la domanda originale non ha taggato Android.
Lo-Tan

1

La risposta accettata va bene, ma vorrei aggiungere qualcosa a questo dato che stavo usando IntelliJ su Mac e non riuscivo a farlo funzionare usando il JAVA_HOME variabile path.

Si scopre che Java Home era diverso quando si esegue l'applicazione da IntelliJ.

Per capire esattamente dove si trova, puoi semplicemente fare System.getProperty("java.home")come da dove vengono letti i certificati attendibili.


1

Ho avuto il problema che stavo passando un URL in una libreria che chiamava url.openConnection();ho adattato la risposta di jon-daniel,

public class TrustHostUrlStreamHandler extends URLStreamHandler {

    private static final Logger LOG = LoggerFactory.getLogger(TrustHostUrlStreamHandler.class);

    @Override
    protected URLConnection openConnection(final URL url) throws IOException {

        final URLConnection urlConnection = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile()).openConnection();

        // adapated from
        // /programming/2893819/accept-servers-self-signed-ssl-certificate-in-java-client
        if (urlConnection instanceof HttpsURLConnection) {
            final HttpsURLConnection conHttps = (HttpsURLConnection) urlConnection;

            try {
                // Set up a Trust all manager
                final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    @Override
                    public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
                    }

                    @Override
                    public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
                    }
                } };

                // Get a new SSL context
                final SSLContext sc = SSLContext.getInstance("TLSv1.2");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                // Set our connection to use this SSL context, with the "Trust all" manager in place.
                conHttps.setSSLSocketFactory(sc.getSocketFactory());
                // Also force it to trust all hosts
                final HostnameVerifier allHostsValid = new HostnameVerifier() {
                    @Override
                    public boolean verify(final String hostname, final SSLSession session) {
                        return true;
                    }
                };

                // and set the hostname verifier.
                conHttps.setHostnameVerifier(allHostsValid);

            } catch (final NoSuchAlgorithmException e) {
                LOG.warn("Failed to override URLConnection.", e);
            } catch (final KeyManagementException e) {
                LOG.warn("Failed to override URLConnection.", e);
            }

        } else {
            LOG.warn("Failed to override URLConnection. Incorrect type: {}", urlConnection.getClass().getName());
        }

        return urlConnection;
    }

}

Utilizzando questa classe è possibile creare un nuovo URL con:

trustedUrl = new URL(new URL(originalUrl), "", new TrustHostUrlStreamHandler());
trustedUrl.openConnection();

Questo ha il vantaggio che è localizzato e non sostituisce l'impostazione predefinita URL.openConnection.


0

Se "loro" utilizzano un certificato autofirmato, spetta a loro eseguire i passaggi necessari per rendere utilizzabile il proprio server. In particolare, ciò significa fornirti il ​​loro certificato offline in modo affidabile. Quindi faglielo fare. Quindi importalo nel tuo truststore utilizzando il keytool come descritto nella Guida di riferimento JSSE. Non pensare nemmeno all'insicuro TrustManager pubblicato qui.

EDIT A beneficio dei diciassette (!) Downvoters e dei numerosi commentatori di seguito, che chiaramente non hanno effettivamente letto ciò che ho scritto qui, questo non è un jeremiad contro i certificati autofirmati. Non c'è niente di sbagliato con i certificati autofirmati se implementati correttamente. Tuttavia, il modo corretto per implementarli è che il certificato venga consegnato in modo sicuro tramite un processo offline, piuttosto che tramite il canale non autenticato che verranno utilizzati per l'autenticazione. Sicuramente questo è ovvio? È certamente ovvio per ogni organizzazione attenta alla sicurezza per cui abbia mai lavorato, dalle banche con migliaia di filiali alle mie aziende. La "soluzione" di base di codice lato client per fidarsi di tuttii certificati, inclusi i certificati autofirmati firmati da chiunque o da qualsiasi organo arbitrale che si costituisca come CA, non sono ipso facto sicuri. Sta solo giocando con la sicurezza. È inutile. Stai intrattenendo una conversazione privata, a prova di manomissione, a prova di risposta, a prova di iniezione con ... qualcuno. Chiunque. Un uomo in mezzo. Un imitatore. Chiunque. Puoi anche usare solo testo in chiaro.


2
Solo perché alcuni server hanno deciso di utilizzare https, non significa che la persona con il client si preoccupi della sicurezza per i propri scopi.
Gus

3
Sono sorpreso che questa risposta sia stata sottovalutata così tanto. Mi piacerebbe capire un po 'di più il motivo. Sembra che EJP suggerisca di non utilizzare l'opzione 2 perché consente un grave difetto di sicurezza. Qualcuno potrebbe spiegare perché (oltre alle impostazioni di pre-distribuzione) perché questa risposta è di bassa qualità?
cr1pto

2
Beh, immagino tutto. Che cosa significa "sta a loro prendere le misure necessarie per rendere utilizzabile il loro server" ? Cosa deve fare un operatore di server per renderlo utilizzabile? Quali sono i passaggi che hai in mente? Potete fornire un elenco di loro? Ma tornando indietro a 300 metri, come si collega al problema che l'OP ha chiesto? Vuole sapere come fare in modo che il client accetti il ​​certificato autofirmato in Java. È una semplice questione di conferire fiducia nel codice poiché l'OP trova il certificato accettabile.
jww

2
@EJP - Correggimi se sbaglio, ma accettare un certificato autofirmato è una decisione politica lato client. Non ha nulla a che fare con le operazioni lato server. Il cliente deve prendere la decisione. Le parità devono collaborare per risolvere il problema della distribuzione delle chiavi, ma ciò non ha nulla a che fare con il rendere utilizzabile il server.
jww

3
@EJP - Certamente non ho detto "fidati di tutti i certificati" . Forse mi manca qualcosa (o stai leggendo troppo nelle cose) ... L'OP ha il certificato e per lui è accettabile. Vuole sapere come fidarsi. Probabilmente mi sto dividendo i capelli, ma non è necessario che il certificato venga consegnato offline. Dovrebbe essere utilizzata una verifica fuori banda, ma non è la stessa cosa che "deve essere consegnata al client offline" . Potrebbe anche essere il negozio che produce il server e il client, quindi ha la conoscenza a priori richiesta .
jww


0

Invece di utilizzare keytool come suggerito dal commento in alto, su RHEL puoi utilizzare update-ca-trust a partire dalle versioni più recenti di RHEL 6. Dovrai avere il certificato in formato pem. Poi

trust anchor <cert.pem>

Modifica /etc/pki/ca-trust/source/cert.p11-kit e cambia "categoria certificato: altra voce" in "categoria certificato: autorità". (Oppure usa sed per farlo in uno script.) Quindi fallo

update-ca-trust

Un paio di avvertimenti:

  • Non sono riuscito a trovare "fiducia" sul mio server RHEL 6 e yum non si è offerto di installarlo. Ho finito per usarlo su un server RHEL 7 e copiare il file .p11-kit.
  • Per fare in modo che funzioni per te, potresti doverlo fare update-ca-trust enable . Questo sostituirà / etc / pki / java / cacerts con un collegamento simbolico che punta a / etc / pki / ca-trust / extracted / java / cacerts. (Quindi potresti voler eseguire prima il backup del primo.)
  • Se il tuo client java utilizza cacerts archiviati in un'altra posizione, ti consigliamo di sostituirlo manualmente con un collegamento simbolico a / etc / pki / ca-trust / extracted / java / cacerts o sostituirlo con quel file.

0

La risposta accettata necessita di un'opzione 3

INOLTRE l'opzione 2 è TERRIBILE . Non dovrebbe MAI essere usato (specialmente in produzione) poiché fornisce un FALSO senso di sicurezza. Usa semplicemente HTTP invece dell'opzione 2.

OPZIONE 3

Utilizzare il certificato autofirmato per effettuare la connessione Https.

Ecco un esempio:

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.KeyStore;

/*
 * Use a SSLSocket to send a HTTP GET request and read the response from an HTTPS server.
 * It assumes that the client is not behind a proxy/firewall
 */

public class SSLSocketClientCert
{
    private static final String[] useProtocols = new String[] {"TLSv1.2"};
    public static void main(String[] args) throws Exception
    {
        URL inputUrl = null;
        String certFile = null;
        if(args.length < 1)
        {
            System.out.println("Usage: " + SSLSocketClient.class.getName() + " <url>");
            System.exit(1);
        }
        if(args.length == 1)
        {
            inputUrl = new URL(args[0]);
        }
        else
        {
            inputUrl = new URL(args[0]);
            certFile = args[1];
        }
        SSLSocket sslSocket = null;
        PrintWriter outWriter = null;
        BufferedReader inReader = null;
        try
        {
            SSLSocketFactory sslSocketFactory = getSSLSocketFactory(certFile);

            sslSocket = (SSLSocket) sslSocketFactory.createSocket(inputUrl.getHost(), inputUrl.getPort() == -1 ? inputUrl.getDefaultPort() : inputUrl.getPort());
            String[] enabledProtocols = sslSocket.getEnabledProtocols();
            System.out.println("Enabled Protocols: ");
            for(String enabledProtocol : enabledProtocols) System.out.println("\t" + enabledProtocol);

            String[] supportedProtocols = sslSocket.getSupportedProtocols();
            System.out.println("Supported Protocols: ");
            for(String supportedProtocol : supportedProtocols) System.out.println("\t" + supportedProtocol + ", ");

            sslSocket.setEnabledProtocols(useProtocols);

            /*
             * Before any data transmission, the SSL socket needs to do an SSL handshake.
             * We manually initiate the handshake so that we can see/catch any SSLExceptions.
             * The handshake would automatically  be initiated by writing & flushing data but
             * then the PrintWriter would catch all IOExceptions (including SSLExceptions),
             * set an internal error flag, and then return without rethrowing the exception.
             *
             * This means any error messages are lost, which causes problems here because
             * the only way to tell there was an error is to call PrintWriter.checkError().
             */
            sslSocket.startHandshake();
            outWriter = sendRequest(sslSocket, inputUrl);
            readResponse(sslSocket);
            closeAll(sslSocket, outWriter, inReader);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            closeAll(sslSocket, outWriter, inReader);
        }
    }

    private static PrintWriter sendRequest(SSLSocket sslSocket, URL inputUrl) throws IOException
    {
        PrintWriter outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sslSocket.getOutputStream())));
        outWriter.println("GET " + inputUrl.getPath() + " HTTP/1.1");
        outWriter.println("Host: " + inputUrl.getHost());
        outWriter.println("Connection: Close");
        outWriter.println();
        outWriter.flush();
        if(outWriter.checkError())        // Check for any PrintWriter errors
            System.out.println("SSLSocketClient: PrintWriter error");
        return outWriter;
    }

    private static void readResponse(SSLSocket sslSocket) throws IOException
    {
        BufferedReader inReader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
        String inputLine;
        while((inputLine = inReader.readLine()) != null)
            System.out.println(inputLine);
    }

    // Terminate all streams
    private static void closeAll(SSLSocket sslSocket, PrintWriter outWriter, BufferedReader inReader) throws IOException
    {
        if(sslSocket != null) sslSocket.close();
        if(outWriter != null) outWriter.close();
        if(inReader != null) inReader.close();
    }

    // Create an SSLSocketFactory based on the certificate if it is available, otherwise use the JVM default certs
    public static SSLSocketFactory getSSLSocketFactory(String certFile)
        throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException
    {
        if (certFile == null) return (SSLSocketFactory) SSLSocketFactory.getDefault();
        Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(new File(certFile)));

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("server", certificate);

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

        return sslContext.getSocketFactory();
    }
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.