From 259de2ed39db240d5b5768dfa1fa046ca2b94eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Peterli=C4=87?= Date: Tue, 29 Aug 2023 08:32:19 +0200 Subject: [PATCH] BAEL-6700 - Check if Certificate is Self-Signed or CA Signed with Java (#14628) * BAEL-6700 - Check if Certificate is Self-Signed or CA Signed with Java * Added new module to parent pom * Update test method names --- .../core-java-security-4/README.md | 7 ++ .../core-java-security-4/pom.xml | 16 ++++ .../certificate/RootCertificateUtil.java | 51 ++++++++++++ .../src/main/resources/keystore.jks | Bin 0 -> 3783 bytes .../src/main/resources/truststore.jks | Bin 0 -> 2327 bytes .../SignedCertificateUnitTest.java | 76 ++++++++++++++++++ core-java-modules/pom.xml | 1 + 7 files changed, 151 insertions(+) create mode 100644 core-java-modules/core-java-security-4/README.md create mode 100644 core-java-modules/core-java-security-4/pom.xml create mode 100644 core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java create mode 100644 core-java-modules/core-java-security-4/src/main/resources/keystore.jks create mode 100644 core-java-modules/core-java-security-4/src/main/resources/truststore.jks create mode 100644 core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java diff --git a/core-java-modules/core-java-security-4/README.md b/core-java-modules/core-java-security-4/README.md new file mode 100644 index 0000000000..e850841d2b --- /dev/null +++ b/core-java-modules/core-java-security-4/README.md @@ -0,0 +1,7 @@ +## Core Java Security + +This module contains articles about core Java Security + +### Relevant Articles: + +- More articles: [[<-- prev]](/core-java-modules/core-java-security-3) diff --git a/core-java-modules/core-java-security-4/pom.xml b/core-java-modules/core-java-security-4/pom.xml new file mode 100644 index 0000000000..cca86d804a --- /dev/null +++ b/core-java-modules/core-java-security-4/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + core-java-security-4 + core-java-security-4 + jar + + + com.baeldung.core-java-modules + core-java-modules + 0.0.1-SNAPSHOT + + + \ No newline at end of file diff --git a/core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java b/core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java new file mode 100644 index 0000000000..3e8445971f --- /dev/null +++ b/core-java-modules/core-java-security-4/src/main/java/com/baeldung/certificate/RootCertificateUtil.java @@ -0,0 +1,51 @@ +package com.baeldung.certificate; + +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Enumeration; + +public class RootCertificateUtil { + + private RootCertificateUtil() { + } + + public static X509Certificate getRootCertificate(X509Certificate endEntityCertificate, KeyStore trustStore) + throws Exception { + X509Certificate issuerCertificate = findIssuerCertificate(endEntityCertificate, trustStore); + if (issuerCertificate != null) { + if (isRoot(issuerCertificate)) { + return issuerCertificate; + } else { + return getRootCertificate(issuerCertificate, trustStore); + } + } + return null; + } + + private static X509Certificate findIssuerCertificate(X509Certificate certificate, KeyStore trustStore) + throws KeyStoreException { + Enumeration aliases = trustStore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + Certificate cert = trustStore.getCertificate(alias); + if (cert instanceof X509Certificate) { + X509Certificate x509Cert = (X509Certificate) cert; + if (x509Cert.getSubjectX500Principal().equals(certificate.getIssuerX500Principal())) { + return x509Cert; + } + } + } + return null; + } + + private static boolean isRoot(X509Certificate certificate) { + try { + certificate.verify(certificate.getPublicKey()); + return certificate.getKeyUsage() != null && certificate.getKeyUsage()[5]; + } catch (Exception e) { + return false; + } + } +} diff --git a/core-java-modules/core-java-security-4/src/main/resources/keystore.jks b/core-java-modules/core-java-security-4/src/main/resources/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..656c6c17d3c190f683a12e553bd56610ce673d83 GIT binary patch literal 3783 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 certificate.verify(certificate.getPublicKey())); + } + + @Test + void whenCertificateIsCASigned_thenItCantBeVerifiedWithItsOwnPublicKey() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("baeldung"); + assertThrows(SignatureException.class, () -> certificate.verify(certificate.getPublicKey())); + } + + @Test + void whenCertificateIsCASigned_thenRootCanBeFoundInTruststore() throws Exception { + X509Certificate endEntityCertificate = (X509Certificate) keyStore.getCertificate("baeldung"); + X509Certificate rootCertificate = getRootCertificate(endEntityCertificate, trustStore); + assertNotNull(rootCertificate); + } + + @Test + void whenCertificateIsCA_thenItCanBeUsedToSignOtherCertificates() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("cloudflare"); + assertTrue(certificate.getKeyUsage()[5]); + } + + @Test + void whenCertificateIsCA_thenBasicConstrainsReturnsZeroOrGreaterThanZero() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("cloudflare"); + assertNotEquals(-1, certificate.getBasicConstraints()); + } + + @Test + void whenCertificateIsSelfSigned_thenItCantBeUsedToSignOtherCertificates() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("selfsigned"); + assertNull(certificate.getKeyUsage()); + } +} \ No newline at end of file diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index e9bb86e500..4f21da40f5 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -127,6 +127,7 @@ core-java-scanner core-java-security-2 core-java-security-3 + core-java-security-4 core-java-security-algorithms core-java-streams core-java-streams-3