創建 CRL 需要用到有 CRL 權限的 CA 機構私鑰和證書:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 準備好創建 CRL 所需的私鑰和證書
PrivateKey caPrivateKey = ......
X509Certificate caCertificate = ......
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(
new X500Name(caCertificate.getSubjectDN().getName()),
new Date()
);
crlBuilder.setNextUpdate(new Date(System.currentTimeMillis() + 86400 * 1000)); // 1 天有效期
crlBuilder.addCRLEntry(111/*被撤銷證書序列號*/, new Date() /*被撤銷時間*/, 1 /*被撤銷原因*/);
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSA");
contentSignerBuilder.setProvider("BC");
X509CRLHolder crlHolder = crlBuilder.build(contentSignerBuilder.build(caPrivateKey));
JcaX509CRLConverter converter = new JcaX509CRLConverter();
converter.setProvider("BC");
X509CRL crl = converter.getCRL(crlHolder);
根證書創建方法可以看:根據 CSR 創建證書。
撤銷證書時需要指定撤銷原因,有以下幾種:
原因 | 說明 |
---|---|
unspecified | 未指定 |
keyCompromise | 私鑰泄漏 |
cACompromise | CA 私鑰可能泄漏 |
affiliationChanged | 組織變化,隸屬關係變更 |
superseded | 被取代 |
cessationOfOperation | CA 停用 |
certificateHold | 臨時吊銷 |
removeFromCRL | 使用 certificateHold 吊銷的證書,可以用 removeFromCRL 取消吊銷 |
privilegeWithdrawn | 因證書某權限被撤銷而吊銷 |
aACompromise | indicates that it is known or suspected that aspects of the AA validated in the attribute certificate have been compromised |
如果驗證一個證書是否在 CRL 撤銷列表裏呢?
// 讀取 CRL 對象
X509CRL x509CRL = ......
// 讀取簽發 CRL 的公鑰,一般簽發 CRL 的公鑰和簽發證書的公鑰是相同的
PublicKey publicKey = ......
// 驗證 CRL 合法性
x509CRL.verify(publicKey);
// 讀取待驗證的證書
X509Certificate certificate = ......
// 驗證該證書是否被撤銷
boolean isRevoked = x509CRL.isRevoked(certificate);
isRevoked 方法具體做了哪些事呢?可以看下 X509CRLImpl 裏的實現:
- 判斷證書類型是否是 X.509
- 判斷證書序列號是否在 CRL 裏
- 判斷證書籤發者和 CRL 簽發者是否是同一個
public boolean isRevoked(Certificate var1) {
if (!var1.getType().equals("X.509")) {
throw new IllegalArgumentException("X.509 CRL used with non X.509 Cert");
} else {
Enumeration var2 = this.c.getRevokedCertificateEnumeration();
X500Name var3 = this.c.getIssuer();
if (var2.hasMoreElements()) {
BigInteger var4 = ((X509Certificate)var1).getSerialNumber();
while(var2.hasMoreElements()) {
CRLEntry var5 = CRLEntry.getInstance(var2.nextElement());
if (this.isIndirect && var5.hasExtensions()) {
Extension var6 = var5.getExtensions().getExtension(Extension.certificateIssuer);
if (var6 != null) {
var3 = X500Name.getInstance(GeneralNames.getInstance(var6.getParsedValue()).getNames()[0].getName());
}
}
if (var5.getUserCertificate().hasValue(var4)) {
X500Name var9;
if (var1 instanceof X509Certificate) {
var9 = X500Name.getInstance(((X509Certificate)var1).getIssuerX500Principal().getEncoded());
} else {
try {
var9 = org.bouncycastle.asn1.x509.Certificate.getInstance(var1.getEncoded()).getIssuer();
} catch (CertificateEncodingException var8) {
throw new IllegalArgumentException("Cannot process certificate: " + var8.getMessage());
}
}
if (!var3.equals(var9)) {
return false;
}
return true;
}
}
}
return false;
}
}