aboutsummaryrefslogtreecommitdiffstats
path: root/utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java
diff options
context:
space:
mode:
Diffstat (limited to 'utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java')
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java161
1 files changed, 161 insertions, 0 deletions
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
new file mode 100644
index 00000000..0787872c
--- /dev/null
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/security/SelfSignedKeyStore.java
@@ -0,0 +1,161 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+
+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.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;
+
+/**
+ * Keystore, containing a self-signed certificate, valid for one day (see the argument to
+ * the "-valid" flag below). For use in junit tests.
+ */
+@Getter
+public class SelfSignedKeyStore {
+ public static final String KEYSTORE_PASSWORD = "Pol1cy_0nap";
+ public static final String PRIVATE_KEY_PASSWORD = KEYSTORE_PASSWORD;
+ public static final String RELATIVE_PATH = "target/test-classes/policy-keystore";
+
+ /**
+ * File containing subject-alternative names (i.e., list of servers that may use this
+ * keystore).
+ */
+ private static final String KEYSTORE_SAN = "keystore_san.txt";
+
+ private final String keystoreName;
+
+
+ /**
+ * Generates the keystore, if it does not exist or if it's more than a few hours old.
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws InterruptedException if an interrupt occurs
+ */
+ public SelfSignedKeyStore() throws IOException, InterruptedException {
+ this(RELATIVE_PATH);
+ }
+
+ /**
+ * Generates the keystore, if it does not exist or if it's more than a few hours old.
+ *
+ * @param relativePath path to the keystore, relative to the "user.dir" system
+ * property
+ * @throws IOException if an I/O error occurs
+ * @throws InterruptedException if an interrupt occurs
+ */
+ public SelfSignedKeyStore(String relativePath) throws IOException, InterruptedException {
+ keystoreName = System.getProperty("user.dir") + "/" + relativePath;
+
+ // use existing file if it isn't too old
+ var keystoreFile = new File(keystoreName);
+ if (keystoreFile.exists()) {
+ if (System.currentTimeMillis() < keystoreFile.lastModified()
+ + TimeUnit.MILLISECONDS.convert(5, TimeUnit.HOURS)) {
+ return;
+ }
+
+ Files.delete(keystoreFile.toPath());
+ }
+
+ /*
+ * Read the list of subject-alternative names, joining the lines with commas, and
+ * dropping the trailing comma.
+ */
+ String sanFileName = getKeystoreSanName();
+ var sanString = ResourceUtils.getResourceAsString(sanFileName);
+ if (sanString == null) {
+ throw new FileNotFoundException(sanFileName);
+ }
+
+ var sanArray = sanString.replace("DNS:", "").replace("\r", "").split("\n");
+ GeneralName[] nameArray = Arrays.stream(sanArray).map(name -> new GeneralName(GeneralName.dNSName, name))
+ .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);
+ }
+ }
+
+ // may be overridden by junit tests
+
+ protected String getKeystoreSanName() {
+ return KEYSTORE_SAN;
+ }
+}