Obtener de forma programática KeyStore de PEM

¿Cómo se puede obtener mediante programación un KeyStore de un archivo PEM que contiene un certificado y una clave privada? Estoy intentando proporcionar un certificado de cliente a un servidor en una conexión HTTPS. He confirmado que el certificado de cliente funciona si utilizo openssl y keytool para obtener un archivo jks, que se carga dinámicamente. Incluso puedo hacer que funcione leyendo dinámicamente en un archivo p12 (PKCS12).

Estoy estudiando el uso de la clase PEMReader de BouncyCastle, pero no puedo superar algunos errores. Estoy ejecutando el cliente Java con la opción -Djavax.net.debug = all y el servidor web Apache con el debug LogLevel. Aunque no estoy seguro de qué buscar. El registro de errores de Apache indica:

...
OpenSSL: Write: SSLv3 read client certificate B
OpenSSL: Exit: error in SSLv3 read client certificate B
Re-negotiation handshake failed: Not accepted by client!?

El programa cliente de Java indica:

...
main, WRITE: TLSv1 Handshake, length = 48
main, waiting for close_notify or alert: state 3
main, Exception while waiting for close java.net.SocketException: Software caused connection abort: recv failed
main, handling exception: java.net.SocketException: Software caused connection abort: recv failed
%% Invalidated:  [Session-3, TLS_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT:  fatal, description = unexpected_message
...

El código del cliente:

public void testClientCertPEM() throws Exception {
    String requestURL = "https://mydomain/authtest";
    String pemPath = "C:/Users/myusername/Desktop/client.pem";

    HttpsURLConnection con;

    URL url = new URL(requestURL);
    con = (HttpsURLConnection) url.openConnection();
    con.setSSLSocketFactory(getSocketFactoryFromPEM(pemPath));
    con.setRequestMethod("GET");
    con.setDoInput(true);
    con.setDoOutput(false);  
    con.connect();

    String line;

    BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));

    while((line = reader.readLine()) != null) {
        System.out.println(line);
    }       

    reader.close();
    con.disconnect();
}

public SSLSocketFactory getSocketFactoryFromPEM(String pemPath) throws Exception {
    Security.addProvider(new BouncyCastleProvider());        
    SSLContext context = SSLContext.getInstance("TLS");

    PEMReader reader = new PEMReader(new FileReader(pemPath));
    X509Certificate cert = (X509Certificate) reader.readObject();        

    KeyStore keystore = KeyStore.getInstance("JKS");
    keystore.load(null);
    keystore.setCertificateEntry("alias", cert);

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(keystore, null);

    KeyManager[] km = kmf.getKeyManagers(); 

    context.init(km, null, null);

    return context.getSocketFactory();
} 

Noté que el servidor está emitiendo SSLv3 en el registro mientras que el cliente es TLSv1. Si agrego la propiedad del sistema -Dhttps.protocols = SSLv3, el cliente también usará SSLv3, pero aparece el mismo mensaje de error. También he intentado agregar -Dsun.security.ssl.allowUnsafeRenegotiation = true sin ningún cambio en el resultado.

He buscado en Google y la respuesta habitual para esta pregunta es usar openssl y keytool primero. En mi caso necesito leer el PEM directamente sobre la marcha. De hecho, estoy portando un programa en C ++ que ya lo hace, y francamente, estoy muy sorprendido de lo difícil que es hacerlo en Java. El código C ++:

  curlpp::Easy request;
  ...
  request.setOpt(new Options::Url(myurl));
  request.setOpt(new Options::SslVerifyPeer(false));
  request.setOpt(new Options::SslCertType("PEM"));
  request.setOpt(new Options::SslCert(cert));
  request.perform();

Respuestas a la pregunta(1)

Su respuesta a la pregunta