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 return newKeyless(privateKeyMethod, Files.newInputStream(chain.toPath()));
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public static BoringSSLKeylessManagerFactory newKeyless(BoringSSLAsyncPrivateKeyMethod privateKeyMethod,
90 InputStream chain)
91 throws CertificateException, IOException,
92 KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
93 return newKeyless(privateKeyMethod, QuicSslContext.toX509Certificates0(chain));
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public static BoringSSLKeylessManagerFactory newKeyless(BoringSSLAsyncPrivateKeyMethod privateKeyMethod,
109 X509Certificate... certificateChain)
110 throws CertificateException, IOException,
111 KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
112 checkNotNull(certificateChain, "certificateChain");
113 KeyStore store = new KeylessKeyStore(certificateChain.clone());
114 store.load(null, null);
115 BoringSSLKeylessManagerFactory factory = new BoringSSLKeylessManagerFactory(
116 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()), privateKeyMethod);
117 factory.init(store, null);
118 return factory;
119 }
120
121 private static final class KeylessManagerFactorySpi extends KeyManagerFactorySpi {
122
123 private final KeyManagerFactory keyManagerFactory;
124
125 KeylessManagerFactorySpi(KeyManagerFactory keyManagerFactory) {
126 this.keyManagerFactory = requireNonNull(keyManagerFactory, "keyManagerFactory");
127 }
128
129 @Override
130 protected void engineInit(KeyStore ks, char[] password)
131 throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
132 keyManagerFactory.init(ks, password);
133 }
134
135 @Override
136 protected void engineInit(ManagerFactoryParameters spec) {
137 throw new UnsupportedOperationException("Not supported");
138 }
139
140 @Override
141 protected KeyManager[] engineGetKeyManagers() {
142 return keyManagerFactory.getKeyManagers();
143 }
144 }
145 private static final class KeylessKeyStore extends KeyStore {
146 private static final String ALIAS = "key";
147 private KeylessKeyStore(final X509Certificate[] certificateChain) {
148 super(new KeyStoreSpi() {
149
150 private final Date creationDate = new Date();
151
152 @Override
153 @Nullable
154 public Key engineGetKey(String alias, char[] password) {
155 if (engineContainsAlias(alias)) {
156 return BoringSSLKeylessPrivateKey.INSTANCE;
157 }
158 return null;
159 }
160
161 @Override
162 public Certificate @Nullable [] engineGetCertificateChain(String alias) {
163 return engineContainsAlias(alias)? certificateChain.clone() : null;
164 }
165
166 @Override
167 @Nullable
168 public Certificate engineGetCertificate(String alias) {
169 return engineContainsAlias(alias)? certificateChain[0] : null;
170 }
171
172 @Override
173 @Nullable
174 public Date engineGetCreationDate(String alias) {
175 return engineContainsAlias(alias)? creationDate : null;
176 }
177
178 @Override
179 public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
180 throws KeyStoreException {
181 throw new KeyStoreException("Not supported");
182 }
183
184 @Override
185 public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
186 throw new KeyStoreException("Not supported");
187 }
188
189 @Override
190 public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
191 throw new KeyStoreException("Not supported");
192 }
193
194 @Override
195 public void engineDeleteEntry(String alias) throws KeyStoreException {
196 throw new KeyStoreException("Not supported");
197 }
198
199 @Override
200 public Enumeration<String> engineAliases() {
201 return Collections.enumeration(Collections.singleton(ALIAS));
202 }
203
204 @Override
205 public boolean engineContainsAlias(String alias) {
206 return ALIAS.equals(alias);
207 }
208
209 @Override
210 public int engineSize() {
211 return 1;
212 }
213
214 @Override
215 public boolean engineIsKeyEntry(String alias) {
216 return engineContainsAlias(alias);
217 }
218
219 @Override
220 public boolean engineIsCertificateEntry(String alias) {
221 return engineContainsAlias(alias);
222 }
223
224 @Override
225 @Nullable
226 public String engineGetCertificateAlias(Certificate cert) {
227 if (cert instanceof X509Certificate) {
228 for (X509Certificate x509Certificate : certificateChain) {
229 if (x509Certificate.equals(cert)) {
230 return ALIAS;
231 }
232 }
233 }
234 return null;
235 }
236
237 @Override
238 public void engineStore(OutputStream stream, char[] password) {
239 throw new UnsupportedOperationException();
240 }
241
242 @Override
243 public void engineLoad(@Nullable InputStream stream, char @Nullable [] password) {
244 if (stream != null && password != null) {
245 throw new UnsupportedOperationException();
246 }
247 }
248 }, null, "keyless");
249 }
250 }
251 }