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
|
||||
private byte[] privateKey = new byte[0];
|
||||
|
||||
private String fingerprint;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -39,6 +41,10 @@ public class OpenSSLCertificateCreator {
|
|||
|
||||
[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;
|
||||
|
||||
|
@ -75,13 +81,15 @@ public class OpenSSLCertificateCreator {
|
|||
if (
|
||||
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 unsignedCert = createSigningRequest(request, childKey, tmpDir.resolve("child.csr"));
|
||||
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)
|
||||
|
@ -272,6 +280,34 @@ public class OpenSSLCertificateCreator {
|
|||
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 {
|
||||
try {
|
||||
return executableResolver.getOpenSSLPath();
|
||||
|
|
|
@ -18,6 +18,7 @@ public class OpenSSLCertificateResult implements AutoCloseable {
|
|||
private final Path tmpDir;
|
||||
private final Path certificatePath;
|
||||
private final Path privateKeyPath;
|
||||
private final String certificateFingerPrint;
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
|
Loading…
Add table
Reference in a new issue