still getting Received fatal alert: bad_certificate ,

i have key and cert (combined) into one cert.pem file , and i getting , "exception": "javax.net.ssl.SSLHandshakeException", "message": "Received fatal alert: bad_certificate", pem file is right, but i think problem is how i generating jks keystore file.

.pem cert format

BEGIN CERTIFICATE

...

END CERTIFICATE

BEGIN CERTIFICATE

...

END CERTIFICATE

BEGIN RSA PRIVATE KEY

...

END RSA PRIVATE KEY###`

combine it with keytool comand comand is

keytool -import -trustcacerts -alias yourdomain -file combined.pem -keystore yourkeystore.jks

java code is

public class HttpsTrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {
        // TODO Auto-generated method stub

    }

    @Override
    public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {
        // TODO Auto-generated method stub

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[]{};
    }
}

request is

FileInputStream instream = new FileInputStream(
      new File(this.resourcePath()+"/path_to.jks")
  );
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(instream, "password".toCharArray());

    SSLContext sslContext = SSLContexts.custom()
            .loadKeyMaterial(keyStore, "password".toCharArray()) // use null as second param if you don't have a separate key password
            .build();

    sslContext.init(null,new X509TrustManager[]{new HttpsTrustManager()}, new SecureRandom());


    HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
    HttpResponse response = httpClient.execute(
            new HttpPost("https://url")
    );
    HttpEntity entity = response.getEntity();

    System.out.println("----------------------------------------");
    System.out.println(response.getStatusLine());
    EntityUtils.consume(entity);

1 answer

  • answered 2018-05-21 21:31 dave_thompson_085

    When you use Apache SSLContexts.custom().loadKeyMaterial().build() it initializes the built context with the specified keystore and the default trustmanager. You then call sslContext.init() to re-initialize it with no keymanager and the specified trustmanager; this ignores and discards the prior initialization. As a result your context has no keymanager, and cannot do client auth.

    You need to be consistent. Either use Apache and give the (same) builder both loadKeyMaterial and loadTrustMaterial corresponding to what you want -- in particular httpclient 4.5.4 adds org.apache.http.conn.ssl.TrustAllStrategy which implements "cheerfully let all thieves and crooks see and change my supposedly secure data". Alternatively, use JSSE to directly create an SSLContext with .getInstance() and .init() it (once!) with your zero-security trustmanager and a keymanager created from your keystore (and an explicit SecureRandom if you like but if you omit that it defaults).

    However, this may not work because the keytool command you show is correct only if yourdomain was a pre-existing PrivateKeyEntry matching the cert chain you imported to it. Use keytool -list -alias yourdomain to make sure it's a PrivateKeyEntry and NOT a TrustedCertEntry. If not, and if you need to use the privatekey from the PEM file (rather than one already in a keystore) you need to first convert the key and cert chain to PKCS12 with OpenSSL, and then depending on your Java maybe convert the PKCS12 to JKS with keytool. There are dozens of Qs (and As) on several Stacks for this.