From 628ed81f0e56f7163b08b57a8d54833b646239d5 Mon Sep 17 00:00:00 2001 From: Bartosz Gardziejewski Date: Wed, 26 Feb 2020 14:46:14 +0100 Subject: Refactor CSR model to be POJO Issue-ID: AAF-997 Signed-off-by: Bartosz Gardziejewski Change-Id: Ia06dd580a64e56dcf1d8bf5f3db6fe6394cdb1c8 --- .../certservice/certification/CsrModelFactory.java | 2 +- .../configuration/model/Cmpv2Server.java | 8 +- .../certservice/certification/model/CsrModel.java | 130 +++++++++++++++++---- .../configuration/CmpServersConfigLoaderTest.java | 4 +- .../configuration/Cmpv2ServerProviderTest.java | 3 +- .../Cmpv2ServerConfigurationValidatorTest.java | 14 +-- .../certification/model/CsrModelTest.java | 100 ++++++++++++---- 7 files changed, 198 insertions(+), 63 deletions(-) (limited to 'certService/src') diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/CsrModelFactory.java b/certService/src/main/java/org/onap/aaf/certservice/certification/CsrModelFactory.java index bca30dee..6f356c1a 100644 --- a/certService/src/main/java/org/onap/aaf/certservice/certification/CsrModelFactory.java +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/CsrModelFactory.java @@ -47,7 +47,7 @@ public class CsrModelFactory { throws DecryptionException { PKCS10CertificationRequest decodedCsr = decodeCsr(csr); PemObject decodedPrivateKey = decodePrivateKey(privateKey); - return new CsrModel(decodedCsr, decodedPrivateKey); + return new CsrModel.CsrModelBuilder(decodedCsr, decodedPrivateKey).build(); } private PemObject decodePrivateKey(StringBase64 privateKey) diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/model/Cmpv2Server.java b/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/model/Cmpv2Server.java index 9a9f9c5d..9f8f9796 100644 --- a/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/model/Cmpv2Server.java +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/configuration/model/Cmpv2Server.java @@ -20,6 +20,7 @@ package org.onap.aaf.certservice.certification.configuration.model; +import org.bouncycastle.asn1.x500.X500Name; import org.hibernate.validator.constraints.Length; import org.onap.aaf.certservice.certification.configuration.validation.constraints.Cmpv2URL; @@ -32,8 +33,7 @@ public class Cmpv2Server { private CaMode caMode; @Length(min = 1, max = 128) private String caName; - @Length(min = 4, max = 256) - private String issuerDN; + private X500Name issuerDN; @Cmpv2URL private String url; @@ -61,11 +61,11 @@ public class Cmpv2Server { this.caName = caName; } - public String getIssuerDN() { + public X500Name getIssuerDN() { return issuerDN; } - public void setIssuerDN(String issuerDN) { + public void setIssuerDN(X500Name issuerDN) { this.issuerDN = issuerDN; } diff --git a/certService/src/main/java/org/onap/aaf/certservice/certification/model/CsrModel.java b/certService/src/main/java/org/onap/aaf/certservice/certification/model/CsrModel.java index 2421c5a4..b59f4e3a 100644 --- a/certService/src/main/java/org/onap/aaf/certservice/certification/model/CsrModel.java +++ b/certService/src/main/java/org/onap/aaf/certservice/certification/model/CsrModel.java @@ -21,6 +21,13 @@ package org.onap.aaf.certservice.certification.model; import java.io.IOException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -35,50 +42,127 @@ import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.util.io.pem.PemObject; import org.onap.aaf.certservice.certification.exception.CsrDecryptionException; +import org.onap.aaf.certservice.certification.exception.DecryptionException; +import org.onap.aaf.certservice.certification.exception.KeyDecryptionException; public class CsrModel { private final PKCS10CertificationRequest csr; - private final PemObject privateKey; + private final X500Name subjectData; + private final PrivateKey privateKey; + private final PublicKey publicKey; + private final List sans; - public CsrModel(PKCS10CertificationRequest csr, PemObject privateKey) { + CsrModel( + PKCS10CertificationRequest csr, X500Name subjectData, + PrivateKey privateKey, PublicKey publicKey, List sans) { this.csr = csr; + this.subjectData = subjectData; this.privateKey = privateKey; + this.publicKey = publicKey; + this.sans = sans; } - public PemObject getPublicKey() throws CsrDecryptionException { - try { - return new PemObject("PUBLIC KEY", csr.getSubjectPublicKeyInfo().getEncoded()); - } catch (IOException e) { - throw new CsrDecryptionException("Reading Public Key from CSR failed", e.getCause()); - } + public PKCS10CertificationRequest getCsr() { + return csr; } - public PemObject getPrivateKey() { - return privateKey; + public X500Name getSubjectData() { + return subjectData; } - public X500Name getSubjectData() { - return csr.getSubject(); + public PrivateKey getPrivateKey() { + return privateKey; } - public List getSansData() { - Extensions extensions = - Extensions.getInstance(csr.getAttributes()[0].getAttrValues().getObjectAt(0)); - GeneralName[] arrayOfAlternativeNames = - GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName).getNames(); + public PublicKey getPublicKey() { + return publicKey; + } - return Arrays.stream(arrayOfAlternativeNames) - .map(GeneralName::getName) - .map(Objects::toString) - .collect(Collectors.toList()); + public List getSans() { + return sans; } @Override public String toString() { - return "Subject: { " + getSubjectData().toString() - + " ,SANs: " + getSansData().toString() + " }"; + return "Subject: { " + subjectData + + " ,SANs: " + sans + " }"; + } + + public static class CsrModelBuilder { + + private final PKCS10CertificationRequest csr; + private final PemObject privateKey; + + public CsrModel build() + throws DecryptionException + { + + X500Name subjectData = getSubjectData(); + PrivateKey javaPrivateKey = convertingPemPrivateKeyToJavaSecurityPrivateKey(getPrivateKey()); + PublicKey javaPublicKey = convertingPemPublicKeyToJavaSecurityPublicKey(getPublicKey()); + List sans = getSansData(); + + return new CsrModel(csr, subjectData, javaPrivateKey, javaPublicKey, sans); + } + + public CsrModelBuilder(PKCS10CertificationRequest csr, PemObject privateKey) { + this.csr = csr; + this.privateKey = privateKey; + } + + private PemObject getPublicKey() throws CsrDecryptionException { + try { + return new PemObject("PUBLIC KEY", csr.getSubjectPublicKeyInfo().getEncoded()); + } catch (IOException e) { + throw new CsrDecryptionException("Reading Public Key from CSR failed", e.getCause()); + } + } + + private PemObject getPrivateKey() { + return privateKey; + } + + private X500Name getSubjectData() { + return csr.getSubject(); + } + + private List getSansData() { + Extensions extensions = + Extensions.getInstance(csr.getAttributes()[0].getAttrValues().getObjectAt(0)); + GeneralName[] arrayOfAlternativeNames = + GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName).getNames(); + + return Arrays.stream(arrayOfAlternativeNames) + .map(GeneralName::getName) + .map(Objects::toString) + .collect(Collectors.toList()); + } + + private PrivateKey convertingPemPrivateKeyToJavaSecurityPrivateKey(PemObject privateKey) + throws KeyDecryptionException + { + try { + KeyFactory factory = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey.getContent()); + return factory.generatePrivate(keySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new KeyDecryptionException("Converting Private Key failed", e.getCause()); + } + } + + private PublicKey convertingPemPublicKeyToJavaSecurityPublicKey(PemObject publicKey) + throws KeyDecryptionException + { + try { + KeyFactory factory = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey.getContent()); + return factory.generatePublic(keySpec); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new KeyDecryptionException("Converting Public Key from CSR failed", e.getCause()); + } + } } } diff --git a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java index b4eec400..cf8c07a1 100644 --- a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java +++ b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/CmpServersConfigLoaderTest.java @@ -88,9 +88,9 @@ class CmpServersConfigLoaderTest { private void verifyThatCmpServerEquals(Cmpv2Server cmpv2Server, Map expected) { assertThat(cmpv2Server.getCaName()).isEqualTo(expected.get("CA_NAME")); assertThat(cmpv2Server.getUrl()).isEqualTo(expected.get("URL")); - assertThat(cmpv2Server.getIssuerDN()).isEqualTo(expected.get("ISSUER_DN")); + assertThat(cmpv2Server.getIssuerDN().toString()).isEqualTo(expected.get("ISSUER_DN")); assertThat(cmpv2Server.getCaMode().name()).isEqualTo(expected.get("CA_MODE")); assertThat(cmpv2Server.getAuthentication().getIak()).isEqualTo(expected.get("IAK")); assertThat(cmpv2Server.getAuthentication().getRv()).isEqualTo(expected.get("RV")); } -} \ No newline at end of file +} diff --git a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/Cmpv2ServerProviderTest.java b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/Cmpv2ServerProviderTest.java index d3c09e9c..20a85783 100644 --- a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/Cmpv2ServerProviderTest.java +++ b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/Cmpv2ServerProviderTest.java @@ -20,6 +20,7 @@ package org.onap.aaf.certservice.certification.configuration; +import org.bouncycastle.asn1.x500.X500Name; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -83,7 +84,7 @@ class Cmpv2ServerProviderTest { private Cmpv2Server createTestServer() { Cmpv2Server testServer = new Cmpv2Server(); testServer.setCaName(TEST_CA); - testServer.setIssuerDN("testIssuer"); + testServer.setIssuerDN(new X500Name("CN=testIssuer")); testServer.setUrl("http://test.ca.server"); Authentication testAuthentication = new Authentication(); testAuthentication.setIak("testIak"); diff --git a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/validation/Cmpv2ServerConfigurationValidatorTest.java b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/validation/Cmpv2ServerConfigurationValidatorTest.java index ea15740c..18097608 100644 --- a/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/validation/Cmpv2ServerConfigurationValidatorTest.java +++ b/certService/src/test/java/org/onap/aaf/certservice/certification/configuration/validation/Cmpv2ServerConfigurationValidatorTest.java @@ -20,6 +20,7 @@ package org.onap.aaf.certservice.certification.configuration.validation; +import org.bouncycastle.asn1.x500.X500Name; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -83,15 +84,6 @@ class Cmpv2ServerConfigurationValidatorTest { assertThrows(IllegalArgumentException.class, () -> validator.validate(server)); } - @Test - public void givenWrongIssuerDNLengthInURLServerDetailsWhenValidatingShouldThrowException() { - //given - server.setIssuerDN("123"); - - //then - assertThrows(IllegalArgumentException.class, () -> validator.validate(server)); - } - @Test public void givenWrongRVLengthInURLServerDetailsWhenValidatingShouldThrowException() { //given @@ -114,7 +106,7 @@ class Cmpv2ServerConfigurationValidatorTest { server = new Cmpv2Server(); server.setCaMode(CaMode.CLIENT); server.setCaName("TEST"); - server.setIssuerDN("CN=ManagementCA"); + server.setIssuerDN(new X500Name("CN=ManagementCA")); server.setUrl("http://127.0.0.1/ejbca/publicweb/cmp/cmp"); server.setAuthentication(authentication); } @@ -124,4 +116,4 @@ class Cmpv2ServerConfigurationValidatorTest { authentication.setRv("testRV"); authentication.setIak("testIAK"); } -} \ No newline at end of file +} diff --git a/certService/src/test/java/org/onap/aaf/certservice/certification/model/CsrModelTest.java b/certService/src/test/java/org/onap/aaf/certservice/certification/model/CsrModelTest.java index bde1dcce..f47f495f 100644 --- a/certService/src/test/java/org/onap/aaf/certservice/certification/model/CsrModelTest.java +++ b/certService/src/test/java/org/onap/aaf/certservice/certification/model/CsrModelTest.java @@ -33,14 +33,13 @@ import org.onap.aaf.certservice.certification.exception.KeyDecryptionException; import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.onap.aaf.certservice.certification.TestData.TEST_CSR; +import static org.onap.aaf.certservice.certification.TestData.TEST_PEM; import static org.onap.aaf.certservice.certification.TestData.TEST_PK; -import static org.onap.aaf.certservice.certification.TestUtils.pemObjectToString; class CsrModelTest { @@ -52,20 +51,21 @@ class CsrModelTest { @Test void shouldByConstructedAndReturnProperFields() throws DecryptionException, IOException { // given + PemObject testPrivateKey = getPemPrivateKey(); PemObject testPublicKey = generateTestPublicKey(); + PKCS10CertificationRequest testCsr = generateTestCertificationRequest(); // when - CsrModel csrModel = generateTestCsrModel(); - + CsrModel csrModel = generateTestCsrModel(testCsr); // then - assertEquals( - pemObjectToString(csrModel.getPrivateKey()).trim(), - TEST_PK.trim()); - assertEquals( - pemObjectToString(csrModel.getPublicKey()).trim(), - pemObjectToString((testPublicKey)).trim()); - assertThat(csrModel.getSansData()) + assertThat(csrModel.getCsr()) + .isEqualTo(testCsr); + assertThat(csrModel.getPrivateKey().getEncoded()) + .contains(testPrivateKey.getContent()); + assertThat(csrModel.getPublicKey().getEncoded()) + .contains(testPublicKey.getContent()); + assertThat(csrModel.getSans()) .contains( "gerrit.onap.org", "test.onap.org", "onap.com"); assertThat(csrModel.getSubjectData().toString()) @@ -74,24 +74,20 @@ class CsrModelTest { } @Test - void shouldThrowExceptionWhenPublicKeyIsNotCorrect() throws KeyDecryptionException, IOException { + void shouldThrowExceptionWhenPublicKeyIsNotCorrect() throws DecryptionException, IOException { // given - PemObjectFactory pemObjectFactory = new PemObjectFactory(); + PemObject testPrivateKey = getPemPrivateKey(); PKCS10CertificationRequest testCsr = mock(PKCS10CertificationRequest.class); SubjectPublicKeyInfo wrongKryInfo = mock(SubjectPublicKeyInfo.class); when(testCsr.getSubjectPublicKeyInfo()) .thenReturn(wrongKryInfo); when(wrongKryInfo.getEncoded()) .thenThrow(new IOException()); - PemObject testPrivateKey = pemObjectFactory.createPemObject(TEST_PK).orElseThrow( - () -> new KeyDecryptionException("Private key decoding fail") - ); - CsrModel csrModel = new CsrModel(testCsr, testPrivateKey); // when Exception exception = assertThrows( CsrDecryptionException.class, - csrModel::getPublicKey + () -> new CsrModel.CsrModelBuilder(testCsr, testPrivateKey).build() ); String expectedMessage = "Reading Public Key from CSR failed"; @@ -101,12 +97,74 @@ class CsrModelTest { assertTrue(actualMessage.contains(expectedMessage)); } - private CsrModel generateTestCsrModel() throws DecryptionException { + @Test + void shouldThrowExceptionWhenPrivateKeyPemIsNotProperPrivateKey() throws KeyDecryptionException, IOException { + // given + PemObject testPrivateKey = getPemWrongKey(); + PKCS10CertificationRequest testCsr = mock(PKCS10CertificationRequest.class); + SubjectPublicKeyInfo wrongKryInfo = mock(SubjectPublicKeyInfo.class); + when(testCsr.getSubjectPublicKeyInfo()) + .thenReturn(wrongKryInfo); + when(wrongKryInfo.getEncoded()) + .thenThrow(new IOException()); + + // when + Exception exception = assertThrows( + KeyDecryptionException.class, + () -> new CsrModel.CsrModelBuilder(testCsr, testPrivateKey).build() + ); + + String expectedMessage = "Converting Private Key failed"; + String actualMessage = exception.getMessage(); + + // then + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + void shouldThrowExceptionWhenPublicKeyPemIsNotProperPublicKey() throws KeyDecryptionException, IOException { + // given + PemObject testPrivateKey = getPemPrivateKey(); + PemObject testPublicKey = getPemWrongKey(); + PKCS10CertificationRequest testCsr = mock(PKCS10CertificationRequest.class); + SubjectPublicKeyInfo wrongKryInfo = mock(SubjectPublicKeyInfo.class); + when(testCsr.getSubjectPublicKeyInfo()) + .thenReturn(wrongKryInfo); + when(wrongKryInfo.getEncoded()) + .thenReturn(testPublicKey.getContent()); + + // when + Exception exception = assertThrows( + KeyDecryptionException.class, + () -> new CsrModel.CsrModelBuilder(testCsr, testPrivateKey).build() + ); + + String expectedMessage = "Converting Public Key from CSR failed"; + String actualMessage = exception.getMessage(); + + // then + assertTrue(actualMessage.contains(expectedMessage)); + } + + private PemObject getPemPrivateKey() throws KeyDecryptionException { + PemObjectFactory pemObjectFactory = new PemObjectFactory(); + return pemObjectFactory.createPemObject(TEST_PK).orElseThrow( + () -> new KeyDecryptionException("Private key decoding fail") + ); + } + + private PemObject getPemWrongKey() throws KeyDecryptionException { + PemObjectFactory pemObjectFactory = new PemObjectFactory(); + return pemObjectFactory.createPemObject(TEST_PEM).orElseThrow( + () -> new KeyDecryptionException("Private key decoding fail") + ); + } + + private CsrModel generateTestCsrModel(PKCS10CertificationRequest testCsr) throws DecryptionException { PemObject testPrivateKey = pemObjectFactory.createPemObject(TEST_PK).orElseThrow( () -> new DecryptionException("Incorrect Private Key, decryption failed") ); - PKCS10CertificationRequest testCsr = generateTestCertificationRequest(); - return new CsrModel(testCsr, testPrivateKey); + return new CsrModel.CsrModelBuilder(testCsr, testPrivateKey).build(); } private PemObject generateTestPublicKey() throws DecryptionException, IOException { -- cgit 1.2.3-korg