在java中验证证书会引发异常 – 无法找到所请求目标的有效证书路
我有一个Web应用程序,要求客户端发送它的证书,服务器必须验证证书(即查看颁发者是否是有效的颁发者并出现在服务器的信任库中).这是代码:
FileInputStream fin=new FileInputStream("C:/trustedca"); KeyStore anchors = KeyStore.getInstance("JKS","SUN"); anchors.load(fin,"server".toCharArray()); X509CertSelector target = new X509CertSelector(); FileInputStream fin1=new FileInputStream("C:/client.crt"); CertificateFactory cf=CertificateFactory.getInstance("X.509"); X509Certificate cert=null; while (fin1.available() > 0) { System.out.println("in while---------"); cert =(X509Certificate) cf.generateCertificate(fin1); } target.setCertificate(cert); PKIXBuilderParameters params = new PKIXBuilderParameters(anchors,target); CertPathBuilder builder = (CertPathBuilder) CertPathBuilder.getInstance("PKIX").build(params); PKIXCertPathBuilderResult r = (PKIXCertPathBuilderResult) builder.build((CertPathParameters)params);<br> 但我得到一个例外: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target<br> 注意 : 解决方法
如果您期望获得客户端证书,请让JSSE为您完成所有这些工作.如果要将特定连接用于自己的信任库,请配置JSSE以使用它.检查参考文档中的
Customizing JSSE部分.
以下是使用自定义信任库构建SSLContext的简短示例. (其他更复杂的X509TrustManagers也可以使用,但你很少需要它.) TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance("JKS"); FileInputStream fis = new FileInputStream("/.../example.jks"); ks.load(fis,null); // or ks.load(fis,"thepassword".toCharArray()); fis.close(); tmf.init(ks); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null,tmf.getTrustManagers(),null); 如果您正在使用现有的应用程序服务器,那么如何通过配置传递将取决于服务器及其预期配置方式. 如果你通过其他方式获得证书并想要验证它,你需要使用PKI API.如果你按照Example of Validating a Certification Path using the PKIX algorithm,你应该得到这样的东西: X509Certificate certToVerify = ... CertificateFactory cf = CertificateFactory.getInstance("X.509"); CertPath cp = cf.generateCertPath(Arrays .asList(new X509Certificate[] { certToVerify })); TrustAnchor trustAnchor = new TrustAnchor(caCert,null); CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); PKIXParameters pkixParams = new PKIXParameters( Collections.singleton(trustAnchor)); pkixParams.setRevocationEnabled(false); cpv.validate(cp,pkixParams); 检查来自validate的结果(当然它没有抛出验证异常).在这里,我已禁用撤销检查以简化.您还可以设置PKIXParameters的其他方面以进行策略检查.这可能变得非常复杂(为什么最好让默认的JSSE经理为你做这件事). 您还在Security.SE:What is the actual value of a certificate fingerprint?上提出的另一个问题的上下文中询问了所有这些问题. 假设您有两个X509Certificates:serverCert和caCert,您要在其中验证serverCert是否由caCert签署(与公钥匹配的私钥). 最简单的方法: serverCert.verify(caCert.getPublicKey()); 如果您想手动执行此操作,请使用Signature API: System.out .println("Signature algorithm: " + serverCert.getSigAlgName()); Signature sig = Signature.getInstance(serverCert.getSigAlgName()); sig.initVerify(caCert.getPublicKey()); sig.update(serverCert.getTBSCertificate()); System.out .println("Verified? " + sig.verify(serverCert.getSignature())); 假设算法是SHA1withRSA,您还可以计算摘要: MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); digest.update(serverCert.getTBSCertificate()); byte[] digestBytes = digest.digest(); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE,caCert.getPublicKey()); byte[] cipherText = cipher.doFinal(serverCert.getSignature()); 摘要本身只是使用Cipher的结果的一部分:你从serverCert.getSignature()得到的实际上是一个更复杂的ASN.1结构,其中包括摘要算法标识符,在这种情况下,digestBytes应该是前缀的与某事like this: SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H. (如果要正确分析ASN.1结构,则BouncyCastle可能很有用.) 请注意,这些都不会验证时间有效性或任何其他属性. PKIX合规性不仅仅是检查签名(参见RFC 3820和5820). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |