La autenticación del cliente fue exitosa cuando se usa un pfx con Java, falla al usar OpenSSL. ¿Por qué?

1

He estado tratando de solucionar problemas con la autenticación del cliente y veo un comportamiento diferente cuando me conecto desde una aplicación Java frente a OpenSSL.

Un tercero me ha proporcionado un pfx, he extraído el certificado y la clave (que coinciden entre sí) y he intentado iniciar una conexión mediante openssl. Me sale el siguiente fallo de saludo:

CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=2 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 2006 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 3 Public Primary Certification Authority - G5
verify return:1
depth=1 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = Terms of use at https://www.verisign.com/rpa (c)10, CN = VeriSign Class 3 International Server CA - G3
verify return:1
depth=0 C = US, ST = Somewhere, L = Somewhere, O = The Third Party, OU = TTP, CN = thethirdparty.com
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server certificate request A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client certificate A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write certificate verify A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL3 alert read:fatal:handshake failure
SSL_connect:failed in SSLv3 read finished A
140735253803088:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:s3_pkt.c:1472:SSL alert number 40
140735253803088:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:

El tercero también me envió una aplicación Java, que usa el mismo pfx, y se autentica correctamente. El código es el siguiente:

    private void postHTTPSUsingClientAuth()
    {
        log.info("starting test");
        final String url="https://thethirdpartyendpoint.com";
        final String GUID = "(A guid)";
        final String KEY = "(A key)";
        final String DATA = "Any Data";
        final String clientCert="/testdata/theClientCert.pfx";
        final String password = "password here";

        log.info("using URL: "+url);
        log.info("using guid | key: "+GUID+" | "+KEY);
        log.info("using certificate: "+clientCert);

        try
        {
            KeyStore keyStore = getKeyStore(clientCert,password);
            CloseableHttpClient client=getHttpClientWithClientCert(keyStore,password);
            HttpPost request = new HttpPost(url);
            request.addHeader("clientId", GUID);
            request.addHeader("key", KEY);
            request.setEntity(new StringEntity(DATA));

            // add request header
            HttpResponse response = client.execute(request);
            log.info("got response: "+response.getStatusLine().getStatusCode());

            BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer result = new StringBuffer();
            String line = "";
            log.info("writing response");
            while ((line = rd.readLine()) != null)
            {
                result.append(line);
            }
            log.info("result=\n"+result);
        }
        catch (Exception e)
        {
            log.error("error occurred: "+e.toString());
        }
        log.info("test complete");
    }



private KeyStore getKeyStore(String certFile, String password) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
    {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //log.info("testing resource location");
        //log.info("available="+getClass().getResourceAsStream(certFile).available());
        keyStore.load(getClass().getResourceAsStream(certFile), password.toCharArray());
        return keyStore;
    }

    private CloseableHttpClient getHttpClientWithClientCert(KeyStore keyStore, String password) throws Exception
    {
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
        keyManagerFactory.init(keyStore, password.toCharArray());
        final SSLContext context = SSLContext.getInstance("TLS");
        context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
        return HttpClientBuilder.create()
                .setSSLSocketFactory(new SSLConnectionSocketFactory(context)).build();      
    }   

¿Alguien puede explicar por qué, al usar el mismo certificado, el protocolo de enlace falla para OpenSSL?

El certificado del cliente contiene una cadena:

Bag Attributes
    localKeyID: 01 00 00 00 
subject=/O=Something/OU=Something/CN=Something.Something.com
issuer=/DC=net/DC=Something/DC=Something/CN=Something
-----BEGIN CERTIFICATE-----
(cert data)
-----END CERTIFICATE-----
Bag Attributes: <Empty Attributes>
subject=/O=Something/CN=Something
issuer=/O=Something/CN=Something
-----BEGIN CERTIFICATE-----
(cert data)
-----END CERTIFICATE-----
Bag Attributes: <Empty Attributes>
subject=/DC=Something/DC=Something/DC=Something/CN=Something
issuer=/O=Something/CN=Something
-----BEGIN CERTIFICATE-----
(cert data)
-----END CERTIFICATE-----

¿Existe la posibilidad de que OpenSSL omita esta cadena y solo envíe el certificado superior?

    
pregunta Mark Kelly 12.11.2015 - 01:29
fuente

1 respuesta

1

Mi conjetura es que simplemente ha agregado el certificado de hoja y el certificado de cadena al mismo archivo y luego utilizó openssl s_client -cert file.pem en él. Pero, la documentación para los estados del cliente:

-CAfile file
    A file containing trusted certificates to use during server authentication
    and to use when attempting to build the client certificate chain.

Esto significa que tiene que dar el certificado de hoja con la opción -cert pero agregar los certificados de cadena con la opción -CAfile . Consulte también enlace

    
respondido por el Steffen Ullrich 12.11.2015 - 06:33
fuente

Lea otras preguntas en las etiquetas