summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreBuilder.java')
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreBuilder.java165
1 files changed, 165 insertions, 0 deletions
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreBuilder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreBuilder.java
new file mode 100644
index 00000000..a1e3a824
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/credential/inline/InlineKeyStoreBuilder.java
@@ -0,0 +1,165 @@
+package at.gv.egiz.eaaf.core.impl.credential.inline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Objects;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Convenience class to load keys and certificates in PEM-format into a
+ * {@link KeyStore} by providing the file paths.
+ */
+@Slf4j
+public class InlineKeyStoreBuilder {
+ private final KeyStore keyStore;
+ private final ResourceLoader loader;
+ private final URI configRootDir;
+
+ /**
+ * Create a new instance.
+ *
+ * @param type the type of the KeyStore to be built, e.g.
+ * "PKCS12"
+ * @param configRootDirectory Root directory for configuration
+ * @param resourceLoader Spring ResourceLoader
+ * @throws GeneralSecurityException if the empty KeyStore object could not be
+ * created
+ * @throws IOException if the empty KeyStore object could not be
+ * created
+ */
+ public InlineKeyStoreBuilder(String type, ResourceLoader resourceLoader,
+ URI configRootDirectory)
+ throws GeneralSecurityException, IOException {
+ loader = resourceLoader;
+ configRootDir = configRootDirectory;
+
+ keyStore = KeyStore.getInstance(type);
+ keyStore.load(null, null);
+
+ }
+
+ /**
+ * Sets a key entry, i.e. build a key store.
+ *
+ * @param privateKeyFile the path to the private key file
+ * @param certificateFiles the paths to the certificate files
+ * @throws GeneralSecurityException if a file could not be parsed
+ * @throws IOException if a file could not be read
+ * @throws EaafConfigurationException if a file could not be found
+ */
+ public void setKeyEntry(String privateKeyFile, String[] certificateFiles)
+ throws GeneralSecurityException, IOException, EaafConfigurationException {
+ final X509Certificate[] certificates = readCertificates(certificateFiles);
+ final PrivateKey privateKey = readPrivateKey(privateKeyFile);
+ keyStore.setKeyEntry("keyEntry", privateKey, new char[0], certificates);
+
+ }
+
+ /**
+ * Sets certificate entries, i.e. build a trust store.
+ *
+ * @param certificateFiles the path to the certificate files
+ * @throws GeneralSecurityException if a file could not be parsed
+ */
+ public void setCertificateEntries(String[] certificateFiles) throws GeneralSecurityException {
+
+ final X509Certificate[] certificates = readCertificates(certificateFiles);
+
+ for (int i = 0; i < certificates.length; i++) {
+ keyStore.setCertificateEntry("certificateEntry" + i, certificates[i]);
+ }
+ }
+
+ /**
+ * Sets a secret key, i.e. builds a keystore.
+ *
+ * @param secret the secret encoded as a Base64 string
+ * @throws KeyStoreException if the secret key could not be added to the store
+ */
+ public void setSecretEntry(final String secret) throws KeyStoreException {
+ final byte[] decodedKey = Base64.getDecoder().decode(secret);
+ final SecretKey key = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
+ keyStore.setEntry("secret", new KeyStore.SecretKeyEntry(key),
+ new KeyStore.PasswordProtection(new char[] {}));
+ }
+
+ public KeyStore getKeyStore() {
+ return keyStore;
+ }
+
+ private X509Certificate[] readCertificates(String[] certificateFiles) throws CertificateException {
+ final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+
+ return Arrays.stream(certificateFiles).map(certificateFile -> {
+ try (InputStream is = readResourceFromFile(certificateFile)) {
+ return (X509Certificate) certificateFactory.generateCertificate(is);
+
+ } catch (CertificateException | IOException | EaafConfigurationException e) {
+ log.error("Failed to load certificate file {}.", certificateFile, e);
+ return null;
+
+ }
+ }).filter(Objects::nonNull).toArray(X509Certificate[]::new);
+ }
+
+ private PrivateKey readPrivateKey(String filePath) throws IOException, EaafConfigurationException {
+ try (
+ Reader fileReader = new InputStreamReader(readResourceFromFile(filePath));
+ PEMParser pemParser = new PEMParser(fileReader)) {
+
+ final Object object = pemParser.readObject();
+ final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
+
+ if (object instanceof PrivateKeyInfo) {
+ return converter.getPrivateKey((PrivateKeyInfo) object);
+
+ } else if (object instanceof PEMKeyPair) {
+ return converter.getKeyPair((PEMKeyPair) object).getPrivate();
+
+ } else {
+ throw new IllegalArgumentException("Unsupported object: " + object.getClass());
+
+ }
+ }
+ }
+
+ private InputStream readResourceFromFile(String filePath) throws IOException, EaafConfigurationException {
+ final String absKeyStorePath = FileUtils.makeAbsoluteUrl(filePath, configRootDir);
+ log.debug("Use filepath from config: {}", absKeyStorePath);
+ Resource ressource = loader.getResource(absKeyStorePath);
+
+ if (!ressource.exists()) {
+ throw new EaafConfigurationException("internal.keystore.15",
+ new Object[] { "RessourceLoader does NOT find File at: " + ressource.getURI() });
+
+ }
+
+ return ressource.getInputStream();
+
+ }
+}