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.buffer.ByteBufAllocator;
19 import io.netty.internal.tcnative.CertificateRequestedCallback;
20 import io.netty.internal.tcnative.SSL;
21
22 import javax.net.ssl.SSLException;
23 import javax.net.ssl.X509KeyManager;
24 import javax.security.auth.x500.X500Principal;
25 import java.security.PrivateKey;
26 import java.security.cert.X509Certificate;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Map;
30 import java.util.Set;
31
32 import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.freeBio;
33 import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
34
35
36
37
38
39 class OpenSslKeyMaterialManager {
40
41
42
43
44
45
46
47 static final String KEY_TYPE_RSA = "RSA";
48 static final String KEY_TYPE_DH_RSA = "DH_RSA";
49 static final String KEY_TYPE_EC = "EC";
50 static final String KEY_TYPE_EC_EC = "EC_EC";
51 static final String KEY_TYPE_EC_RSA = "EC_RSA";
52
53
54 private static final Map<String, String> KEY_TYPES = new HashMap<String, String>();
55 static {
56 KEY_TYPES.put("RSA", KEY_TYPE_RSA);
57 KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
58 KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
59 KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
60 KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
61 KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
62 KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
63 }
64
65 private final X509KeyManager keyManager;
66 private final String password;
67
68 OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) {
69 this.keyManager = keyManager;
70 this.password = password;
71 }
72
73 void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException {
74 long ssl = engine.sslPointer();
75 String[] authMethods = SSL.authenticationMethods(ssl);
76 Set<String> aliases = new HashSet<String>(authMethods.length);
77 for (String authMethod : authMethods) {
78 String type = KEY_TYPES.get(authMethod);
79 if (type != null) {
80 String alias = chooseServerAlias(engine, type);
81 if (alias != null && aliases.add(alias)) {
82 setKeyMaterial(ssl, alias);
83 }
84 }
85 }
86 }
87
88 CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
89 X500Principal[] issuer) throws SSLException {
90 String alias = chooseClientAlias(engine, keyTypes, issuer);
91 long keyBio = 0;
92 long keyCertChainBio = 0;
93 long pkey = 0;
94 long certChain = 0;
95
96 try {
97
98 X509Certificate[] certificates = keyManager.getCertificateChain(alias);
99 if (certificates == null || certificates.length == 0) {
100 return null;
101 }
102
103 PrivateKey key = keyManager.getPrivateKey(alias);
104 keyCertChainBio = toBIO(certificates);
105 certChain = SSL.parseX509Chain(keyCertChainBio);
106 if (key != null) {
107 keyBio = toBIO(key);
108 pkey = SSL.parsePrivateKey(keyBio, password);
109 }
110 CertificateRequestedCallback.KeyMaterial material = new CertificateRequestedCallback.KeyMaterial(
111 certChain, pkey);
112
113
114
115
116 certChain = pkey = 0;
117 return material;
118 } catch (SSLException e) {
119 throw e;
120 } catch (Exception e) {
121 throw new SSLException(e);
122 } finally {
123 freeBio(keyBio);
124 freeBio(keyCertChainBio);
125 SSL.freePrivateKey(pkey);
126 SSL.freeX509Chain(certChain);
127 }
128 }
129
130 private void setKeyMaterial(long ssl, String alias) throws SSLException {
131 long keyBio = 0;
132 long keyCertChainBio = 0;
133 long keyCertChainBio2 = 0;
134
135 try {
136
137 X509Certificate[] certificates = keyManager.getCertificateChain(alias);
138 if (certificates == null || certificates.length == 0) {
139 return;
140 }
141
142 PrivateKey key = keyManager.getPrivateKey(alias);
143
144
145 PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, certificates);
146 try {
147 keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
148 keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
149
150 if (key != null) {
151 keyBio = toBIO(key);
152 }
153 SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password);
154
155
156 SSL.setCertificateChainBio(ssl, keyCertChainBio2, true);
157 } finally {
158 encoded.release();
159 }
160 } catch (SSLException e) {
161 throw e;
162 } catch (Exception e) {
163 throw new SSLException(e);
164 } finally {
165 freeBio(keyBio);
166 freeBio(keyCertChainBio);
167 freeBio(keyCertChainBio2);
168 }
169 }
170
171 protected String chooseClientAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine,
172 String[] keyTypes, X500Principal[] issuer) {
173 return keyManager.chooseClientAlias(keyTypes, issuer, null);
174 }
175
176 protected String chooseServerAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, String type) {
177 return keyManager.chooseServerAlias(type, null, null);
178 }
179 }