Проверка сертификатов PKCS#7 в Java
нужна помощь с крипто процедуры в Java.
учитывая подпись PKCS#7, я хочу проверить все сертификаты, которые он содержит, на доверенное хранилище. Я предполагаю, что все сертификаты, содержащиеся в подписи, находятся в правильном порядке, чтобы сформировать действительный путь сертификата (или цепочку, что угодно), так что
- topmost (#0) - сертификат подписи;
- следующий (#1) - промежуточный сертификат, используемый для подписи #0;
- следующий (#2) еще промежуточный сертификат, используемый для подписи #1;
- и так далее.
последний сертификат (#N) подписан CA.
вот что мне удалось взломать до сих пор:
// Exception handling skipped for readability
//byte[] signature = ...
pkcs7 = new PKCS7(signature); // `sun.security.pkcs.PKCS7;`
// *** Checking some PKCS#7 parameters here
X509Certificate prevCert = null; // Previous certificate we've found
X509Certificate[] certs = pkcs7.getCertificates(); // `java.security.cert.X509Certificate`
for (int i = 0; i < certs.length; i++) {
// *** Checking certificate validity period here
if (cert != null) {
// Verify previous certificate in chain against this one
prevCert.verify(certs[i].getPublicKey());
}
prevCert = certs[i];
}
//String keyStorePath = ...
KeyStore keyStore = KeyStore.getInstance("JKS"); // `java.security.KeyStore`
keyStore.load(new FileInputStream(keyStorePath), null);
// Get trusted VeriSign class 1 certificate
Certificate caCert = keyStore.getCertificate("verisignclass1ca"); // `java.security.cert.Certificate`
// Verify last certificate against trusted certificate
cert.verify(caCert.getPublicKey());
Итак, вопрос в том, как это можно сделать с помощью стандартных классов Java, таких как CertPath
и друзей? У меня такое чувство, что я заново изобретаю велосипед. Или, если у кого-то есть пример с библиотекой BouncyCastle, это тоже было бы хорошо.
бонус-вопрос: как проверить сертификат в доверенном хранилище, чтобы корневой сертификат был выбран автоматически?
2 ответов
нашел решение сам. Итак, вот как можно извлечь и проверить цепочку сертификатов в доверенном хранилище (обработка исключений пропущена для удобства чтения):
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// Get ContentInfo
//byte[] signature = ... // PKCS#7 signature bytes
InputStream signatureIn = new ByteArrayInputStream(signature);
DERObject obj = new ASN1InputStream(signatureIn).readObject();
ContentInfo contentInfo = ContentInfo.getInstance(obj);
// Extract certificates
SignedData signedData = SignedData.getInstance(contentInfo.getContent());
Enumeration certificates = signedData.getCertificates().getObjects();
// Build certificate path
List certList = new ArrayList();
while (certificates.hasMoreElements()) {
DERObject certObj = (DERObject) certificates.nextElement();
InputStream in = new ByteArrayInputStream(certObj.getDEREncoded());
certList.add(cf.generateCertificate(in));
}
CertPath certPath = cf.generateCertPath(certList);
// Load key store
//String keyStorePath = ...
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keyStorePath), null);
// Set validation parameters
PKIXParameters params = new PKIXParameters(keyStore);
params.setRevocationEnabled(false); // to avoid exception on empty CRL
// Validate certificate path
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
CertPathValidatorResult result = validator.validate(certPath, params);
validate()
выдаст исключение, если проверка завершится неудачно.
Docs:ASN1Set
, ContentInfo
, SignedData
. Все другие экзотические имена и связанные с ними документы можно найти в java.security.cert
.
здесь нет зависимости от солнца, только после установки BouncyCastle библиотека провайдера это.
этой вопрос (и особенно ответ) тоже может помочь.
вы хотите CertificateFactory. Последний пример в javadocs делает именно то, что вы хотите.