feat: Implement method for checking pKey encryption passphrase

This commit is contained in:
Magnus Leßmann (@MarkL4YG) 2024-11-23 12:15:14 +01:00
parent 8d83cba2cd
commit 693f6c7778
2 changed files with 51 additions and 5 deletions

View file

@ -25,6 +25,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.zeroturnaround.exec.ProcessExecutor; import org.zeroturnaround.exec.ProcessExecutor;
@ -281,6 +282,43 @@ public class OpenSSLCertificateCreator {
} }
} }
public boolean isKeyEncrypted(@NonNull Path keyFile) throws InterruptedException, CommandLineOperationException {
// If any random passphrase works, the key is not encrypted.
return !verifyKeyPassphrase(keyFile, null);
}
/**
* Verifies a passphrase against a provided key.
* @implNote Due to the implementation of the OpenSSL cli, any password will be valid for unencrypted keys. (Check with {@link #isKeyEncrypted(Path) or by passing {@code null} as the passphrase.)
*/
public boolean verifyKeyPassphrase(@NonNull Path keyFile, @Nullable String passphrase)
throws CommandLineOperationException, InterruptedException {
// Run OpenSSL command: openssl rsa -check -in <keyFile> -passin pass:<randomKey> -noout and check exit code
try {
String keyPass = passphrase != null ? passphrase : passwordProvider.generateNewPassword();
StartedProcess verifyCommand = new ProcessExecutor()
.command(
resolveOpenSSL(),
"rsa",
"-check",
"-in",
keyFile.toString(),
"-passin",
"pass:" + keyPass,
"-noout"
)
.redirectOutput(Slf4jStream.ofCaller().asError())
.redirectError(Slf4jStream.ofCaller().asError())
.start();
var verifyResult = verifyCommand.getFuture().get();
boolean commandSuccess = verifyResult.getExitValue() == 0;
log.trace("Key check {} with passphrase provided={}", commandSuccess, passphrase != null);
return commandSuccess;
} catch (IOException | InterruptedException | ExecutionException e) {
throw new CommandLineOperationException("Failed to verify key encryption", e);
}
}
private Path signCertificate( private Path signCertificate(
CertificateRequest request, CertificateRequest request,
Path caCert, Path caCert,

View file

@ -14,6 +14,8 @@ class TestOpenSSLCertificateCreator {
public static final String TEST_CERT_PASSPHRASE = "ABC-123"; 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 Path TEST_CERT_PATH = Path.of("src/test/resources/openssl");
public static final String ERR_NOT_ENCRYPTED = "Private key not encrypted";
public static final String ERR_VERIFY_FAILED = "Certificate verification failed";
private CertificatePasswordProvider passwordProvider; private CertificatePasswordProvider passwordProvider;
@BeforeEach @BeforeEach
@ -50,8 +52,11 @@ class TestOpenSSLCertificateCreator {
try (var cert = certificateCreator.createCertificate(certRequest)) { try (var cert = certificateCreator.createCertificate(certRequest)) {
assertThat(certificateCreator.verifyCertificate(cert.certificatePath(), cert.certificatePath())) assertThat(certificateCreator.verifyCertificate(cert.certificatePath(), cert.certificatePath()))
.isEqualTo(true); .withFailMessage(ERR_VERIFY_FAILED)
System.out.println("Certificate created: " + cert); .isTrue();
assertThat(certificateCreator.isKeyEncrypted(cert.certificateKeyPath()))
.withFailMessage(ERR_NOT_ENCRYPTED)
.isTrue();
CertificateRequest childRequest = CertificateRequest CertificateRequest childRequest = CertificateRequest
.builder() .builder()
@ -73,12 +78,15 @@ class TestOpenSSLCertificateCreator {
doNothing().when(spiedCert).close(); doNothing().when(spiedCert).close();
when(certificateProvider.requestCertificateUsage(cert.fingerprint())).thenReturn(spiedCert); when(certificateProvider.requestCertificateUsage(cert.fingerprint())).thenReturn(spiedCert);
try (var childCert = certificateCreator.createCertificate(childRequest)) { try (var childCert = certificateCreator.createCertificate(childRequest)) {
System.out.println("Child certificate created: " + childCert);
Path fullchain = childCert.fullchainPath(); Path fullchain = childCert.fullchainPath();
assertThat( assertThat(
certificateCreator.verifyCertificate(cert.certificatePath(), Objects.requireNonNull(fullchain)) certificateCreator.verifyCertificate(Objects.requireNonNull(fullchain), cert.certificatePath())
) )
.isEqualTo(true); .withFailMessage(ERR_VERIFY_FAILED)
.isTrue();
assertThat(certificateCreator.isKeyEncrypted(childCert.certificateKeyPath()))
.withFailMessage(ERR_NOT_ENCRYPTED)
.isTrue();
} }
} }
} }