From 2608bca4286391a8cb54dc06c4a75c8ffa18a08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Le=C3=9Fmann=20=28=40MarkL4YG=29?= Date: Tue, 19 Nov 2024 22:23:40 +0100 Subject: [PATCH] feat: Use password provider to store certificates encrypted --- .../openssl/CertPasswordProvider.java | 9 +++++ .../openssl/OpenSSLCertificateCreator.java | 39 ++++++++++++------- .../TestOpenSSLCertificateCreator.java | 12 +++--- 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 src/main/java/de/mlessmann/certassist/openssl/CertPasswordProvider.java diff --git a/src/main/java/de/mlessmann/certassist/openssl/CertPasswordProvider.java b/src/main/java/de/mlessmann/certassist/openssl/CertPasswordProvider.java new file mode 100644 index 0000000..b069821 --- /dev/null +++ b/src/main/java/de/mlessmann/certassist/openssl/CertPasswordProvider.java @@ -0,0 +1,9 @@ +package de.mlessmann.certassist.openssl; + +public interface CertPasswordProvider { + String generateNewPassword(); + + String getPasswordFor(String certificateFingerprint); + + void setPasswordFor(String certificateFingerprint, String password); +} diff --git a/src/main/java/de/mlessmann/certassist/openssl/OpenSSLCertificateCreator.java b/src/main/java/de/mlessmann/certassist/openssl/OpenSSLCertificateCreator.java index cd41d56..bc9f7be 100644 --- a/src/main/java/de/mlessmann/certassist/openssl/OpenSSLCertificateCreator.java +++ b/src/main/java/de/mlessmann/certassist/openssl/OpenSSLCertificateCreator.java @@ -46,6 +46,7 @@ public class OpenSSLCertificateCreator { ); private final ExecutableResolver executableResolver; + private final CertPasswordProvider passwordProvider; private static String buildSubjectArg(CertificateRequest request) { String certSubject = OPENSSL_CERT_SUBJECT_TEMPLATE @@ -75,8 +76,9 @@ public class OpenSSLCertificateCreator { throw new CommandLineOperationException("Could not create temporary directory for certificate creation", e); } - Path keyFile = createKeyfile(request, tmpDir.resolve("root.key")); - Path rootCert = createCertificate(request, keyFile, tmpDir.resolve("root.crt")); + String certPassword = passwordProvider.generateNewPassword(); + Path keyFile = createKeyfile(request, tmpDir.resolve("root.key"), certPassword); + Path rootCert = createCertificate(request, keyFile, tmpDir.resolve("root.crt"), certPassword); if ( request.getType() == RequestType.ROOT_AUTHORITY || request.getType() == RequestType.STANDALONE_CERTIFICATE ) { @@ -84,14 +86,15 @@ public class OpenSSLCertificateCreator { return new OpenSSLCertificateResult(tmpDir, rootCert, keyFile, fingerprint); } - Path childKey = createKeyfile(request, tmpDir.resolve("child.key")); - Path unsignedCert = createSigningRequest(request, childKey, tmpDir.resolve("child.csr")); - Path signedCert = signCertificate(request, rootCert, keyFile, unsignedCert); + Path childKey = createKeyfile(request, tmpDir.resolve("child.key"), certPassword); + Path unsignedCert = createSigningRequest(request, childKey, tmpDir.resolve("child.csr"), certPassword); + Path signedCert = signCertificate(request, rootCert, keyFile, unsignedCert, certPassword); String fingerPrint = getCertificateFingerprint(signedCert); + passwordProvider.setPasswordFor(fingerPrint, certPassword); return new OpenSSLCertificateResult(tmpDir, signedCert, childKey, fingerPrint); } - private Path createKeyfile(CertificateRequest request, Path outFile) + private Path createKeyfile(CertificateRequest request, Path outFile, String filePassword) throws CommandLineOperationException, InterruptedException { Path keyFile = outFile.toAbsolutePath(); log.atDebug().log("Writing new certificate key to {}", keyFile); @@ -107,7 +110,7 @@ public class OpenSSLCertificateCreator { "env:KEY_PASS", Integer.toString(request.getRequestedKeyLength()) ) - .environment("KEY_PASS", request.getOid()) + .environment("KEY_PASS", filePassword) .redirectOutput(Slf4jStream.ofCaller().asDebug()) .redirectError(Slf4jStream.ofCaller().asError()) .start(); @@ -120,7 +123,7 @@ public class OpenSSLCertificateCreator { return keyFile; } - private Path createCertificate(CertificateRequest request, Path keyFile, Path outFile) + private Path createCertificate(CertificateRequest request, Path keyFile, Path outFile, String certPassword) throws CommandLineOperationException, InterruptedException { log.atDebug().log("Writing new certificate file {}", outFile); @@ -147,7 +150,7 @@ public class OpenSSLCertificateCreator { "-subj", certSubject ) - .environment("KEY_PASS", request.getOid()) + .environment("KEY_PASS", certPassword) .redirectOutput(Slf4jStream.ofCaller().asDebug()) .redirectError(Slf4jStream.ofCaller().asError()) .start(); @@ -160,7 +163,7 @@ public class OpenSSLCertificateCreator { return outFile; } - private Path createSigningRequest(CertificateRequest request, Path keyFile, Path outFile) + private Path createSigningRequest(CertificateRequest request, Path keyFile, Path outFile, String certPassword) throws CommandLineOperationException, InterruptedException { log.atDebug().log("Writing new certificate signing request file {}", outFile); @@ -184,7 +187,7 @@ public class OpenSSLCertificateCreator { "-subj", certSubject ) - .environment("KEY_PASS", request.getOid()) + .environment("KEY_PASS", certPassword) .redirectOutput(Slf4jStream.ofCaller().asDebug()) .redirectError(Slf4jStream.ofCaller().asError()) .start(); @@ -211,8 +214,13 @@ public class OpenSSLCertificateCreator { } } - private Path signCertificate(CertificateRequest request, Path caCert, Path caKey, Path csrFile) - throws CommandLineOperationException, InterruptedException { + private Path signCertificate( + CertificateRequest request, + Path caCert, + Path caKey, + Path csrFile, + String certPassword + ) throws CommandLineOperationException, InterruptedException { Path outFile = csrFile.resolveSibling(csrFile.getFileName().toString().replace(".csr", ".crt")); log.atDebug().log("Writing new signed certificate file {}", outFile); Path extFile = csrFile.resolveSibling(csrFile.getFileName().toString().replace(".csr", ".ext")); @@ -265,8 +273,11 @@ public class OpenSSLCertificateCreator { "-out", outFile.toString(), "-extfile", - extFile.toString() + extFile.toString(), + "-passout", + "env:KEY_PASS" ) + .environment("KEY_PASS", certPassword) .redirectOutput(Slf4jStream.ofCaller().asDebug()) .redirectError(Slf4jStream.ofCaller().asError()) .start(); diff --git a/src/test/java/de/mlessmann/certassist/TestOpenSSLCertificateCreator.java b/src/test/java/de/mlessmann/certassist/TestOpenSSLCertificateCreator.java index e3be9e6..67f3345 100644 --- a/src/test/java/de/mlessmann/certassist/TestOpenSSLCertificateCreator.java +++ b/src/test/java/de/mlessmann/certassist/TestOpenSSLCertificateCreator.java @@ -1,12 +1,11 @@ package de.mlessmann.certassist; import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import de.mlessmann.certassist.openssl.CertificateRequest; +import de.mlessmann.certassist.openssl.*; import de.mlessmann.certassist.openssl.CertificateRequest.RequestType; -import de.mlessmann.certassist.openssl.CertificateRequestExtension; -import de.mlessmann.certassist.openssl.CertificateSubject; -import de.mlessmann.certassist.openssl.OpenSSLCertificateCreator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -16,8 +15,11 @@ class TestOpenSSLCertificateCreator { @BeforeEach void setUp() { + CertPasswordProvider passwordProvider = mock(CertPasswordProvider.class); + when(passwordProvider.generateNewPassword()).thenReturn("ABC-123"); + ExecutableResolver executableResolver = new ExecutableResolver(); - openSSLCertificateCreator = new OpenSSLCertificateCreator(executableResolver); + openSSLCertificateCreator = new OpenSSLCertificateCreator(executableResolver, passwordProvider); } @Test