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
Vous devez vous connecter pour publier un commentaire.
J'ai tout compris. Le problème est que le X509Certificate par lui-même n'est pas suffisante. J'avais besoin de mettre la clé privée dans le générées dynamiquement fichier de clés. Il ne semble pas qu'BouncyCastle PEMReader peut gérer un fichier PEM avec les deux cert et la clé privée en une seule fois, mais il peut traiter chaque pièce séparément. Je peux lire le PEM en mémoire de moi-même et de le diviser en deux catégories distinctes et puis les nourrir chacun à une distincte PEMReader. Depuis que je sais que le PEM fichiers que je fais face à aura le cert première et la clé privée seconde je peux simplifier le code du coût de la robustesse. Je sais aussi que le CERTIFICAT de FIN d'séparateur sera toujours entouré de cinq traits d'union. La mise en œuvre qui fonctionne pour moi est:
Mise à jour: Il semble que cela peut être fait sans BouncyCastle:
...