1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18
19 import io.netty.util.CharsetUtil;
20 import org.jetbrains.annotations.Nullable;
21
22 import javax.net.ssl.SSLException;
23 import javax.net.ssl.SSLHandshakeException;
24 import javax.net.ssl.X509ExtendedKeyManager;
25 import javax.security.auth.x500.X500Principal;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.security.PrivateKey;
29 import java.security.cert.CertificateEncodingException;
30 import java.security.cert.X509Certificate;
31 import java.util.Arrays;
32 import java.util.Base64;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.LinkedHashSet;
37 import java.util.Map;
38 import java.util.Set;
39
40 final class BoringSSLCertificateCallback {
41 private static final byte[] BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
42 private static final byte[] END_PRIVATE_KEY = "\n-----END PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
43
44
45
46
47
48 private static final byte TLS_CT_RSA_SIGN = 1;
49 private static final byte TLS_CT_DSS_SIGN = 2;
50 private static final byte TLS_CT_RSA_FIXED_DH = 3;
51 private static final byte TLS_CT_DSS_FIXED_DH = 4;
52 private static final byte TLS_CT_ECDSA_SIGN = 64;
53 private static final byte TLS_CT_RSA_FIXED_ECDH = 65;
54 private static final byte TLS_CT_ECDSA_FIXED_ECDH = 66;
55
56
57
58
59
60
61
62 static final String KEY_TYPE_RSA = "RSA";
63 static final String KEY_TYPE_DH_RSA = "DH_RSA";
64 static final String KEY_TYPE_EC = "EC";
65 static final String KEY_TYPE_EC_EC = "EC_EC";
66 static final String KEY_TYPE_EC_RSA = "EC_RSA";
67
68
69 private static final Map<String, String> DEFAULT_SERVER_KEY_TYPES = new HashMap<String, String>();
70 static {
71 DEFAULT_SERVER_KEY_TYPES.put("RSA", KEY_TYPE_RSA);
72 DEFAULT_SERVER_KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
73 DEFAULT_SERVER_KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
74 DEFAULT_SERVER_KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
75 DEFAULT_SERVER_KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
76 DEFAULT_SERVER_KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
77 DEFAULT_SERVER_KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
78 }
79
80 private static final Set<String> DEFAULT_CLIENT_KEY_TYPES = Collections.unmodifiableSet(new LinkedHashSet<>(
81 Arrays.asList(KEY_TYPE_RSA,
82 KEY_TYPE_DH_RSA,
83 KEY_TYPE_EC,
84 KEY_TYPE_EC_RSA,
85 KEY_TYPE_EC_EC)));
86
87
88 private static final long[] NO_KEY_MATERIAL_CLIENT_SIDE = new long[] { 0, 0 };
89
90 private final QuicheQuicSslEngineMap engineMap;
91 private final X509ExtendedKeyManager keyManager;
92 private final String password;
93 private final Map<String, String> serverKeyTypes;
94 private final Set<String> clientKeyTypes;
95
96 BoringSSLCertificateCallback(QuicheQuicSslEngineMap engineMap,
97 @Nullable X509ExtendedKeyManager keyManager,
98 String password,
99 Map<String, String> serverKeyTypes,
100 Set<String> clientKeyTypes) {
101 this.engineMap = engineMap;
102 this.keyManager = keyManager;
103 this.password = password;
104
105 this.serverKeyTypes = serverKeyTypes != null ? serverKeyTypes : DEFAULT_SERVER_KEY_TYPES;
106 this.clientKeyTypes = clientKeyTypes != null ? clientKeyTypes : DEFAULT_CLIENT_KEY_TYPES;
107 }
108
109 @SuppressWarnings("unused")
110 long @Nullable [] handle(long ssl, byte[] keyTypeBytes, byte @Nullable [][] asn1DerEncodedPrincipals,
111 String[] authMethods) {
112 QuicheQuicSslEngine engine = engineMap.get(ssl);
113 if (engine == null) {
114 return null;
115 }
116
117 try {
118 if (keyManager == null) {
119 if (engine.getUseClientMode()) {
120 return NO_KEY_MATERIAL_CLIENT_SIDE;
121 }
122 return null;
123 }
124 if (engine.getUseClientMode()) {
125 final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
126 final String[] keyTypes = keyTypesSet.toArray(new String[0]);
127 final X500Principal[] issuers;
128 if (asn1DerEncodedPrincipals == null) {
129 issuers = null;
130 } else {
131 issuers = new X500Principal[asn1DerEncodedPrincipals.length];
132 for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
133 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
134 }
135 }
136 return removeMappingIfNeeded(ssl, selectKeyMaterialClientSide(ssl, engine, keyTypes, issuers));
137 } else {
138
139
140 return removeMappingIfNeeded(ssl, selectKeyMaterialServerSide(ssl, engine, authMethods));
141 }
142 } catch (SSLException e) {
143 engineMap.remove(ssl);
144 return null;
145 } catch (Throwable cause) {
146 engineMap.remove(ssl);
147 throw cause;
148 }
149 }
150
151 private long @Nullable [] removeMappingIfNeeded(long ssl, long @Nullable [] result) {
152 if (result == null) {
153 engineMap.remove(ssl);
154 }
155 return result;
156 }
157
158 private long @Nullable [] selectKeyMaterialServerSide(long ssl, QuicheQuicSslEngine engine, String[] authMethods)
159 throws SSLException {
160 if (authMethods.length == 0) {
161 throw new SSLHandshakeException("Unable to find key material");
162 }
163
164
165
166
167 Set<String> typeSet = new HashSet<String>(serverKeyTypes.size());
168 for (String authMethod : authMethods) {
169 String type = serverKeyTypes.get(authMethod);
170 if (type != null && typeSet.add(type)) {
171 String alias = chooseServerAlias(engine, type);
172 if (alias != null) {
173 return selectMaterial(ssl, engine, alias) ;
174 }
175 }
176 }
177 throw new SSLHandshakeException("Unable to find key material for auth method(s): "
178 + Arrays.toString(authMethods));
179 }
180
181 private long @Nullable [] selectKeyMaterialClientSide(long ssl, QuicheQuicSslEngine engine, String[] keyTypes,
182 X500Principal @Nullable [] issuer) {
183 String alias = chooseClientAlias(engine, keyTypes, issuer);
184
185
186
187 if (alias != null) {
188 return selectMaterial(ssl, engine, alias) ;
189 }
190 return NO_KEY_MATERIAL_CLIENT_SIDE;
191 }
192
193 private long @Nullable [] selectMaterial(long ssl, QuicheQuicSslEngine engine, String alias) {
194 X509Certificate[] certificates = keyManager.getCertificateChain(alias);
195 if (certificates == null || certificates.length == 0) {
196 return null;
197 }
198 byte[][] certs = new byte[certificates.length][];
199
200 for (int i = 0; i < certificates.length; i++) {
201 try {
202 certs[i] = certificates[i].getEncoded();
203 } catch (CertificateEncodingException e) {
204 return null;
205 }
206 }
207
208 final long key;
209 PrivateKey privateKey = keyManager.getPrivateKey(alias);
210 if (privateKey == BoringSSLKeylessPrivateKey.INSTANCE) {
211 key = 0;
212 } else {
213 byte[] pemKey = toPemEncoded(privateKey);
214 if (pemKey == null) {
215 return null;
216 }
217 key = BoringSSL.EVP_PKEY_parse(pemKey, password);
218 }
219 long chain = BoringSSL.CRYPTO_BUFFER_stack_new(ssl, certs);
220 engine.setLocalCertificateChain(certificates);
221
222
223 return new long[] { key, chain };
224 }
225
226 private static byte @Nullable [] toPemEncoded(PrivateKey key) {
227 try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
228 out.write(BEGIN_PRIVATE_KEY);
229 out.write(Base64.getEncoder().encode(key.getEncoded()));
230 out.write(END_PRIVATE_KEY);
231 return out.toByteArray();
232 } catch (IOException e) {
233 return null;
234 }
235 }
236
237 @Nullable
238 private String chooseClientAlias(QuicheQuicSslEngine engine,
239 String[] keyTypes, X500Principal @Nullable [] issuer) {
240 return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine);
241 }
242
243 @Nullable
244 private String chooseServerAlias(QuicheQuicSslEngine engine, String type) {
245 return keyManager.chooseEngineServerAlias(type, null, engine);
246 }
247
248
249
250
251
252
253
254
255
256 private Set<String> supportedClientKeyTypes(byte @Nullable[] clientCertificateTypes) {
257 if (clientCertificateTypes == null) {
258
259 return clientKeyTypes;
260 }
261 Set<String> result = new HashSet<>(clientCertificateTypes.length);
262 for (byte keyTypeCode : clientCertificateTypes) {
263 String keyType = clientKeyType(keyTypeCode);
264 if (keyType == null) {
265
266 continue;
267 }
268 result.add(keyType);
269 }
270 return result;
271 }
272
273 @Nullable
274 private static String clientKeyType(byte clientCertificateType) {
275
276 switch (clientCertificateType) {
277 case TLS_CT_RSA_SIGN:
278 return KEY_TYPE_RSA;
279 case TLS_CT_RSA_FIXED_DH:
280 return KEY_TYPE_DH_RSA;
281 case TLS_CT_ECDSA_SIGN:
282 return KEY_TYPE_EC;
283 case TLS_CT_RSA_FIXED_ECDH:
284 return KEY_TYPE_EC_RSA;
285 case TLS_CT_ECDSA_FIXED_ECDH:
286 return KEY_TYPE_EC_EC;
287 default:
288 return null;
289 }
290 }
291 }