feat: Implement way of retrieving CAs in signing process

This commit is contained in:
Magnus Leßmann (@MarkL4YG) 2024-11-19 23:02:27 +01:00
parent 2608bca428
commit fc34320ffd
4 changed files with 53 additions and 17 deletions

View file

@ -0,0 +1,11 @@
package de.mlessmann.certassist.openssl;
/**
* Accessor interface to the certificate storage.
*/
public interface CertificateProvider {
/**
* A stored certificate is needed (e.g. for command line operations when signing sub certificates).
*/
CertificateUsage requestCertificateUsage(String fingerprint);
}

View file

@ -0,0 +1,17 @@
package de.mlessmann.certassist.openssl;
import java.nio.file.Path;
/**
* Instance of a certificate that is temporarily stored on disk to be available for use in command line calls.
* The instance implements AutoCloseable to enable cleanup after the stored files are no longer needed.
* @implSpec The files should be removed from disk when the instance is closed, UNLESS the provided paths are the permanent storage location for the certificate files.
*/
public interface CertificateUsage extends AutoCloseable {
Path certificatePath();
Path certificateKeyPath();
String fingerprint();
@Override
void close();
}

View file

@ -47,6 +47,7 @@ public class OpenSSLCertificateCreator {
private final ExecutableResolver executableResolver; private final ExecutableResolver executableResolver;
private final CertPasswordProvider passwordProvider; private final CertPasswordProvider passwordProvider;
private final CertificateProvider certificateProvider;
private static String buildSubjectArg(CertificateRequest request) { private static String buildSubjectArg(CertificateRequest request) {
String certSubject = OPENSSL_CERT_SUBJECT_TEMPLATE String certSubject = OPENSSL_CERT_SUBJECT_TEMPLATE
@ -77,21 +78,23 @@ public class OpenSSLCertificateCreator {
} }
String certPassword = passwordProvider.generateNewPassword(); String certPassword = passwordProvider.generateNewPassword();
Path keyFile = createKeyfile(request, tmpDir.resolve("root.key"), certPassword); Path keyFile = createKeyfile(request, tmpDir.resolve("certificate.key"), certPassword);
Path rootCert = createCertificate(request, keyFile, tmpDir.resolve("root.crt"), certPassword);
if ( if (
request.getType() == RequestType.ROOT_AUTHORITY || request.getType() == RequestType.STANDALONE_CERTIFICATE request.getType() == RequestType.ROOT_AUTHORITY || request.getType() == RequestType.STANDALONE_CERTIFICATE
) { ) {
String fingerprint = getCertificateFingerprint(rootCert); Path certificate = createCertificate(request, keyFile, tmpDir.resolve("certificate.crt"), certPassword);
return new OpenSSLCertificateResult(tmpDir, rootCert, keyFile, fingerprint); String fingerprint = getCertificateFingerprint(certificate);
passwordProvider.setPasswordFor(fingerprint, certPassword);
return new OpenSSLCertificateResult(tmpDir, certificate, keyFile, fingerprint);
} }
Path childKey = createKeyfile(request, tmpDir.resolve("child.key"), certPassword); try (var certAuthority = certificateProvider.requestCertificateUsage(request.getTrustingAuthority())) {
Path unsignedCert = createSigningRequest(request, childKey, tmpDir.resolve("child.csr"), certPassword); Path unsignedCert = createSigningRequest(request, keyFile, tmpDir.resolve("child.csr"), certPassword);
Path signedCert = signCertificate(request, rootCert, keyFile, unsignedCert, certPassword); Path signedCert = signCertificate(request, certAuthority.certificatePath(), certAuthority.certificateKeyPath(), unsignedCert, certPassword);
String fingerPrint = getCertificateFingerprint(signedCert); String fingerprint = getCertificateFingerprint(signedCert);
passwordProvider.setPasswordFor(fingerPrint, certPassword); passwordProvider.setPasswordFor(fingerprint, certPassword);
return new OpenSSLCertificateResult(tmpDir, signedCert, childKey, fingerPrint); return new OpenSSLCertificateResult(tmpDir, signedCert, keyFile, fingerprint);
}
} }
private Path createKeyfile(CertificateRequest request, Path outFile, String filePassword) private Path createKeyfile(CertificateRequest request, Path outFile, String filePassword)

View file

@ -11,19 +11,24 @@ import org.junit.jupiter.api.Test;
class TestOpenSSLCertificateCreator { class TestOpenSSLCertificateCreator {
private OpenSSLCertificateCreator openSSLCertificateCreator; private CertPasswordProvider passwordProvider;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
CertPasswordProvider passwordProvider = mock(CertPasswordProvider.class); passwordProvider = mock(CertPasswordProvider.class);
when(passwordProvider.generateNewPassword()).thenReturn("ABC-123"); when(passwordProvider.generateNewPassword()).thenReturn("ABC-123");
ExecutableResolver executableResolver = new ExecutableResolver();
openSSLCertificateCreator = new OpenSSLCertificateCreator(executableResolver, passwordProvider);
} }
@Test @Test
void testCertificateCreation() throws Exception { void testCertificateCreation() throws Exception {
CertificateProvider certificateProvider = mock(CertificateProvider.class);
ExecutableResolver executableResolver = new ExecutableResolver();
var certificateCreator = new OpenSSLCertificateCreator(
executableResolver,
passwordProvider,
certificateProvider
);
CertificateRequest certRequest = CertificateRequest CertificateRequest certRequest = CertificateRequest
.builder() .builder()
.commonName("test.home") .commonName("test.home")
@ -32,8 +37,8 @@ class TestOpenSSLCertificateCreator {
.extension(CertificateRequestExtension.builder().alternativeNames("test2.home", "test3.home")) .extension(CertificateRequestExtension.builder().alternativeNames("test2.home", "test3.home"))
.build(); .build();
try (var cert = openSSLCertificateCreator.createCertificate(certRequest)) { try (var cert = certificateCreator.createCertificate(certRequest)) {
assertThat(openSSLCertificateCreator.verifyCertificate(cert.getCertificatePath())).isEqualTo(true); assertThat(certificateCreator.verifyCertificate(cert.getCertificatePath())).isEqualTo(true);
System.out.println("Certificate created: " + cert); System.out.println("Certificate created: " + cert);
} }
} }