1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import org.jetbrains.annotations.Nullable;
19
20 import javax.net.ssl.KeyManager;
21 import javax.net.ssl.KeyManagerFactory;
22 import javax.net.ssl.KeyManagerFactorySpi;
23 import javax.net.ssl.ManagerFactoryParameters;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.nio.file.Files;
29 import java.security.Key;
30 import java.security.KeyStore;
31 import java.security.KeyStoreException;
32 import java.security.KeyStoreSpi;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.UnrecoverableKeyException;
35 import java.security.cert.Certificate;
36 import java.security.cert.CertificateException;
37 import java.security.cert.X509Certificate;
38 import java.util.Collections;
39 import java.util.Date;
40 import java.util.Enumeration;
41
42 import static io.netty.util.internal.ObjectUtil.checkNotNull;
43 import static java.util.Objects.requireNonNull;
44
45
46
47
48 public final class BoringSSLKeylessManagerFactory extends KeyManagerFactory {
49
50 final BoringSSLAsyncPrivateKeyMethod privateKeyMethod;
51
52 private BoringSSLKeylessManagerFactory(KeyManagerFactory keyManagerFactory,
53 BoringSSLAsyncPrivateKeyMethod privateKeyMethod) {
54 super(new KeylessManagerFactorySpi(keyManagerFactory),
55 keyManagerFactory.getProvider(), keyManagerFactory.getAlgorithm());
56 this.privateKeyMethod = requireNonNull(privateKeyMethod, "privateKeyMethod");
57 }
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public static BoringSSLKeylessManagerFactory newKeyless(BoringSSLAsyncPrivateKeyMethod privateKeyMethod, File chain)
72 throws CertificateException, IOException,
73 KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
74 try (InputStream chainInputStream = Files.newInputStream(chain.toPath())) {
75 return newKeyless(privateKeyMethod, chainInputStream);
76 }
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public static BoringSSLKeylessManagerFactory newKeyless(BoringSSLAsyncPrivateKeyMethod privateKeyMethod,
92 InputStream chain)
93 throws CertificateException, IOException,
94 KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
95 return newKeyless(privateKeyMethod, QuicSslContext.toX509Certificates0(chain));
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public static BoringSSLKeylessManagerFactory newKeyless(BoringSSLAsyncPrivateKeyMethod privateKeyMethod,
111 X509Certificate... certificateChain)
112 throws CertificateException, IOException,
113 KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
114 checkNotNull(certificateChain, "certificateChain");
115 KeyStore store = new KeylessKeyStore(certificateChain.clone());
116 store.load(null, null);
117 BoringSSLKeylessManagerFactory factory = new BoringSSLKeylessManagerFactory(
118 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()), privateKeyMethod);
119 factory.init(store, null);
120 return factory;
121 }
122
123 private static final class KeylessManagerFactorySpi extends KeyManagerFactorySpi {
124
125 private final KeyManagerFactory keyManagerFactory;
126
127 KeylessManagerFactorySpi(KeyManagerFactory keyManagerFactory) {
128 this.keyManagerFactory = requireNonNull(keyManagerFactory, "keyManagerFactory");
129 }
130
131 @Override
132 protected void engineInit(KeyStore ks, char[] password)
133 throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
134 keyManagerFactory.init(ks, password);
135 }
136
137 @Override
138 protected void engineInit(ManagerFactoryParameters spec) {
139 throw new UnsupportedOperationException("Not supported");
140 }
141
142 @Override
143 protected KeyManager[] engineGetKeyManagers() {
144 return keyManagerFactory.getKeyManagers();
145 }
146 }
147 private static final class KeylessKeyStore extends KeyStore {
148 private static final String ALIAS = "key";
149 private KeylessKeyStore(final X509Certificate[] certificateChain) {
150 super(new KeyStoreSpi() {
151
152 private final Date creationDate = new Date();
153
154 @Override
155 @Nullable
156 public Key engineGetKey(String alias, char[] password) {
157 if (engineContainsAlias(alias)) {
158 return BoringSSLKeylessPrivateKey.INSTANCE;
159 }
160 return null;
161 }
162
163 @Override
164 public Certificate @Nullable [] engineGetCertificateChain(String alias) {
165 return engineContainsAlias(alias)? certificateChain.clone() : null;
166 }
167
168 @Override
169 @Nullable
170 public Certificate engineGetCertificate(String alias) {
171 return engineContainsAlias(alias)? certificateChain[0] : null;
172 }
173
174 @Override
175 @Nullable
176 public Date engineGetCreationDate(String alias) {
177 return engineContainsAlias(alias)? creationDate : null;
178 }
179
180 @Override
181 public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
182 throws KeyStoreException {
183 throw new KeyStoreException("Not supported");
184 }
185
186 @Override
187 public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
188 throw new KeyStoreException("Not supported");
189 }
190
191 @Override
192 public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
193 throw new KeyStoreException("Not supported");
194 }
195
196 @Override
197 public void engineDeleteEntry(String alias) throws KeyStoreException {
198 throw new KeyStoreException("Not supported");
199 }
200
201 @Override
202 public Enumeration<String> engineAliases() {
203 return Collections.enumeration(Collections.singleton(ALIAS));
204 }
205
206 @Override
207 public boolean engineContainsAlias(String alias) {
208 return ALIAS.equals(alias);
209 }
210
211 @Override
212 public int engineSize() {
213 return 1;
214 }
215
216 @Override
217 public boolean engineIsKeyEntry(String alias) {
218 return engineContainsAlias(alias);
219 }
220
221 @Override
222 public boolean engineIsCertificateEntry(String alias) {
223 return engineContainsAlias(alias);
224 }
225
226 @Override
227 @Nullable
228 public String engineGetCertificateAlias(Certificate cert) {
229 if (cert instanceof X509Certificate) {
230 for (X509Certificate x509Certificate : certificateChain) {
231 if (x509Certificate.equals(cert)) {
232 return ALIAS;
233 }
234 }
235 }
236 return null;
237 }
238
239 @Override
240 public void engineStore(OutputStream stream, char[] password) {
241 throw new UnsupportedOperationException();
242 }
243
244 @Override
245 public void engineLoad(@Nullable InputStream stream, char @Nullable [] password) {
246 if (stream != null && password != null) {
247 throw new UnsupportedOperationException();
248 }
249 }
250 }, null, "keyless");
251 }
252 }
253 }