feat: Implement certificate fingerprinting on creation
This commit is contained in:
parent
d709a59145
commit
1380b39977
3 changed files with 41 additions and 2 deletions
|
@ -50,4 +50,6 @@ public class Certificate {
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
private byte[] privateKey = new byte[0];
|
private byte[] privateKey = new byte[0];
|
||||||
|
|
||||||
|
private String fingerprint;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -39,6 +41,10 @@ public class OpenSSLCertificateCreator {
|
||||||
|
|
||||||
[alt_names]
|
[alt_names]
|
||||||
""";
|
""";
|
||||||
|
private static final Pattern FINGERPRINT_EXTRACTOR = Pattern.compile(
|
||||||
|
"^(?<algo>[0-9a-z]+) Fingerprint=(?<finger>[a-z:A-Z0-9]+)",
|
||||||
|
Pattern.CASE_INSENSITIVE
|
||||||
|
);
|
||||||
|
|
||||||
private final ExecutableResolver executableResolver;
|
private final ExecutableResolver executableResolver;
|
||||||
|
|
||||||
|
@ -75,13 +81,15 @@ public class OpenSSLCertificateCreator {
|
||||||
if (
|
if (
|
||||||
request.getType() == RequestType.ROOT_AUTHORITY || request.getType() == RequestType.STANDALONE_CERTIFICATE
|
request.getType() == RequestType.ROOT_AUTHORITY || request.getType() == RequestType.STANDALONE_CERTIFICATE
|
||||||
) {
|
) {
|
||||||
return new OpenSSLCertificateResult(tmpDir, rootCert, keyFile);
|
String fingerprint = getCertificateFingerprint(rootCert);
|
||||||
|
return new OpenSSLCertificateResult(tmpDir, rootCert, keyFile, fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path childKey = createKeyfile(request, tmpDir.resolve("child.key"));
|
Path childKey = createKeyfile(request, tmpDir.resolve("child.key"));
|
||||||
Path unsignedCert = createSigningRequest(request, childKey, tmpDir.resolve("child.csr"));
|
Path unsignedCert = createSigningRequest(request, childKey, tmpDir.resolve("child.csr"));
|
||||||
Path signedCert = signCertificate(request, rootCert, keyFile, unsignedCert);
|
Path signedCert = signCertificate(request, rootCert, keyFile, unsignedCert);
|
||||||
return new OpenSSLCertificateResult(tmpDir, signedCert, childKey);
|
String fingerPrint = getCertificateFingerprint(signedCert);
|
||||||
|
return new OpenSSLCertificateResult(tmpDir, signedCert, childKey, fingerPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path createKeyfile(CertificateRequest request, Path outFile)
|
private Path createKeyfile(CertificateRequest request, Path outFile)
|
||||||
|
@ -272,6 +280,34 @@ public class OpenSSLCertificateCreator {
|
||||||
return outFile;
|
return outFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getCertificateFingerprint(Path certificate)
|
||||||
|
throws CommandLineOperationException, InterruptedException {
|
||||||
|
try {
|
||||||
|
StartedProcess fingerprintProc = new ProcessExecutor()
|
||||||
|
.command(resolveOpenSSL(), "x509", "-in", certificate.toString(), "-noout", "-fingerprint")
|
||||||
|
.readOutput(true)
|
||||||
|
.redirectError(Slf4jStream.ofCaller().asError())
|
||||||
|
.start();
|
||||||
|
var fingerprintResult = fingerprintProc.getFuture().get();
|
||||||
|
String output = fingerprintResult.getOutput().getUTF8();
|
||||||
|
Matcher matcher = FINGERPRINT_EXTRACTOR.matcher(output);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
log.debug(output);
|
||||||
|
throw new CommandLineOperationException("Unexpected output of fingerprint command. (See log for more details)");
|
||||||
|
}
|
||||||
|
String algorithm = matcher.group("algo");
|
||||||
|
String fingerprint = matcher.group("finger");
|
||||||
|
if (StringUtils.isBlank(algorithm) || StringUtils.isBlank(fingerprint)) {
|
||||||
|
throw new CommandLineOperationException(
|
||||||
|
"Unexpected output of fingerprint command: %s %s".formatted(algorithm, fingerprint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return "%s;%s".formatted(algorithm, fingerprint);
|
||||||
|
} catch (IOException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveOpenSSL() throws CommandLineOperationException {
|
private String resolveOpenSSL() throws CommandLineOperationException {
|
||||||
try {
|
try {
|
||||||
return executableResolver.getOpenSSLPath();
|
return executableResolver.getOpenSSLPath();
|
||||||
|
|
|
@ -18,6 +18,7 @@ public class OpenSSLCertificateResult implements AutoCloseable {
|
||||||
private final Path tmpDir;
|
private final Path tmpDir;
|
||||||
private final Path certificatePath;
|
private final Path certificatePath;
|
||||||
private final Path privateKeyPath;
|
private final Path privateKeyPath;
|
||||||
|
private final String certificateFingerPrint;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
|
Loading…
Add table
Reference in a new issue