aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Hahn <jrh3.lf@gmail.com>2021-09-20 23:23:38 -0400
committerLiam Fallon <liam.fallon@est.tech>2021-09-22 08:03:44 +0000
commitf65519cfc06693ed1775e9c00c642ab65f32ed05 (patch)
tree0da63e8584e1fcf9d6c5b36b7b83c1eba8f7bd96
parent340dce2b7c9d79c994e4be7f45428820b9b8c50b (diff)
Don't use keytool in test code
Modified code to generate a self-signed certificate file programmatically instead of using keytool. Issue-ID: POLICY-3587 Change-Id: I53b6ffe65f33e5710eba633973e5d23b148f049f Signed-off-by: Jim Hahn <jrh3.lf@gmail.com>
-rw-r--r--utils-test/pom.xml5
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java101
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/security/SelfSignedKeyStoreTest.java9
3 files changed, 78 insertions, 37 deletions
diff --git a/utils-test/pom.xml b/utils-test/pom.xml
index 863467f1..ca2e83c7 100644
--- a/utils-test/pom.xml
+++ b/utils-test/pom.xml
@@ -40,6 +40,11 @@
<dependencies>
<dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-fips</artifactId>
+ <version>1.0.5</version>
+ </dependency>
+ <dependency>
<groupId>com.google.re2j</groupId>
<artifactId>re2j</artifactId>
</dependency>
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java b/utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java
index 11dff4b4..647ff1ba 100644
--- a/utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java
@@ -22,11 +22,34 @@ package org.onap.policy.common.utils.security;
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
-import java.lang.ProcessBuilder.Redirect;
+import java.math.BigInteger;
import java.nio.file.Files;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.Date;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import lombok.Getter;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.onap.policy.common.utils.resources.ResourceUtils;
/**
@@ -70,49 +93,63 @@ public class SelfSignedKeyStore {
keystoreName = System.getProperty("user.dir") + "/" + relativePath;
// use existing file if it isn't too old
- var keystore = new File(keystoreName);
- if (keystore.exists()) {
- if (System.currentTimeMillis() < keystore.lastModified()
+ var keystoreFile = new File(keystoreName);
+ if (keystoreFile.exists()) {
+ if (System.currentTimeMillis() < keystoreFile.lastModified()
+ TimeUnit.MILLISECONDS.convert(5, TimeUnit.HOURS)) {
return;
}
- Files.delete(keystore.toPath());
+ Files.delete(keystoreFile.toPath());
}
/*
* Read the list of subject-alternative names, joining the lines with commas, and
* dropping the trailing comma.
*/
- String sanName = getKeystoreSanName();
- var subAltNames = ResourceUtils.getResourceAsString(sanName);
- if (subAltNames == null) {
- throw new FileNotFoundException(sanName);
+ String sanFileName = getKeystoreSanName();
+ var sanString = ResourceUtils.getResourceAsString(sanFileName);
+ if (sanString == null) {
+ throw new FileNotFoundException(sanFileName);
}
- subAltNames = subAltNames.replace("\r", "").replace("\n", ",");
- subAltNames = "SAN=" + subAltNames.substring(0, subAltNames.length() - 1);
-
- // build up the "keytool" command
-
- // @formatter:off
- var builder = new ProcessBuilder("keytool", "-genkeypair",
- "-alias", "policy@policy.onap.org",
- "-validity", "1",
- "-keyalg", "RSA",
- "-dname", "C=US, O=ONAP, OU=OSAAF, OU=policy@policy.onap.org:DEV, CN=policy",
- "-keystore", keystoreName,
- "-keypass", PRIVATE_KEY_PASSWORD,
- "-storepass", KEYSTORE_PASSWORD,
- "-ext", subAltNames);
- // @formatter:on
-
- Process proc = builder.redirectOutput(Redirect.INHERIT).redirectError(Redirect.INHERIT).start();
- proc.waitFor();
-
- int exitCode = proc.exitValue();
- if (exitCode != 0) {
- throw new IOException("keytool exited with " + exitCode);
+ var sanArray = sanString.replace("DNS:", "").replace("\r", "").split("\n");
+ GeneralName[] nameArray = Arrays.stream(sanArray).map(name -> new GeneralName(GeneralName.dNSName, name))
+ .collect(Collectors.toList()).toArray(new GeneralName[0]);
+ final var names = new GeneralNames(nameArray);
+
+ try (var ostr = new FileOutputStream(keystoreFile)) {
+ var keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ final var keyPair = keyPairGenerator.generateKeyPair();
+
+ final long tcur = System.currentTimeMillis();
+
+ final var dn = new X500Name("C=US, O=ONAP, OU=OSAAF, OU=policy@policy.onap.org:DEV, CN=policy");
+ final var serial = BigInteger.valueOf(new SecureRandom().nextInt());
+ final var notBefore = new Date(tcur);
+ final var notAfter = new Date(tcur + TimeUnit.MILLISECONDS.convert(365, TimeUnit.DAYS));
+ final var pubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA")
+ .setProvider(new BouncyCastleFipsProvider()).build(keyPair.getPrivate());
+
+ X509CertificateHolder holder = new X509v3CertificateBuilder(dn, serial, notBefore, notAfter, dn, pubKeyInfo)
+ .addExtension(Extension.subjectAlternativeName, false, names).build(signer);
+
+ var cert = new JcaX509CertificateConverter().setProvider(new BouncyCastleFipsProvider())
+ .getCertificate(holder);
+ final Certificate[] chain = {cert};
+
+ var keystore = KeyStore.getInstance("PKCS12");
+ keystore.load(null, null);
+ keystore.setKeyEntry("policy@policy.onap.org", keyPair.getPrivate(), PRIVATE_KEY_PASSWORD.toCharArray(),
+ chain);
+
+ keystore.store(ostr, KEYSTORE_PASSWORD.toCharArray());
+
+ } catch (NoSuchAlgorithmException | OperatorCreationException | CertificateException | KeyStoreException e) {
+ throw new IOException("cannot create certificate", e);
}
}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/security/SelfSignedKeyStoreTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/security/SelfSignedKeyStoreTest.java
index 62565bde..27bceacf 100644
--- a/utils-test/src/test/java/org/onap/policy/common/utils/security/SelfSignedKeyStoreTest.java
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/security/SelfSignedKeyStoreTest.java
@@ -118,12 +118,12 @@ public class SelfSignedKeyStoreTest {
}
/**
- * Tests the constructor, when keytool fails.
+ * Tests the constructor, when write fails.
*/
@Test
- public void testSelfSignedKeyStoreStringKeytoolFailure() throws Exception {
+ public void testSelfSignedKeyStoreStringWriteFailure() throws Exception {
assertThatThrownBy(() -> new SelfSignedKeyStore("target/unknown/path/to/keystore"))
- .isInstanceOf(IOException.class).hasMessageContaining("keytool exited with");
+ .isInstanceOf(IOException.class);
}
@Test
@@ -140,8 +140,7 @@ public class SelfSignedKeyStoreTest {
assertThat(defaultKeystore).exists();
// try again using the original relative path - should fail, as it's now deeper
- assertThatThrownBy(() -> new SelfSignedKeyStore(relpath)).isInstanceOf(IOException.class)
- .hasMessageContaining("keytool exited with");
+ assertThatThrownBy(() -> new SelfSignedKeyStore(relpath)).isInstanceOf(IOException.class);
}
private static void delete(File file) {