Skip to content

Commit

Permalink
Added support for system trusted certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
Hakky54 committed Dec 28, 2024
1 parent 2116303 commit 9a7c5ea
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 23 deletions.
28 changes: 19 additions & 9 deletions src/main/java/nl/altindag/crip/command/SharedProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import nl.altindag.crip.model.CertificateHolder;
import nl.altindag.ssl.util.CertificateExtractingClient;
import nl.altindag.ssl.util.CertificateUtils;
import nl.altindag.ssl.util.internal.UriUtils;
import picocli.CommandLine.Option;

Expand All @@ -26,7 +27,6 @@
import java.security.cert.X509Certificate;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -38,8 +38,10 @@
@SuppressWarnings({"unused", "FieldCanBeLocal", "FieldMayBeFinal"})
public class SharedProperties {

@Option(names = {"-u", "--url"}, description = "Url of the target server to extract the certificates", required = true)
private String[] urls;
private static final String SYSTEM = "system";

@Option(names = {"-u", "--url"}, description = "Url of the target server to extract the certificates")
private List<String> urls = new ArrayList<>();
private List<String> uniqueUrls;

@Option(names = {"--proxy-host"}, description = "Proxy host")
Expand All @@ -60,6 +62,9 @@ public class SharedProperties {
@Option(names = {"--resolve-ca"}, description = "Indicator to automatically resolve the root ca%nPossible options: true, false")
private Boolean resolveRootCa = true;

@Option(names = {"--extract-system-ca"}, description = "Indicator to extract the operating system trusted root ca%nPossible options: true, false")
private Boolean includeSystemCertificates = false;

public CertificateHolder getCertificateHolder() {
List<String> resolvedUrls = getUrls();

Expand All @@ -68,14 +73,19 @@ public CertificateHolder getCertificateHolder() {
Map<String, List<X509Certificate>> urlsToCertificates = resolvedUrls.stream()
.distinct()
.map(url -> new AbstractMap.SimpleEntry<>(url, client.get(url)))
.collect(Collectors.collectingAndThen(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue, (key1, key2) -> key1, LinkedHashMap::new), Collections::unmodifiableMap));
.collect(Collectors.collectingAndThen(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue, (key1, key2) -> key1, LinkedHashMap::new), HashMap::new));

return new CertificateHolder(urlsToCertificates);
}
if (includeSystemCertificates) {
List<X509Certificate> systemTrustedCertificates = CertificateUtils.getSystemTrustedCertificates();
urlsToCertificates.put(SYSTEM, systemTrustedCertificates);
}

public List<X509Certificate> getCertificatesFromFirstUrl() {
CertificateExtractingClient client = createClient();
return client.get(urls[0]);
if (urlsToCertificates.isEmpty()) {
System.out.printf("%nNo certificates have been extracted. Please provide at least one url");
System.exit(0);
}

return new CertificateHolder(urlsToCertificates);
}

private CertificateExtractingClient createClient() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public void run() {
if (combined) {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

if (sharedProperties.getUrls().size() == 1) {
List<X509Certificate> certificates = sharedProperties.getCertificatesFromFirstUrl();
if (certificateHolder.getUrlsToCertificates().size() == 1) {
List<X509Certificate> certificates = certificateHolder.getUniqueCertificates();
Path destination = null;

if (!certificates.isEmpty()) {
Expand Down
25 changes: 13 additions & 12 deletions src/main/java/nl/altindag/crip/command/export/PemExportCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.cert.X509Certificate;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -56,8 +56,8 @@ public void run() {
CertificateHolder certificateHolder = sharedProperties.getCertificateHolder();

if (combined) {
if (sharedProperties.getUrls().size() == 1) {
List<X509Certificate> certificates = sharedProperties.getCertificatesFromFirstUrl();
if (certificateHolder.getUrlsToCertificates().size() == 1) {
List<X509Certificate> certificates = certificateHolder.getUniqueCertificates();
Path destination = null;

if (!certificates.isEmpty()) {
Expand All @@ -78,28 +78,29 @@ public void run() {

filenameToCertificate = new HashMap<>();
for (Entry<String, List<X509Certificate>> entry : certificateHolder.getUrlsToCertificates().entrySet()) {
String fileName = reformatFileName(UriUtils.extractHost(entry.getKey()));
String fileName = Optional.ofNullable(UriUtils.extractHost(entry.getKey()))
.map(this::reformatFileName)
.orElse(entry.getKey());

if (filenameToCertificate.containsKey(fileName)) {
fileName = fileName + "-" + counter++;
}

List<X509Certificate> certificates = entry.getValue();
if (!certificates.isEmpty()) {
String certificateAsPem = String.join(System.lineSeparator(), CertificateUtils.convertToPem(certificates));
String certificateAsPem = certificates.stream()
.map(CertificateUtils::convertToPem)
.map(certificate -> includeHeader ? certificate : removeHeader(certificate))
.collect(Collectors.joining(System.lineSeparator()));
filenameToCertificate.put(fileName, certificateAsPem);
}
}
} else {
filenameToCertificate = certificateHolder.getUrlsToCertificates().values().stream()
.flatMap(Collection::stream)
.collect(collectingAndThen(collectingAndThen(toList(), CertificateUtils::generateAliases),
entry -> entry.entrySet().stream().collect(toMap(Entry::getKey, element -> CertificateUtils.convertToPem(element.getValue())))));
}

if (!includeHeader) {
filenameToCertificate = filenameToCertificate.entrySet().stream()
.map(entry -> new SimpleEntry<>(entry.getKey(), removeHeader(entry.getValue())))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
entry -> entry.entrySet().stream().collect(toMap(Entry::getKey, element -> includeHeader ? CertificateUtils.convertToPem(element.getValue()) : removeHeader(CertificateUtils.convertToPem(element.getValue())))))
);
}

Path directory = getDestination().orElseGet(this::getCurrentDirectory);
Expand Down

0 comments on commit 9a7c5ea

Please sign in to comment.