使用.cer证书进行HTTPS请求

问题描述:

我已经看到了这个问题: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

如果您确实不想创建新的密钥库文件,那么可以使用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

这是一个粗略的例子。表示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();