zhoushihao
2024-10-11 f4644873804165e9db88375f242421f00b0903f2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package com.mes.milo.utils;
 
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.stack.client.security.DefaultClientCertificateValidator;
import org.eclipse.milo.opcua.stack.core.security.DefaultTrustListManager;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateBuilder;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
 
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.regex.Pattern;
 
@Slf4j
public 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 X509Certificate[] clientCertificateChain;
    private KeyPair clientKeyPair;
    private DefaultClientCertificateValidator certificateValidator;
 
    public KeyStoreLoader load() throws Exception {
        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        Files.createDirectories(securityTempDir);
        if (!Files.exists(securityTempDir)) {
            throw new Exception("unable to create security dir: " + securityTempDir);
        }
 
        File pkiDir = securityTempDir.resolve("pki").toFile();
 
        log.info("security temp dir: {}", securityTempDir.toAbsolutePath());
 
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
 
        Path serverKeyStore = securityTempDir.resolve("milo-client.pfx");
 
        DefaultTrustListManager trustListManager = new DefaultTrustListManager(pkiDir);
 
        certificateValidator = new DefaultClientCertificateValidator(trustListManager);
 
        log.info("Loading KeyStore at {}", serverKeyStore);
 
        if (!Files.exists(serverKeyStore)) {
            keyStore.load(null, PASSWORD);
 
            KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);
 
            SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder(keyPair)
                    .setCommonName("Milo Client")
                    .setOrganization("kangaroohy")
                    .setOrganizationalUnit("dev")
                    .setLocalityName("Folsom")
                    .setStateName("CA")
                    .setCountryCode("US")
                    .setApplicationUri("urn:kangaroohy:milo:client")
                    .addDnsName("localhost")
                    .addIpAddress("127.0.0.1");
 
            // Get as many hostnames and IP addresses as we can listed in the certificate.
            for (String hostname : CustomUtil.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(serverKeyStore)) {
                keyStore.store(out, PASSWORD);
            }
        } else {
            try (InputStream in = Files.newInputStream(serverKeyStore)) {
                keyStore.load(in, PASSWORD);
            }
        }
 
        Key clientPrivateKey = keyStore.getKey(CLIENT_ALIAS, PASSWORD);
        if (clientPrivateKey instanceof PrivateKey) {
            clientCertificate = (X509Certificate) keyStore.getCertificate(CLIENT_ALIAS);
 
            clientCertificateChain = Arrays.stream(keyStore.getCertificateChain(CLIENT_ALIAS))
                    .map(X509Certificate.class::cast)
                    .toArray(X509Certificate[]::new);
 
            PublicKey clientPublicKey = clientCertificate.getPublicKey();
            clientKeyPair = new KeyPair(clientPublicKey, (PrivateKey) clientPrivateKey);
        }
 
        return this;
    }
 
    public X509Certificate getClientCertificate() {
        return clientCertificate;
    }
 
    public X509Certificate[] getClientCertificateChain() {
        return clientCertificateChain;
    }
 
    public DefaultClientCertificateValidator getCertificateValidator() {
        return certificateValidator;
    }
 
    public KeyPair getClientKeyPair() {
        return clientKeyPair;
    }
 
}