X.509 Certificate Parsing in Java

Overview

X.509 is a standard format for public key certificates, widely used in TLS/SSL, code signing, document signing, and client authentication. Java provides comprehensive support for X.509 certificate parsing and validation through the java.security.cert package.

Basic Certificate Parsing

1. Basic Certificate Loading and Parsing

import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.util.Base64;
public class BasicCertificateParser {
public static X509Certificate loadCertificateFromFile(String filePath) throws Exception {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
try (FileInputStream fis = new FileInputStream(filePath)) {
return (X509Certificate) certFactory.generateCertificate(fis);
}
}
public static X509Certificate loadCertificateFromBase64(String base64Cert) throws Exception {
byte[] certData = Base64.getDecoder().decode(base64Cert);
return loadCertificateFromBytes(certData);
}
public static X509Certificate loadCertificateFromBytes(byte[] certData) throws Exception {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
try (ByteArrayInputStream bis = new ByteArrayInputStream(certData)) {
return (X509Certificate) certFactory.generateCertificate(bis);
}
}
public static void printBasicCertificateInfo(X509Certificate cert) {
System.out.println("=== X.509 Certificate Information ===");
System.out.println("Subject: " + cert.getSubjectX500Principal());
System.out.println("Issuer: " + cert.getIssuerX500Principal());
System.out.println("Serial Number: " + cert.getSerialNumber());
System.out.println("Version: " + cert.getVersion());
System.out.println("Valid From: " + cert.getNotBefore());
System.out.println("Valid Until: " + cert.getNotAfter());
System.out.println("Signature Algorithm: " + cert.getSigAlgName());
System.out.println("Public Key Algorithm: " + cert.getPublicKey().getAlgorithm());
// Check validity
try {
cert.checkValidity();
System.out.println("Certificate is currently valid");
} catch (Exception e) {
System.out.println("Certificate validity check failed: " + e.getMessage());
}
}
public static void main(String[] args) {
try {
// Example with a certificate file
X509Certificate cert = loadCertificateFromFile("example.cer");
printBasicCertificateInfo(cert);
} catch (Exception e) {
e.printStackTrace();
}
}
}

2. Advanced Certificate Information Extraction

import java.security.cert.X509Certificate;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPublicKey;
import java.util.*;
import javax.security.auth.x500.X500Principal;
public class AdvancedCertificateParser {
public static void parseCertificateDetails(X509Certificate cert) throws Exception {
System.out.println("\n=== Detailed Certificate Analysis ===");
// Subject DN analysis
parseDistinguishedName("Subject", cert.getSubjectX500Principal());
// Issuer DN analysis
parseDistinguishedName("Issuer", cert.getIssuerX500Principal());
// Key information
analyzePublicKey(cert.getPublicKey());
// Extensions analysis
analyzeExtensions(cert);
// Signature verification
verifySignature(cert);
}
private static void parseDistinguishedName(String type, X500Principal principal) {
System.out.println("\n" + type + " DN Analysis:");
String dn = principal.getName();
System.out.println("Full DN: " + dn);
// Parse individual components
Map<String, String> components = parseDNComponents(dn);
components.forEach((key, value) -> 
System.out.println("  " + key + ": " + value));
}
private static Map<String, String> parseDNComponents(String dn) {
Map<String, String> components = new LinkedHashMap<>();
String[] parts = dn.split(",");
for (String part : parts) {
String[] keyValue = part.trim().split("=", 2);
if (keyValue.length == 2) {
String key = keyValue[0].trim();
String value = keyValue[1].trim();
// Handle common OIDs
if (key.startsWith("OID.")) {
key = resolveOID(key.substring(4));
}
components.put(key, value);
}
}
return components;
}
private static String resolveOID(String oid) {
// Common OID mappings
Map<String, String> oidMap = Map.of(
"2.5.4.3", "CN", // Common Name
"2.5.4.6", "C",  // Country
"2.5.4.7", "L",  // Locality
"2.5.4.8", "ST", // State/Province
"2.5.4.10", "O", // Organization
"2.5.4.11", "OU", // Organizational Unit
"2.5.4.97", "Organization Identifier",
"1.2.840.113549.1.9.1", "E" // Email
);
return oidMap.getOrDefault(oid, "OID." + oid);
}
private static void analyzePublicKey(PublicKey publicKey) {
System.out.println("\nPublic Key Analysis:");
System.out.println("Algorithm: " + publicKey.getAlgorithm());
System.out.println("Format: " + publicKey.getFormat());
if (publicKey instanceof RSAPublicKey) {
RSAPublicKey rsaKey = (RSAPublicKey) publicKey;
System.out.println("RSA Modulus: " + rsaKey.getModulus());
System.out.println("RSA Exponent: " + rsaKey.getPublicExponent());
System.out.println("Key Size: " + rsaKey.getModulus().bitLength() + " bits");
} else if (publicKey instanceof DSAPublicKey) {
DSAPublicKey dsaKey = (DSAPublicKey) publicKey;
System.out.println("DSA Y: " + dsaKey.getY());
System.out.println("DSA Params: " + dsaKey.getParams());
} else if (publicKey instanceof ECPublicKey) {
ECPublicKey ecKey = (ECPublicKey) publicKey;
System.out.println("EC Point: " + ecKey.getW());
System.out.println("EC Params: " + ecKey.getParams());
} else {
System.out.println("Encoded Key: " + 
Base64.getEncoder().encodeToString(publicKey.getEncoded()));
}
}
private static void analyzeExtensions(X509Certificate cert) throws Exception {
System.out.println("\nCertificate Extensions:");
// Get critical extension OIDs
Set<String> criticalExtensions = cert.getCriticalExtensionOIDs();
if (criticalExtensions != null && !criticalExtensions.isEmpty()) {
System.out.println("Critical Extensions:");
criticalExtensions.forEach(oid -> System.out.println("  " + oid));
}
// Get non-critical extension OIDs
Set<String> nonCriticalExtensions = cert.getNonCriticalExtensionOIDs();
if (nonCriticalExtensions != null && !nonCriticalExtensions.isEmpty()) {
System.out.println("Non-Critical Extensions:");
nonCriticalExtensions.forEach(oid -> System.out.println("  " + oid));
}
// Analyze specific important extensions
analyzeKeyUsage(cert);
analyzeExtendedKeyUsage(cert);
analyzeSubjectAlternativeNames(cert);
analyzeBasicConstraints(cert);
}
private static void analyzeKeyUsage(X509Certificate cert) throws Exception {
boolean[] keyUsage = cert.getKeyUsage();
if (keyUsage != null) {
System.out.println("\nKey Usage:");
String[] usageNames = {
"Digital Signature", "Non-Repudiation", "Key Encipherment",
"Data Encipherment", "Key Agreement", "Key Cert Sign",
"CRL Sign", "Encipher Only", "Decipher Only"
};
for (int i = 0; i < keyUsage.length && i < usageNames.length; i++) {
if (keyUsage[i]) {
System.out.println("  ✓ " + usageNames[i]);
}
}
}
}
private static void analyzeExtendedKeyUsage(X509Certificate cert) throws Exception {
List<String> extendedKeyUsage = cert.getExtendedKeyUsage();
if (extendedKeyUsage != null) {
System.out.println("\nExtended Key Usage:");
extendedKeyUsage.forEach(usage -> System.out.println("  " + usage));
}
}
private static void analyzeSubjectAlternativeNames(X509Certificate cert) throws Exception {
Collection<List<?>> sans = cert.getSubjectAlternativeNames();
if (sans != null) {
System.out.println("\nSubject Alternative Names:");
for (List<?> san : sans) {
if (san.size() >= 2) {
Integer type = (Integer) san.get(0);
String value = san.get(1).toString();
String typeName = getSanTypeName(type);
System.out.println("  " + typeName + ": " + value);
}
}
}
}
private static String getSanTypeName(Integer type) {
switch (type) {
case 1: return "RFC822 Name (Email)";
case 2: return "DNS Name";
case 3: return "X400 Address";
case 4: return "Directory Name";
case 5: return "EDI Party Name";
case 6: return "URI";
case 7: return "IP Address";
case 8: return "Registered ID";
default: return "Unknown (" + type + ")";
}
}
private static void analyzeBasicConstraints(X509Certificate cert) throws Exception {
int pathLen = cert.getBasicConstraints();
if (pathLen != -1) {
System.out.println("\nBasic Constraints:");
System.out.println("  CA Certificate: Yes");
System.out.println("  Path Length Constraint: " + 
(pathLen == Integer.MAX_VALUE ? "None" : pathLen));
} else {
System.out.println("\nBasic Constraints: End Entity Certificate");
}
}
private static void verifySignature(X509Certificate cert) {
try {
// Verify the certificate's signature using its own public key
// This verifies the certificate's integrity
cert.verify(cert.getPublicKey());
System.out.println("\nSignature Verification: ✓ Valid (self-signed integrity check)");
} catch (Exception e) {
System.out.println("\nSignature Verification: ✗ Failed - " + e.getMessage());
}
}
}

Certificate Chain Validation

3. Certificate Chain Validation

import java.security.cert.*;
import java.security.KeyStore;
import java.io.FileInputStream;
import java.util.*;
public class CertificateChainValidator {
public static void validateCertificateChain(X509Certificate targetCert, 
List<X509Certificate> intermediateCerts,
X509Certificate rootCert) throws Exception {
// Create certificate chain
List<X509Certificate> certChain = new ArrayList<>();
certChain.add(targetCert);
certChain.addAll(intermediateCerts);
// Set up trust anchor
Set<TrustAnchor> trustAnchors = Collections.singleton(
new TrustAnchor(rootCert, null)
);
// Create certificate path
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
CertPath certPath = certFactory.generateCertPath(certChain);
// Set up PKIX parameters
PKIXParameters params = new PKIXParameters(trustAnchors);
params.setRevocationEnabled(false); // Disable CRL checking for simplicity
// Perform validation
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
try {
PKIXCertPathValidatorResult result = 
(PKIXCertPathValidatorResult) validator.validate(certPath, params);
System.out.println("✓ Certificate chain validation successful");
System.out.println("Trust Anchor: " + 
result.getTrustAnchor().getTrustedCert().getSubjectX500Principal());
} catch (CertPathValidatorException e) {
System.out.println("✗ Certificate chain validation failed: " + e.getMessage());
throw e;
}
}
public static void validateWithKeyStore(X509Certificate cert, String keystorePath, 
String keystorePassword) throws Exception {
// Load truststore
KeyStore trustStore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream(keystorePath)) {
trustStore.load(fis, keystorePassword.toCharArray());
}
// Set up trust manager
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(trustStore);
X509TrustManager trustManager = (X509TrustManager) tmf.getTrustManagers()[0];
try {
trustManager.checkClientTrusted(new X509Certificate[]{cert}, "RSA");
System.out.println("✓ Certificate is trusted by the truststore");
} catch (CertificateException e) {
System.out.println("✗ Certificate is not trusted: " + e.getMessage());
throw e;
}
}
public static List<X509Certificate> buildCertificateChain(X509Certificate leafCert, 
List<X509Certificate> availableCerts) {
List<X509Certificate> chain = new ArrayList<>();
chain.add(leafCert);
X509Certificate currentCert = leafCert;
boolean chainBuilt = false;
while (!chainBuilt) {
String issuerDN = currentCert.getIssuerX500Principal().getName();
String subjectDN = currentCert.getSubjectX500Principal().getName();
// Check if issuer is the same as subject (self-signed root)
if (issuerDN.equals(subjectDN)) {
chainBuilt = true;
break;
}
// Find issuer certificate
X509Certificate issuerCert = findIssuerCertificate(issuerDN, availableCerts);
if (issuerCert == null) {
break; // Cannot find issuer
}
// Check for circular reference
if (chain.contains(issuerCert)) {
break;
}
chain.add(issuerCert);
currentCert = issuerCert;
}
return chain;
}
private static X509Certificate findIssuerCertificate(String issuerDN, 
List<X509Certificate> availableCerts) {
for (X509Certificate cert : availableCerts) {
if (cert.getSubjectX500Principal().getName().equals(issuerDN)) {
return cert;
}
}
return null;
}
public static void printCertificateChain(List<X509Certificate> chain) {
System.out.println("\n=== Certificate Chain ===");
for (int i = 0; i < chain.size(); i++) {
X509Certificate cert = chain.get(i);
System.out.println("\n[" + i + "] " + cert.getSubjectX500Principal());
System.out.println("    Issuer: " + cert.getIssuerX500Principal());
System.out.println("    Serial: " + cert.getSerialNumber());
System.out.println("    Valid: " + cert.getNotBefore() + " to " + cert.getNotAfter());
}
}
}

CRL and OCSP Validation

4. Certificate Revocation Checking

import java.security.cert.*;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.cert.CRLException;
import java.util.*;
public class CertificateRevocationChecker {
public static void checkCertificateRevocation(X509Certificate cert) throws Exception {
System.out.println("\n=== Certificate Revocation Check ===");
// Check CRL Distribution Points
checkCRL(cert);
// Check OCSP (if available)
checkOCSP(cert);
}
private static void checkCRL(X509Certificate cert) throws Exception {
// Get CRL distribution points from certificate
byte[] crlDistributionPoints = cert.getExtensionValue("2.5.29.31");
if (crlDistributionPoints == null) {
System.out.println("No CRL Distribution Points found");
return;
}
// In a real implementation, you would parse the CRL distribution points extension
// and download the CRL from the URLs
System.out.println("CRL Distribution Points extension present");
// Implementation would continue with CRL downloading and parsing
}
public static void checkRevocationWithCRL(X509Certificate cert, String crlUrl) throws Exception {
try {
// Download CRL
X509CRL crl = downloadCRL(crlUrl);
// Check if certificate is revoked
if (crl.isRevoked(cert)) {
throw new CertificateException("Certificate has been revoked");
}
System.out.println("✓ Certificate is not revoked according to CRL");
} catch (Exception e) {
System.out.println("✗ CRL check failed: " + e.getMessage());
throw e;
}
}
private static X509CRL downloadCRL(String crlUrl) throws Exception {
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(crlUrl))
.GET()
.build();
HttpResponse<byte[]> response = client.send(request, 
HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
throw new RuntimeException("Failed to download CRL: HTTP " + response.statusCode());
}
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return (X509CRL) certFactory.generateCRL(new ByteArrayInputStream(response.body()));
}
private static void checkOCSP(X509Certificate cert) throws Exception {
// Get OCSP responder URL from certificate
String ocspUrl = getOCSPResponderUrl(cert);
if (ocspUrl == null) {
System.out.println("No OCSP responder URL found");
return;
}
System.out.println("OCSP Responder: " + ocspUrl);
// Implementation would continue with OCSP request generation and sending
}
private static String getOCSPResponderUrl(X509Certificate cert) {
// Parse Authority Information Access extension to find OCSP responder
// This is a simplified example - real implementation would parse the extension
byte[] aiaExtension = cert.getExtensionValue("1.3.6.1.5.5.7.1.1");
if (aiaExtension != null) {
// Parse the extension to find OCSP responder URL
// For demonstration, return a placeholder
return "http://ocsp.example.com";
}
return null;
}
public static void validateCertificateWithRevocation(X509Certificate cert,
List<X509Certificate> chain) throws Exception {
// Perform basic validation first
cert.checkValidity();
// Then check revocation for each certificate in the chain
for (X509Certificate chainCert : chain) {
checkCertificateRevocation(chainCert);
}
System.out.println("✓ Certificate and chain passed revocation checks");
}
}

Certificate Generation and CSR Processing

5. Certificate Signing Request (CSR) Processing

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.io.*;
import java.util.Base64;
public class CertificateCSRProcessor {
public static String generateCSR(KeyPair keyPair, String subjectDN) throws Exception {
StringWriter csrWriter = new StringWriter();
// Basic CSR structure in PEM format
csrWriter.write("-----BEGIN CERTIFICATE REQUEST-----\n");
// In a real implementation, you would use BouncyCastle or similar library
// to generate a proper PKCS#10 CSR
// For demonstration, creating a simplified version
String csrContent = "Subject: " + subjectDN + "\n" +
"Public Key: " + Base64.getEncoder().encodeToString(
keyPair.getPublic().getEncoded());
String base64CSR = Base64.getEncoder().encodeToString(csrContent.getBytes());
// Split into 64-character lines
for (int i = 0; i < base64CSR.length(); i += 64) {
int end = Math.min(i + 64, base64CSR.length());
csrWriter.write(base64CSR.substring(i, end));
csrWriter.write("\n");
}
csrWriter.write("-----END CERTIFICATE REQUEST-----\n");
return csrWriter.toString();
}
public static KeyPair generateKeyPair(String algorithm, int keySize) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
keyGen.initialize(keySize);
return keyGen.generateKeyPair();
}
public static void savePrivateKey(PrivateKey privateKey, String filename, 
String password) throws Exception {
// Encrypt and save private key
// In production, use proper encryption
byte[] encodedKey = privateKey.getEncoded();
String base64Key = Base64.getEncoder().encodeToString(encodedKey);
try (PrintWriter writer = new PrintWriter(filename)) {
writer.write("-----BEGIN PRIVATE KEY-----\n");
writer.write(base64Key);
writer.write("\n-----END PRIVATE KEY-----\n");
}
}
public static PrivateKey loadPrivateKey(String filename, String password) throws Exception {
StringBuilder keyContent = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
boolean inKeyBlock = false;
while ((line = reader.readLine()) != null) {
if (line.contains("BEGIN PRIVATE KEY")) {
inKeyBlock = true;
continue;
}
if (line.contains("END PRIVATE KEY")) {
break;
}
if (inKeyBlock) {
keyContent.append(line);
}
}
}
byte[] keyBytes = Base64.getDecoder().decode(keyContent.toString());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
return keyFactory.generatePrivate(keySpec);
}
}

Practical Example: Complete Certificate Manager

6. Comprehensive Certificate Manager

import java.security.cert.*;
import java.security.*;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
public class CertificateManager {
private KeyStore keyStore;
private String keyStorePath;
private char[] keyStorePassword;
public CertificateManager(String keyStorePath, String keyStorePassword) throws Exception {
this.keyStorePath = keyStorePath;
this.keyStorePassword = keyStorePassword.toCharArray();
this.keyStore = loadKeyStore();
}
private KeyStore loadKeyStore() throws Exception {
KeyStore ks = KeyStore.getInstance("JKS");
File keyStoreFile = new File(keyStorePath);
if (keyStoreFile.exists()) {
try (FileInputStream fis = new FileInputStream(keyStoreFile)) {
ks.load(fis, keyStorePassword);
}
} else {
// Create new keystore
ks.load(null, keyStorePassword);
saveKeyStore();
}
return ks;
}
private void saveKeyStore() throws Exception {
try (FileOutputStream fos = new FileOutputStream(keyStorePath)) {
keyStore.store(fos, keyStorePassword);
}
}
public void addCertificate(String alias, X509Certificate cert) throws Exception {
keyStore.setCertificateEntry(alias, cert);
saveKeyStore();
System.out.println("Certificate added with alias: " + alias);
}
public void addKeyPair(String alias, PrivateKey privateKey, X509Certificate[] chain, 
String password) throws Exception {
keyStore.setKeyEntry(alias, privateKey, password.toCharArray(), chain);
saveKeyStore();
System.out.println("Key pair added with alias: " + alias);
}
public X509Certificate getCertificate(String alias) throws Exception {
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
return (X509Certificate) cert;
}
throw new Exception("Certificate not found or not X.509: " + alias);
}
public List<X509Certificate> listCertificates() throws Exception {
List<X509Certificate> certificates = new ArrayList<>();
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isCertificateEntry(alias)) {
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
certificates.add((X509Certificate) cert);
}
}
}
return certificates;
}
public void validateAllCertificates() throws Exception {
List<X509Certificate> certificates = listCertificates();
System.out.println("\n=== Validating All Certificates in Keystore ===");
for (X509Certificate cert : certificates) {
try {
cert.checkValidity();
System.out.println("✓ " + getCertificateAlias(cert) + " - Valid");
} catch (CertificateExpiredException e) {
System.out.println("✗ " + getCertificateAlias(cert) + " - EXPIRED");
} catch (CertificateNotYetValidException e) {
System.out.println("✗ " + getCertificateAlias(cert) + " - NOT YET VALID");
}
}
}
private String getCertificateAlias(X509Certificate cert) throws Exception {
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate storedCert = keyStore.getCertificate(alias);
if (cert.equals(storedCert)) {
return alias;
}
}
return "Unknown Alias";
}
public void findCertificatesBySubject(String subjectPattern) throws Exception {
List<X509Certificate> certificates = listCertificates();
System.out.println("\n=== Certificates Matching Subject: " + subjectPattern + " ===");
for (X509Certificate cert : certificates) {
String subject = cert.getSubjectX500Principal().getName();
if (subject.toLowerCase().contains(subjectPattern.toLowerCase())) {
System.out.println("Alias: " + getCertificateAlias(cert));
System.out.println("Subject: " + subject);
System.out.println("Issuer: " + cert.getIssuerX500Principal());
System.out.println("Expires: " + cert.getNotAfter());
System.out.println("---");
}
}
}
public void exportCertificate(String alias, String outputPath) throws Exception {
X509Certificate cert = getCertificate(alias);
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
fos.write(cert.getEncoded());
}
System.out.println("Certificate exported to: " + outputPath);
}
public void exportCertificatePEM(String alias, String outputPath) throws Exception {
X509Certificate cert = getCertificate(alias);
try (PrintWriter writer = new PrintWriter(outputPath)) {
writer.write("-----BEGIN CERTIFICATE-----\n");
String base64Cert = Base64.getEncoder().encodeToString(cert.getEncoded());
// Split into 64-character lines
for (int i = 0; i < base64Cert.length(); i += 64) {
int end = Math.min(i + 64, base64Cert.length());
writer.write(base64Cert.substring(i, end));
writer.write("\n");
}
writer.write("-----END CERTIFICATE-----\n");
}
System.out.println("Certificate exported in PEM format to: " + outputPath);
}
public static void main(String[] args) {
try {
CertificateManager manager = new CertificateManager("mykeystore.jks", "password");
// Load and analyze a certificate
X509Certificate cert = BasicCertificateParser.loadCertificateFromFile("example.cer");
AdvancedCertificateParser.parseCertificateDetails(cert);
// Add to keystore
manager.addCertificate("example-cert", cert);
// List all certificates
List<X509Certificate> certs = manager.listCertificates();
System.out.println("\nKeystore contains " + certs.size() + " certificates");
// Validate all certificates
manager.validateAllCertificates();
// Find certificates by subject
manager.findCertificatesBySubject("example");
// Export certificate
manager.exportCertificatePEM("example-cert", "exported-cert.pem");
} catch (Exception e) {
e.printStackTrace();
}
}
}

Security Best Practices

7. Security Considerations

import java.security.cert.*;
import java.security.*;
import java.util.*;
public class CertificateSecurityChecker {
public static void performSecurityAudit(X509Certificate cert) throws Exception {
System.out.println("\n=== Security Audit ===");
checkWeakAlgorithms(cert);
checkKeyStrength(cert);
checkValidityPeriod(cert);
checkCertificateTransparency(cert);
checkCertificatePinning(cert);
}
private static void checkWeakAlgorithms(X509Certificate cert) {
String sigAlg = cert.getSigAlgName().toUpperCase();
Set<String> weakAlgorithms = Set.of(
"MD2", "MD5", "SHA1", "MD2WITHRSA", "MD5WITHRSA", "SHA1WITHRSA"
);
if (weakAlgorithms.stream().anyMatch(sigAlg::contains)) {
System.out.println("⚠ WEAK SIGNATURE ALGORITHM: " + sigAlg);
} else {
System.out.println("✓ Strong signature algorithm: " + sigAlg);
}
}
private static void checkKeyStrength(X509Certificate cert) throws Exception {
PublicKey publicKey = cert.getPublicKey();
int keySize = getKeySize(publicKey);
if (keySize < 2048 && publicKey.getAlgorithm().equals("RSA")) {
System.out.println("⚠ WEAK KEY: RSA key size is only " + keySize + " bits (minimum 2048 recommended)");
} else if (keySize < 256 && publicKey.getAlgorithm().equals("EC")) {
System.out.println("⚠ WEAK KEY: EC key size is only " + keySize + " bits (minimum 256 recommended)");
} else {
System.out.println("✓ Strong key: " + publicKey.getAlgorithm() + " " + keySize + " bits");
}
}
private static int getKeySize(PublicKey publicKey) {
if (publicKey instanceof RSAPublicKey) {
return ((RSAPublicKey) publicKey).getModulus().bitLength();
} else if (publicKey instanceof ECPublicKey) {
// For EC, return the field size
return ((ECPublicKey) publicKey).getParams().getOrder().bitLength();
}
return -1;
}
private static void checkValidityPeriod(X509Certificate cert) {
long validityDays = (cert.getNotAfter().getTime() - cert.getNotBefore().getTime()) 
/ (1000 * 60 * 60 * 24);
if (validityDays > 825) { // Approximately 2 years and 3 months
System.out.println("⚠ LONG VALIDITY PERIOD: " + validityDays + " days (maximum 825 recommended)");
} else {
System.out.println("✓ Reasonable validity period: " + validityDays + " days");
}
}
private static void checkCertificateTransparency(X509Certificate cert) {
// Check for Certificate Transparency extension
byte[] ctExtension = cert.getExtensionValue("1.3.6.1.4.1.11129.2.4.2");
if (ctExtension == null) {
System.out.println("⚠ MISSING CERTIFICATE TRANSPARENCY: SCT extension not found");
} else {
System.out.println("✓ Certificate Transparency: SCT extension present");
}
}
private static void checkCertificatePinning(X509Certificate cert) {
// In a real implementation, this would check against pinned certificates
System.out.println("ℹ Certificate pinning check would be implemented here");
}
public static boolean isCertificateTrusted(X509Certificate cert, 
Set<X509Certificate> trustedCAs) {
try {
// Create a custom trust manager that only trusts the specified CAs
KeyStore customTrustStore = KeyStore.getInstance("JKS");
customTrustStore.load(null, null);
int i = 0;
for (X509Certificate ca : trustedCAs) {
customTrustStore.setCertificateEntry("ca-" + i++, ca);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(customTrustStore);
X509TrustManager trustManager = (X509TrustManager) tmf.getTrustManagers()[0];
trustManager.checkClientTrusted(new X509Certificate[]{cert}, "RSA");
return true;
} catch (Exception e) {
return false;
}
}
}

Key Features Covered

  1. Basic Certificate Parsing: Loading from files, Base64, and byte arrays
  2. Detailed Certificate Analysis: Subject/Issuer DN parsing, extensions, key information
  3. Certificate Chain Validation: PKIX path validation, trust store integration
  4. Revocation Checking: CRL and OCSP support
  5. CSR Processing: Certificate Signing Request generation and handling
  6. Certificate Management: Keystore operations, import/export
  7. Security Auditing: Weak algorithm detection, key strength analysis
  8. Best Practices: Certificate transparency, pinning, validity checks

This comprehensive X.509 certificate parsing implementation provides everything needed to work with digital certificates in Java, from basic parsing to advanced validation and security auditing.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper