在我开发的应用程序中,我检查客户端在传入消息中发出的证书:除了基本证书有效性检查(证书签名,到期日期......)之外,我还检查客户端是否可信。< / p>
为此,我创建了一个仅包含可信证书的密钥库:如果收到的证书不在列表中,我拒绝传入的消息。 客户端证书位于证书路径中,我检查所有证书路径。
对于认证路径验证,我使用以下算法: (wikipedia)
1)从客户证书开始
2)虽然当前证书不是根证书:
3)在密钥库中搜索父证书:为此,我在密钥库中搜索当前证书的SubjectDN = IssuerDN的证书。如果未找到,则测试的证书无效
4)使用父证书的公钥
检查当前证书的签名因此,整个路径已经过验证
这里是验证器的完整代码: (感谢this article)的作者
请注意,此处,撤销列表(CRL)检查已禁用。
public class CertificateChainValidator {
private static Logger logger = Logger.getLogger(CertificateChainValidator.class);
/**
* path of the keystore.
*/
private static final String TRUSTED_KEYSTORE = "/trusted.jks";
/**
* password for opening the keystore.
*/
private static final char[] TRUSTED_KEYSTORE_PWD = new char[] { '$' , '$' , '$','$','$','$','$'};
/**
* the keystore loaded.
*/
private static KeyStore trustedKeystore;
/**
* Validate keychain
*
* @param client
* is the client X509Certificate
* @param keyStore
* containing all trusted certificate
* @return true if validation until root certificate success, false
* otherwise
* @throws KeyStoreException
* @throws CertificateException
* @throws InvalidAlgorithmParameterException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
public static boolean validateKeyChain(final X509Certificate client, final KeyStore keyStore)
throws KeyStoreException, CertificateException, InvalidAlgorithmParameterException,
NoSuchAlgorithmException, NoSuchProviderException {
X509Certificate[] certs = new X509Certificate[keyStore.size()];
int i = 0;
Enumeration<String> alias = keyStore.aliases();
while (alias.hasMoreElements()) {
certs[i++] = (X509Certificate) keyStore.getCertificate(alias.nextElement());
}
return validateKeyChain(client, certs);
}
/**
* Validate keychain
*
* @param client
* is the client X509Certificate
* @param trustedCerts
* is Array containing all trusted X509Certificate
* @return true if validation until root certificate success, false
* otherwise
* @throws CertificateException
* @throws InvalidAlgorithmParameterException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
@SuppressWarnings("unchecked")
private static boolean validateKeyChain(final X509Certificate client, final X509Certificate... trustedCerts)
throws CertificateException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchProviderException {
boolean found = false;
int i = trustedCerts.length;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
TrustAnchor anchor;
@SuppressWarnings("rawtypes")
Set anchors;
CertPath path;
@SuppressWarnings("rawtypes")
List list;
PKIXParameters params;
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
while (!found && i > 0) {
anchor = new TrustAnchor(trustedCerts[--i], null);
anchors = Collections.singleton(anchor);
list = Arrays.asList(new Certificate[] { client });
path = cf.generateCertPath(list);
params = new PKIXParameters(anchors);
params.setRevocationEnabled(false);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Test certificate chain : client=%s IssuerDN=%s", client.getIssuerDN(),
trustedCerts[i].getSubjectDN()));
}
if (client.getIssuerDN().equals(trustedCerts[i].getSubjectDN())) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Validation certificate : IssuerDN=%s", trustedCerts[i].getSubjectDN()));
}
try {
validator.validate(path, params);
if (isSelfSigned(trustedCerts[i])) {
// found root ca
if (logger.isDebugEnabled()) {
logger.debug(String.format("certificate root validated : IssuerDN=%s",
trustedCerts[i].getSubjectDN()));
}
found = true;
} else if (!client.equals(trustedCerts[i])) {
// find parent ca
if (logger.isDebugEnabled()) {
logger.debug(String.format("certificate intermerdiart validated : IssuerDN=%s",
trustedCerts[i].getSubjectDN()));
}
found = validateKeyChain(trustedCerts[i], trustedCerts);
}
} catch (CertPathValidatorException e) {
// validation fail, check next certifiacet in the
// trustedCerts array
}
}
}
return found;
}
/**
*
* @param cert
* is X509Certificate that will be tested
* @return true if cert is self signed, false otherwise
* @throws CertificateException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
private static boolean isSelfSigned(final X509Certificate cert)
throws CertificateException, NoSuchAlgorithmException, NoSuchProviderException {
try {
PublicKey key = cert.getPublicKey();
cert.verify(key);
return true;
} catch (SignatureException sigEx) {
return false;
} catch (InvalidKeyException keyEx) {
return false;
}
}
/**
* donne le trusted keystore (le charge une seule fois).
*
* @return
* @throws CertificateIsabelSignatureVerificationException
*/
private synchronized static KeyStore getTrustedKeystore() throws CertificateIsabelSignatureVerificationException {
if (trustedKeystore == null) {
trustedKeystore = loadKeystore(TRUSTED_KEYSTORE, TRUSTED_KEYSTORE_PWD);
}
return trustedKeystore;
}
/**
* chargement du keystore spécifié.
*
* @param path
* chemin du keystore, dans le classpath.
* @return le keystore chargé.
* @throws CertificateIsabelSignatureVerificationException
*/
private static KeyStore loadKeystore(final String path, final char[] passsword)
throws CertificateIsabelSignatureVerificationException {
try {
if (logger.isDebugEnabled()) {
logger.debug(String.format("loading keystore %s ...", path));
}
KeyStore ks = KeyStore.getInstance("JKS");
ks.load( //
CertificateChainValidator.class.getResourceAsStream(path) //
, passsword //
);
return ks;
} catch (Exception ex) {
throw new CertificateIsabelSignatureVerificationException(
String.format("Echec lecture du keystore %s", path), ex);
}
}
/**
* Valide le certificat client : s'assure qu'il est valide et vérifie qu'il
* est bien associé à un certifact root connu (dans trusted.jks).
*
* @param certEncoded
* @throws CertificateIsabelSignatureVerificationException
*/
public static void validateClientCertificate(final byte[] certEncoded)
throws CertificateIsabelSignatureVerificationException {
try {
// le keystore contenant tous les certificats reconnus
KeyStore ks = getTrustedKeystore();
// récupère le certificat client
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificat = (X509Certificate) certFactory
.generateCertificate(new ByteArrayInputStream(certEncoded));
if (logger.isDebugEnabled()) {
logger.debug(String.format("certificate validation : IssuerDN=%s", certificat.getSubjectDN()));
}
boolean valid = validateKeyChain(certificat, ks);
if (logger.isDebugEnabled()) {
logger.debug(String.format("certificate valid : %s", valid));
}
if (!valid) {
throw new CertificateIsabelSignatureVerificationException("The certificate is not valid");
}
} catch (CertificateIsabelSignatureVerificationException ex) {
throw ex;
} catch (Exception ex) {
throw new CertificateIsabelSignatureVerificationException("Error during validation", ex);
}
}
}
答案 0 :(得分:2)
您无法比较issuerDN,因为任何人都可以使用该字符串创建证书。
每个证书都已使用颁发者的私钥进行数字签名,因此您需要使用信任库中现有证书的公钥验证客户端证书的签名。如果匹配,那么您的证书将被信任&#34;,但继续使用认证链中的下一个证书。
注意:我没有检查你的代码。您可能需要查看建议的链接