1import java.io.InputStream;
2import java.nio.file.Files;
3import java.nio.file.Path;
4import java.security.cert.CertPath;
5import java.security.cert.CertPathValidator;
6import java.security.cert.CertPathValidatorException;
7import java.security.cert.CertificateFactory;
8import java.security.cert.PKIXParameters;
9import java.security.cert.TrustAnchor;
10import java.security.cert.X509Certificate;
11import java.util.List;
12import java.util.Set;
13
14public class VerifyChain {
15 static final CertificateFactory X509;
16
17 static {
18 try {
19 X509 = CertificateFactory.getInstance("X.509");
20 } catch (Exception e) {
21 throw new ExceptionInInitializerError(e);
22 }
23 }
24
25 static X509Certificate load(String path) throws Exception {
26 try (InputStream in = Files.newInputStream(Path.of(path))) {
27 return (X509Certificate) X509.generateCertificate(in);
28 }
29 }
30
31 /** Validates leaf + intermediates (leaf first, root excluded) against one trusted root. */
32 static void verify(List<X509Certificate> chain, X509Certificate root) throws Exception {
33 CertPath path = X509.generateCertPath(chain);
34 PKIXParameters params = new PKIXParameters(Set.of(new TrustAnchor(root, null)));
35 params.setRevocationEnabled(false); // a test CA publishes no CRL or OCSP; keep it on in production
36 CertPathValidator.getInstance("PKIX").validate(path, params); // throws if anything is wrong
37 }
38
39 public static void main(String[] args) throws Exception {
40 X509Certificate root = load("root.pem"), intermediate = load("intermediate.pem");
41 verify(List.of(load("leaf.pem"), intermediate), root);
42 System.out.println("valid: api.example.com -> Issuing CA 1 -> Root CA");
43
44 String[][] cases = {
45 {"impostor root", "leaf.pem", "intermediate.pem", "impostor-root.pem"},
46 {"expired leaf", "expired.pem", "intermediate.pem", "root.pem"},
47 {"missing intermediate", "leaf.pem", null, "root.pem"},
48 };
49 for (String[] c : cases) {
50 List<X509Certificate> chain = c[2] == null ? List.of(load(c[1])) : List.of(load(c[1]), load(c[2]));
51 try {
52 verify(chain, load(c[3]));
53 } catch (CertPathValidatorException e) {
54 System.out.println(c[0] + ": " + e.getMessage() + " (reason " + e.getReason() + ", index " + e.getIndex() + ")");
55 }
56 }
57 }
58}
59