feat: Implement Truststore/Keystore creation
chore: Run spotless feat: Update ordering of certificate chains to match what JDK demands feat: Implement creating trust- and keystores from certs :)
This commit is contained in:
parent
861b7469d2
commit
402bd99abf
10 changed files with 403 additions and 41 deletions
|
@ -0,0 +1,20 @@
|
||||||
|
package de.mlessmann.certassist.except;
|
||||||
|
|
||||||
|
public class JavaSecurityException extends Exception {
|
||||||
|
|
||||||
|
public JavaSecurityException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaSecurityException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaSecurityException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaSecurityException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package de.mlessmann.certassist.keystore;
|
||||||
|
|
||||||
|
import de.mlessmann.certassist.except.JavaSecurityException;
|
||||||
|
import de.mlessmann.certassist.openssl.CertificatePasswordProvider;
|
||||||
|
import de.mlessmann.certassist.openssl.CertificateUsage;
|
||||||
|
import de.mlessmann.certassist.openssl.OpenSSLCertificateCreator;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.OpenOption;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.util.Base64;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class KeyStoreManager {
|
||||||
|
|
||||||
|
private static final OpenOption[] CREATE_TRUNCATE = {
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
};
|
||||||
|
private final OpenSSLCertificateCreator certificateCreator;
|
||||||
|
private final CertificatePasswordProvider passwordProvider;
|
||||||
|
|
||||||
|
public KeystoreUsage createKeyStore(String keyStorePassphrase, CertificateUsage... serverCerts)
|
||||||
|
throws JavaSecurityException {
|
||||||
|
try {
|
||||||
|
Path keystorePath = Files.createTempFile("keystore", ".jks");
|
||||||
|
String keystorePassword = "changeit";
|
||||||
|
String alias = "mykey";
|
||||||
|
|
||||||
|
// Load the keystore
|
||||||
|
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
keystore.load(null, null);
|
||||||
|
|
||||||
|
for (CertificateUsage serverCert : serverCerts) {
|
||||||
|
PrivateKey privateKey = loadPrivateKey(
|
||||||
|
serverCert.certificateKeyPath(),
|
||||||
|
passwordProvider.getPasswordFor(serverCert.fingerprint())
|
||||||
|
);
|
||||||
|
Certificate[] certChain = loadCertificateChain(serverCert.fullchainPath());
|
||||||
|
keystore.setKeyEntry(alias, privateKey, keystorePassword.toCharArray(), certChain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the keystore
|
||||||
|
try (var keystoreOut = Files.newOutputStream(keystorePath, CREATE_TRUNCATE)) {
|
||||||
|
keystore.store(keystoreOut, keystorePassword.toCharArray());
|
||||||
|
}
|
||||||
|
return new KeystoreResult(keystorePath);
|
||||||
|
} catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException e) {
|
||||||
|
throw new JavaSecurityException("Failed to create keystore!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private PrivateKey loadPrivateKey(Path privateKey, String passphrase) {
|
||||||
|
String pemContent;
|
||||||
|
if (certificateCreator.isKeyEncrypted(privateKey)) {
|
||||||
|
pemContent = certificateCreator.readDecryptedKey(privateKey, passphrase);
|
||||||
|
} else {
|
||||||
|
pemContent = Files.readString(privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (var fis = Files.newInputStream(privateKey)) {
|
||||||
|
String privateKeyPEM = pemContent
|
||||||
|
.replaceAll(".*?-----BEGIN PRIVATE KEY-----", "")
|
||||||
|
.replace("-----END PRIVATE KEY-----", "")
|
||||||
|
.replaceAll("\\s", "");
|
||||||
|
byte[] decodedKey = Base64.getDecoder().decode(privateKeyPEM);
|
||||||
|
return KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private Certificate[] loadCertificateChain(Path certChainPath) {
|
||||||
|
// Load the certificate chain from a PEM file
|
||||||
|
try (var fis = Files.newInputStream(certChainPath)) {
|
||||||
|
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
return certFactory.generateCertificates(fis).toArray(Certificate[]::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package de.mlessmann.certassist.keystore;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
record KeystoreResult(Path truststorePath) implements KeystoreUsage {
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(truststorePath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to delete truststore at {}. Scheduling delete on exit.", truststorePath, e);
|
||||||
|
truststorePath.toFile().deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package de.mlessmann.certassist.keystore;
|
||||||
|
|
||||||
|
import de.mlessmann.certassist.except.JavaSecurityException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
public interface KeystoreUsage extends AutoCloseable {
|
||||||
|
Path truststorePath();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void close() {
|
||||||
|
// Default implementation does nothing - overwrite this if you need to close resources.
|
||||||
|
}
|
||||||
|
|
||||||
|
default KeyStore readAsKeystore(String passphrase) throws JavaSecurityException {
|
||||||
|
try {
|
||||||
|
return KeyStore.getInstance(truststorePath().toFile(), passphrase.toCharArray());
|
||||||
|
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException e) {
|
||||||
|
throw new JavaSecurityException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package de.mlessmann.certassist.keystore;
|
||||||
|
|
||||||
|
import de.mlessmann.certassist.openssl.CertificateUsage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.OpenOption;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TruststoreManager {
|
||||||
|
|
||||||
|
private static final OpenOption[] CREATE_TRUNCATE = {
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
};
|
||||||
|
|
||||||
|
public KeystoreUsage createTruststore(String truststorePassphrase, CertificateUsage... trustedCertificates) {
|
||||||
|
try {
|
||||||
|
Path truststorePath = Files.createTempFile("truststore", ".jks");
|
||||||
|
truststorePath.toFile().deleteOnExit();
|
||||||
|
log.debug("Creating truststore at {}", truststorePath);
|
||||||
|
|
||||||
|
KeyStore truststore = buildTruststore(trustedCertificates);
|
||||||
|
try (var outputStream = Files.newOutputStream(truststorePath, CREATE_TRUNCATE)) {
|
||||||
|
truststore.store(outputStream, truststorePassphrase.toCharArray());
|
||||||
|
}
|
||||||
|
return new KeystoreResult(truststorePath);
|
||||||
|
} catch (IOException | KeyStoreException | CertificateException | NoSuchAlgorithmException e) {
|
||||||
|
throw new IllegalStateException("Failed to create truststore!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private static KeyStore buildTruststore(CertificateUsage[] trustedCertificates) {
|
||||||
|
KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
truststore.load(null, null);
|
||||||
|
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
|
||||||
|
if (trustedCertificates == null || trustedCertificates.length == 0) {
|
||||||
|
log.warn("No trusted certificates provided, truststore will be empty!");
|
||||||
|
} else {
|
||||||
|
for (CertificateUsage trustedCertificate : trustedCertificates) {
|
||||||
|
try (var inputStream = Files.newInputStream(trustedCertificate.certificatePath())) {
|
||||||
|
X509Certificate jdkCert = (X509Certificate) certificateFactory.generateCertificate(inputStream);
|
||||||
|
truststore.setCertificateEntry(trustedCertificate.fingerprint(), jdkCert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return truststore;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,5 +36,7 @@ public interface CertificateUsage extends AutoCloseable {
|
||||||
String fingerprint();
|
String fingerprint();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void close();
|
default void close() {
|
||||||
|
// Default implementation does nothing - overwrite this if you need to close resources.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,8 +139,9 @@ public class OpenSSLCertificateCreator {
|
||||||
Path certAuthFullchain = Optional
|
Path certAuthFullchain = Optional
|
||||||
.ofNullable(certAuthority.fullchainPath())
|
.ofNullable(certAuthority.fullchainPath())
|
||||||
.orElse(certAuthority.certificatePath());
|
.orElse(certAuthority.certificatePath());
|
||||||
Files.write(fullchain, Files.readAllBytes(certAuthFullchain), StandardOpenOption.CREATE);
|
// Leaf certificate first, then the CA chain
|
||||||
Files.write(fullchain, Files.readAllBytes(signedCert), StandardOpenOption.APPEND);
|
Files.write(fullchain, Files.readAllBytes(signedCert), StandardOpenOption.APPEND);
|
||||||
|
Files.write(fullchain, Files.readAllBytes(certAuthFullchain), StandardOpenOption.CREATE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CommandLineOperationException("Failed to create fullchain file.", e);
|
throw new CommandLineOperationException("Failed to create fullchain file.", e);
|
||||||
}
|
}
|
||||||
|
@ -616,4 +617,30 @@ public class OpenSSLCertificateCreator {
|
||||||
default -> throw new IllegalStateException("Unexpected subject key: %s in line: %s".formatted(key, line));
|
default -> throw new IllegalStateException("Unexpected subject key: %s in line: %s".formatted(key, line));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String readDecryptedKey(Path keyFile, String passphrase) throws CommandLineOperationException {
|
||||||
|
StartedProcess keyReadProc = null;
|
||||||
|
try {
|
||||||
|
keyReadProc =
|
||||||
|
new ProcessExecutor()
|
||||||
|
.command(resolveOpenSSL(), "rsa", "-in", keyFile.toString(), "-passin", OSSL_ARG_KEY_PW)
|
||||||
|
.environment(OSSL_ENV_KEY_PW, passphrase)
|
||||||
|
.readOutput(true)
|
||||||
|
.redirectError(Slf4jStream.of(openSSLLogger).asError())
|
||||||
|
.start();
|
||||||
|
var keyReadResult = keyReadProc.getFuture().get(30, SECONDS);
|
||||||
|
if (keyReadResult.getExitValue() != 0) {
|
||||||
|
throw new CommandLineOperationException(
|
||||||
|
"Failed to read decrypted key - is the passphrase correct? Exit code: %d".formatted(
|
||||||
|
keyReadResult.getExitValue()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return keyReadResult.getOutput().getUTF8();
|
||||||
|
} catch (IOException | InterruptedException | ExecutionException | TimeoutException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
killIfActive(keyReadProc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
119
src/test/java/de/mlessmann/certassist/TestKeystoreCreation.java
Normal file
119
src/test/java/de/mlessmann/certassist/TestKeystoreCreation.java
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
package de.mlessmann.certassist;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import de.mlessmann.certassist.keystore.KeyStoreManager;
|
||||||
|
import de.mlessmann.certassist.keystore.TruststoreManager;
|
||||||
|
import de.mlessmann.certassist.openssl.CertificateProvider;
|
||||||
|
import de.mlessmann.certassist.openssl.CertificateUsage;
|
||||||
|
import de.mlessmann.certassist.openssl.OpenSSLCertificateCreator;
|
||||||
|
import de.mlessmann.certassist.service.InMemoryCertificatePasswordProvider;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
public class TestKeystoreCreation {
|
||||||
|
|
||||||
|
private static final String STORE_PASSPHRASE = "changeit";
|
||||||
|
private static final SecureRandom TEST_RANDOM = new SecureRandom();
|
||||||
|
private final CertificateUsage dummyCert = new CertificateUsage() {
|
||||||
|
@Override
|
||||||
|
public String fingerprint() {
|
||||||
|
return TestOpenSSLCertificateCreator.TEST_CERT_FINGERPRINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path certificatePath() {
|
||||||
|
return TestOpenSSLCertificateCreator.TEST_CERT_PATH.resolve("x509forImport.pem");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path certificateKeyPath() {
|
||||||
|
return TestOpenSSLCertificateCreator.TEST_CERT_PATH.resolve("x509forImport.key.pem");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path fullchainPath() {
|
||||||
|
return TestOpenSSLCertificateCreator.TEST_CERT_PATH.resolve("x509forImport.fullchain.pem");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testTruststore() throws Exception {
|
||||||
|
var passwordProvider = new InMemoryCertificatePasswordProvider();
|
||||||
|
passwordProvider.setPasswordFor(dummyCert.fingerprint(), TestOpenSSLCertificateCreator.TEST_CERT_PASSPHRASE);
|
||||||
|
|
||||||
|
var certificateProvider = Mockito.mock(CertificateProvider.class);
|
||||||
|
var opensslCertCreator = new OpenSSLCertificateCreator(
|
||||||
|
new ExecutableResolver(),
|
||||||
|
passwordProvider,
|
||||||
|
certificateProvider
|
||||||
|
);
|
||||||
|
var truststoreManager = new TruststoreManager();
|
||||||
|
var keyStoreManager = new KeyStoreManager(opensslCertCreator, passwordProvider);
|
||||||
|
AtomicBoolean serverAccepted = new AtomicBoolean(false);
|
||||||
|
AtomicBoolean clientAccepted = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
try (
|
||||||
|
var tmpTruststore = truststoreManager.createTruststore(STORE_PASSPHRASE, dummyCert);
|
||||||
|
var tmpKeyStore = keyStoreManager.createKeyStore(STORE_PASSPHRASE, dummyCert)
|
||||||
|
) {
|
||||||
|
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
|
||||||
|
KeyManagerFactory.getDefaultAlgorithm()
|
||||||
|
);
|
||||||
|
keyManagerFactory.init(tmpTruststore.readAsKeystore(STORE_PASSPHRASE), STORE_PASSPHRASE.toCharArray());
|
||||||
|
|
||||||
|
SSLContext tlsSrvContext = SSLContext.getInstance("TLS");
|
||||||
|
tlsSrvContext.init(keyManagerFactory.getKeyManagers(), null, TEST_RANDOM);
|
||||||
|
int serverPort = 1024 + TEST_RANDOM.nextInt(22_000);
|
||||||
|
|
||||||
|
ServerSocket serverSocket = tlsSrvContext.getServerSocketFactory().createServerSocket(0);
|
||||||
|
var serverThread = Thread.startVirtualThread(() -> {
|
||||||
|
try {
|
||||||
|
var remote = serverSocket.accept();
|
||||||
|
serverAccepted.set(true);
|
||||||
|
try {
|
||||||
|
Thread.sleep(2_000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
remote.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("Failed to create server socket!", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
trustManagerFactory.init(tmpTruststore.readAsKeystore(STORE_PASSPHRASE));
|
||||||
|
|
||||||
|
SSLContext tlsContext = SSLContext.getInstance("TLS");
|
||||||
|
tlsContext.init(null, trustManagerFactory.getTrustManagers(), TEST_RANDOM);
|
||||||
|
|
||||||
|
var clientThread = Thread.startVirtualThread(() -> {
|
||||||
|
try {
|
||||||
|
var socket = tlsContext.getSocketFactory().createSocket("127.0.0.1", serverSocket.getLocalPort());
|
||||||
|
clientAccepted.set(true);
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("Failed to create client socket!", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
serverThread.join();
|
||||||
|
clientThread.join();
|
||||||
|
if (!serverSocket.isClosed()) {
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(serverAccepted.get()).withFailMessage("Server did not accept connection!").isTrue();
|
||||||
|
assertThat(clientAccepted.get()).withFailMessage("Client did not accept connection!").isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import java.nio.file.Path;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
|
@ -18,18 +17,16 @@ 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 TEST_CERT_FINGERPRINT =
|
||||||
public static final String ERR_VERIFY_FAILED = "Certificate verification failed";
|
"SHA1;4E:D6:0A:47:F0:63:AD:96:26:83:16:28:32:F5:E8:36:5A:62:91:95";
|
||||||
|
private static final String ERR_NOT_ENCRYPTED = "Private key not encrypted";
|
||||||
@Autowired
|
private static final String ERR_VERIFY_FAILED = "Certificate verification failed";
|
||||||
OpenSSLCertificateCreator openSSLCertificateCreator;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
CertificatePasswordProvider passwordProvider;
|
CertificatePasswordProvider passwordProvider;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
passwordProvider = mock(CertificatePasswordProvider.class);
|
|
||||||
when(passwordProvider.generateNewPassword()).thenReturn(TEST_CERT_PASSPHRASE);
|
when(passwordProvider.generateNewPassword()).thenReturn(TEST_CERT_PASSPHRASE);
|
||||||
when(passwordProvider.getPasswordFor(anyString())).thenReturn(TEST_CERT_PASSPHRASE);
|
when(passwordProvider.getPasswordFor(anyString())).thenReturn(TEST_CERT_PASSPHRASE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,4 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
|
||||||
HowJo/ZfrlzZf8753cfF8Kza6NUA
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFrjCCA5agAwIBAgIUMhyzffHXKaQnfX/ckbx3KZ9AVXswDQYJKoZIhvcNAQEL
|
MIIFrjCCA5agAwIBAgIUMhyzffHXKaQnfX/ckbx3KZ9AVXswDQYJKoZIhvcNAQEL
|
||||||
BQAwUDELMAkGA1UEBhMCREUxCzAJBgNVBAgMAlNIMQswCQYDVQQHDAJISDETMBEG
|
BQAwUDELMAkGA1UEBhMCREUxCzAJBgNVBAgMAlNIMQswCQYDVQQHDAJISDETMBEG
|
||||||
A1UECgwKQ3JhenktQ2F0czESMBAGA1UEAwwJdGVzdC5ob21lMB4XDTI0MTEyMjE4
|
A1UECgwKQ3JhenktQ2F0czESMBAGA1UEAwwJdGVzdC5ob21lMB4XDTI0MTEyMjE4
|
||||||
|
@ -63,3 +31,35 @@ USrygPv8w4UT3SFoiABp1ThDjCheROLISAo/SIag8XUw58bmmiDRuVPLZDQfYBYu
|
||||||
KgSLJpFB99QMzvhkNBhImEpmWRrKAFSmwNG4/l/yR19udd4AxpjH62LT8mUZOf23
|
KgSLJpFB99QMzvhkNBhImEpmWRrKAFSmwNG4/l/yR19udd4AxpjH62LT8mUZOf23
|
||||||
dQ6pRi1hNlM1v6ZvFDdq8Rgw
|
dQ6pRi1hNlM1v6ZvFDdq8Rgw
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFgTCCA2mgAwIBAgIUVTm2kFBiacDG3Om6JFaZKvJ6CScwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwUDELMAkGA1UEBhMCREUxCzAJBgNVBAgMAlNIMQswCQYDVQQHDAJISDETMBEG
|
||||||
|
A1UECgwKQ3JhenktQ2F0czESMBAGA1UEAwwJdGVzdC5ob21lMB4XDTI0MTEyMjE4
|
||||||
|
NTc0MFoXDTI1MTEyMjE4NTc0MFowUDELMAkGA1UEBhMCREUxCzAJBgNVBAgMAlNI
|
||||||
|
MQswCQYDVQQHDAJISDETMBEGA1UECgwKQ3JhenktQ2F0czESMBAGA1UEAwwJdGVz
|
||||||
|
dC5ob21lMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnnYaTE8TKKTu
|
||||||
|
IE2hcHwHm0RnM+4VwPnNT6q6b4oYSJJeGJCbQYt8CAAkBxvY3j1H0xP6imD7ULUK
|
||||||
|
ymx2fQiHK+bRAdXyoguLHaPYWPInfUyHp9Y2w2AglKCG/U2paMni4xL0LH4N3V1r
|
||||||
|
x5hQG9ORwJzVH5wMiYoETzgbd1ED7G0tVuKYrH84Ma8znEXVZ4XfAlDfYEGKPNDN
|
||||||
|
dZDkFEQFYHb5RSPB6ym3vrbZJfLkNy01m/Cpdj3/GqJ460zo7x/apzVPNj/khW1v
|
||||||
|
fME8c8sz1LqEbQBVdUU9xN8DfTjT/z1NHA5S/1O7Yb9Z0t1tjvs3u/iyCjBNMbd5
|
||||||
|
7FNqMVjXFjENav21zrrr0LAiUfBcbokQZD72/j053gXz9LkcTjLvkPN3i1oVfNIA
|
||||||
|
b/Ce4hHzpWk2kvZuFyqfKj8Yc8oTfjr88sGxe1JCgbhnCvkw/5d7hy7OJVG4mTIH
|
||||||
|
WliOY92R7xPwEBhqc+A4VYqhAIrp+Qzen+XGrBih+PneEsSWVfM3PyjKt/qURK4j
|
||||||
|
gWCGFIEI80xyFaHhwHpeKszZcMOVAHjV3Ik91wutL/HoZ0r5uPYvwqQb6QZ7ubqX
|
||||||
|
FWiuNUf970TFS7eIA33Xr0IojPBziinU3/uYnJBODR4Sl2npijzwqsRrGsrSDUF7
|
||||||
|
cxxhsyv64ri2p3u4wnP4faLf1Dtk3kUCAwEAAaNTMFEwHQYDVR0OBBYEFICs29k3
|
||||||
|
J5Pnza2xgkgycaxBxAcSMB8GA1UdIwQYMBaAFICs29k3J5Pnza2xgkgycaxBxAcS
|
||||||
|
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAFiqNg1yXlajI1ZJ
|
||||||
|
l4qXADvi1xpFLEn17162jN+zb6DgRRohqwrsP71fAqyuCticYELk3gBHt8KizEBj
|
||||||
|
xPSggahX+ZIGG5/Tnb5cQ61y0GMZHWyABHjgiOGi26Gxar5wi7ET6W4D6w09u8U3
|
||||||
|
wd8q8U164aSj6Rh153S0r8SJJOhqtiZhcYllOMB8SNgjxodlco+YvCGoqkhPdJef
|
||||||
|
H2S02mgbjxMlo8P4ivoirD7boLirlXkoNidmaWvC/hD4ZwsTWMrRnHL1S5DEhKef
|
||||||
|
WSgtX3tUEvHrEyqsGcSn49l4CNE6Xbx5wWo+4c9bs642f7u34OoUnitYmGZDzT1d
|
||||||
|
zQOyBirn9k6fB/SX7Ug+PF6+KbJCXEdWffgNqe5HAG8Lo2EOEnocp3kncRMSq3zY
|
||||||
|
qzbTBqaWI512cqN2RA+Q0NPzVH01jPG8yKaSxVzf4Sp1Iqjl7fe9WZL9/L4DJZ7o
|
||||||
|
QWRPZvwH5Rz8utGUylfe9LxSisX7xZMNoGLqsQfanowqZCiS1M1GRoHsILnFuFNw
|
||||||
|
3ONu4qp0Gr3+PxsKoE6NBstqD6Lkrm0uf/IhC7fwIbdq3qqe0E4xZou9W9nkmapw
|
||||||
|
0iKhdhCtnp3HsF6f2Kc0ipyPxVXDnP5TCx4NLst2RvoYryUBwqIKfwU8X3yOBmhq
|
||||||
|
HowJo/ZfrlzZf8753cfF8Kza6NUA
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
Loading…
Add table
Reference in a new issue