KeyStoreLoader.java

/*
 * Copyright (c) 2019 the Eclipse Milo Authors
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 */

package de.dlr.bt.stc.source.opcua;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;

import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateBuilder;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;

import de.dlr.bt.stc.exceptions.SourceConfigurationException;
import lombok.extern.slf4j.Slf4j;

@Slf4j
class KeyStoreLoader {

//	private static final Pattern IP_ADDR_PATTERN = Pattern
//			.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");

	private static final String CLIENT_ALIAS = "client-ai";
	private static final char[] PASSWORD = "password".toCharArray();

	private X509Certificate clientCertificate;
	private KeyPair clientKeyPair;

	KeyStoreLoader load(File keyStoreFile, boolean createIfNotExisting) throws SourceConfigurationException {
		try {
			KeyStore keyStore = KeyStore.getInstance("PKCS12");

			log.info("Loading KeyStore at {}", keyStoreFile);

			if (!keyStoreFile.exists()) {
				if (!createIfNotExisting)
					throw new SourceConfigurationException(
							"Keystore " + keyStoreFile + " not found and automatic creation is disabled!");
				keyStore.load(null, PASSWORD);

				KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);

				SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder(keyPair)
						.setCommonName("Shepard Timeseries Connector").setOrganization("DLR e.V.")
						.setOrganizationalUnit("BT").setLocalityName("Augsburg").setStateName("BY").setCountryCode("DE")
						.setApplicationUri("urn:idms:stc").addDnsName("localhost").addIpAddress("127.0.0.1");

				// Get as many hostnames and IP addresses as we can listed in the certificate.
//			for (String hostname : HostnameUtil.getHostnames("0.0.0.0")) {
//				if (IP_ADDR_PATTERN.matcher(hostname)
//						.matches()) {
//					builder.addIpAddress(hostname);
//				} else {
//					builder.addDnsName(hostname);
//				}
//			}

				X509Certificate certificate = builder.build();

				keyStore.setKeyEntry(CLIENT_ALIAS, keyPair.getPrivate(), PASSWORD,
						new X509Certificate[] { certificate });
				try (OutputStream out = Files.newOutputStream(keyStoreFile.toPath())) {
					keyStore.store(out, PASSWORD);
				}
			} else {
				try (InputStream in = Files.newInputStream(keyStoreFile.toPath())) {
					keyStore.load(in, PASSWORD);
				}
			}

			Key serverPrivateKey = keyStore.getKey(CLIENT_ALIAS, PASSWORD);
			if (serverPrivateKey instanceof PrivateKey) {
				clientCertificate = (X509Certificate) keyStore.getCertificate(CLIENT_ALIAS);
				PublicKey serverPublicKey = clientCertificate.getPublicKey();
				clientKeyPair = new KeyPair(serverPublicKey, (PrivateKey) serverPrivateKey);
			}

			return this;
		} catch (Exception ex) {
			// This is ugly, but builder throws a generic Exception ...
			throw new SourceConfigurationException("Keystore operation failed", ex);
		}
	}

	X509Certificate getClientCertificate() {
		return clientCertificate;
	}

	KeyPair getClientKeyPair() {
		return clientKeyPair;
	}

}