OnlineCertificateChainProvider.java
package io.mersel.dss.signer.api.services.certificate;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.net.URL;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
/**
* AIA (Authority Information Access) üzerinden issuer sertifikalarını indirerek sertifika zinciri oluşturur.
* Güncel sertifikaları sağladığı için tercih edilen yöntemdir.
*/
public class OnlineCertificateChainProvider implements CertificateChainProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(OnlineCertificateChainProvider.class);
private static final String CA_ISSUER_OID = "1.3.6.1.5.5.7.48.2";
@Override
public List<X509Certificate> buildChain(X509Certificate cert) throws Exception {
List<X509Certificate> chain = new ArrayList<>();
chain.add(cert);
X509Certificate currentCert = cert;
while (!isSelfSigned(currentCert)) {
X509Certificate issuerCert = fetchIssuerCertificate(currentCert);
if (issuerCert == null) {
LOGGER.warn("Could not fetch issuer certificate for: {}",
currentCert.getSubjectX500Principal());
break;
}
chain.add(issuerCert);
currentCert = issuerCert;
// Güvenlik kontrolü: Sonsuz döngüyü önle
if (chain.size() > 10) {
LOGGER.warn("Sertifika zinciri çok uzun (>10), durduruluyor");
break;
}
}
LOGGER.info("Sertifika zinciri çevrimiçi olarak {} sertifika ile oluşturuldu", chain.size());
return chain;
}
@Override
public int getPriority() {
return 10; // Yüksek öncelik
}
private X509Certificate fetchIssuerCertificate(X509Certificate cert) {
try {
String aiaUrl = getAiaIssuerUrl(cert);
if (aiaUrl == null) {
LOGGER.debug("Sertifikada AIA issuer URL bulunamadı");
return null;
}
LOGGER.debug("Issuer sertifikası indiriliyor: {}", aiaUrl);
return downloadCertificate(aiaUrl);
} catch (Exception e) {
LOGGER.debug("Issuer sertifikası getirilemedi: {}", e.getMessage());
return null;
}
}
private String getAiaIssuerUrl(X509Certificate cert) throws Exception {
byte[] aiaExt = cert.getExtensionValue(Extension.authorityInfoAccess.getId());
if (aiaExt == null) {
return null;
}
ASN1Sequence seq = ASN1Sequence.getInstance(
JcaX509ExtensionUtils.parseExtensionValue(aiaExt));
for (ASN1Encodable encodable : seq.toArray()) {
ASN1Sequence subSeq = ASN1Sequence.getInstance(encodable);
if (subSeq.size() < 2) {
continue;
}
ASN1ObjectIdentifier id = (ASN1ObjectIdentifier) subSeq.getObjectAt(0);
if (CA_ISSUER_OID.equals(id.getId())) {
GeneralName generalName = GeneralName.getInstance(subSeq.getObjectAt(1));
return ((DERIA5String) generalName.getName()).getString();
}
}
return null;
}
private X509Certificate downloadCertificate(String urlStr) throws Exception {
URL url = new URL(urlStr);
try (InputStream in = url.openStream()) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509Certificate) cf.generateCertificate(in);
}
}
private boolean isSelfSigned(X509Certificate cert) {
return cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal());
}
}