我正在从事的项目有很多安全操作。我以前从未遇到过安全问题。因此,我的问题可以是初级水平。
在我的问题中,我得到一个字节数组数据,它有一个证书和一些其他参数。我需要验证此证书及其签名。但是我无法处理签名验证。其实我不知道应该用哪个公钥来验证。
代码如下。 感谢您的帮助..!
public boolean startValidation(PublicKey publicKey) {
CertificateFactory cf;
try {
cf = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
e.printStackTrace();
return false;
}
try {
certificate = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certBytes));
} catch (CertificateException e) {
e.printStackTrace();
setCertError(0);
return false;
}
if (!checkProvider()){
setCertError(1);
return false;
}
boolean[] usages = certificate.getKeyUsage();
boolean usage = usages[0] && usages[2];
if (!usage){
setCertError(2);
}
try {
certificate.checkValidity();
} catch (CertificateNotYetValidException e) {
e.printStackTrace();
setCertError(3);
return false;
} catch (CertificateExpiredException e) {
e.printStackTrace();
setCertError(4);
return false;
}
System.out.println("Sign Algorithm Name " + certificate.getSigAlgName());
//Output is SHA256WithRSAEncryption
// Problem area
try {
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initVerify(publicKey); //Should I use this certificate.getPublicKey() or what ??
if(signature.verify(certificate.getSignature())){
System.out.println("Accepted");
}else System.out.println("Failure");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
System.out.println("Public Key Format " + publicKey.getFormat() + "\nPublic Key Algorithm " + publicKey.getAlgorithm() );
System.out.println("Subject DN -> " + certificate.getSubjectDN().getName());
return true;
}
最佳答案
典型的 PKI 系统使用 Certificate Authorities向主题颁发证书(通过签名)。通过签署证书颁发机构形成从 CA 到主体证书的链,如果 CA1(根 CA)签发 CA2(中间 CA)证书,则该链可以包含多个 CA,其中turn 唱出受试者的证书。这在互联网(对于 SSL/TLS)和数字签名场景中很常见。
因此您很可能至少需要一个 CA 的证书和它的公钥来验证主体的证书。您的程序也可以支持多个独立的 CA。您的程序接受的 CA 通常称为 Trust Anchors .将信任 anchor 保持在 KeyStore 中也很方便。
因此,您最终可能会得到一个包含信任 anchor 和中间 CA 的 keystore 。从那里开始,您需要形成链并验证 chin 中从根 CA(信任 anchor )到您尝试验证的主题证书的所有证书的签名。
为了进行正确的证书验证,除了链的签名之外,您还需要检查其他内容,例如 key 使用、基本约束、吊销信息等。所有这些都在 RFC5280 中指定。在证书路径验证中。
幸运的是,已经有 CertPath API 形式的 Java API这可以帮助你。一个适合您的用例的非常基本的示例是:
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
final X509Certificate certificateToCheck = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes));
final KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream keyStoreStream = ...
trustStore.load(keyStoreStrem, "your password".toCharArray());
final CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
final X509CertSelector certSelector = new X509CertSelector();
certSelector.setCertificate(certificateToCheck);
final CertPathParameters certPathParameters = new PKIXBuilderParameters(trustStore, certSelector);
final CertPathBuilderResult certPathBuilderResult = certPathBuilder.build(certPathParameters);
final CertPath certPath = certPathBuilderResult.getCertPath();
final CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
final PKIXParameters validationParameters = new PKIXParameters(trustStore);
validationParameters.setRevocationEnabled(true); // if you want to check CRL
final X509CertSelector keyUsageSelector = new X509CertSelector();
keyUsageSelector.setKeyUsage(new boolean[] { true, false, true }); // to check digitalSignature and keyEncipherment bits
validationParameters.setTargetCertConstraints(keyUsageSelector);
final PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) certPathValidator.validate(certPath, validationParameters);
System.out.println(result);
但请注意有很多more nuances and details必须妥善解决这个问题,以便真正安全地实现。错误的证书路径检查是安全问题的常见原因。
关于Java 安全 - 使用公钥的 X509 证书验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33493109/