Próbuję połączyć się z serwerem SSL, który wymaga ode mnie uwierzytelnienia. Aby korzystać z SSL przez Apache MINA, potrzebuję odpowiedniego pliku JKS. Jednak dostałem tylko plik .PEM.
Jak bym zabrał się do tworzenia pliku JKS z pliku PEM?
Jeśli pójdę w ten sposób, pojawia się błąd: błąd narzędzia keytool: java.lang Wyjątek: dane wejściowe nie są certyfikatem X.509
poziom frandevel
1
@frandevel, ten błąd może być spowodowany tym, że plik wejściowy PEM ma nagłówek nad ogranicznikiem --- BEGIN lub ma wiele PEM w jednym pliku lub w obu. Usuń wszystkie zbędne dane i podaj dane z każdego PEM pojedynczo lub użyj mojego narzędzia, jak opisano w mojej odpowiedzi.
Alastair McCormack
Dzięki @ Fuzzyfelt, przyjrzę się
frandevel
1
Ten sam problem i plik .PEM jest czysty, ze wszystkimi odpowiednimi nagłówkami.
Brian Knoblauch,
17
Opracowałem http://code.google.com/p/java-keyutil/, który importuje certyfikaty PEM bezpośrednio do magazynu kluczy Java. Jego głównym celem jest importowanie wieloczęściowych pakietów certyfikatów systemu operacyjnego PEM, takich jak ca-bundle.crt. Często zawierają one nagłówki, których keytool nie obsługuje
Niezły projekt zabawki, ale keytooljuż robi to wszystko dla Ciebie (i nie tylko). (Nawiasem mówiąc, powinieneś zamknąć swoje FileOutputStreami zamknąć strumienie I / O finally, jeśli zdarzy się wyjątek.)
Bruno
8
Cześć Bruno, dzięki za wskazówki. Prawdziwym przypadkiem użycia jest zaimportowanie wszystkich wpisów z /etc/pki/tls/certs/ca-bundle.crt (RHEL / CentOS) za jednym razem. AFAIK, keytool zaimportuje tylko pierwszy wpis. Widziałem, jak wiele osób robi to inaczej, ale zwykle wymaga to wielokrotnego wywoływania keytool dla każdego certyfikatu. Ubuntu ma skrypt aktualizacyjny, który robi dokładnie to, z wyjątkiem tego, że Ubuntu przechowuje swoje certyfikaty w katalogu. W najbliższej przyszłości dodam obsługę katalogów. Jeszcze raz dziękujemy za przejrzenie kodu.
Alastair McCormack
14
W moim przypadku miałem plik pem, który zawierał dwa certyfikaty i zaszyfrowany klucz prywatny do wykorzystania we wzajemnym uwierzytelnianiu SSL. Więc mój plik pem wyglądał tak:
Podziel plik na trzy oddzielne pliki, tak aby każdy z nich zawierał tylko jeden wpis, zaczynając ---BEGIN..od ---END..linii i kończąc na nich . Załóżmy teraz mamy trzy pliki: cert1.pem, cert2.pem, i pkey.pem.
Konwertuj pkey.pemna format DER przy użyciu openssl i następującej składni:
Zwróć uwagę, że jeśli klucz prywatny jest zaszyfrowany, musisz podać hasło (uzyskać je od dostawcy oryginalnego pliku pem), aby przekonwertować go do formatu DER,
opensslpoprosi Cię o hasło w ten sposób: „wprowadź hasło dla pkey.pem:”.
Jeśli konwersja się powiedzie, otrzymasz nowy plik o nazwie pkey.der.
Utwórz nowy magazyn kluczy java i zaimportuj klucz prywatny oraz certyfikaty:
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());
(opcjonalnie) Sprawdź zawartość nowego magazynu kluczy:
Typ magazynu kluczy: JKS Dostawca magazynu kluczy: SUN
Twój magazyn kluczy zawiera 3 wpisy:
cn = ..., ou = ..., o = .., 2 września 2014 r., trustCertEntry, odcisk cyfrowy certyfikatu (SHA1): 2C: B8: ...
importkey, 2 września 2014 r., PrivateKeyEntry, odcisk cyfrowy certyfikatu (SHA1): 9C: B0: ...
cn = ..., o = ...., 2 września 2014 r., trustCertEntry, odcisk cyfrowy certyfikatu (SHA1): 83:63: ...
(opcjonalnie) Przetestuj swoje certyfikaty i klucz prywatny z nowego magazynu kluczy na serwerze SSL: (możesz chcieć włączyć debugowanie jako opcję maszyny wirtualnej: -Djavax.net.debug = all)
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..
Na koniec zarejestruj swoje certyfikaty za pomocą HttpsURLConnection, jeśli planujesz z niego korzystać:
Weryfikator Twojej nazwy hosta jest błędny, session.getPeerHost()nie zwraca nazwy w certyfikacie, ale nazwę, z którą się połączyłeś (czyli urlHostNametutaj), więc to zawsze będzie prawda. I tak zawsze truewracasz.
Bruno,
9
Jeśli potrzebujesz prostego sposobu na ładowanie plików PEM w Javie bez konieczności korzystania z zewnętrznych narzędzi (opensll, keytool) , oto mój kod, którego używam na produkcji:
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));}}
Portecle to przyjazna dla użytkownika aplikacja GUI do tworzenia, zarządzania i sprawdzania magazynów kluczy, kluczy, certyfikatów, żądań certyfikatów, list odwołania certyfikatów i nie tylko.
eksplorator magazynu kluczy to nowoczesna wersja portecle. nie ma żadnej różnicy między ich menu a funkcjami.
Setmax
0
Mam to z internetu. Działa całkiem dobrze w przypadku plików PEM, które zawierają wiele wpisów.
#!/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>
Odpowiedzi:
Najpierw przekonwertuj swój certyfikat na format DER:
Następnie zaimportuj go do magazynu kluczy:
źródło
Jeśli chcesz zaimportować tylko certyfikat w formacie PEM do magazynu kluczy, narzędzie keytool wykona zadanie:
źródło
Opracowałem http://code.google.com/p/java-keyutil/, który importuje certyfikaty PEM bezpośrednio do magazynu kluczy Java. Jego głównym celem jest importowanie wieloczęściowych pakietów certyfikatów systemu operacyjnego PEM, takich jak ca-bundle.crt. Często zawierają one nagłówki, których keytool nie obsługuje
źródło
keytool
już robi to wszystko dla Ciebie (i nie tylko). (Nawiasem mówiąc, powinieneś zamknąć swojeFileOutputStream
i zamknąć strumienie I / Ofinally
, jeśli zdarzy się wyjątek.)W moim przypadku miałem plik pem, który zawierał dwa certyfikaty i zaszyfrowany klucz prywatny do wykorzystania we wzajemnym uwierzytelnianiu SSL. Więc mój plik pem wyglądał tak:
Oto co zrobiłem
Podziel plik na trzy oddzielne pliki, tak aby każdy z nich zawierał tylko jeden wpis, zaczynając
---BEGIN..
od---END..
linii i kończąc na nich . Załóżmy teraz mamy trzy pliki:cert1.pem
,cert2.pem
, ipkey.pem
.Konwertuj
pkey.pem
na format DER przy użyciu openssl i następującej składni:Zwróć uwagę, że jeśli klucz prywatny jest zaszyfrowany, musisz podać hasło (uzyskać je od dostawcy oryginalnego pliku pem), aby przekonwertować go do formatu DER,
openssl
poprosi Cię o hasło w ten sposób: „wprowadź hasło dlapkey.pem
:”.Jeśli konwersja się powiedzie, otrzymasz nowy plik o nazwie
pkey.der
.Utwórz nowy magazyn kluczy java i zaimportuj klucz prywatny oraz certyfikaty:
(opcjonalnie) Sprawdź zawartość nowego magazynu kluczy:
Typ magazynu kluczy: JKS Dostawca magazynu kluczy: SUN
Twój magazyn kluczy zawiera 3 wpisy:
cn = ..., ou = ..., o = .., 2 września 2014 r., trustCertEntry, odcisk cyfrowy certyfikatu (SHA1): 2C: B8: ...
importkey, 2 września 2014 r., PrivateKeyEntry, odcisk cyfrowy certyfikatu (SHA1): 9C: B0: ...
cn = ..., o = ...., 2 września 2014 r., trustCertEntry, odcisk cyfrowy certyfikatu (SHA1): 83:63: ...
(opcjonalnie) Przetestuj swoje certyfikaty i klucz prywatny z nowego magazynu kluczy na serwerze SSL: (możesz chcieć włączyć debugowanie jako opcję maszyny wirtualnej: -Djavax.net.debug = all)
Na koniec zarejestruj swoje certyfikaty za pomocą HttpsURLConnection, jeśli planujesz z niego korzystać:
źródło
session.getPeerHost()
nie zwraca nazwy w certyfikacie, ale nazwę, z którą się połączyłeś (czyliurlHostName
tutaj), więc to zawsze będzie prawda. I tak zawszetrue
wracasz.Jeśli potrzebujesz prostego sposobu na ładowanie plików PEM w Javie bez konieczności korzystania z zewnętrznych narzędzi (opensll, keytool) , oto mój kod, którego używam na produkcji:
Baw się dobrze.
źródło
Zawsze zapominam, jak to zrobić, ponieważ jest to coś, co robię od czasu do czasu, jest to jedno z możliwych rozwiązań i po prostu działa:
Wykonaj dwa następujące wiersze kodu:
W przypadku wykonywania w środowisku Java SE dodaj następujące opcje:
Lub dodaj do kodu java:
Inną opcją dla kroku 2 jest użycie
keytool
polecenia. Poniżej przykład z łańcuchem certyfikatów:źródło
Użyłem Keystore Explorer
źródło
Istnieje również narzędzie GUI, które umożliwia wizualne tworzenie JKS i importowanie certyfikatów.
http://portecle.sourceforge.net/
źródło
Mam to z internetu. Działa całkiem dobrze w przypadku plików PEM, które zawierają wiele wpisów.
źródło