PEM'i Java Anahtar Deposuna Aktar


Yanıtlar:


235

İlk olarak, sertifikanızı DER formatında dönüştürün:

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

Ve sonra anahtar deposuna aktarın:

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

7
.Pem dosyası birden fazla sertifika içeriyorsa çalışmaz.
MarioVilas

14
Tek bir sertifika .pem var ve bu çalışmıyor. 1795: hata: 0906D06C: PEM yordamları: PEM_read_bio: başlangıç ​​satırı yok: / usr / src / secure / lib / libcrypto /../../../ kripto / openssl / kripto / pem / pem_lib.c: 648: Bekleniyor : GÜVENİLİR SERTİFİKA
Brian Knoblauch

4
Çözümü buldum. Kök ve ara sertifikaları .pem dosyasına önceden ekleyin, sonra dönüştürün.
Brian Knoblauch

1
@Anthony bu komut yalnızca PEM'in JKS'ye nasıl aktarılacağını anlatır. JKS'yi mağazadan dışa aktarmak için bir komut eklemek iyi bir fikir olabilir.
Vishal Biyani

2
.Pem üzerinde birden fazla sertifikam varsa, Java anahtar deposuna nasıl aktarırım?
Erick

55

Bir sertifikayı yalnızca anahtar deposuna PEM biçiminde içe aktarmak istiyorsanız, keytool işi yapar:

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

11
Eğer böyle gidersem bir hata alıyorum: keytool hatası: java.lang.Exception: Giriş X.509 sertifikası değil
frandevel

1
@frandevel, bu hata --- BEGIN sınırlayıcısının üstünde bir başlığa sahip olan veya bir dosyada veya her ikisinde birden çok PEM bulunan PEM girdi dosyasından kaynaklanabilir. Tüm yabancı verileri kaldırın ve her PEM'de birer birer besleyin veya cevabımda ayrıntılı olarak açıklandığı şekilde aracımı kullanın.
Alastair McCormack

Thanks @Fuzzyfelt, ben bir göz
atacağım

1
Aynı sorun ve .PEM dosyası, tüm uygun üstbilgileri ile temiz.
Brian Knoblauch

17

PEM sertifikalarını doğrudan bir Java anahtar deposuna aktaran http://code.google.com/p/java-keyutil/ geliştirdim . Birincil amacı ca-bundle.crt gibi çok parçalı bir PEM İşletim Sistemi sertifika paketlerini içe aktarmaktır. Bunlar genellikle tuş takımının işleyemediği başlıkları içerir

</self promotion>

4
Kötü bir oyuncak projesi değil, ama keytoolzaten tüm bunları sizin için yapıyor (ve daha fazlası). (Bu arada, bir istisna olursa FileOutputStreamG / Ç akışlarınızı kapatmanız ve G / Ç akışlarınızı kapatmanız gerekir finally.)
Bruno

8
Merhaba Bruno, ipuçları için teşekkürler. Gerçek kullanım durumu tek seferde /etc/pki/tls/certs/ca-bundle.crt (RHEL / CentOS) girişlerini içeri aktarmaktır. AFAIK, keytool yalnızca ilk girişi içe aktaracak. Bir çok insanın bunu farklı yaptığını gördüm, ancak genellikle her sertifika için tuş takımını birden çok kez çağırmayı içerir. Ubuntu, sertifikalarını bir dizinde saklaması dışında, tam olarak bunu yapan bir güncelleme komut dosyasına sahiptir. Yakın gelecekte dizinler için destek ekleyeceğim. Kodu incelediğiniz için tekrar teşekkür ederiz.
Alastair McCormack

14

Benim durumumda, iki sertifika içeren bir pem dosyası ve karşılıklı SSL kimlik doğrulamasında kullanılacak şifreli bir özel anahtarım vardı. Pem dosyam şöyle görünüyordu:

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

İşte yaptığım şey

Dosyayı üç ayrı dosyaya bölün, böylece her biri satırlarla başlayan ---BEGIN..ve ---END..satırlarla biten tek bir girdi içerir . Varsayalım Lets şimdi üç dosya vardır: cert1.pem, cert2.pem, ve pkey.pem.

pkey.pemOpenssl ve aşağıdaki sözdizimini kullanarak DER biçimine dönüştürün :

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

Özel anahtar şifrelenirse, DER biçimine dönüştürmek için bir şifre girmeniz (orijinal pem dosyasının sağlayıcısından edinmeniz), opensslbunun gibi bir şifre isteyeceğini unutmayın: "için bir parola girin pkey.pem:".

Dönüştürme başarılı olursa, adlı yeni bir dosya alırsınız pkey.der.

Yeni bir java anahtar deposu oluşturun ve özel anahtarı ve sertifikaları içe aktarın:

String keypass = "password";  // this is a new password, you need to come up with to protect your java key store file
String 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 certificates 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 };

String alias1 = ((X509Certificate) crt1).getSubjectX500Principal().getName();
String 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());

(isteğe bağlı) Yeni anahtar deponuzun içeriğini doğrulayın:

$ keytool -list -keystore mykeystore -storepass password

Anahtar deposu türü: JKS Anahtar deposu sağlayıcısı: SUN

Anahtar deponuz 3 giriş içeriyor:

  • cn = ..., ou = ..., o = .., 2 Eyl 2014, güvenilirCertEntry, Sertifika parmak izi (SHA1): 2C: B8: ...

  • importkey, 2 Eyl 2014, PrivateKeyEntry, Sertifika parmak izi (SHA1): 9C: B0: ...

  • cn = ..., o = ...., 2 Eyl 2014, güvenilirCertEntry, Sertifika parmak izi (SHA1): 83:63: ...

(isteğe bağlı) Yeni anahtar deponuzdaki sertifikalarınızı ve özel anahtarınızı SSL sunucunuza karşı test edin: (Hata ayıklamayı VM seçeneği olarak etkinleştirmek isteyebilirsiniz: -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..

Son olarak, kullanmayı planlıyorsanız sertifikalarınızı HttpsURLConnection'a kaydedin:

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

Ana bilgisayar adı doğrulayıcınız yanlış, session.getPeerHost()sertifikadaki adı değil, bağlandığınız adı (yani urlHostNameburada) döndürdüğünden , bu her zaman doğru olacaktır. trueYine de geri dönüyorsun .
Bruno

9

Harici araçlarla (opensll, keytool) uğraşmak zorunda kalmadan PEM dosyalarını Java'ya yüklemek için kolay bir yola ihtiyacınız varsa , burada üretimde kullandığım kodum:

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 certificatePem, String password) throws Exception {
        final SSLContext context = SSLContext.getInstance("TLS");
        final KeyStore keystore = createKeyStore(privateKeyPem, certificatePem, 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 certificatePem the certificate(s) PEM file
     * @param the password to set to protect the private key
     */
    public static KeyStore createKeyStore(File privateKeyPem, File certificatePem, final String password)
            throws Exception, KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
        final X509Certificate[] cert = createCertificates(certificatePem);
        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));
        String s = r.readLine();
        if (s == null || !s.contains("BEGIN PRIVATE KEY")) {
            r.close();
            throw new IllegalArgumentException("No PRIVATE KEY found");
        }
        final StringBuilder b = new StringBuilder();
        s = "";
        while (s != null) {
            if (s.contains("END PRIVATE KEY")) {
                break;
            }
            b.append(s);
            s = r.readLine();
        }
        r.close();
        final String hexString = b.toString();
        final byte[] bytes = DatatypeConverter.parseBase64Binary(hexString);
        return generatePrivateKeyFromDER(bytes);
    }

    private static X509Certificate[] createCertificates(File certificatePem) throws Exception {
        final List<X509Certificate> result = new ArrayList<X509Certificate>();
        final BufferedReader r = new BufferedReader(new FileReader(certificatePem));
        String s = r.readLine();
        if (s == null || !s.contains("BEGIN CERTIFICATE")) {
            r.close();
            throw new IllegalArgumentException("No CERTIFICATE found");
        }
        StringBuilder b = new StringBuilder();
        while (s != null) {
            if (s.contains("END CERTIFICATE")) {
                String hexString = b.toString();
                final byte[] bytes = DatatypeConverter.parseBase64Binary(hexString);
                X509Certificate cert = generateCertificateFromDER(bytes);
                result.add(cert);
                b = new StringBuilder();
            } 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));
    }

}

İyi eğlenceler.


Soru, sağlanan " PEM işlevinden SSLServerSocketFactory" ile yapılandırılması daha kolay olan "Apache MINA üzerinden SSL" hakkındaydı, bkz. Mina.apache.org/mina-project/userguide/ch11-ssl-filter/… .
BluEOS

8

Bunu nasıl yapacağımı her zaman unutuyorum çünkü bu arada bir yaptığım bir şey, bu olası bir çözüm ve sadece işe yarıyor:

  1. Favori tarayıcınıza gidin ve güvenli web sitesinden ana sertifikayı indirin.
  2. Aşağıdaki iki kod satırını yürütün:

    $ openssl x509 -outform der -in GlobalSignRootCA.crt -out GlobalSignRootCA.der
    $ keytool -import -alias GlobalSignRootCA -keystore GlobalSignRootCA.jks -file GlobalSignRootCA.der
  3. Java SE ortamında yürütülüyorsa aşağıdaki seçenekleri ekleyin:

    $ java -Djavax.net.ssl.trustStore=GlobalSignRootCA.jks -Djavax.net.ssl.trustStorePassword=trustStorePassword -jar MyJar.jar
  4. Veya java koduna aşağıdakileri ekleyin:

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

Adım 2 için diğer seçenek sadece keytoolkomutu kullanmaktır . Körük, sertifika zincirine sahip bir örnektir:

$ 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

7

Keystore Explorer'ı kullandım

  1. JKS'yi özel bir anahtarla açma
  2. CA'dan imzalı PEM'yi inceleyin
  3. İçe aktarma anahtarı
  4. JKS'yi Kaydet

3
Keystore Explorer harika ve çok yönlü. Terminalde birkaç akılsız dakika geçirmekten bir kez tasarruf sağlar.
TheRealChx101

3

Ayrıca görsel JKS oluşturmaya ve sertifikaları içe aktarmaya izin veren bir GUI aracı da vardır.

http://portecle.sourceforge.net/

Portecle, anahtar depoları, anahtarlar, sertifikalar, sertifika istekleri, sertifika iptal listeleri ve daha fazlasını oluşturmak, yönetmek ve incelemek için kullanıcı dostu bir GUI uygulamasıdır.


1
anahtar mağaza kaşif portecle modern sürümüdür. menüleri ve işlevleri arasında hiçbir fark yoktur.
Setmax

0

İnternetten aldım. Birden fazla giriş içeren pem dosyaları için oldukça iyi çalışır.

#!/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 <pem to import> <pass for new jks>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.