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 0000000000..656c6c17d3 Binary files /dev/null and b/core-java-modules/core-java-security-4/src/main/resources/keystore.jks differ diff --git a/core-java-modules/core-java-security-4/src/main/resources/truststore.jks b/core-java-modules/core-java-security-4/src/main/resources/truststore.jks new file mode 100644 index 0000000000..5e1a9b4ce1 Binary files /dev/null and b/core-java-modules/core-java-security-4/src/main/resources/truststore.jks differ diff --git a/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java b/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java new file mode 100644 index 0000000000..f5ea3c1b87 --- /dev/null +++ b/core-java-modules/core-java-security-4/src/test/java/com/baeldung/certificate/SignedCertificateUnitTest.java @@ -0,0 +1,76 @@ +package com.baeldung.certificate; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.security.KeyStore; +import java.security.SignatureException; +import java.security.cert.X509Certificate; + +import static com.baeldung.certificate.RootCertificateUtil.getRootCertificate; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class SignedCertificateUnitTest { + + private KeyStore keyStore; + + private KeyStore trustStore; + + @BeforeEach + public void setUp() throws Exception { + char[] passwd = "changeit".toCharArray(); + keyStore = KeyStore.getInstance("JKS"); + keyStore.load(this.getClass().getClassLoader().getResourceAsStream("keystore.jks"), passwd); + trustStore = KeyStore.getInstance("JKS"); + trustStore.load(this.getClass().getClassLoader().getResourceAsStream("truststore.jks"), passwd); + } + + @Test + void whenCertificateIsSelfSigned_thenSubjectIsEqualToIssuer() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("selfsigned"); + assertEquals(certificate.getSubjectDN(), certificate.getIssuerDN()); + } + + @Test + void whenCertificateIsSelfSigned_thenItCanBeVerifiedWithItsOwnPublicKey() throws Exception { + X509Certificate certificate = (X509Certificate) keyStore.getCertificate("selfsigned"); + assertDoesNotThrow(() -> 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