View Javadoc
1   /*
2    * Copyright (c) 2021 the Eclipse Milo Authors
3    *
4    * This program and the accompanying materials are made
5    * available under the terms of the Eclipse Public License 2.0
6    * which is available at https://www.eclipse.org/legal/epl-2.0/
7    *
8    * SPDX-License-Identifier: EPL-2.0
9    */
10  
11  package de.dlr.bt.stc.opcuaserver;
12  
13  import java.io.File;
14  import java.io.FileInputStream;
15  import java.io.FileOutputStream;
16  import java.nio.file.Path;
17  import java.security.Key;
18  import java.security.KeyPair;
19  import java.security.KeyStore;
20  import java.security.PrivateKey;
21  import java.security.PublicKey;
22  import java.security.cert.X509Certificate;
23  import java.util.Arrays;
24  import java.util.Set;
25  import java.util.UUID;
26  import java.util.regex.Pattern;
27  
28  import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil;
29  import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateBuilder;
30  import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
31  
32  import com.google.common.collect.Sets;
33  
34  import lombok.extern.slf4j.Slf4j;
35  
36  @Slf4j
37  class KeyStoreLoader {
38  
39  	private static final Pattern IP_ADDR_PATTERN = Pattern
40  			.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
41  
42  	private static final String SERVER_ALIAS = "server-ai";
43  	private static final char[] PASSWORD = "password".toCharArray();
44  
45  	private X509Certificate[] serverCertificateChain;
46  	private X509Certificate serverCertificate;
47  	private KeyPair serverKeyPair;
48  
49  	KeyStoreLoader load(Path baseDir) throws Exception {
50  		KeyStore keyStore = KeyStore.getInstance("PKCS12");
51  
52  		File serverKeyStore = baseDir.resolve("example-server.pfx").toFile();
53  
54  		log.info("Loading KeyStore at {}", serverKeyStore);
55  
56  		if (!serverKeyStore.exists()) {
57  			keyStore.load(null, PASSWORD);
58  
59  			KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);
60  
61  			String applicationUri = "urn:dlr:stc:server:" + UUID.randomUUID();
62  
63  			SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder(keyPair)
64  					.setCommonName("Shepard Timeseries Collector").setOrganization("DLR e.V.")
65  					.setOrganizationalUnit("BT").setLocalityName("Augsburg").setStateName("BY").setCountryCode("DE")
66  					.setApplicationUri(applicationUri);
67  
68  			// Get as many hostnames and IP addresses as we can listed in the certificate.
69  			Set<String> hostnames = Sets.union(Sets.newHashSet(HostnameUtil.getHostname()),
70  					HostnameUtil.getHostnames("0.0.0.0", false));
71  
72  			for (String hostname : hostnames) {
73  				if (IP_ADDR_PATTERN.matcher(hostname).matches()) {
74  					builder.addIpAddress(hostname);
75  				} else {
76  					builder.addDnsName(hostname);
77  				}
78  			}
79  
80  			X509Certificate certificate = builder.build();
81  
82  			keyStore.setKeyEntry(SERVER_ALIAS, keyPair.getPrivate(), PASSWORD, new X509Certificate[] { certificate });
83  			keyStore.store(new FileOutputStream(serverKeyStore), PASSWORD);
84  		} else {
85  			keyStore.load(new FileInputStream(serverKeyStore), PASSWORD);
86  		}
87  
88  		Key serverPrivateKey = keyStore.getKey(SERVER_ALIAS, PASSWORD);
89  		if (serverPrivateKey instanceof PrivateKey) {
90  			serverCertificate = (X509Certificate) keyStore.getCertificate(SERVER_ALIAS);
91  
92  			serverCertificateChain = Arrays.stream(keyStore.getCertificateChain(SERVER_ALIAS))
93  					.map(X509Certificate.class::cast).toArray(X509Certificate[]::new);
94  
95  			PublicKey serverPublicKey = serverCertificate.getPublicKey();
96  			serverKeyPair = new KeyPair(serverPublicKey, (PrivateKey) serverPrivateKey);
97  		}
98  
99  		return this;
100 	}
101 
102 	X509Certificate getServerCertificate() {
103 		return serverCertificate;
104 	}
105 
106 	public X509Certificate[] getServerCertificateChain() {
107 		return serverCertificateChain;
108 	}
109 
110 	KeyPair getServerKeyPair() {
111 		return serverKeyPair;
112 	}
113 
114 }