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.SSLException;
19 import javax.net.ssl.SSLHandshakeException;
20 import javax.net.ssl.X509ExtendedKeyManager;
21 import javax.net.ssl.X509KeyManager;
22 import javax.security.auth.x500.X500Principal;
23 import java.security.PrivateKey;
24 import java.security.cert.X509Certificate;
25 import java.util.Arrays;
26
27
28
29
30
31
32 final class OpenSslKeyMaterialManager {
33
34
35
36
37
38
39
40 static final String KEY_TYPE_RSA = "RSA";
41 static final String KEY_TYPE_DH_RSA = "DH_RSA";
42 static final String KEY_TYPE_EC = "EC";
43 static final String KEY_TYPE_EC_EC = "EC_EC";
44 static final String KEY_TYPE_EC_RSA = "EC_RSA";
45
46 private static final int TYPE_RSA = 1;
47 private static final int TYPE_DH_RSA = 1 << 1;
48 private static final int TYPE_EC = 1 << 2;
49 private static final int TYPE_EC_EC = 1 << 3;
50 private static final int TYPE_EC_RSA = 1 << 4;
51
52 private final OpenSslKeyMaterialProvider provider;
53 private final boolean hasTmpDhKeys;
54
55 OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider, boolean hasTmpDhKeys) {
56 this.provider = provider;
57 this.hasTmpDhKeys = hasTmpDhKeys;
58 }
59
60 void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException {
61 String[] authMethods = engine.authMethods();
62 if (authMethods.length == 0) {
63 throw new SSLHandshakeException("Unable to find key material");
64 }
65
66
67
68
69
70 int seenTypes = 0;
71 for (String authMethod : authMethods) {
72 int typeBit = resolveKeyTypeBit(authMethod);
73 if (typeBit == 0 || (seenTypes & typeBit) != 0) {
74 continue;
75 }
76
77 seenTypes |= typeBit;
78
79 String keyType = keyTypeString(typeBit);
80 String alias = chooseServerAlias(engine, keyType);
81 if (alias != null) {
82 setKeyMaterial(engine, alias);
83 return;
84 }
85 }
86
87 if (hasTmpDhKeys && authMethods.length == 1 &&
88 ("DH_anon".equals(authMethods[0]) || "ECDH_anon".equals(authMethods[0]))) {
89 return;
90 }
91 throw new SSLHandshakeException("Unable to find key material for auth method(s): "
92 + Arrays.toString(authMethods));
93 }
94
95 private static int resolveKeyTypeBit(String authMethod) {
96 switch (authMethod) {
97 case "RSA":
98 case "DHE_RSA":
99 case "ECDHE_RSA":
100 return TYPE_RSA;
101 case "DH_RSA":
102 return TYPE_DH_RSA;
103 case "ECDHE_ECDSA":
104 return TYPE_EC;
105 case "ECDH_ECDSA":
106 return TYPE_EC_EC;
107 case "ECDH_RSA":
108 return TYPE_EC_RSA;
109 default:
110 return 0;
111 }
112 }
113
114 private static String keyTypeString(int typeBit) {
115 switch (typeBit) {
116 case TYPE_RSA: return KEY_TYPE_RSA;
117 case TYPE_DH_RSA: return KEY_TYPE_DH_RSA;
118 case TYPE_EC: return KEY_TYPE_EC;
119 case TYPE_EC_EC: return KEY_TYPE_EC_EC;
120 case TYPE_EC_RSA: return KEY_TYPE_EC_RSA;
121 default: return null;
122 }
123 }
124
125 void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
126 X500Principal[] issuer) throws SSLException {
127 String alias = chooseClientAlias(engine, keyTypes, issuer);
128
129
130
131 if (alias != null) {
132 setKeyMaterial(engine, alias);
133 }
134 }
135
136 private void setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException {
137 OpenSslKeyMaterial keyMaterial = null;
138 try {
139 keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
140 if (keyMaterial == null) {
141 return;
142 }
143 engine.setKeyMaterial(keyMaterial);
144 } catch (SSLException e) {
145 throw e;
146 } catch (Exception e) {
147 throw new SSLException(e);
148 } finally {
149 if (keyMaterial != null) {
150 keyMaterial.release();
151 }
152 }
153 }
154 private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
155 String[] keyTypes, X500Principal[] issuer) {
156 X509KeyManager manager = provider.keyManager();
157 if (manager instanceof X509ExtendedKeyManager) {
158 return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine);
159 }
160 return manager.chooseClientAlias(keyTypes, issuer, null);
161 }
162
163 private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
164 X509KeyManager manager = provider.keyManager();
165 if (manager instanceof X509ExtendedKeyManager) {
166 return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine);
167 }
168 return manager.chooseServerAlias(type, null, null);
169 }
170 }