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

在java中验证证书会引发异常-无法找到请求目标的有效证书路径,java,certificate,x509certificate,keystore,pkix,Java,Certificate,X509certificate,Keystore,Pkix,我有一个web应用程序,需要客户端发送其证书,服务器必须验证证书(即,查看颁发者是否是有效的颁发者,是否存在于服务器的信任库中)。下面是代码: FileInputStream fin=new FileInputStream("C:/trustedca"); KeyStore anchors = KeyStore.getInstance("JKS","SUN"); anchors.load(fin, "server".toCharArray()); X509CertSele

我有一个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>
FileInputStream fin=newfileinputstream(“C:/trustedca”);
KeyStore anchors=KeyStore.getInstance(“JKS”、“SUN”);
加载(fin,“server.tocharray());
X509CertSelector目标=新的X509CertSelector();
FileInputStream fin1=新的FileInputStream(“C:/client.crt”);
CertificateFactory cf=CertificateFactory.getInstance(“X.509”);
X509证书证书证书=空;
while(fin1.available()>0)
{
System.out.println(“in while-----------”);
证书=(X509Certificate)cf.generateCertificate(fin1);
}
target.setCertificate(证书);
PKIXBuilderParameters params=新的PKIXBuilderParameters(锚,目标);
CertPathBuilder=(CertPathBuilder)CertPathBuilder.getInstance(“PKIX”).build(params);
PKIXCertPathBuilderResult r=(PKIXCertPathBuilderResult)builder.build((CertPathParameters)参数)
但我有一个例外:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
 certification path to requested target<br>
sun.security.provider.certpath.SunCertPathBuilderException:找不到有效的
请求目标的认证路径
注意:
这里,客户端发送的证书是client.crt,用于签署client.crt证书的证书是密钥库“trustedca”中的ca.crt。那为什么会有这样的例外呢

i、 e查看颁发者是否是有效的颁发者,以及是否存在于服务器的 信托商店


JSSE已经做到了这一切。您无需执行任何操作,只需验证对等证书是否已过期。

如果您需要客户端证书,请让JSSE为您执行所有这些操作。如果要为特定连接使用自己的信任存储,请将JSSE配置为使用它。检查参考文档中的部分

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

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

如果您通过其他方式获得证书并希望对其进行验证,则需要使用。如果您遵循以下步骤,您应该得到如下结果:

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上询问的另一个问题中也询问了这一切

假设您有两个
X509Certificate
s:
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
应该加上前缀:

(如果您想正确分析ASN.1结构,可能会很有用。)


请注意,所有这些都不会验证时间有效性或任何其他属性。PKIX合规性远不止是检查签名(请参见RFC 3820和5820)。

可能无法构造有效路径,因为缺少一些中间证书。加载证书的循环将丢弃除最后一个之外的所有证书。相反,保存所有这些证书,并将它们传递给
CertPathBuilder
,以帮助构建路径

另一个常见问题是默认情况下执行撤销检查,这有利于安全性。如果您不了解如何获取CRL或使用OCSP,则可能会降低安全性并禁用吊销检查。下面的示例中也显示了这一点

...
CertificateFactory fac = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream("client.crt");
Collection<? extends Certificate> intermediate;
try {
  intermediate = fac.generateCertificates(is);
} finally {
  is.close();
}
X509Certificate client = null;
for (Certificate c : intermediate)
  client = (X509Certificate) c;
if (client == null)
  throw new IllegalArgumentException("Empty chain.");
X509CertSelector t = new X509CertSelector();
t.setCertificate(client);
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, t);
CertStoreParameters store = new CollectionCertStoreParameters(intermediate);
params.addCertStore(CertStore.getInstance("Collection", store));
params.setRevocationEnabled(false);
...
。。。
CertificateFactory fac=CertificateFactory.getInstance(“X.509”);
FileInputStream是=新的FileInputStream(“client.crt”);

Collection@suraj你没得到什么?当您向信任库中添加证书时,您告诉信任库信任该证书。如果你不信任它,就不要添加它。@suraj如果它是由授权CA签署的,你根本不需要添加它。使用Java分发的信任库已经信任所有已识别的CA。这就是全部想法。@suraj您的信任库最初应该包含与JDK一起分发的信任库中的所有内容,或者至少包含您准备信任的CA证书。这种机制完全避免了将客户端证书加载到信任库中。这就是信任库机制和整个X.509机制的全部内容。@suraj如果您将自签名证书放入信任库,您就信任它。这就是手术的意思。如果你不信任它,就不要添加它。我已经说过了。您已经说过您的信任库不是默认的Java信任库。我的问题是为什么不呢?在我听来,你做这一切都是错的。您根本不必为证书taken编写代码,因为它应该是一个具有独立验证的脱机进程。否则你所做的一切
SHA-1:   (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H.
...
CertificateFactory fac = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream("client.crt");
Collection<? extends Certificate> intermediate;
try {
  intermediate = fac.generateCertificates(is);
} finally {
  is.close();
}
X509Certificate client = null;
for (Certificate c : intermediate)
  client = (X509Certificate) c;
if (client == null)
  throw new IllegalArgumentException("Empty chain.");
X509CertSelector t = new X509CertSelector();
t.setCertificate(client);
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, t);
CertStoreParameters store = new CollectionCertStoreParameters(intermediate);
params.addCertStore(CertStore.getInstance("Collection", store));
params.setRevocationEnabled(false);
...