根据Java中的CA验证X.509证书

根据Java中的CA验证X.509证书,java,ssl,x509certificate,x509,x509trustmanager,Java,Ssl,X509certificate,X509,X509trustmanager,假设我有这样的代码(客户端代码): 这段代码功能完整,但我真的不知道如何根据pem文件中提供的一个具体CA证书验证服务器的证书 所有证书都由我的自签名CA签名,并且它是我需要验证的CA(仅针对此CA) 每一个答案都很感激 编辑: 作为对Jgluie的回应(非常感谢您,我不能投票支持您的答案) 我创建了解决方案: new X509TrustManager() { @Override public java.security.cert.X509Certificate

假设我有这样的代码(客户端代码):

这段代码功能完整,但我真的不知道如何根据pem文件中提供的一个具体CA证书验证服务器的证书

所有证书都由我的自签名CA签名,并且它是我需要验证的CA(仅针对此CA)

每一个答案都很感激

编辑:

作为对Jgluie的回应(非常感谢您,我不能投票支持您的答案)

我创建了解决方案:

new X509TrustManager() {

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        @Override
        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
                throws CertificateException {
            InputStream inStream = null;
            try {
                // Loading the CA cert
                URL u = getClass().getResource("tcp/cacert.pem");
                inStream = new FileInputStream(u.getFile());
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                X509Certificate ca = (X509Certificate) cf.generateCertificate(inStream);
                inStream.close();

                for (X509Certificate cert : certs) {
                    // Verifing by public key
                    cert.verify(ca.getPublicKey());
                }
            } catch (Exception ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    inStream.close();
                } catch (IOException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }
    }
};

我假设您的CA的自签名证书已加载,如下所示:

CertificateFactory cf = CertificateFactory.getInstance("X.509");   
FileInputStream finStream = new FileInputStream("CACertificate.pem"); 
X509Certificate caCertificate = (X509Certificate)cf.generateCertificate(finStream);  
然后在检查证书的方法中:

@Override        
 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)  throws CertificateException {

 if (certs == null || certs.length == 0) {  
      throw new IllegalArgumentException("null or zero-length certificate chain");  
 }  

 if (authType == null || authType.length() == 0) {  
            throw new IllegalArgumentException("null or zero-length authentication type");  
  }  

   //Check if certificate send is your CA's
    if(!certs[0].equals(caCertificate)){
         try
         {   //Not your CA's. Check if it has been signed by your CA
             certs[0].verify(caCertificate.getPublicKey())
         }
         catch(Exception e){   
              throw new CertificateException("Certificate not trusted",e);
         }
    }
    //If we end here certificate is trusted. Check if it has expired.  
     try{
          certs[0].checkValidity();
      }
      catch(Exception e){
            throw new CertificateException("Certificate not trusted. It has expired",e);
      }  
}
免责声明:甚至没有尝试编译代码

这段代码是完全实用的

这段代码完全不正常。它是完全不安全的,甚至不符合自己的规范。很少需要提供您自己的TrustManager,默认的TrustManager工作得非常好

您需要做的就是确保您拥有的CA证书存在于您的信任库中,然后将系统属性
javax.net.ssl.truststore
设置为指向它(如果它不是默认的Java信任库文件)。如果不通过命令行-D选项进行设置,则不需要在可能的
System.setProperty()
之外编写任何代码


编辑您的“解决方案”通常肯定不起作用。它假定链中的每个证书都由您的证书签名。只有当签名证书=您的证书时,长度为1或长度为2的链才是如此。

接受的答案极不正确。它不会以加密方式验证服务器证书和可信证书颁发机构之间的任何连接。通常,您几乎不需要实现自己的TrustManager,这样做是非常危险的

正如EJP所述,不需要实现您自己的TrustManager,您只需使用默认的TrustManager,并确保已将受信任的CA证书添加到您的默认TrustStore中。有关更多信息,请参阅


看看JDK中的类,它验证了从服务器自己的证书到可信CA的连续信任链。有关证书链验证的介绍,请参阅。

这不是一个真正的答案,也远远不是真的。如果您编写的软件将通过ssl连接到特定服务器,则应覆盖TrustManager并主动检查所连接的服务器是否是您信任的服务器。这对你抵御MIM攻击有很大帮助。这个答案怎么会有6张反对票?我完全正确!override
TrustManager
这只适用于少数情况,通常情况下,当您在生产模式下进行某些测试时。。。如果OP ask希望根据特定CA验证证书,则只使用此CA创建信任库,而不是覆盖
TrustManager
@albciff,我想说原因很清楚-它没有回答问题。@EJP问题,原始问题,是关于如何针对固定CA验证TLS证书的。您尚未提供有关如何针对固定CA验证TLS证书的任何信息。此答案是正确的-我感到奇怪和担心的是,此答案已被多次否决。实现您自己的TrustManager是一个非常糟糕的主意,除非您对加密和Java非常了解。特别是,上面由Jakub提供的特定解决方案与普通证书链验证不同。您应该使用JDK的X509TrustManager。嗨,您好,我正在尝试为
checkServerTrusted
实现您的解决方案。我有一个带有完整证书链的.crt文件,它是在打开网站后从浏览器导出的。但在
for
循环到
验证
public时,我遇到了异常。我的基本问题是什么是pem文件?如何生成它?它包含哪些私钥信息或公钥信息。?对不起,我问的问题太基本了..添加问题这不符合要求。在
证书[0],
中发送的证书永远不能是CA证书。它必须是对等方自己的证书,签名CA的证书位于链的更上层。此外,这些方法的规范中没有允许
chain
参数为null或零长度,也没有允许
authType
null
或空字符串
authType
实际上是密钥交换算法的名称,它不能是这两种算法中的任何一种。就像一个老板:“免责声明:我甚至没有尝试编译代码”
@Override        
 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)  throws CertificateException {

 if (certs == null || certs.length == 0) {  
      throw new IllegalArgumentException("null or zero-length certificate chain");  
 }  

 if (authType == null || authType.length() == 0) {  
            throw new IllegalArgumentException("null or zero-length authentication type");  
  }  

   //Check if certificate send is your CA's
    if(!certs[0].equals(caCertificate)){
         try
         {   //Not your CA's. Check if it has been signed by your CA
             certs[0].verify(caCertificate.getPublicKey())
         }
         catch(Exception e){   
              throw new CertificateException("Certificate not trusted",e);
         }
    }
    //If we end here certificate is trusted. Check if it has expired.  
     try{
          certs[0].checkValidity();
      }
      catch(Exception e){
            throw new CertificateException("Certificate not trusted. It has expired",e);
      }  
}