Saya mencoba terhubung ke server SSL yang mengharuskan saya untuk mengotentikasi diri. Untuk menggunakan SSL melalui Apache MINA saya perlu file JKS yang cocok. Namun, saya hanya diberi file .PEM.
Bagaimana cara saya membuat file JKS dari file PEM?
Jika saya pergi seperti ini saya mendapatkan kesalahan: kesalahan keytool: java.lang.Exception: Input bukan sertifikat X.509
frandevel
1
@ frandevel, kesalahan ini dapat disebabkan oleh file input PEM memiliki header di atas pemisah --- BEGIN atau memiliki beberapa PEM dalam satu file atau keduanya. Hapus semua data asing dan masukan dalam setiap PEM dalam satu per satu atau gunakan alat saya, seperti yang dijelaskan dalam jawaban saya.
Alastair McCormack
Terima kasih @ Fuzzyfelt, saya akan melihatnya
frandevel
1
Masalah yang sama dan file .PEM bersih, dengan semua header yang sesuai.
Brian Knoblauch
17
Saya telah mengembangkan http://code.google.com/p/java-keyutil/ yang mengimpor sertifikat PEM langsung ke Java keystore. Tujuan utamanya adalah mengimpor bundel sertifikat Sistem Operasi PEM multi-bagian seperti ca-bundle.crt. Ini sering termasuk header yang tidak bisa ditangani keytool
Bukan proyek mainan yang buruk, tetapi keytoolsudah melakukan semua ini untuk Anda (dan banyak lagi). (Omong-omong, Anda harus menutup FileOutputStream, dan menutup aliran I / O Anda finally, jika pengecualian terjadi.)
Bruno
8
Hai Bruno, terima kasih atas tipsnya. Kasus penggunaan sebenarnya adalah mengimpor semua entri /etc/pki/tls/certs/ca-bundle.crt (RHEL / CentOS) dalam sekali jalan. AFAIK, keytool hanya akan mengimpor entri pertama. Saya telah melihat sejumlah orang melakukan ini secara berbeda tetapi biasanya melibatkan memanggil keytool beberapa kali untuk setiap sertifikat. Ubuntu memiliki skrip pembaruan yang melakukan hal ini, kecuali bahwa Ubuntu menyimpan sertifikatnya dalam direktori. Saya akan menambahkan dukungan untuk direktori dalam waktu dekat. Sekali lagi terima kasih telah meninjau kode.
Alastair McCormack
14
Dalam kasus saya, saya memiliki file pem yang berisi dua sertifikat dan kunci pribadi terenkripsi untuk digunakan dalam otentikasi SSL bersama. Jadi file pem saya terlihat seperti ini:
Membagi file menjadi tiga file terpisah, sehingga masing-masing berisi hanya satu entri, dimulai dengan ---BEGIN..dan diakhiri dengan ---END..garis. Mari kita asumsikan kita sekarang memiliki tiga file: cert1.pem, cert2.pem, dan pkey.pem.
Konversikan pkey.pemke dalam format DER menggunakan openssl dan sintaks berikut:
Perhatikan, bahwa jika kunci pribadi dienkripsi Anda perlu memberikan kata sandi (mendapatkannya dari pemasok file pem yang asli) untuk dikonversi ke format DER,
opensslakan meminta kata sandi seperti ini: "masukkan frasa sandi untuk pkey.pem:".
Jika konversi berhasil, Anda akan mendapatkan file baru bernama pkey.der.
Buat java keystore baru dan impor kunci pribadi dan sertifikat:
String keypass ="password";// this is a new password, you need to come up with to protect your java key store fileString 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(newFileOutputStream("mykeystore"), keypass.toCharArray());
ks.load(newFileInputStream("mykeystore"), keypass.toCharArray());// end of section..// read the key file from disk and create a PrivateKeyFileInputStream fis =newFileInputStream("pkey.der");DataInputStream dis =newDataInputStream(fis);byte[] bytes =newbyte[dis.available()];
dis.readFully(bytes);ByteArrayInputStream bais =newByteArrayInputStream(bytes);byte[] key =newbyte[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(newFileInputStream("cert1.pem"));Collection col_crt2 =CertificateFactory.getInstance("X509").generateCertificates(newFileInputStream("cert2.pem"));Certificate crt1 =(Certificate) col_crt1.iterator().next();Certificate crt2 =(Certificate) col_crt2.iterator().next();Certificate[] chain =newCertificate[]{ 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(newFileOutputStream("mykeystore"),keypass.toCharArray());
(opsional) Verifikasi konten penyimpanan kunci baru Anda:
cn = ..., o = ...., 2 Sep 2014, trustCertEntry, Sertifikat sidik jari (SHA1): 83:63: ...
(opsional) Uji sertifikat dan kunci pribadi Anda dari penyimpanan kunci baru Anda terhadap server SSL Anda: (Anda mungkin ingin mengaktifkan debugging sebagai opsi VM: -Djavax.net.debug = semua)
char[] passw ="password".toCharArray();KeyStore ks =KeyStore.getInstance("JKS","SUN");
ks.load(newFileInputStream("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..
Akhirnya daftarkan sertifikat Anda dengan HttpsURLConnection jika berencana untuk menggunakannya:
Verifier nama host Anda salah, session.getPeerHost()tidak mengembalikan nama dalam sertifikat, tetapi nama yang terhubung dengan Anda (yaitu di urlHostNamesini), jadi itu selalu benar. Lagi truepula, kau selalu kembali .
Bruno
9
Jika Anda memerlukan cara mudah untuk memuat file PEM di Jawa tanpa harus berurusan dengan alat eksternal (opensll, keytool) , berikut adalah kode saya yang saya gunakan dalam produksi:
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;publicclassPEMImporter{publicstaticSSLServerSocketFactory createSSLFactory(File privateKeyPem,File certificatePem,String password)throwsException{finalSSLContext context =SSLContext.getInstance("TLS");finalKeyStore keystore = createKeyStore(privateKeyPem, certificatePem, password);finalKeyManagerFactory kmf =KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, password.toCharArray());finalKeyManager[] 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
*/publicstaticKeyStore createKeyStore(File privateKeyPem,File certificatePem,finalString password)throwsException,KeyStoreException,IOException,NoSuchAlgorithmException,CertificateException{final X509Certificate[] cert = createCertificates(certificatePem);finalKeyStore keystore =KeyStore.getInstance("JKS");
keystore.load(null);// Import private keyfinalPrivateKey key = createPrivateKey(privateKeyPem);
keystore.setKeyEntry(privateKeyPem.getName(), key, password.toCharArray(), cert);return keystore;}privatestaticPrivateKey createPrivateKey(File privateKeyPem)throwsException{finalBufferedReader r =newBufferedReader(newFileReader(privateKeyPem));String s = r.readLine();if(s ==null||!s.contains("BEGIN PRIVATE KEY")){
r.close();thrownewIllegalArgumentException("No PRIVATE KEY found");}finalStringBuilder b =newStringBuilder();
s ="";while(s !=null){if(s.contains("END PRIVATE KEY")){break;}
b.append(s);
s = r.readLine();}
r.close();finalString hexString = b.toString();finalbyte[] bytes =DatatypeConverter.parseBase64Binary(hexString);return generatePrivateKeyFromDER(bytes);}privatestatic X509Certificate[] createCertificates(File certificatePem)throwsException{finalList<X509Certificate> result =newArrayList<X509Certificate>();finalBufferedReader r =newBufferedReader(newFileReader(certificatePem));String s = r.readLine();if(s ==null||!s.contains("BEGIN CERTIFICATE")){
r.close();thrownewIllegalArgumentException("No CERTIFICATE found");}StringBuilder b =newStringBuilder();while(s !=null){if(s.contains("END CERTIFICATE")){String hexString = b.toString();finalbyte[] bytes =DatatypeConverter.parseBase64Binary(hexString);
X509Certificate cert = generateCertificateFromDER(bytes);
result.add(cert);
b =newStringBuilder();}else{if(!s.startsWith("----")){
b.append(s);}}
s = r.readLine();}
r.close();return result.toArray(new X509Certificate[result.size()]);}privatestaticRSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes)throwsInvalidKeySpecException,NoSuchAlgorithmException{final PKCS8EncodedKeySpec spec =new PKCS8EncodedKeySpec(keyBytes);finalKeyFactory factory =KeyFactory.getInstance("RSA");return(RSAPrivateKey) factory.generatePrivate(spec);}privatestatic X509Certificate generateCertificateFromDER(byte[] certBytes)throwsCertificateException{finalCertificateFactory factory =CertificateFactory.getInstance("X.509");return(X509Certificate) factory.generateCertificate(newByteArrayInputStream(certBytes));}}
Saya selalu lupa bagaimana melakukan ini karena itu adalah sesuatu yang hanya saya lakukan sesekali, ini adalah salah satu solusi yang mungkin, dan itu hanya berfungsi:
Buka browser favorit Anda dan unduh sertifikat utama dari situs web yang diamankan.
Portecle adalah aplikasi GUI yang mudah digunakan untuk membuat, mengelola, dan memeriksa keystores, kunci, sertifikat, permintaan sertifikat, daftar pencabutan sertifikat, dan lainnya.
key store explorer adalah versi modern dari portecle. tidak ada perbedaan antara menu dan fungsi mereka sama sekali.
Setmax
0
Saya mendapatkannya dari internet. Ini berfungsi cukup baik untuk file pem yang berisi banyak entri.
#!/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 fornew jks>
Jawaban:
Pertama, konversi sertifikat Anda dalam format DER:
Dan setelah itu, impor di keystore:
sumber
Jika Anda hanya ingin mengimpor sertifikat dalam format PEM ke dalam keystore, keytool akan melakukan pekerjaan:
sumber
Saya telah mengembangkan http://code.google.com/p/java-keyutil/ yang mengimpor sertifikat PEM langsung ke Java keystore. Tujuan utamanya adalah mengimpor bundel sertifikat Sistem Operasi PEM multi-bagian seperti ca-bundle.crt. Ini sering termasuk header yang tidak bisa ditangani keytool
sumber
keytool
sudah melakukan semua ini untuk Anda (dan banyak lagi). (Omong-omong, Anda harus menutupFileOutputStream
, dan menutup aliran I / O Andafinally
, jika pengecualian terjadi.)Dalam kasus saya, saya memiliki file pem yang berisi dua sertifikat dan kunci pribadi terenkripsi untuk digunakan dalam otentikasi SSL bersama. Jadi file pem saya terlihat seperti ini:
Inilah yang saya lakukan
Membagi file menjadi tiga file terpisah, sehingga masing-masing berisi hanya satu entri, dimulai dengan
---BEGIN..
dan diakhiri dengan---END..
garis. Mari kita asumsikan kita sekarang memiliki tiga file:cert1.pem
,cert2.pem
, danpkey.pem
.Konversikan
pkey.pem
ke dalam format DER menggunakan openssl dan sintaks berikut:Perhatikan, bahwa jika kunci pribadi dienkripsi Anda perlu memberikan kata sandi (mendapatkannya dari pemasok file pem yang asli) untuk dikonversi ke format DER,
openssl
akan meminta kata sandi seperti ini: "masukkan frasa sandi untukpkey.pem
:".Jika konversi berhasil, Anda akan mendapatkan file baru bernama
pkey.der
.Buat java keystore baru dan impor kunci pribadi dan sertifikat:
(opsional) Verifikasi konten penyimpanan kunci baru Anda:
Jenis Keystore: JKS Keystore penyedia: SUN
Keystore Anda berisi 3 entri:
cn = ..., ou = ..., o = .., 2 Sep 2014, trustCertEntry, Sertifikat sidik jari (SHA1): 2C: B8: ...
importkey, 2 Sep 2014, PrivateKeyEntry, Sertifikat sidik jari (SHA1): 9C: B0: ...
cn = ..., o = ...., 2 Sep 2014, trustCertEntry, Sertifikat sidik jari (SHA1): 83:63: ...
(opsional) Uji sertifikat dan kunci pribadi Anda dari penyimpanan kunci baru Anda terhadap server SSL Anda: (Anda mungkin ingin mengaktifkan debugging sebagai opsi VM: -Djavax.net.debug = semua)
Akhirnya daftarkan sertifikat Anda dengan HttpsURLConnection jika berencana untuk menggunakannya:
sumber
session.getPeerHost()
tidak mengembalikan nama dalam sertifikat, tetapi nama yang terhubung dengan Anda (yaitu diurlHostName
sini), jadi itu selalu benar. Lagitrue
pula, kau selalu kembali .Jika Anda memerlukan cara mudah untuk memuat file PEM di Jawa tanpa harus berurusan dengan alat eksternal (opensll, keytool) , berikut adalah kode saya yang saya gunakan dalam produksi:
Selamat bersenang-senang.
sumber
Saya selalu lupa bagaimana melakukan ini karena itu adalah sesuatu yang hanya saya lakukan sesekali, ini adalah salah satu solusi yang mungkin, dan itu hanya berfungsi:
Jalankan dua baris kode berikut:
Jika mengeksekusi di lingkungan Java SE tambahkan opsi berikut:
Atau tambahkan yang berikut ini ke kode java:
Opsi lain untuk langkah 2 adalah dengan hanya menggunakan
keytool
perintah. Di bawah ini adalah contoh dengan rangkaian sertifikat:sumber
Saya menggunakan Keystore Explorer
sumber
Ada juga alat GUI yang memungkinkan pembuatan JKS visual dan impor sertifikat.
http://portecle.sourceforge.net/
sumber
Saya mendapatkannya dari internet. Ini berfungsi cukup baik untuk file pem yang berisi banyak entri.
sumber