2010-09-26 16 views
6

Pliki kluczy używanych w mojej aplikacji internetowej wygasły w zeszłym tygodniu. Wygenerowałem to dawno temu. Zacząłem więc generować nowy certyfikat za pomocą keytool. Użyłem tego certyfikatu do połączenia serwera transakcji i serwera WWW. Chciałem użyć samopodpisanego certyfikatu dla tej aplikacji. Generuję go za pomocą następującej komendy, aby wygenerować samopodpisany klucz dla serwera transakcji.Wygeneruj certyfikat SSL za pomocą narzędzia keytool dostarczanego w jdk

keytool -genkey -keystore keys/SvrKeyStore -keyalg rsa -validity 365 -alias Svr -storepass 123456 -keypass abcdefg -dname "CN=One1, OU=Development1, O=One, L=Bamba, S=Western Prov1, C=S1" 

następujące commnad do generowania kluczy dla aplikacji internetowych

keytool -genkey -keystore keys/ClientKeyStore -keyalg rsa -validity 365 -alias Web -storepass 123456 -keypass abcdefg -dname "CN=One, OU=Development, O=One, L=Bamba, S=Western Prov, C=SL" 

użyłem następujący kod w serwerze transakcji w celu utworzenia połączenia z gniazdem

  String KEYSTORE = Config.KEYSTORE_FILE;//SvrKeyStore keystore file 
      char[] KEYSTOREPW = "123456".toCharArray(); 
      char[] KEYPW = "abcdefg".toCharArray(); 
      com.sun.net.ssl.TrustManagerFactory tmf; 

      boolean requireClientAuthentication; 

      java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl. 
              Provider()); 
      java.security.KeyStore keystore = java.security.KeyStore.getInstance(
       "JKS"); 
      keystore.load(new FileInputStream(KEYSTORE), KEYSTOREPW); 

      com.sun.net.ssl.KeyManagerFactory kmf = com.sun.net.ssl. 
       KeyManagerFactory.getInstance("SunX509"); 
      kmf.init(keystore, KEYPW); 

      com.sun.net.ssl.SSLContext sslc = com.sun.net.ssl.SSLContext. 
       getInstance("SSLv3"); 
      tmf = com.sun.net.ssl.TrustManagerFactory.getInstance("sunx509"); 
      tmf.init(keystore); 

      sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 
      SSLServerSocketFactory ssf = sslc.getServerSocketFactory(); 
      SSLServerSocket ssocket = (SSLServerSocket) ssf.createServerSocket(port); 
      ssocket.setNeedClientAuth(true); 

ale daje następujący wyjątek, gdy użyłem to w mojej aplikacji i spróbuj połączyć się z serwerem transakcji za pośrednictwem serwera WWW

javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHands 
hakeException: java.security.cert.CertificateException: Untrusted Server Certifi 
cate Chain 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.jav 
a:1172) 
     at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java: 
65) 
     at net.schubart.fixme.internal.MessageInput.readExactly(MessageInput.jav 
a:166) 
     at net.schubart.fixme.internal.MessageInput.readMessage(MessageInput.jav 
a:78) 
     at cc.aot.itsWeb.ClientWriterThread.run(ClientWriterThread.java:241) 
     at java.lang.Thread.run(Thread.java:619) 
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateEx 
ception: Untrusted Server Certificate Chain 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1 
520) 
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:182) 
     at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:176) 
     at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien 
tHandshaker.java:975) 
     at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHa 
ndshaker.java:123) 
     at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:5 
11) 
     at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.jav 
a:449) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.j 
ava:817) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SS 
LSocketImpl.java:1029) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl. 
java:621) 
     at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.ja 
va:59) 
     at java.io.OutputStream.write(OutputStream.java:58) 

Proszę może ktoś mi powiedzieć gdzie jest problem

Odpowiedz

11

Po pierwsze, należy unikać używania pakietów i klas com.sun.net.ssl bezpośrednio. Architektura JSSE została zbudowana w taki sposób, aby można było używać fabryk i określać dostawców później. Zamiast tego użyj javax.net.ssl.TrustManagerFactory (to samo dla KeyManagerFactory i SSLContext). (Proponuję użyć "PKIX" zamiast "SunX509" dla algorytmu menedżera zaufania, ponieważ zwykle jest to ustawienie domyślne dla dostawcy Sun, lub lepiej, użyj TrustManagerFactory.getDefaultAlgorithm()).

Po drugie, nie trzeba konfigurować keymanager po stronie klienta, chyba że używa się uwierzytelniania certyfikatu klienta.

Wreszcie (i być może najważniejszym), należy wyeksportować samopodpisany certyfikat wygenerowany po stronie serwera (tylko certyfikat, a nie klucz prywatny) i zaimportować go do magazynu kluczy, którego używasz jako magazyn zaufania po stronie klienta.

Podczas generowania certyfikatu powinieneś upewnić się, że używasz CN=the.server.host.name.

keytool -genkey -keystore server-keystore.jks -alias server_alias \ 
     -dname "CN=the.server.host.name,OU=whateveryoulike" \ 
     -keyalg "RSA" -sigalg "SHA1withRSA" -keysize 2048 -validity 365 

keytool -export -keystore server-keystore.jks -alias server_alias -file server.crt 

keytool -import -keystore client-truststore.jks -file server.crt 

Jeśli chcesz korzystać z uwierzytelniania klienta certyfikat, trzeba powtórzyć operację poprzez zastąpienie serwera-kluczy i klient-klient-magazynu zaufanych certyfikatów z serwera kluczy i truststore odpowiednio.

W tym przypadku server-keystore.jks i server-truststore.jks mogą być tymi samymi plikami, ale nie muszą (takie same po stronie klienta).

+0

Ohh, świetnie się udało. Dzięki stary.. – nath

0

Wszystko, co potrzebne do zrobienia było keytool -selfcert - alias XXX -validity DDD gdzie XXX jest taka sama jak przed alias i DDD jest liczba dni przed wygaśnięcie, dla certyfikatu serwera, a następnie wyeksportuj ten certyfikat i zaimportuj go do magazynu zaufanych klientów. Powtórz w odwrotnej kolejności dla klienta. Pominięto część eksportu/importu.

Jednak znaczna część tego kodu jest już przestarzała. Nie musisz wywoływać metody addProvider(), możesz też zmienić com.sun.net.ssl ​​na javax.net.ssl ​​w pozostałej części.

0

Aby to zrozumieć, musisz zrozumieć, jak działają certyfikaty.

Ponieważ każdy może utworzyć certyfikat (tak jak zrobiłeś), nie wystarczy go tylko utworzyć - certyfikaty muszą być zaufane. Certyfikat jest zaufany tylko wtedy, gdy jest podpisany przez inny certyfikat, który jest zaufany. Oprócz zaufania do "łańcucha pokarmowego" istnieje kilka głównych urzędów certyfikacji, którym można zapłacić, aby certyfikat był "publicznie zaufany" (na komputerze są zainstalowane jego certyfikaty).

Oczywiście nie musisz płacić do urzędu certyfikacji w celu złożenia wniosku, ALE musisz naśladować to zachowanie. Najprawdopodobniej będziesz musiał wyeksportować klucz publiczny serwera/klienta i zainstalować go w jakimś zaufanym sklepie.

Sprawdź, jak interfejs API pozwala określić, gdzie znajdują się zaufane certyfikaty.

Powiązane problemy