在java中验证证书会抛出异常 - 无法找到有效的请求目标的证书路径 [英] Validating a certificate in java throws an exception - unable to find valid certificate path to requested target

查看:554
本文介绍了在java中验证证书会抛出异常 - 无法找到有效的请求目标的证书路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个网络应用程序,需要客户端发送它的证书,服务器必须验证证书(即查看发行者是否是有效的发行者,并且存在于服务器的信任库中)。下面是代码:

I have a web app that requires a client to send it's certificate and the server has to validate the certificate(i.e see if the issuer is a valid issuer and present in the server's truststore). Here is the code :

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>

但我遇到了一个例外:

But I get an exception :

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
 certification path to requested target<br>

注意

客户端是client.crt,用于签署client.crt证书的证书是存在于密钥库trustedca中的ca.crt。

NOTE :
Here the certificate sent by the client is client.crt and the cerificate used to sign the client.crt certificate is the ca.crt which is present in the keystore "trustedca". Then why is it giving this exception?

推荐答案

如果您希望获得客户端证书,请让JSSE执行所有这些操作您。如果要对特定连接使用自己的信任库,请将JSSE配置为使用它。请参阅参考文档中的自定义JSSE 部分。

If you're expecting a client certificate, let the JSSE do all of this for you. If you want to use your own trust store for a particular connection, configure the JSSE to use it. Check the Customizing JSSE section in the reference documentation.

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

Here is a short example for building an SSLContext with a custom trust store. (Other, more complex X509TrustManagers can also be used, but you rarely need that.)

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也可以确保密钥使用属性是合适的。

If you're using an existing application server, how to pass configure all this will depend on the server and how it expects to be configured. Using the JSSE for this will also make sure that the key usage attributes are appropriate.

如果你通过其他方式获得证书,并想要验证它,您需要使用 PKI API 。如果您遵循 验证证书路径示例,使用PKIX算法 ,您应该得到这样的:

If you get the certificate via some other means and want to validate it, you need to use the PKI API. If you follow the Example of Validating a Certification Path using the PKIX algorithm, you should get to something like this:

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经理为你做)。

Check the result from validate (and that it hasn't thrown a validation exception, of course). Here, I've disabled revocation checks to simplify. You can also set other aspects of the PKIXParameters for policy checks. This can get quite complex (and why it's better to let the default JSSE managers do that for you).

也询问关于您在Security.SE上提出的其他问题的上下文: 什么是实际价值

You were also asking about all this in the context of this other question you asked on Security.SE: What is the actual value of a certificate fingerprint?.

假设您有两个 X509凭证 s: serverCert caCert ,您要验证 serverCert

Suppose you have two X509Certificates: serverCert and caCert, where you want to verify that serverCert was signed by (the private key matching the public key in) caCert.

最简单的方法:

serverCert.verify(caCert.getPublicKey());

如果你想更多地手动操作,使用 Signature API:

If you want to do this a bit more manually, use the 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 应该以喜欢的形式作为前缀。 :

The digest itself will only be part of the result from using Cipher: what you get from serverCert.getSignature() is in fact a more complex ASN.1 structure, which includes the digest algorithm identifier, in this case, the digestBytes should be prefixed with something like this:

SHA-1:   (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H.

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

(BouncyCastle may be useful if you want to analyse the ASN.1 structure properly.)

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

Note that none of this verifies the time validity or any other attributes. PKIX compliance is far more than checking the signature (see RFC 3820 and 5820).

这篇关于在java中验证证书会抛出异常 - 无法找到有效的请求目标的证书路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆