Importation de PEM dans le magasin de clés Java

J’essaie de me connecter à un serveur SSL qui me demande de m’authentifier. Pour utiliser SSL sur Apache MINA, j’ai besoin d’un fichier JKS approprié. Cependant, je n’ai reçu qu’un fichier .PEM.

Comment pourrais-je créer un fichier JKS à partir d’un fichier PEM?

Tout d’abord, convertissez votre certificate au format DER:

openssl x509 -outform der -in certificatee.pem -out certificatee.der 

Et après, importez-le dans le magasin de clés:

 keytool -import -alias your-alias -keystore cacerts -file certificatee.der 

Si vous souhaitez uniquement importer un certificate au format PEM dans un fichier de clés, keytool fera le travail:

 keytool -import -alias *alias* -keystore cacerts -file *cert.pem* 

J’ai développé http://code.google.com/p/java-keyutil/ qui importe les certificates PEM directement dans un magasin de clés Java. Son objective principal est d’importer des ensembles de certificates de système d’exploitation PEM en plusieurs parties, tels que ca-bundle.crt. Ceux-ci incluent souvent des en-têtes que keytool ne peut pas gérer

  

Dans mon cas, j’avais un fichier pem contenant deux certificates et une clé privée chiffrée à utiliser pour l’authentification SSL mutuelle. Donc, mon fichier pem ressemblait à ceci:

 -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,C8BF220FC76AA5F9 ... -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- 

Voici ce que j’ai fait

Divisez le fichier en trois fichiers distincts, de sorte que chacun contienne une seule entrée, en commençant par ---BEGIN.. et en terminant par ---END.. Supposons que nous avons maintenant trois fichiers: cert1.pem , cert2.pem et pkey.pem .

Convertissez pkey.pem au format DER en utilisant openssl et la syntaxe suivante:

openssl pkcs8 -topk8 -nocrypt -in pkey.pem -inform PEM -out pkey.der -outform DER

Notez que si la clé privée est chiffrée, vous devez fournir un mot de passe (obtenir auprès du fournisseur du fichier pem d’origine) pour convertir au format DER, openssl vous demandera le mot de passe comme ceci: “entrez une phrase secrète pour pkey.pem : “.

Si la conversion réussit, vous obtiendrez un nouveau fichier appelé pkey.der .

Créez un magasin de clés java et importez la clé privée et les certificates:

 Ssortingng keypass = "password"; // this is a new password, you need to come up with to protect your java key store file Ssortingng defaultalias = "importkey"; KeyStore ks = KeyStore.getInstance("JKS", "SUN"); // this section does not make much sense to me, // but I will leave it intact as this is how it was in the original example I found on internet: ks.load( null, keypass.toCharArray()); ks.store( new FileOutputStream ( "mykeystore" ), keypass.toCharArray()); ks.load( new FileInputStream ( "mykeystore" ), keypass.toCharArray()); // end of section.. // read the key file from disk and create a PrivateKey FileInputStream fis = new FileInputStream("pkey.der"); DataInputStream dis = new DataInputStream(fis); byte[] bytes = new byte[dis.available()]; dis.readFully(bytes); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); byte[] key = new byte[bais.available()]; KeyFactory kf = KeyFactory.getInstance("RSA"); bais.read(key, 0, bais.available()); bais.close(); PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key ); PrivateKey ff = kf.generatePrivate (keysp); // read the certificatees from the files and load them into the key store: Collection col_crt1 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert1.pem")); Collection col_crt2 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert2.pem")); Certificate crt1 = (Certificate) col_crt1.iterator().next(); Certificate crt2 = (Certificate) col_crt2.iterator().next(); Certificate[] chain = new Certificate[] { crt1, crt2 }; Ssortingng alias1 = ((X509Certificate) crt1).getSubjectX500Principal().getName(); Ssortingng alias2 = ((X509Certificate) crt2).getSubjectX500Principal().getName(); ks.setCertificateEntry(alias1, crt1); ks.setCertificateEntry(alias2, crt2); // store the private key ks.setKeyEntry(defaultalias, ff, keypass.toCharArray(), chain ); // save the key store to a file ks.store(new FileOutputStream ( "mykeystore" ),keypass.toCharArray()); 

(facultatif) Vérifiez le contenu de votre nouvelle clé de stockage:

 $ keytool -list -keystore mykeystore -storepass password 

Type de magasin de clés: Fournisseur de clés JKS: SUN

Votre fichier de clés contient 3 entrées:

  • cn = …, ou = …, o = .., 2 septembre 2014, trustedCertEntry, empreinte de certificate (SHA1): 2C: B8: …

  • importkey, 2 sep 2014, PrivateKeyEntry, empreinte de certificate (SHA1): 9C: B0: …

  • cn = …, o = …., 2 septembre 2014, trustedCertEntry, empreinte de certificate (SHA1): 83:63: …

(facultatif) Testez vos certificates et votre clé privée à partir de votre nouvelle clé de stockage sur votre serveur SSL: (Vous pouvez activer le débogage en tant qu’option de machine virtuelle: -Djavax.net.debug = all)

  char[] passw = "password".toCharArray(); KeyStore ks = KeyStore.getInstance("JKS", "SUN"); ks.load(new FileInputStream ( "mykeystore" ), passw ); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passw); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); TrustManager[] tm = tmf.getTrustManagers(); SSLContext sclx = SSLContext.getInstance("TLS"); sclx.init( kmf.getKeyManagers(), tm, null); SSLSocketFactory factory = sclx.getSocketFactory(); SSLSocket socket = (SSLSocket) factory.createSocket( "192.168.1.111", 443 ); socket.startHandshake(); //if no exceptions are thrown in the startHandshake method, then everything is fine.. 

Enfin, enregistrez vos certificates avec HttpsURLConnection si vous prévoyez de l’utiliser:

  char[] passw = "password".toCharArray(); KeyStore ks = KeyStore.getInstance("JKS", "SUN"); ks.load(new FileInputStream ( "mykeystore" ), passw ); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passw); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); TrustManager[] tm = tmf.getTrustManagers(); SSLContext sclx = SSLContext.getInstance("TLS"); sclx.init( kmf.getKeyManagers(), tm, null); HostnameVerifier hv = new HostnameVerifier() { public boolean verify(Ssortingng urlHostName, SSLSession session) { if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) { System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'."); } return true; } }; HttpsURLConnection.setDefaultSSLSocketFactory( sclx.getSocketFactory() ); HttpsURLConnection.setDefaultHostnameVerifier(hv); 

J’oublie toujours comment faire parce que c’est quelque chose que je fais juste de temps en temps, c’est une solution possible, et ça marche:

  1. Accédez à votre navigateur préféré et téléchargez le certificate principal à partir du site Web sécurisé.
  2. Exécutez les deux lignes de code suivantes:

     $ openssl x509 -outform der -in GlobalSignRootCA.crt -out GlobalSignRootCA.der $ keytool -import -alias GlobalSignRootCA -keystore GlobalSignRootCA.jks -file GlobalSignRootCA.der 
  3. Si vous exécutez l’environnement Java SE, ajoutez les options suivantes:

     $ java -Djavax.net.ssl.trustStore=GlobalSignRootCA.jks -Djavax.net.ssl.trustStorePassword=trustStorePassword -jar MyJar.jar 
  4. Ou ajoutez ce qui suit au code java:

     System.setProperty("javax.net.ssl.trustStore", "GlobalSignRootCA.jks"); System.setProperty("javax.net.ssl.trustStorePassword","trustStorePassword"); 

L’autre option pour l’étape 2 consiste à utiliser simplement la commande keytool . Voici un exemple avec une chaîne de certificates:

 $ keytool -import -file org.eu.crt -alias orgcrt -keystore globalsignrs.jks $ keytool -import -file GlobalSignOrganizationValidationCA-SHA256-G2.crt -alias globalsignorgvalca -keystore globalsignrs.jks $ keytool -import -file GlobalSignRootCA.crt -alias globalsignrootca -keystore globalsignrs.jks 

Si vous avez besoin d’un moyen simple de charger des fichiers PEM en Java sans avoir à utiliser des outils externes (opensll, keytool) , voici mon code en production:

 import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.List; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.xml.bind.DatatypeConverter; public class PEMImporter { public static SSLServerSocketFactory createSSLFactory(File privateKeyPem, File certificateePem, Ssortingng password) throws Exception { final SSLContext context = SSLContext.getInstance("TLS"); final KeyStore keystore = createKeyStore(privateKeyPem, certificateePem, password); final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(keystore, password.toCharArray()); final KeyManager[] km = kmf.getKeyManagers(); context.init(km, null, null); return context.getServerSocketFactory(); } /** * Create a KeyStore from standard PEM files * * @param privateKeyPem the private key PEM file * @param certificateePem the certificatee(s) PEM file * @param the password to set to protect the private key */ public static KeyStore createKeyStore(File privateKeyPem, File certificateePem, final Ssortingng password) throws Exception, KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { final X509Certificate[] cert = createCertificates(certificateePem); final KeyStore keystore = KeyStore.getInstance("JKS"); keystore.load(null); // Import private key final PrivateKey key = createPrivateKey(privateKeyPem); keystore.setKeyEntry(privateKeyPem.getName(), key, password.toCharArray(), cert); return keystore; } private static PrivateKey createPrivateKey(File privateKeyPem) throws Exception { final BufferedReader r = new BufferedReader(new FileReader(privateKeyPem)); Ssortingng s = r.readLine(); if (s == null || !s.contains("BEGIN PRIVATE KEY")) { r.close(); throw new IllegalArgumentException("No PRIVATE KEY found"); } final SsortingngBuilder b = new SsortingngBuilder(); s = ""; while (s != null) { if (s.contains("END PRIVATE KEY")) { break; } b.append(s); s = r.readLine(); } r.close(); final Ssortingng hexSsortingng = b.toSsortingng(); final byte[] bytes = DatatypeConverter.parseBase64Binary(hexSsortingng); return generatePrivateKeyFromDER(bytes); } private static X509Certificate[] createCertificates(File certificateePem) throws Exception { final List result = new ArrayList(); final BufferedReader r = new BufferedReader(new FileReader(certificateePem)); Ssortingng s = r.readLine(); if (s == null || !s.contains("BEGIN CERTIFICATE")) { r.close(); throw new IllegalArgumentException("No CERTIFICATE found"); } SsortingngBuilder b = new SsortingngBuilder(); while (s != null) { if (s.contains("END CERTIFICATE")) { Ssortingng hexSsortingng = b.toSsortingng(); final byte[] bytes = DatatypeConverter.parseBase64Binary(hexSsortingng); X509Certificate cert = generateCertificateFromDER(bytes); result.add(cert); b = new SsortingngBuilder(); } else { if (!s.startsWith("----")) { b.append(s); } } s = r.readLine(); } r.close(); return result.toArray(new X509Certificate[result.size()]); } private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException { final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); final KeyFactory factory = KeyFactory.getInstance("RSA"); return (RSAPrivateKey) factory.generatePrivate(spec); } private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException { final CertificateFactory factory = CertificateFactory.getInstance("X.509"); return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes)); } } 

S’amuser.

Il existe également un outil graphique permettant la création visuelle de JKS et l’importation de certificates.

http://portecle.sourceforge.net/

Portecle est une application graphique conviviale permettant de créer, gérer et examiner des fichiers de clés, des clés, des certificates, des demandes de certificates, des listes de révocation de certificates, etc.

Je l’ai eu sur internet. Cela fonctionne très bien pour les fichiers pem qui contiennent plusieurs entrées.

 #!/bin/bash pemToJks() { # number of certs in the PEM file pemCerts=$1 certPass=$2 newCert=$(basename "$pemCerts") newCert="${newCert%%.*}" newCert="${newCert}"".JKS" ##echo $newCert $pemCerts $certPass CERTS=$(grep 'END CERTIFICATE' $pemCerts| wc -l) echo $CERTS # For every cert in the PEM file, extract it and import into the JKS keystore # awk command: step 1, if line is in the desired cert, print the line # step 2, increment counter when last line of cert is found for N in $(seq 0 $(($CERTS - 1))); do ALIAS="${pemCerts%.*}-$N" cat $pemCerts | awk "n==$N { print }; /END CERTIFICATE/ { n++ }" | $KEYTOOLCMD -noprompt -import -trustcacerts \ -alias $ALIAS -keystore $newCert -storepass $certPass done } pemToJks