feat: Implement method for checking pKey encryption passphrase
This commit is contained in:
parent
8d83cba2cd
commit
693f6c7778
2 changed files with 51 additions and 5 deletions
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue