当前位置: 首页 > 面试题库 >

在Java中验证证书会引发异常-无法找到到请求目标的有效证书路径

吉玉宸
2023-03-14
问题内容

我有一个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>

注意:
此处,客户端发送的证书为client.crt,用于签署client.crt证书的证书为密钥库“ trustedca”中的ca.crt。那为什么给这个例外呢?


问题答案:

如果您希望获得客户证书,请让JSSE为您完成所有这些工作。如果要为特定的连接使用自己的信任库,请配置JSSE以使用它。检查参考文档中的“
定制JSSE”部分。

这是SSLContext使用自定义信任库构建的简短示例。(X509TrustManager也可以使用其他更复杂的,但是您很少需要它。)

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

如果您使用的是现有的应用程序服务器,则如何通过配置这一切将取决于服务器及其期望的配置方式。为此,使用JSSE还将确保密钥用法属性合适。

如果您通过其他方式获得证书并想要对其进行验证,则需要使用PKI
API
。如果遵循
使用PKIX算法验证证书路径

示例
,则应获得如下信息:

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上询问的其他问题中还询问了所有这些问题:
证书指纹的实际值是多少?

假设您有两个X509Certificates:serverCertcaCert,您要在其中验证serverCert签名(与私钥匹配的私钥)caCert

最简单的方法:

serverCert.verify(caCert.getPublicKey());

如果您想手动进行一些操作,请使用SignatureAPI:

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

摘要本身仅是使用结果的一部分CipherserverCert.getSignature()实际上,您所获得的是更复杂的ASN.1结构,其中包含摘要算法标识符,在这种情况下,digestBytes前缀应为以下内容:

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



 类似资料:
  • 我最近为我的maven repo(Apache代理背后的人工制品)切换到了letsencrypt证书。通过浏览器访问回购协议工作正常,证书没有问题(下面的屏幕截图)。 如果我手动将证书导入到java密钥库中,它也可以工作。 但是根据这个SO问题,Java应该接受以8u101开头的lets加密证书。 我总是遇到这样的例外:

  • 我正在使用restTemplate发出post请求,并收到以下错误:无法找到到请求目标的有效证书路径 我的方法如下:

  • 问题内容: 我有一个可以从https服务器下载文件的类。当我运行它时,它返回很多错误。我的证书似乎有问题。是否可以忽略客户端服务器认证?如果是这样,怎么办? 错误: 问题答案: 当你的服务器具有自签名证书时,会出现此问题。要解决此问题,你可以将此证书添加到JVM的受信任证书列表中。 在本文中,作者描述了如何从浏览器中获取证书并将其添加到JVM的cacerts文件中。你可以使用-参数编辑文件或运行应

  • 我在Flutter中创建了一个新应用程序。我尝试在Android Mobile上运行该应用程序。它显示在错误下方。 但当我试图在Chrome或Edge(网络设备)上运行同样的程序时。它在跑。

  • 问题内容: 我有一个Java客户端尝试使用自签名证书访问服务器。 当我尝试发布到服务器时,出现以下错误: 无法找到到请求目标的有效认证路径 在对该问题进行了一些研究之后,我进行了以下工作。 1. 2. 将我的服务器域名保存为root.cer文件。 3. 在我的Glassfish服务器的JRE中,运行了此命令: 4. keytool -import -alias example -keystore

  • 我在Apache Tomcat7上有一个web应用程序,我的web应用程序上有不可信的证书。我的web应用程序必须与另一个使用HTTPS的web应用程序通信。然而,我总是遇到这样一个例外: 连接失败:javax.net.ssl.sslhandShakeException:sun.security.validator.validatoreXception:PKIX路径构建失败:sun.securit