feat: Implement import of CA bundles to keystores

This commit is contained in:
Magnus Leßmann (@MarkL4YG) 2024-11-24 12:44:06 +01:00
parent a4f495ab91
commit 6b1c969ce6
8 changed files with 207 additions and 7 deletions

View file

@ -7,13 +7,20 @@ import de.mlessmann.certassist.repositories.CertificateRepository;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.StreamSupport;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class CertificateCreationService {
@ -21,12 +28,15 @@ public class CertificateCreationService {
private final CertificateRepository certificateRepository;
private final OpenSSLService openSSLService;
private final PassphraseService passphraseService;
private final Pattern CERT_START_PATTERN = Pattern.compile("-+BEGIN CERTIFICATE-+");
private final Pattern CERT_END_PATTERN = Pattern.compile("-+END CERTIFICATE-+");
public Certificate createCertificate(final CertificateInfo certificateInfo) {
final Certificate certificate = createEntityFromRequest(certificateInfo);
try (OpenSSLCertificateResult certificateCreatorResult = openSSLService.createCertificate(certificateInfo);) {
Path keyPath = certificateCreatorResult.certificateKeyPath();
certificate.setFingerprint(certificateCreatorResult.fingerprint());
if (keyPath != null) {
certificate.setPrivateKey(Files.readAllBytes(keyPath));
}
@ -74,6 +84,7 @@ public class CertificateCreationService {
String fingerprint = openSSLService.getCertificateFingerprint(certificate);
var generatedRequest = openSSLService.getCertificateInfo(certificate);
Certificate entity = createEntityFromRequest(generatedRequest);
entity.setFingerprint(fingerprint);
entity.setCert(Files.readAllBytes(certificate));
if (keyFile != null) {
entity.setPrivateKey(Files.readAllBytes(keyFile));
@ -87,6 +98,36 @@ public class CertificateCreationService {
}
}
public List<Certificate> importCertificateTrustBundle(@NonNull Path bundleFile) {
try {
Map<String, Certificate> certsInBundle = new HashMap<>();
String pemContent = Files.readString(bundleFile);
Matcher beginMatcher = CERT_START_PATTERN.matcher(pemContent);
while (beginMatcher.find()) {
int startIdx = beginMatcher.start();
Matcher endMatcher = CERT_END_PATTERN.matcher(pemContent);
if (!endMatcher.find(startIdx)) {
throw new IllegalStateException("Certificate has a startIdx but not an end??");
}
int endIdx = endMatcher.end();
String singleCert = pemContent.substring(startIdx, endIdx);
String fingerprint = openSSLService.getCertificateFingerprint(singleCert);
var generatedRequest = openSSLService.getCertificateInfo(singleCert);
Certificate entity = createEntityFromRequest(generatedRequest);
entity.setFingerprint(fingerprint);
entity.setCert(singleCert.getBytes());
certsInBundle.put(fingerprint, entity);
log.debug("Found certificate in bundle at {} to {}: {}", startIdx, endIdx, fingerprint);
}
var saveResult = certificateRepository.saveAll(certsInBundle.values());
return StreamSupport.stream(saveResult.spliterator(), false).toList();
} catch (CommandLineOperationException | IOException e) {
throw new RuntimeException("Unable to import certificate", e);
}
}
private CertificateType mapCertificateRequestType(CertificateInfo.RequestType requestType) {
return switch (requestType) {
case ROOT_AUTHORITY -> CertificateType.ROOT_CA;