NIFI-12021 Refactored Groovy TLS Toolkit Tests to Java

This closes #7674

Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
dan-s1 2023-09-08 18:32:21 +00:00 committed by exceptionfactory
parent 47f4c8ce2e
commit 796ae2f5d1
No known key found for this signature in database
GPG Key ID: 29B6A52D2AAE8DBA
5 changed files with 276 additions and 415 deletions

View File

@ -90,11 +90,6 @@
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -1,214 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.toolkit.tls.standalone
import org.apache.nifi.security.cert.builder.StandardCertificateBuilder
import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator
import org.bouncycastle.util.io.pem.PemWriter
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import javax.security.auth.x500.X500Principal
import java.nio.file.Files
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.SignatureException
import java.security.cert.X509Certificate
import java.time.Duration
import static org.junit.jupiter.api.Assertions.assertThrows
class TlsToolkitStandaloneGroovyTest {
private final String TEST_SRC_DIR = "src/test/resources/"
private final String DEFAULT_KEY_PAIR_ALGORITHM = "RSA"
@Test
void testShouldVerifyCertificateSignatureWhenSelfSigned(@TempDir File tempDir) {
// Arrange
// Create a temp directory for this test and populate it with the nifi-cert.pem and nifi-key.key files
File baseDir = createBaseDirAndPopulateWithCAFiles(tempDir)
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig()
standaloneConfig.setBaseDir(baseDir)
standaloneConfig.setInstanceDefinitions([])
standaloneConfig.setClientDns([])
standaloneConfig.initDefaults()
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
// Act
standalone.createNifiKeystoresAndTrustStores(standaloneConfig)
// Assert
// The test will fail with an exception if the certificate is not signed by a known certificate
}
/**
* The certificate under examination is self-signed, but there is another signing cert which will be iterated over first, fail, and then the self-signed signature will be validated.
*/
@Test
void testShouldVerifyCertificateSignatureWithMultipleSigningCerts(@TempDir File tempDir) {
// Create a temp directory for this test and populate it with the nifi-cert.pem and nifi-key.key files
File baseDir = createBaseDirAndPopulateWithCAFiles(tempDir)
// Create a different cert and persist it to the base dir
X509Certificate otherCert = generateX509Certificate()
File otherCertFile = writeCertificateToPEMFile(otherCert, "${baseDir.path}/other.pem")
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig()
standaloneConfig.setBaseDir(baseDir)
standaloneConfig.setInstanceDefinitions([])
standaloneConfig.setClientDns([])
standaloneConfig.initDefaults()
// Inject the additional CA cert path
standaloneConfig.setAdditionalCACertificate(otherCertFile.path)
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
// Act
standalone.createNifiKeystoresAndTrustStores(standaloneConfig)
}
/**
* The certificate under examination is signed with the external signing cert.
*/
@Test
void testShouldVerifyCertificateSignatureWithAdditionalSigningCert(@TempDir File baseDir) {
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then provide the root
KeyPair rootKeyPair = generateKeyPair()
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair)
File rootCertFile = writeCertificateToPEMFile(rootCert, "${baseDir.path}/root.pem")
KeyPair intermediateKeyPair = generateKeyPair()
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
.setSubject(new X500Principal("CN=Intermediate CA"))
.setSubjectPublicKey(intermediateKeyPair.getPublic())
.build()
File intermediateCertFile = writeCertificateToPEMFile(intermediateCert, "${baseDir.path}/nifi-cert.pem")
// Write the private key of the intermediate cert to nifi-key.key
File intermediateKeyFile = writePrivateKeyToFile(intermediateKeyPair, "${baseDir}/nifi-key.key")
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig()
standaloneConfig.setBaseDir(baseDir)
standaloneConfig.setInstanceDefinitions([])
standaloneConfig.setClientDns([])
standaloneConfig.initDefaults()
// Inject the additional CA cert path
standaloneConfig.setAdditionalCACertificate(rootCertFile.path)
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
// Act
standalone.createNifiKeystoresAndTrustStores(standaloneConfig)
}
@Test
void testShouldNotVerifyCertificateSignatureWithWrongSigningCert(@TempDir File baseDir) {
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then do not provide the root
KeyPair rootKeyPair = generateKeyPair()
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair)
KeyPair intermediateKeyPair = generateKeyPair()
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
.setSubject(new X500Principal("CN=Intermediate CA"))
.setSubjectPublicKey(intermediateKeyPair.getPublic())
.build()
File intermediateCertFile = writeCertificateToPEMFile(intermediateCert, "${baseDir.path}/nifi-cert.pem")
// Write the private key of the intermediate cert to nifi-key.key
File intermediateKeyFile = writePrivateKeyToFile(intermediateKeyPair, "${baseDir.path}/nifi-key.key")
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig()
standaloneConfig.setBaseDir(baseDir)
standaloneConfig.setInstanceDefinitions([])
standaloneConfig.setClientDns([])
standaloneConfig.initDefaults()
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
assertThrows(SignatureException.class, () -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig))
}
private static File writePrivateKeyToFile(KeyPair intermediateKeyPair, String destination) {
File intermediateKeyFile = new File(destination)
PemWriter pemWriter = new PemWriter(new FileWriter(intermediateKeyFile))
pemWriter.writeObject(new JcaMiscPEMGenerator(intermediateKeyPair))
pemWriter.close()
intermediateKeyFile
}
private File createBaseDirAndPopulateWithCAFiles(File baseDir) {
populateBaseDirWithCAFiles(baseDir)
}
private File populateBaseDirWithCAFiles(File baseDir) {
File certificateFile = new File(TEST_SRC_DIR, "rootCert.crt")
File keyFile = new File(TEST_SRC_DIR, "rootCert.key")
File destinationCertFile = new File(baseDir.path, "nifi-cert.pem")
Files.copy(certificateFile.toPath(), destinationCertFile.toPath())
File destinationKeyFile = new File(baseDir.path, "nifi-key.key")
Files.copy(keyFile.toPath(), destinationKeyFile.toPath())
baseDir
}
/**
* Returns an {@link X509Certificate} with the provided DN and default algorithms. The validity period is only 1 day.
*
* @param dn the DN (defaults to {@code CN=Test Certificate})
* @return the X509Certificate
*/
private X509Certificate generateX509Certificate(String dn = "CN=Test Certificate", KeyPair keyPair = generateKeyPair()) {
new StandardCertificateBuilder(keyPair, new X500Principal(dn), Duration.ofDays(1)).build()
}
private KeyPair generateKeyPair() {
KeyPairGenerator instance = KeyPairGenerator.getInstance(DEFAULT_KEY_PAIR_ALGORITHM)
instance.initialize(2048)
instance.generateKeyPair()
}
/**
* Writes the provided {@link X509Certificate} to the specified file in PEM format.
*
* @param certificate the certificate
* @param destination the path to write the certificate in PEM format
* @return the file
*/
private static File writeCertificateToPEMFile(X509Certificate certificate, String destination) {
File certificateFile = new File(destination)
PemWriter pemWriter = new PemWriter(new FileWriter(certificateFile))
pemWriter.writeObject(new JcaMiscPEMGenerator(certificate))
pemWriter.close()
certificateFile
}
}

View File

@ -1,102 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.toolkit.tls.util
import org.bouncycastle.crypto.params.RSAKeyParameters
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import javax.security.auth.x500.X500Principal
import java.security.KeyPair
import java.security.PrivateKey
import java.security.Security
import java.security.cert.X509Certificate
class TlsHelperGroovyTest {
@BeforeAll
static void setProvider() {
System.setProperty("org.bouncycastle.rsa.allow_unsafe_mod","true")
Security.addProvider(new BouncyCastleProvider())
BCRSAPublicKey badPublicKey = new BCRSAPublicKey(new RSAKeyParameters(false, new BigInteger("3", 10), new BigInteger("1", 10)))
}
@Test
void testShouldVerifyCertificateSignatureWhenSelfSigned() {
File certificateFile = new File("src/test/resources/rootCert.crt")
FileReader certReader = new FileReader(certificateFile)
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [certificate])
assert isCertificateSigned
}
@Test
void testShouldVerifyCertificateSignatureWithMultipleSigningCerts() {
File certificateFile = new File("src/test/resources/rootCert.crt")
FileReader certReader = new FileReader(certificateFile)
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
X509Certificate mockCertificate = [
getSubjectX500Principal: { -> new X500Principal("CN=Mock Certificate") },
getPublicKey : { -> badPublicKey }
] as X509Certificate
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [mockCertificate, certificate])
assert isCertificateSigned
}
@Test
void testShouldNotVerifyCertificateSignatureWithNoSigningCerts() {
File certificateFile = new File("src/test/resources/rootCert.crt")
FileReader certReader = new FileReader(certificateFile)
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [])
assert !isCertificateSigned
}
@Test
void testShouldNotVerifyCertificateSignatureWithWrongSigningCert() {
File certificateFile = new File("src/test/resources/rootCert.crt")
FileReader certReader = new FileReader(certificateFile)
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
X509Certificate mockCertificate = [
getSubjectX500Principal: { -> new X500Principal("CN=Mock Certificate") },
getPublicKey : { -> badPublicKey }
] as X509Certificate
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [mockCertificate])
assert !isCertificateSigned
}
@Test
void testParseKeyPairFromReaderShouldHandlePKCS8PrivateKey() {
File keyFile = new File("src/test/resources/rootCert-pkcs8.key")
FileReader keyReader = new FileReader(keyFile)
final KeyPair expectedKeyPair = TlsHelper.parseKeyPairFromReader(new FileReader(new File ("src/test/resources/rootCert.key")))
final PrivateKey EXPECTED_PRIVATE_KEY = expectedKeyPair.getPrivate()
KeyPair keyPair = TlsHelper.parseKeyPairFromReader(keyReader)
assert keyPair.private == EXPECTED_PRIVATE_KEY
}
}

View File

@ -17,77 +17,79 @@
package org.apache.nifi.toolkit.tls.standalone;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.nifi.security.cert.builder.StandardCertificateBuilder;
import org.apache.nifi.security.util.KeyStoreUtils;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.toolkit.tls.SystemExitCapturer;
import org.apache.nifi.toolkit.tls.commandLine.BaseTlsToolkitCommandLine;
import org.apache.nifi.toolkit.tls.commandLine.ExitCode;
import org.apache.nifi.toolkit.tls.configuration.TlsConfig;
import org.apache.nifi.toolkit.tls.configuration.InstanceIdentifier;
import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig;
import org.apache.nifi.toolkit.tls.configuration.TlsConfig;
import org.apache.nifi.toolkit.tls.service.TlsCertificateAuthorityTest;
import org.apache.nifi.toolkit.tls.util.TlsHelper;
import org.apache.nifi.toolkit.tls.util.TlsHelperTest;
import org.apache.nifi.util.NiFiProperties;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
import org.bouncycastle.util.io.pem.PemWriter;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.junit.jupiter.api.io.TempDir;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TlsToolkitStandaloneTest {
public static final String NIFI_FAKE_PROPERTY = "nifi.fake.property";
public static final String FAKE_VALUE = "fake value";
public static final String TEST_NIFI_PROPERTIES = "src/test/resources/localhost/nifi.properties";
public static final Logger logger = LoggerFactory.getLogger(TlsToolkitStandaloneTest.class);
private SystemExitCapturer systemExitCapturer;
@TempDir
private File tempDir;
@BeforeEach
public void setup() throws IOException {
tempDir = File.createTempFile("tls-test", UUID.randomUUID().toString());
if (!tempDir.delete()) {
throw new IOException("Couldn't delete " + tempDir);
}
if (!tempDir.mkdirs()) {
throw new IOException("Couldn't make directory " + tempDir);
}
systemExitCapturer = new SystemExitCapturer();
}
@AfterEach
public void teardown() throws IOException {
public void teardown() {
systemExitCapturer.close();
FileUtils.deleteDirectory(tempDir);
}
@Test
@ -104,7 +106,7 @@ public class TlsToolkitStandaloneTest {
@Test
public void testDirOutput() throws Exception {
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
assertNull(nifiProperties.get("nifi.fake.property"));
@ -114,7 +116,7 @@ public class TlsToolkitStandaloneTest {
@Test
public void testDifferentArg() throws Exception {
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-g", "-n", TlsConfig.DEFAULT_HOSTNAME);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
assertNull(nifiProperties.get("nifi.fake.property"));
@ -124,7 +126,7 @@ public class TlsToolkitStandaloneTest {
@Test
public void testFileArg() throws Exception {
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-f", TEST_NIFI_PROPERTIES, "-n", TlsConfig.DEFAULT_HOSTNAME);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
assertEquals(FAKE_VALUE, nifiProperties.get(NIFI_FAKE_PROPERTY));
@ -137,7 +139,7 @@ public class TlsToolkitStandaloneTest {
String nifi3 = "nifi3";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi1 + "," + nifi2);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi3);
checkHostDirAndReturnNifiProperties(nifi1, x509Certificate);
@ -152,7 +154,7 @@ public class TlsToolkitStandaloneTest {
String nifi = "nifi";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
checkHostDirAndReturnNifiProperties(nifi, x509Certificate);
runAndAssertExitCode(ExitCode.ERROR_GENERATING_CONFIG, "-o", tempDir.getAbsolutePath(), "-n", nifi);
}
@ -161,7 +163,7 @@ public class TlsToolkitStandaloneTest {
public void testKeyPasswordArg() throws Exception {
String testKey = "testKey";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-K", testKey, "-n", TlsConfig.DEFAULT_HOSTNAME);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
assertEquals(testKey, nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD));
@ -171,7 +173,7 @@ public class TlsToolkitStandaloneTest {
public void testKeyStorePasswordArg() throws Exception {
String testKeyStore = "testKeyStore";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-S", testKeyStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
assertEquals(testKeyStore, nifiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD));
@ -181,7 +183,7 @@ public class TlsToolkitStandaloneTest {
public void testTrustStorePasswordArg() throws Exception {
String testTrustStore = "testTrustStore";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-P", testTrustStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
assertEquals(testTrustStore, nifiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD));
@ -193,7 +195,7 @@ public class TlsToolkitStandaloneTest {
String nifiDnSuffix = ", OU=nifi";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME,
"--" + TlsToolkitStandaloneCommandLine.NIFI_DN_PREFIX_ARG, nifiDnPrefix, "--" + TlsToolkitStandaloneCommandLine.NIFI_DN_SUFFIX_ARG, nifiDnSuffix);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, nifiDnPrefix, nifiDnSuffix, x509Certificate);
}
@ -202,7 +204,7 @@ public class TlsToolkitStandaloneTest {
final String certificateAuthorityHostname = "certificate-authority";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME, "-T", KeystoreType.PKCS12.toString().toLowerCase(),
"-K", "change", "-S", "change", "-P", "change", "-c", certificateAuthorityHostname);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
}
@ -211,7 +213,7 @@ public class TlsToolkitStandaloneTest {
String clientDn = "OU=NIFI,CN=testuser";
String clientDn2 = "OU=NIFI,CN=testuser2";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-C", clientDn2, "-B", "pass1", "-P", "pass2");
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
checkClientCert(clientDn, x509Certificate);
checkClientCert(clientDn2, x509Certificate);
@ -224,7 +226,7 @@ public class TlsToolkitStandaloneTest {
public void testClientDnsArgNoOverwrite() throws Exception {
String clientDn = "OU=NIFI,CN=testuser";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-B", "passwor");
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
checkClientCert(clientDn, x509Certificate);
@ -236,7 +238,7 @@ public class TlsToolkitStandaloneTest {
String hostname = "static.nifi.apache.org";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
X509Certificate clientCert = (X509Certificate) certificateChain[0];
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
@ -255,7 +257,7 @@ public class TlsToolkitStandaloneTest {
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname, "--subjectAlternativeName", san);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
X509Certificate clientCert = (X509Certificate) certificateChain[0];
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
@ -273,7 +275,7 @@ public class TlsToolkitStandaloneTest {
String san = "alternative.nifi.apache.org";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", san);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
for (InstanceIdentifier hostInstance : (Iterable<InstanceIdentifier>) hostIds::iterator) {
@ -295,7 +297,7 @@ public class TlsToolkitStandaloneTest {
String saNames = "alternative[1-2].nifi.apache.org";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
@ -331,7 +333,7 @@ public class TlsToolkitStandaloneTest {
String saNames = "alternative[3-4].nifi.apache.org";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
@ -367,7 +369,7 @@ public class TlsToolkitStandaloneTest {
String saNames = "alternative[5-7].nifi.apache.org";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
@ -400,7 +402,7 @@ public class TlsToolkitStandaloneTest {
String saNames = "alternative[2-1].nifi.apache.org";
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
X509Certificate x509Certificate = checkLoadCertPrivateKey();
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
@ -438,11 +440,122 @@ public class TlsToolkitStandaloneTest {
runAndAssertExitCode(ExitCode.ERROR_PARSING_INT_ARG, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
}
private X509Certificate checkLoadCertPrivateKey(String algorithm) throws IOException, CertificateException {
@Test
void testShouldVerifyCertificateSignatureWhenSelfSigned() throws Exception {
// Create a temp directory for this test and populate it with the nifi-cert.pem and nifi-key.key files
populateTempDirWithCAFiles();
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig();
standaloneConfig.setBaseDir(tempDir);
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
standaloneConfig.setClientDns(new ArrayList<>());
standaloneConfig.initDefaults();
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
// The test will fail with an exception if the certificate is not signed by a known certificate
assertDoesNotThrow(() -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
}
/**
* The certificate under examination is self-signed, but there is another signing cert which will be iterated over first, fail, and then the self-signed signature will be validated.
*/
@Test
void testShouldVerifyCertificateSignatureWithMultipleSigningCerts() throws Exception {
// Populate temp directory for this test with the nifi-cert.pem and nifi-key.key files
populateTempDirWithCAFiles();
// Create a different cert and persist it to the base dir
X509Certificate otherCert = generateX509Certificate();
File otherCertFile = writeCertificateToPEMFile(otherCert, tempDir.getPath() + "/other.pem");
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig();
standaloneConfig.setBaseDir(tempDir);
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
standaloneConfig.setClientDns(new ArrayList<>());
standaloneConfig.initDefaults();
// Inject the additional CA cert path
standaloneConfig.setAdditionalCACertificate(otherCertFile.getPath());
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
assertDoesNotThrow(() -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
}
/**
* The certificate under examination is signed with the external signing cert.
*/
@Test
void testShouldVerifyCertificateSignatureWithAdditionalSigningCert() throws Exception {
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then provide the root
KeyPair rootKeyPair = generateKeyPair();
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair);
File rootCertFile = writeCertificateToPEMFile(rootCert, tempDir.getPath() + "/root.pem");
KeyPair intermediateKeyPair = generateKeyPair();
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
.setSubject(new X500Principal("CN=Intermediate CA"))
.setSubjectPublicKey(intermediateKeyPair.getPublic())
.build();
//intermediateCertFile
writeCertificateToPEMFile(intermediateCert, tempDir.getPath() + "/nifi-cert.pem");
// Write the private key of the intermediate cert to nifi-key.key
//intermediateKeyFile
writePrivateKeyToFile(intermediateKeyPair, tempDir.getPath() + "/nifi-key.key");
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig();
standaloneConfig.setBaseDir(tempDir);
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
standaloneConfig.setClientDns(new ArrayList<>());
standaloneConfig.initDefaults();
// Inject the additional CA cert path
standaloneConfig.setAdditionalCACertificate(rootCertFile.getPath());
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
assertDoesNotThrow(() -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
}
@Test
void testShouldNotVerifyCertificateSignatureWithWrongSigningCert() throws Exception {
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then do not provide the root
KeyPair rootKeyPair = generateKeyPair();
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair);
KeyPair intermediateKeyPair = generateKeyPair();
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
.setSubject(new X500Principal("CN=Intermediate CA"))
.setSubjectPublicKey(intermediateKeyPair.getPublic())
.build();
//intermediateCertFile
writeCertificateToPEMFile(intermediateCert, tempDir.getPath() + "/nifi-cert.pem");
// Write the private key of the intermediate cert to nifi-key.key
//intermediateKeyFile
writePrivateKeyToFile(intermediateKeyPair, tempDir.getPath() + "/nifi-key.key");
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
StandaloneConfig standaloneConfig = new StandaloneConfig();
standaloneConfig.setBaseDir(tempDir);
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
standaloneConfig.setClientDns(new ArrayList<>());
standaloneConfig.initDefaults();
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
assertThrows(SignatureException.class, () -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
}
private X509Certificate checkLoadCertPrivateKey() throws IOException, CertificateException {
KeyPair keyPair = TlsHelperTest.loadKeyPair(new File(tempDir, TlsToolkitStandalone.NIFI_KEY + ".key"));
assertEquals(algorithm, keyPair.getPrivate().getAlgorithm());
assertEquals(algorithm, keyPair.getPublic().getAlgorithm());
assertEquals(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM, keyPair.getPrivate().getAlgorithm());
assertEquals(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM, keyPair.getPublic().getAlgorithm());
X509Certificate x509Certificate = TlsHelperTest.loadCertificate(new File(tempDir, TlsToolkitStandalone.NIFI_CERT + ".pem"));
assertEquals(keyPair.getPublic(), x509Certificate.getPublicKey());
@ -485,7 +598,7 @@ public class TlsToolkitStandaloneTest {
}
char[] keyPassword = nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD).toCharArray();
if (keyPassword == null || keyPassword.length == 0) {
if(ArrayUtils.isEmpty(keyPassword)) {
keyPassword = keyStorePassword;
}
@ -529,7 +642,6 @@ public class TlsToolkitStandaloneTest {
certificateChain[0].verify(rootCert.getPublicKey());
PublicKey publicKey = certificateChain[0].getPublicKey();
TlsCertificateAuthorityTest.assertPrivateAndPublicKeyMatch(privateKey, publicKey);
}
private Certificate[] loadCertificateChain(String hostname, X509Certificate rootCert) throws Exception {
@ -550,4 +662,65 @@ public class TlsToolkitStandaloneTest {
private void runAndAssertExitCode(ExitCode exitCode, String... args) {
systemExitCapturer.runAndAssertExitCode(() -> TlsToolkitStandaloneCommandLine.main(args), exitCode);
}
private void populateTempDirWithCAFiles() throws Exception {
final String testSrcDir = "src/test/resources/";
File certificateFile = new File(testSrcDir, "rootCert.crt");
File keyFile = new File(testSrcDir, "rootCert.key");
File destinationCertFile = new File(tempDir, "nifi-cert.pem");
Files.copy(certificateFile.toPath(), destinationCertFile.toPath());
File destinationKeyFile = new File(tempDir, "nifi-key.key");
Files.copy(keyFile.toPath(), destinationKeyFile.toPath());
}
/**
* Returns an {@link X509Certificate} with the provided DN and default algorithms. The validity period is only 1 day.
* DN (defaults to {@code CN=Test Certificate})
* @return the X509Certificate
*/
private static X509Certificate generateX509Certificate() throws Exception {
return generateX509Certificate("CN=Test Certificate", generateKeyPair());
}
/**
* Returns an {@link X509Certificate} with the provided DN and default algorithms. The validity period is only 1 day.
*
* @param dn the DN (defaults to {@code CN=Test Certificate})
* @return the X509Certificate
*/
private static X509Certificate generateX509Certificate(String dn, KeyPair keyPair) {
return new StandardCertificateBuilder(keyPair, new X500Principal(dn), Duration.ofDays(1)).build();
}
private static KeyPair generateKeyPair() throws Exception {
final String defaultKeyPairAlgorithm = "RSA";
KeyPairGenerator instance = KeyPairGenerator.getInstance(defaultKeyPairAlgorithm);
instance.initialize(2048);
return instance.generateKeyPair();
}
/**
* Writes the provided {@link X509Certificate} to the specified file in PEM format.
*
* @param certificate the certificate
* @param destination the path to write the certificate in PEM format
* @return the file
*/
private static File writeCertificateToPEMFile(X509Certificate certificate, String destination) throws Exception {
return writePem(certificate, destination);
}
private static File writePem(Object object, String destination) throws Exception{
File destinationFile = new File(destination);
try(PemWriter pemWriter = new PemWriter(new FileWriter(destinationFile))) {
pemWriter.writeObject(new JcaMiscPEMGenerator(object));
}
return destinationFile;
}
private static void writePrivateKeyToFile(KeyPair intermediateKeyPair, String destination) throws Exception {
writePem(intermediateKeyPair, destination);
}
}

View File

@ -34,14 +34,13 @@ import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
import org.bouncycastle.util.IPAddress;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.x500.X500Principal;
import java.io.BufferedReader;
@ -58,6 +57,7 @@ import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
@ -67,6 +67,7 @@ import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@ -75,31 +76,19 @@ import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class TlsHelperTest {
public static final Logger logger = LoggerFactory.getLogger(TlsHelperTest.class);
private static final String PASSWORD = "changeit";
private static X509Certificate rootCert;
private int days;
private int keySize;
private String keyPairAlgorithm;
private String signingAlgorithm;
private KeyPairGenerator keyPairGenerator;
private final String password = "changeit";
@Mock(lenient = true)
OutputStreamFactory outputStreamFactory;
private File file;
public static KeyPair loadKeyPair(final Reader reader) throws IOException {
try (PEMParser pemParser = new PEMParser(reader)) {
Object object = pemParser.readObject();
@ -128,19 +117,16 @@ public class TlsHelperTest {
}
}
@BeforeAll
static void setUpBeforeAll() throws Exception {
rootCert = TlsHelper.parseCertificate(new FileReader("src/test/resources/rootCert.crt"));
}
@BeforeEach
public void setup() throws Exception {
days = 360;
keySize = 2048;
keyPairAlgorithm = "RSA";
signingAlgorithm = "SHA256withRSA";
keyPairGenerator = KeyPairGenerator.getInstance(keyPairAlgorithm);
keyPairGenerator.initialize(keySize);
file = File.createTempFile("keystore", "file");
file.deleteOnExit();
ByteArrayOutputStream tmpFileOutputStream = new ByteArrayOutputStream();
when(outputStreamFactory.create(file)).thenReturn(tmpFileOutputStream);
}
private Date inFuture(int days) {
@ -149,13 +135,8 @@ public class TlsHelperTest {
@Test
public void testTokenLengthInCalculateHmac() throws GeneralSecurityException {
List<String> badTokens = new ArrayList<>();
List<String> goodTokens = new ArrayList<>();
badTokens.add(null);
badTokens.add("");
badTokens.add("123");
goodTokens.add("0123456789abcdefghijklm");
goodTokens.add("0123456789abcdef");
List<String> badTokens = Arrays.asList(null, "", "123");
List<String> goodTokens = Arrays.asList("0123456789abcdefghijklm", "0123456789abcdef");
String dn = "CN=testDN,O=testOrg";
X509Certificate x509Certificate = new StandardCertificateBuilder(TlsHelper.generateKeyPair(keyPairAlgorithm, keySize), new X500Principal(dn), Duration.ofDays(days)).build();
@ -193,14 +174,15 @@ public class TlsHelperTest {
assertTrue(notBefore.before(inFuture(1)));
assertEquals(dn, x509Certificate.getIssuerX500Principal().getName());
assertEquals(signingAlgorithm, x509Certificate.getSigAlgName());
assertEquals("SHA256withRSA", x509Certificate.getSigAlgName());
assertEquals(keyPairAlgorithm, x509Certificate.getPublicKey().getAlgorithm());
x509Certificate.checkValidity();
}
@Test
public void testWriteKeyStoreSuccess() throws IOException, GeneralSecurityException {
public void testWriteKeyStoreSuccess(@Mock OutputStreamFactory outputStreamFactory, @TempDir File file) throws IOException, GeneralSecurityException {
when(outputStreamFactory.create(file)).thenReturn(new ByteArrayOutputStream());
String testPassword = "testPassword";
final KeyStore keyStore = setupKeystore();
assertEquals(testPassword, TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, false));
@ -209,32 +191,29 @@ public class TlsHelperTest {
@Test
public void testShouldIncludeSANFromCSR() throws Exception {
// Arrange
final List<String> SAN_ENTRIES = Arrays.asList("127.0.0.1", "nifi.nifi.apache.org");
final int SAN_COUNT = SAN_ENTRIES.size();
final String DN = "CN=localhost";
final List<String> sanEntries = Arrays.asList("127.0.0.1", "nifi.nifi.apache.org");
final int sanCount = sanEntries.size();
final String dn = "CN=localhost";
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyPairAlgorithm);
keyPairGenerator.initialize(keySize);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
logger.info("Generating CSR with DN: " + DN);
// Act
JcaPKCS10CertificationRequest csrWithSan = TlsHelper.generateCertificationRequest(DN, SAN_ENTRIES, keyPair, TlsConfig.DEFAULT_SIGNING_ALGORITHM);
logger.info("Created CSR with SAN: " + SAN_ENTRIES);
String testCsrPem = TlsHelper.pemEncodeJcaObject(csrWithSan);
logger.info("Encoded CSR as PEM: " + testCsrPem);
JcaPKCS10CertificationRequest csrWithSan = TlsHelper.generateCertificationRequest(dn, sanEntries, keyPair, TlsConfig.DEFAULT_SIGNING_ALGORITHM);
// Assert
String subjectName = csrWithSan.getSubject().toString();
logger.info("CSR Subject Name: " + subjectName);
assert subjectName.equals(DN);
assertEquals(dn, subjectName);
List<String> extractedSans = extractSanFromCsr(csrWithSan);
assert extractedSans.size() == SAN_COUNT + 1;
List<String> formattedSans = SAN_ENTRIES.stream()
assertEquals(sanCount + 1, extractedSans.size());
List<String> formattedSans = sanEntries.stream()
.map(s -> (IPAddress.isValid(s) ? "IP Address: " + new GeneralName(GeneralName.iPAddress, s).getName() : "DNS: " + s))
.collect(Collectors.toList());
assert extractedSans.containsAll(formattedSans);
assertTrue(extractedSans.containsAll(formattedSans));
// We check that the SANs also contain the CN
assert extractedSans.contains("DNS: localhost");
assertTrue(extractedSans.contains("DNS: localhost"));
}
private List<String> extractSanFromCsr(JcaPKCS10CertificationRequest csr) {
@ -246,7 +225,6 @@ public class TlsHelperTest {
GeneralNames gns = GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName);
GeneralName[] names = gns.getNames();
for (GeneralName name : names) {
logger.info("Type: " + name.getTagNo() + " | Name: " + name.getName());
String title = "";
if (name.getTagNo() == GeneralName.dNSName) {
title = "DNS";
@ -325,7 +303,7 @@ public class TlsHelperTest {
private KeyStore setupKeystore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
KeyStore ks = KeyStore.getInstance("JKS");
try (InputStream readStream = getClass().getClassLoader().getResourceAsStream("keystore.jks")) {
ks.load(readStream, password.toCharArray());
ks.load(readStream, PASSWORD.toCharArray());
}
return ks;
}
@ -338,7 +316,7 @@ public class TlsHelperTest {
HashMap<String, Certificate> certs = TlsHelper.extractCerts(keyStore);
TlsHelper.outputCertsAsPem(certs, folder,".crt");
assertEquals(folder.listFiles().length, 2);
assertEquals(2, folder.listFiles().length);
for (File file : folder.listFiles()) {
X509Certificate certFromFile = loadCertificate(file);
@ -354,7 +332,7 @@ public class TlsHelperTest {
@Test
public void testOutputToFileOneKeyAsPem(@TempDir final File folder) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
KeyStore keyStore = setupKeystore();
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, password.toCharArray());
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, PASSWORD.toCharArray());
TlsHelper.outputKeysAsPem(keys, folder, ".key");
for (File file : folder.listFiles()) {
@ -379,8 +357,39 @@ public class TlsHelperTest {
@Test
public void testExtractKeys() throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
KeyStore keyStore = setupKeystore();
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, password.toCharArray());
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, PASSWORD.toCharArray());
assertEquals(1, keys.size());
keys.forEach((String alias, Key key) -> assertEquals("PKCS#8", key.getFormat()));
}
@Test
public void testShouldVerifyCertificateSignatureWhenSelfSigned() {
assertTrue(TlsHelper.verifyCertificateSignature(rootCert, Collections.singletonList(rootCert)));
}
@Test
public void testShouldVerifyCertificateSignatureWithMultipleSigningCerts(@Mock X509Certificate mockCertificate) {
when(mockCertificate.getSubjectX500Principal()).thenReturn(new X500Principal("CN=Mock Certificate"));
assertTrue(TlsHelper.verifyCertificateSignature(rootCert, Arrays.asList(mockCertificate, rootCert)));
}
@Test
public void testShouldNotVerifyCertificateSignatureWithNoSigningCerts() {
assertFalse(TlsHelper.verifyCertificateSignature(rootCert, new ArrayList<>()));
}
@Test
public void testShouldNotVerifyCertificateSignatureWithWrongSigningCert(@Mock X509Certificate mockCertificate) {
when(mockCertificate.getSubjectX500Principal()).thenReturn(new X500Principal("CN=Mock Certificate"));
assertFalse(TlsHelper.verifyCertificateSignature(rootCert, Collections.singletonList(mockCertificate)));
}
@Test
public void testParseKeyPairFromReaderShouldHandlePKCS8PrivateKey() throws Exception {
final KeyPair expectedKeyPair = TlsHelper.parseKeyPairFromReader(new FileReader("src/test/resources/rootCert.key"));
final PrivateKey expectedPrivateKey = expectedKeyPair.getPrivate();
final KeyPair keyPair = TlsHelper.parseKeyPairFromReader(new FileReader("src/test/resources/rootCert-pkcs8.key"));
assertEquals(expectedPrivateKey, keyPair.getPrivate());
}
}