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