2010-09-26 46 views
6

上週我的web應用程序中使用的密鑰庫文件已過期。我很久以前生成了它。所以我開始使用keytool生成新的證書。我使用此證書來連接交易服務器和Web服務器。我想爲此應用程序使用自簽名證書。我使用以下命令生成它,爲事務服務器生成自簽名密鑰。使用keytool在jdk中提供生成SSL證書

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" 

以下commnad生成密鑰存儲爲Web應用程序

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" 

我曾經在交易服務器下面的代碼創建套接字連接

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

但是當我用它給了以下異常它在我的應用程序中,並嘗試通過網絡服務器連接到交易服務器

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) 

請任何一個可以告訴我問題出在哪裏

回答

11

首先,避免直接使用com.sun.net.ssl包和類。 JSSE的體系結構是爲了讓您可以使用工廠並稍後指定提供者而構建的。改爲使用javax.net.ssl.TrustManagerFactoryKeyManagerFactorySSLContext)。 (我建議使用"PKIX"而不是"SunX509"作爲信任管理器算法,因爲它通常是Sun提供程序的默認設置,或者更好的是使用TrustManagerFactory.getDefaultAlgorithm())。

其次,除非使用客戶端證書身份驗證,否則不需要在客戶端設置密鑰管理器。

最後(也許是最重要的),您需要導出您在服務器端生成的自簽名證書(僅限證書,而非私鑰),並將其導入您用作密鑰庫的密鑰庫信任商店在客戶端。

當您生成證書時,應確保使用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 

如果你想使用客戶證書認證,則需要通過與分別客戶端密鑰存儲和服務器信任更換服務器密鑰庫和客戶信任重複操作。

在這種情況下,server-keystore.jksserver-truststore.jks可能是同一個文件,但您不需要(在客戶端一樣)。

+0

哦,它的工作很好。多謝,夥計.. – nath 2010-09-26 13:04:45

0

所有你需要做的是密鑰工具-selfcert - 別名XXX -validity DDD其中XXX是一樣的別名,之前和DDD是天前的數到期,爲服務器證書,然後導出該證書並導入到客戶端的信任庫。爲客戶重複相反的過程。您已經省略了導出/導入部分。

但是很多代碼現在已經過時。您不需要調用addProvider(),並且可以在其餘部分中將com.sun.net.ssl更改爲javax.net.ssl。

0

要了解這一點,您必須瞭解證書如何工作。

由於任何人都可以創建一個證書(就像你做的那樣),僅僅創建證書是不夠的 - 證書必須是可信的。證書只有在被另一個可信的證書籤名時才被信任。 在信任「食物鏈」的頂端,有幾個主要的CA,您可以向其支付資金以使您的證書「公開信任」(您的計算機隨其安裝的證書一起提供)。

當然,您不必爲了申請而向CA支付費用,但是您必須模仿此行爲。您可能需要做的是導出服務器/客戶端公鑰,並將其安裝在某種可信存儲區中。

檢查您的API如何定義您的可信證書。