package de.mlessmann.certassist; import de.mlessmann.certassist.models.CertificateInfo; import de.mlessmann.certassist.models.CertificateInfo.RequestType; import de.mlessmann.certassist.models.CertificateInfoExtension; import de.mlessmann.certassist.models.CertificateInfoSubject; import de.mlessmann.certassist.openssl.CertificatePasswordProvider; import de.mlessmann.certassist.openssl.CertificateProvider; import de.mlessmann.certassist.openssl.OpenSSLService; import de.mlessmann.certassist.service.ExecutableResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import java.nio.file.Path; import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @SpringBootTest class TestOpenSSLService { public static final String TEST_CERT_PASSPHRASE = "ABC-123"; public static final Path TEST_CERT_PATH = Path.of("src/test/resources/openssl"); public static final String TEST_CERT_FINGERPRINT = "SHA1;4E:D6:0A:47:F0:63:AD:96:26:83:16:28:32:F5:E8:36:5A:62:91:95"; private static final String ERR_NOT_ENCRYPTED = "Private key not encrypted"; private static final String ERR_VERIFY_FAILED = "Certificate verification failed"; @MockBean CertificatePasswordProvider passwordProvider; @BeforeEach void setUp() { when(passwordProvider.generateNewPassword()).thenReturn(TEST_CERT_PASSPHRASE); when(passwordProvider.getPasswordFor(anyString())).thenReturn(TEST_CERT_PASSPHRASE); } @Test void testCertificateCreation() throws Exception { CertificateProvider certificateProvider = mock(CertificateProvider.class); ExecutableResolver executableResolver = new ExecutableResolver(); var certificateCreator = new OpenSSLService(executableResolver, passwordProvider, certificateProvider); CertificateInfo certRequest = CertificateInfo .builder() .type(RequestType.STANDALONE_CERTIFICATE) .subject( CertificateInfoSubject .builder() .commonName("test.home") .country("DE") .state("SH") .locality("HH") .organization("Crazy-Cats") ) .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.home", "test3.home")) .build(); try (var cert = certificateCreator.createCertificate(certRequest)) { assertThat(certificateCreator.verifyCertificate(cert.certificatePath(), cert.certificatePath())) .withFailMessage(ERR_VERIFY_FAILED) .isTrue(); assertThat(certificateCreator.isKeyEncrypted(requireNonNull(cert.certificateKeyPath()))) .withFailMessage(ERR_NOT_ENCRYPTED) .isTrue(); CertificateInfo childRequest = CertificateInfo .builder() .type(RequestType.NORMAL_CERTIFICATE) .trustingAuthority(cert.fingerprint()) .subject( CertificateInfoSubject .builder() .commonName("test.local") .country("DE") .state("SH") .locality("HH") .organization("Crazy-Cats") ) .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.local", "test3.local")) .build(); var spiedCert = spy(cert); doNothing().when(spiedCert).close(); when(certificateProvider.requestCertificateUsage(cert.fingerprint())).thenReturn(spiedCert); try (var childCert = certificateCreator.createCertificate(childRequest)) { Path fullchain = childCert.fullchainPath(); assertThat( certificateCreator.verifyCertificate(requireNonNull(fullchain), cert.certificatePath()) ) .withFailMessage(ERR_VERIFY_FAILED) .isTrue(); assertThat(certificateCreator.isKeyEncrypted(requireNonNull(childCert.certificateKeyPath()))) .withFailMessage(ERR_NOT_ENCRYPTED) .isTrue(); } } } @Test void testCertificateImport() throws Exception { CertificateProvider certificateProvider = mock(CertificateProvider.class); ExecutableResolver executableResolver = new ExecutableResolver(); var certificateCreator = new OpenSSLService(executableResolver, passwordProvider, certificateProvider); var request = certificateCreator.getCertificateInfo(TEST_CERT_PATH.resolve("x509forImportCA.pem")); assertThat(request).isNotNull(); assertThat(request.subject().getCommonName()).isEqualTo("test.home"); assertThat(request.subject().getCountry()).isEqualTo("DE"); assertThat(request.subject().getState()).isEqualTo("SH"); assertThat(request.subject().getLocality()).isEqualTo("HH"); assertThat(request.subject().getOrganization()).isEqualTo("Crazy-Cats"); assertThat(request.notBefore()).isEqualTo("2024-11-22T18:57:40Z"); assertThat(request.notAfter()).isEqualTo("2025-11-22T18:57:40Z"); assertThat(request.extensions()).isEmpty(); request = certificateCreator.getCertificateInfo(TEST_CERT_PATH.resolve("x509forImport.pem")); assertThat(request).isNotNull(); assertThat(request.subject().getCommonName()).isEqualTo("test.local"); assertThat(request.subject().getCountry()).isEqualTo("DE"); assertThat(request.subject().getState()).isEqualTo("SH"); assertThat(request.subject().getLocality()).isEqualTo("HH"); assertThat(request.subject().getOrganization()).isEqualTo("Crazy-Cats"); assertThat(request.extensions().getFirst().getAlternativeDnsNames()).containsExactly("test2.local", "test3.local"); } }