Obtenir par programme le KeyStore à partir de PEM

Comment peut-on obtenir par programmation un fichier de clés à partir d'un fichier PEM contenant à la fois un certificat et une clé privée? Je suis tente de fournir un certificat du client à un serveur dans une connexion HTTPS. J'ai confirmé que le certificat du client fonctionne si j'utilise openssl et keytool pour obtenir un fichier jks, dont j'ai la charge dynamiquement. Je peux même le faire fonctionner par dynamiquement la lecture dans un p12 (PKCS12) fichier.

Je suis à la recherche dans l'aide de la PEMReader classe de BouncyCastle, mais je ne peux pas obtenir au-delà de certaines erreurs. Je suis en cours d'exécution Java client -Djavax.net.debug=toutes option et le serveur web Apache avec le LogLevel debug. Je ne suis pas sûr de ce qu'il faut chercher. Le journal des erreurs d'Apache indique:

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

Le client Java programme indique:

...
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
...

Le code de client :

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();
} 

J'ai remarqué que le serveur est outputing SSLv3 dans le journal pendant que le client est TLSv1. Si j'ajoute le système de la propriété -Dhttps.les protocoles=SSLv3 alors le client va utiliser SSLv3, mais j'obtiens le même message d'erreur. J'ai aussi essayé d'ajouter -Dsun.de sécurité.le protocole ssl.allowUnsafeRenegotiation=true avec aucun changement dans les résultats.

J'ai googlé autour et la réponse habituelle à cette question est d'utiliser openssl et keytool premier. Dans mon cas, j'ai besoin de lire le PEM directement à la volée. Je suis en fait le portage d'un programme C++ qui fait déjà cela, et franchement, je suis très surpris de voir combien il est difficile de le faire en Java. Le code 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();

source d'informationauteur Ryan