1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import javax.net.ssl.ExtendedSSLSession;
19 import javax.net.ssl.SSLException;
20 import javax.net.ssl.SSLHandshakeException;
21 import javax.net.ssl.X509ExtendedKeyManager;
22 import javax.net.ssl.X509KeyManager;
23 import javax.security.auth.x500.X500Principal;
24 import java.security.PrivateKey;
25 import java.security.cert.X509Certificate;
26 import java.util.Arrays;
27
28
29
30
31
32
33 final class OpenSslKeyMaterialManager {
34
35
36
37
38
39
40
41 static final String KEY_TYPE_RSA = "RSA";
42 static final String KEY_TYPE_DH_RSA = "DH_RSA";
43 static final String KEY_TYPE_EC = "EC";
44 static final String KEY_TYPE_EC_EC = "EC_EC";
45 static final String KEY_TYPE_EC_RSA = "EC_RSA";
46 static final String KEY_TYPE_EDDSA = "EdDSA";
47
48 private static final int TYPE_RSA = 1;
49 private static final int TYPE_DH_RSA = 1 << 1;
50 private static final int TYPE_EC = 1 << 2;
51 private static final int TYPE_EC_EC = 1 << 3;
52 private static final int TYPE_EC_RSA = 1 << 4;
53 private static final int TYPE_EDDSA = 1 << 5;
54
55 private final OpenSslKeyMaterialProvider provider;
56 private final boolean hasTmpDhKeys;
57
58 OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider, boolean hasTmpDhKeys) {
59 this.provider = provider;
60 this.hasTmpDhKeys = hasTmpDhKeys;
61 }
62
63 void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException {
64
65
66
67
68 if (engine.isTLSv13() && engine.getHandshakeSession() instanceof ExtendedSSLSession) {
69 ExtendedSSLSession session = (ExtendedSSLSession) engine.getHandshakeSession();
70 int seenTypes = 0;
71 for (String algorithm : session.getPeerSupportedSignatureAlgorithms()) {
72 int typeBit = resolveSignatureAlgorithmKeyTypeBit(algorithm);
73 if (typeBit == 0 || (seenTypes & typeBit) != 0) {
74 continue;
75 }
76
77 seenTypes |= typeBit;
78
79 String alias = chooseServerAlias(engine, keyTypeString(typeBit));
80 if (alias != null) {
81 setKeyMaterial(engine, alias);
82 return;
83 }
84 }
85 }
86
87 String[] authMethods = engine.authMethods();
88 if (authMethods.length == 0) {
89 throw new SSLHandshakeException("Unable to find key material");
90 }
91
92
93
94
95
96 int seenTypes = 0;
97 for (String authMethod : authMethods) {
98 int typeBit = resolveKeyTypeBit(authMethod);
99 if (typeBit == 0 || (seenTypes & typeBit) != 0) {
100 continue;
101 }
102
103 seenTypes |= typeBit;
104
105 String keyType = keyTypeString(typeBit);
106 String alias = chooseServerAlias(engine, keyType);
107 if (alias != null) {
108 setKeyMaterial(engine, alias);
109 return;
110 }
111 }
112
113 if (hasTmpDhKeys && authMethods.length == 1 &&
114 ("DH_anon".equals(authMethods[0]) || "ECDH_anon".equals(authMethods[0]))) {
115 return;
116 }
117 throw new SSLHandshakeException("Unable to find key material for auth method(s): "
118 + Arrays.toString(authMethods));
119 }
120
121 private static int resolveSignatureAlgorithmKeyTypeBit(String algorithm) {
122 if ("Ed25519".equals(algorithm) || "Ed448".equals(algorithm)) {
123 return TYPE_EDDSA;
124 }
125 if (algorithm.endsWith("withECDSA")) {
126 return TYPE_EC;
127 }
128 if (algorithm.endsWith("withRSA")) {
129 return TYPE_RSA;
130 }
131 return 0;
132 }
133
134 private static int resolveKeyTypeBit(String authMethod) {
135 switch (authMethod) {
136 case "RSA":
137 case "DHE_RSA":
138 case "ECDHE_RSA":
139 return TYPE_RSA;
140 case "DH_RSA":
141 return TYPE_DH_RSA;
142 case "ECDHE_ECDSA":
143 return TYPE_EC;
144 case "ECDH_ECDSA":
145 return TYPE_EC_EC;
146 case "ECDH_RSA":
147 return TYPE_EC_RSA;
148 default:
149 return 0;
150 }
151 }
152
153 private static String keyTypeString(int typeBit) {
154 switch (typeBit) {
155 case TYPE_RSA: return KEY_TYPE_RSA;
156 case TYPE_DH_RSA: return KEY_TYPE_DH_RSA;
157 case TYPE_EC: return KEY_TYPE_EC;
158 case TYPE_EC_EC: return KEY_TYPE_EC_EC;
159 case TYPE_EC_RSA: return KEY_TYPE_EC_RSA;
160 case TYPE_EDDSA: return KEY_TYPE_EDDSA;
161 default: return null;
162 }
163 }
164
165 void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
166 X500Principal[] issuer) throws SSLException {
167 String alias = chooseClientAlias(engine, keyTypes, issuer);
168
169
170
171 if (alias != null) {
172 setKeyMaterial(engine, alias);
173 }
174 }
175
176 private void setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException {
177 OpenSslKeyMaterial keyMaterial = null;
178 try {
179 keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
180 if (keyMaterial == null) {
181 return;
182 }
183 engine.setKeyMaterial(keyMaterial);
184 } catch (SSLException e) {
185 throw e;
186 } catch (Exception e) {
187 throw new SSLException(e);
188 } finally {
189 if (keyMaterial != null) {
190 keyMaterial.release();
191 }
192 }
193 }
194 private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
195 String[] keyTypes, X500Principal[] issuer) {
196 X509KeyManager manager = provider.keyManager();
197 if (manager instanceof X509ExtendedKeyManager) {
198 return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine);
199 }
200 return manager.chooseClientAlias(keyTypes, issuer, null);
201 }
202
203 private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
204 X509KeyManager manager = provider.keyManager();
205 if (manager instanceof X509ExtendedKeyManager) {
206 return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine);
207 }
208 return manager.chooseServerAlias(type, null, null);
209 }
210 }