2017-10-11 158 views
0

我已經看到了這個問題:Need to do a GET&POST HTTPS Request using a .cer certificate使用.cer證書進行HTTPS請求

我的是完全不同的:

有可能使用Java(香草,或使用任何使一個HTTPS請求庫),信任服務器證書並提供客戶端證書,而不使用密鑰存儲庫,但使用純文本證書?

我有兩種X.509格式的證書,我不想在密鑰庫中擁有每個證書。

+2

使用java例如'HttpsUrlConnection'沒問題。只需爲'SSLContext'創建自己的'KeyManager'。 –

+0

@mrmcwolf你可否詳細說明一下?我正在尋找KeyManager文檔。 – lilezek

+0

@mrmcwolf遵循Java文檔,我發現了這個:https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/X509ExtendedKeyManager.html它有一個受保護的構造函數。有沒有我可以使用的子類? – lilezek

回答

0

如果您確實不想創建新的密鑰庫文件,那麼可以使用KeyStore API在內存中創建並直接加載證書。

InputStream is = new FileInputStream("somecert.cer"); 
// You could get a resource as a stream instead. 

CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
X509Certificate caCert = (X509Certificate)cf.generateCertificate(is); 

TrustManagerFactory tmf = TrustManagerFactory 
    .getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 
ks.load(null); // You don't need the KeyStore instance to come from a file. 
ks.setCertificateEntry("caCert", caCert); 

tmf.init(ks); 

SSLContext sslContext = SSLContext.getInstance("TLS"); 
sslContext.init(null, tmf.getTrustManagers(), null); 

另外,如果你想避免修改默認的cacerts文件,那麼你需要實現自己的TrustManager。但是,TrustManager需要加載密鑰庫,因此您可以創建一個新的密鑰庫文件來導入您的證書。

keytool -import -alias ca -file somecert.cer -keystore truststore.jks -storepass changeit 

並使用類似下面的代碼片段來加載密鑰庫文件。

TrustManagerFactory tmf = TrustManagerFactory 
    .getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
// Using null here initialises the TMF with the default trust store. 
tmf.init((KeyStore) null); 

// Get hold of the default trust manager 
X509TrustManager defaultTm = null; 
for (TrustManager tm : tmf.getTrustManagers()) { 
    if (tm instanceof X509TrustManager) { 
     defaultTm = (X509TrustManager) tm; 
     break; 
    } 
} 

FileInputStream myKeys = new FileInputStream("truststore.jks"); 

// Do the same with your trust store this time 
// Adapt how you load the keystore to your needs 
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
myTrustStore.load(myKeys, "password".toCharArray()); 

myKeys.close(); 

tmf = TrustManagerFactory 
    .getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
tmf.init(myTrustStore); 

SSLContext sslContext = SSLContext.getInstance("TLS"); 
sslContext.init(null, tmf.getTrustManagers(), null); 
+0

你甚至讀過這個問題嗎? –

+0

@編輯後的Code.IT他提供了一個片段直接讀取X.509證書。 Idk如果downvote是你的,但是我會在我測試解決方案後儘快註冊。 – lilezek

1

這是一個粗略的例子。表示X509KeyManager裝飾器。

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
kmf.init(null, null); 

X509KeyManager manager = (X509KeyManager) kmf.getKeyManagers()[0]; 
KeyManager km = new X509KeyManager() { 
    @Override 
    public String[] getClientAliases(String s, Principal[] principals) { 
     return manager.getServerAliases(s, principals); 
    } 

    @Override 
    public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { 
     return manager.chooseClientAlias(strings, principals, socket); 
    } 

    @Override 
    public String[] getServerAliases(String s, Principal[] principals) { 
     return manager.getServerAliases(s, principals); 
    } 

    @Override 
    public String chooseServerAlias(String s, Principal[] principals, Socket socket) { 
     return manager.chooseServerAlias(s, principals, socket); 
    } 

    @Override 
    public X509Certificate[] getCertificateChain(String s) { 
     // You can use `s` to select the appropriate file 

     try { 
      File file = new File("path to certificate"); 

      try(InputStream is = new FileInputStream(file)) { 
       CertificateFactory factory = CertificateFactory.getInstance("X.509"); 
       return new X509Certificate[] { 
         (X509Certificate) factory.generateCertificate(is) 
       }; 
      } 
     } 
     catch (CertificateException| IOException e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 

    @Override 
    public PrivateKey getPrivateKey(String s) { 
     // You can use `s` to select the appropriate file 

     // load and private key from selected certificate 
     // this use for certificate authorisation 

     try { 
      File file = new File("private key file"); 
      byte buffer[] = Files.readAllBytes(file.toPath()); 

      KeySpec keySpec = new PKCS8EncodedKeySpec(buffer); 
      KeyFactory factory = KeyFactory.getInstance("RSA"); 

      return factory.generatePrivate(keySpec); 
     } 
     catch (NoSuchAlgorithmException | IOException | InvalidKeySpecException e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 
}; 

TrustManager tm = new X509TrustManager() { 
    @Override 
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 

    } 

    @Override 
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 

    } 

    @Override 
    public X509Certificate[] getAcceptedIssuers() { 
     try { 
      File file = new File("path to certificate"); 

      try(InputStream is = new FileInputStream(file)) { 
       CertificateFactory factory = CertificateFactory.getInstance("X.509"); 
       return new X509Certificate[] { 
         (X509Certificate) factory.generateCertificate(is) 
       }; 
      } 
     } 
     catch (CertificateException| IOException e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 
}; 

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
tmf.init((KeyStore)null); //use java system trust certificates 

TrustManager managers[] = new TrustManager[tmf.getTrustManagers().length + 1]; 
System.arraycopy(tmf.getTrustManagers(), 0, managers, 0, tmf.getTrustManagers().length); 
managers[managers.length - 1] = tm; 

SSLContext context = SSLContext.getInstance("TLS"); 
context.init(new KeyManager[]{ km }, managers, new SecureRandom()); 

URL url = new URL("https://............/"); 
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); 
connection.setSSLSocketFactory(connection.getSSLSocketFactory()); 

connection.connect(); 
相關問題