1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.http.ssl;
20
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.io.Writer;
26 import java.math.BigInteger;
27 import java.net.URL;
28 import java.security.GeneralSecurityException;
29 import java.security.InvalidKeyException;
30 import java.security.Key;
31 import java.security.KeyPair;
32 import java.security.KeyPairGenerator;
33 import java.security.KeyStore;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.NoSuchProviderException;
36 import java.security.SecureRandom;
37 import java.security.SignatureException;
38 import java.security.cert.Certificate;
39 import java.security.cert.CertificateEncodingException;
40 import java.security.cert.X509Certificate;
41 import java.util.Date;
42 import java.util.HashMap;
43 import java.util.Map;
44
45 import javax.security.auth.x500.X500Principal;
46
47 import org.apache.hadoop.conf.Configuration;
48 import org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory;
49 import org.apache.hadoop.security.ssl.SSLFactory;
50 import org.bouncycastle.x509.X509V1CertificateGenerator;
51
52 public class KeyStoreTestUtil {
53
54 public static String getClasspathDir(Class<?> klass) throws Exception {
55 String file = klass.getName();
56 file = file.replace('.', '/') + ".class";
57 URL url = Thread.currentThread().getContextClassLoader().getResource(file);
58 String baseDir = url.toURI().getPath();
59 baseDir = baseDir.substring(0, baseDir.length() - file.length() - 1);
60 return baseDir;
61 }
62
63
64
65
66
67
68
69
70
71
72 public static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
73 throws CertificateEncodingException, InvalidKeyException, IllegalStateException,
74 NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
75 Date from = new Date();
76 Date to = new Date(from.getTime() + days * 86400000l);
77 BigInteger sn = new BigInteger(64, new SecureRandom());
78 KeyPair keyPair = pair;
79 X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
80 X500Principal dnName = new X500Principal(dn);
81
82 certGen.setSerialNumber(sn);
83 certGen.setIssuerDN(dnName);
84 certGen.setNotBefore(from);
85 certGen.setNotAfter(to);
86 certGen.setSubjectDN(dnName);
87 certGen.setPublicKey(keyPair.getPublic());
88 certGen.setSignatureAlgorithm(algorithm);
89 X509Certificate cert = certGen.generate(pair.getPrivate());
90 return cert;
91 }
92
93 public static KeyPair generateKeyPair(String algorithm)
94 throws NoSuchAlgorithmException {
95 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
96 keyGen.initialize(1024);
97 return keyGen.genKeyPair();
98 }
99
100 private static KeyStore createEmptyKeyStore()
101 throws GeneralSecurityException, IOException {
102 KeyStore ks = KeyStore.getInstance("JKS");
103 ks.load(null, null);
104 return ks;
105 }
106
107 private static void saveKeyStore(KeyStore ks, String filename,
108 String password)
109 throws GeneralSecurityException, IOException {
110 FileOutputStream out = new FileOutputStream(filename);
111 try {
112 ks.store(out, password.toCharArray());
113 } finally {
114 out.close();
115 }
116 }
117
118 public static void createKeyStore(String filename,
119 String password, String alias,
120 Key privateKey, Certificate cert)
121 throws GeneralSecurityException, IOException {
122 KeyStore ks = createEmptyKeyStore();
123 ks.setKeyEntry(alias, privateKey, password.toCharArray(),
124 new Certificate[]{cert});
125 saveKeyStore(ks, filename, password);
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140 public static void createKeyStore(String filename,
141 String password, String keyPassword, String alias,
142 Key privateKey, Certificate cert)
143 throws GeneralSecurityException, IOException {
144 KeyStore ks = createEmptyKeyStore();
145 ks.setKeyEntry(alias, privateKey, keyPassword.toCharArray(),
146 new Certificate[]{cert});
147 saveKeyStore(ks, filename, password);
148 }
149
150 public static void createTrustStore(String filename,
151 String password, String alias,
152 Certificate cert)
153 throws GeneralSecurityException, IOException {
154 KeyStore ks = createEmptyKeyStore();
155 ks.setCertificateEntry(alias, cert);
156 saveKeyStore(ks, filename, password);
157 }
158
159 public static <T extends Certificate> void createTrustStore(
160 String filename, String password, Map<String, T> certs)
161 throws GeneralSecurityException, IOException {
162 KeyStore ks = createEmptyKeyStore();
163 for (Map.Entry<String, T> cert : certs.entrySet()) {
164 ks.setCertificateEntry(cert.getKey(), cert.getValue());
165 }
166 saveKeyStore(ks, filename, password);
167 }
168
169 public static void cleanupSSLConfig(String keystoresDir, String sslConfDir)
170 throws Exception {
171 File f = new File(keystoresDir + "/clientKS.jks");
172 f.delete();
173 f = new File(keystoresDir + "/serverKS.jks");
174 f.delete();
175 f = new File(keystoresDir + "/trustKS.jks");
176 f.delete();
177 f = new File(sslConfDir + "/ssl-client.xml");
178 f.delete();
179 f = new File(sslConfDir + "/ssl-server.xml");
180 f.delete();
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196 public static void setupSSLConfig(String keystoresDir, String sslConfDir,
197 Configuration conf, boolean useClientCert)
198 throws Exception {
199 String clientKS = keystoresDir + "/clientKS.jks";
200 String clientPassword = "clientP";
201 String serverKS = keystoresDir + "/serverKS.jks";
202 String serverPassword = "serverP";
203 String trustKS = keystoresDir + "/trustKS.jks";
204 String trustPassword = "trustP";
205
206 File sslClientConfFile = new File(sslConfDir + "/ssl-client.xml");
207 File sslServerConfFile = new File(sslConfDir + "/ssl-server.xml");
208
209 Map<String, X509Certificate> certs = new HashMap<String, X509Certificate>();
210
211 if (useClientCert) {
212 KeyPair cKP = KeyStoreTestUtil.generateKeyPair("RSA");
213 X509Certificate cCert =
214 KeyStoreTestUtil.generateCertificate("CN=localhost, O=client", cKP, 30,
215 "SHA1withRSA");
216 KeyStoreTestUtil.createKeyStore(clientKS, clientPassword, "client",
217 cKP.getPrivate(), cCert);
218 certs.put("client", cCert);
219 }
220
221 KeyPair sKP = KeyStoreTestUtil.generateKeyPair("RSA");
222 X509Certificate sCert =
223 KeyStoreTestUtil.generateCertificate("CN=localhost, O=server", sKP, 30,
224 "SHA1withRSA");
225 KeyStoreTestUtil.createKeyStore(serverKS, serverPassword, "server",
226 sKP.getPrivate(), sCert);
227 certs.put("server", sCert);
228
229 KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs);
230
231 Configuration clientSSLConf = createClientSSLConfig(clientKS, clientPassword,
232 clientPassword, trustKS);
233 Configuration serverSSLConf = createServerSSLConfig(serverKS, serverPassword,
234 serverPassword, trustKS);
235
236 saveConfig(sslClientConfFile, clientSSLConf);
237 saveConfig(sslServerConfFile, serverSSLConf);
238
239 conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "ALLOW_ALL");
240 conf.set(SSLFactory.SSL_CLIENT_CONF_KEY, sslClientConfFile.getName());
241 conf.set(SSLFactory.SSL_SERVER_CONF_KEY, sslServerConfFile.getName());
242 conf.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, useClientCert);
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256 public static Configuration createClientSSLConfig(String clientKS,
257 String password, String keyPassword, String trustKS) {
258 Configuration clientSSLConf = createSSLConfig(SSLFactory.Mode.CLIENT,
259 clientKS, password, keyPassword, trustKS);
260 return clientSSLConf;
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274 public static Configuration createServerSSLConfig(String serverKS,
275 String password, String keyPassword, String trustKS) throws IOException {
276 Configuration serverSSLConf = createSSLConfig(SSLFactory.Mode.SERVER,
277 serverKS, password, keyPassword, trustKS);
278 return serverSSLConf;
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292
293 private static Configuration createSSLConfig(SSLFactory.Mode mode,
294 String keystore, String password, String keyPassword, String trustKS) {
295 String trustPassword = "trustP";
296
297 Configuration sslConf = new Configuration(false);
298 if (keystore != null) {
299 sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
300 FileBasedKeyStoresFactory.SSL_KEYSTORE_LOCATION_TPL_KEY), keystore);
301 }
302 if (password != null) {
303 sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
304 FileBasedKeyStoresFactory.SSL_KEYSTORE_PASSWORD_TPL_KEY), password);
305 }
306 if (keyPassword != null) {
307 sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
308 FileBasedKeyStoresFactory.SSL_KEYSTORE_KEYPASSWORD_TPL_KEY),
309 keyPassword);
310 }
311 if (trustKS != null) {
312 sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
313 FileBasedKeyStoresFactory.SSL_TRUSTSTORE_LOCATION_TPL_KEY), trustKS);
314 }
315 if (trustPassword != null) {
316 sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
317 FileBasedKeyStoresFactory.SSL_TRUSTSTORE_PASSWORD_TPL_KEY),
318 trustPassword);
319 }
320 sslConf.set(FileBasedKeyStoresFactory.resolvePropertyName(mode,
321 FileBasedKeyStoresFactory.SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY), "1000");
322
323 return sslConf;
324 }
325
326
327
328
329
330
331
332
333 public static void saveConfig(File file, Configuration conf)
334 throws IOException {
335 Writer writer = new FileWriter(file);
336 try {
337 conf.writeXml(writer);
338 } finally {
339 writer.close();
340 }
341 }
342 }