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