1 package net.kwfgrid.gwes.client;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 import java.io.*;
35 import org.apache.commons.io.IOUtils;
36
37 import java.security.*;
38 import java.security.cert.*;
39
40 import javax.net.ssl.*;
41
42 public class CertUtils implements X509TrustManager {
43
44 private X509Certificate[] chain;
45
46 private String truststoreFileName;
47 private String truststorePassphrase;
48 private File truststoreFile;
49 private KeyStore truststore;
50 private X509TrustManager tm;
51
52 private String keystoreFileName;
53 private String keystorePassphrase;
54 private File keystoreFile;
55 private KeyStore keystore;
56 private X509KeyManager[] kms;
57
58 private static CertUtils ourInstance;
59
60
61
62
63
64
65
66
67
68
69 public synchronized static CertUtils getInstance() throws IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException {
70 if (CertUtils.ourInstance == null) {
71 CertUtils.ourInstance = new CertUtils();
72 }
73 return CertUtils.ourInstance;
74 }
75
76
77
78
79
80
81
82
83
84 private CertUtils() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, KeyManagementException {
85 chain = null;
86 setDefaultSystemProperties();
87 truststoreFileName = System.getProperty("javax.net.ssl.trustStore");
88 truststorePassphrase = System.getProperty("javax.net.ssl.trustStorePassword");
89 keystoreFileName = System.getProperty("javax.net.ssl.keyStore");
90 keystorePassphrase = System.getProperty("javax.net.ssl.keyStorePassword");
91 }
92
93 static void setDefaultSystemProperties() {
94 if (System.getProperty("javax.net.ssl.trustStore") == null) {
95 String store = System.getProperty("user.home") + File.separatorChar + ".gwes-truststore.jks";
96 System.out.println("# Using default SSL trust store '"+store+"'...");
97 System.setProperty("javax.net.ssl.trustStore",store);
98 }
99 if (System.getProperty("javax.net.ssl.trustStorePassword") == null) {
100 System.out.println("# Using default SSL trust store password 'changeit'...");
101 System.setProperty("javax.net.ssl.trustStorePassword","changeit");
102 }
103 if (System.getProperty("javax.net.ssl.keyStore") == null) {
104 String store = System.getProperty("user.home") + File.separatorChar + ".gwes-keystore.jks";
105 System.out.println("# Using default SSL key store '"+store+"'...");
106 System.setProperty("javax.net.ssl.keyStore",store);
107 }
108 if (System.getProperty("javax.net.ssl.keyStorePassword") == null) {
109 System.out.println("# Using default SSL key store password 'changeit'...");
110 System.setProperty("javax.net.ssl.keyStorePassword","changeit");
111 }
112 }
113
114 private void copyDefaultJavaTruststore() throws IOException {
115
116 File javadir = new File(System.getProperty("java.home") + File.separatorChar + "lib" + File.separatorChar + "security");
117 File javastore = new File(javadir, "jssecacerts");
118 if (!javastore.isFile()) {
119 javastore = new File(javadir, "cacerts");
120 }
121 System.out.println("# Copying default truststore from "+javastore.getAbsolutePath() + " to "+ truststoreFile.getAbsolutePath() +"...");
122 FileInputStream in = new FileInputStream(javastore);
123 FileOutputStream out = new FileOutputStream(truststoreFile);
124 IOUtils.copy(in,out);
125 IOUtils.closeQuietly(in);
126 IOUtils.closeQuietly(out);
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140 public synchronized boolean installCert(String host, int port) throws NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException, CertificateException {
141 System.out.println("# Opening connection to " + host + ":" + port + "...");
142 chain = null;
143
144
145 try {
146 truststoreFile = new File(truststoreFileName);
147 if (!truststoreFile.isFile()) {
148
149
150 writeEmptyTrustStore();
151 }
152 loadTrustStore();
153 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
154 tmf.init(truststore);
155 tm = (X509TrustManager) tmf.getTrustManagers()[0];
156 } catch (IOException e) {
157 System.out.println("##############################################################################################");
158 System.out.println("TrustStore IOException:");
159 System.out.println(e.getMessage());
160 System.out.println("##############################################################################################");
161 System.out.println("Please use Java property -Djavax.net.ssl.trustStorePassword=<TrustStorePassword> for setting passphrase!");
162 return false;
163 }
164
165
166 try {
167 keystoreFile = new File(keystoreFileName);
168 if (!keystoreFile.isFile()) {
169 writeEmptyKeyStore();
170 }
171 loadKeyStore();
172 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
173 kmf.init(keystore, keystorePassphrase.toCharArray());
174 kms = new X509KeyManager[]{(X509KeyManager)kmf.getKeyManagers()[0]};
175 } catch (FileNotFoundException e) {
176 System.out.println("##############################################################################################");
177 System.out.println("KeyStore FileNotFoundException:");
178 System.out.println(e.getMessage());
179 System.out.println("##############################################################################################");
180 System.out.println("Please create private keystore '"+keystoreFile+"'!");
181 return false;
182 } catch (IOException e) {
183 System.out.println("##############################################################################################");
184 System.out.println("KeyStore IOException:");
185 System.out.println(e.getMessage());
186 System.out.println("##############################################################################################");
187 System.out.println("Please use Java property -Djavax.net.ssl.keyStorePassword=<KeyStorePassword> for setting passphrase!");
188 return false;
189 } catch (UnrecoverableKeyException e) {
190 System.out.println("##############################################################################################");
191 System.out.println("UnrecoverableKeyException:");
192 System.out.println(e.getMessage());
193 System.out.println("##############################################################################################");
194 System.out.println("Please check the passphrase of the key within the keystore '"+keystoreFile+"'!");
195 return false;
196 }
197
198
199 SSLContext context = SSLContext.getInstance("TLS");
200 context.init(kms, new TrustManager[]{this}, null);
201 SSLSocketFactory socketFactory = context.getSocketFactory();
202 SSLSocket socket = (SSLSocket) socketFactory.createSocket(host, port);
203 socket.setSoTimeout(10000);
204 try {
205 System.out.println("# Starting SSL handshake...");
206 socket.startHandshake();
207 socket.close();
208 System.out.println();
209 System.out.println("# No errors, certificate is already trusted");
210 printCertificateChain();
211 return false;
212 } catch (javax.net.ssl.SSLHandshakeException e) {
213 System.out.println();
214 System.out.println("##############################################################################################");
215 System.out.println("SSL Handshake Exception:");
216 System.out.println(e.getMessage());
217 System.out.println("##############################################################################################");
218 if (chain == null) {
219 System.out.println("Could not obtain server certificate chain");
220 return false;
221 }
222
223
224 if (e.getCause() instanceof sun.security.validator.ValidatorException) {
225 System.out.println("Server certificate not trusted.");
226 return addCertificateToTrustStore(host);
227 }
228
229 if (e.getMessage().indexOf("Received fatal alert: bad_certificate")!=-1) {
230 System.out.println("Please import your private key and certificate into keystore '"+keystoreFileName+"'!");
231 System.out.println("For example using 'keytool':");
232 System.out.println(" keytool -importkeystore -srckeystore <user.p12> -srcstoretype pkcs12 -srcstorepass <keypass> -destkeystore "+keystoreFileName+" -deststoretype jks -deststorepass <keypass>");
233 System.out.println("Replace <user.p12> by the filename of your PKCS12 user key/cert and <keypass> by the corresponding passphrase!");
234 return false;
235 }
236 System.out.println("Unsupported Exception:");
237 e.printStackTrace(System.out);
238 } catch (javax.net.ssl.SSLException e) {
239 System.out.println();
240 System.out.println("##############################################################################################");
241 System.out.println("SSL Exception:");
242 System.out.println(e.getMessage());
243 System.out.println("##############################################################################################");
244 if (chain == null) {
245 System.out.println("Could not obtain server certificate chain");
246 return false;
247 }
248 if (e.getMessage().indexOf("the trustAnchors parameter must be non-empty") != -1) {
249 System.out.println("Truststore is empty. Add server certificate.");
250 return addCertificateToTrustStore(host);
251 }
252 System.out.println("Unsupported Exception:");
253 e.printStackTrace(System.out);
254 }
255
256 return false;
257 }
258
259 private boolean addCertificateToTrustStore(String host) throws NoSuchAlgorithmException, IOException, KeyStoreException, CertificateException {
260 printCertificateChain();
261 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
262 System.out.println("Enter certificate to add to truststore or 'q' to quit: [1]");
263 String line = reader.readLine().trim();
264 int k;
265 try {
266 k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
267 } catch (NumberFormatException e) {
268 System.out.println("truststore not changed");
269 return false;
270 }
271
272 X509Certificate cert = chain[k];
273 String alias = host + "-" + (k + 1);
274 truststore.setCertificateEntry(alias, cert);
275 writeTrustStore();
276
277 System.out.println();
278 System.out.println(cert);
279 System.out.println();
280 System.out.println("Added certificate to truststore '"+ truststoreFile.getAbsolutePath() + "' using alias '" + alias + "'");
281 return true;
282 }
283
284 private void writeEmptyTrustStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
285 System.out.println("# Creating empty truststore '" + truststoreFile + "'...");
286 truststore = KeyStore.getInstance(KeyStore.getDefaultType());
287 truststore.load(null,(truststorePassphrase ==null ? null : truststorePassphrase.toCharArray()));
288 writeTrustStore();
289 }
290
291 private void writeEmptyKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
292 System.out.println("# Creating empty keystore '" + keystoreFile + "'...");
293 keystore = KeyStore.getInstance(KeyStore.getDefaultType());
294 keystore.load(null,(keystorePassphrase ==null ? null : keystorePassphrase.toCharArray()));
295 writeKeyStore();
296 }
297
298 private void loadTrustStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
299
300 System.out.println("# Loading truststore '" + truststoreFile + "'...");
301 truststore = KeyStore.getInstance(KeyStore.getDefaultType());
302 if (truststoreFile.length()>0L) {
303 InputStream in = new FileInputStream(truststoreFile);
304 truststore.load(in, (truststorePassphrase ==null ? null : truststorePassphrase.toCharArray()));
305 in.close();
306 } else {
307 truststore.load(null, (truststorePassphrase ==null ? null : truststorePassphrase.toCharArray()));
308 }
309 }
310
311 private void loadKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
312
313 System.out.println("# Loading keystore '" + keystoreFile + "'...");
314 keystore = KeyStore.getInstance(KeyStore.getDefaultType());
315 if (keystoreFile.length()>0L) {
316 InputStream in = new FileInputStream(keystoreFile);
317 keystore.load(in, (keystorePassphrase ==null ? null : keystorePassphrase.toCharArray()));
318 in.close();
319 } else {
320 keystore.load(null, (keystorePassphrase ==null ? null : keystorePassphrase.toCharArray()));
321 }
322 }
323
324 private void writeTrustStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
325 System.out.println("# Writing truststore '" + truststoreFile + "'...");
326 OutputStream out = new FileOutputStream(truststoreFile);
327 truststore.store(out, (truststorePassphrase ==null ? "".toCharArray() : truststorePassphrase.toCharArray()));
328 out.close();
329 }
330
331 private void writeKeyStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
332 System.out.println("# Writing keystore '" + keystoreFile + "'...");
333 OutputStream out = new FileOutputStream(keystoreFile);
334 keystore.store(out, (keystorePassphrase ==null ? "".toCharArray() : keystorePassphrase.toCharArray()));
335 out.close();
336 }
337
338 private void setTrustStorePassword() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
339 System.out.println("# Setting password for new truststore '" + truststoreFile + "'...");
340 InputStream in = new FileInputStream(truststoreFile);
341 truststore = KeyStore.getInstance(KeyStore.getDefaultType());
342 truststore.load(in, null);
343 in.close();
344 writeTrustStore();
345 }
346
347 private void printCertificateChain() throws CertificateEncodingException, NoSuchAlgorithmException {
348 System.out.println();
349 System.out.println("Server sent " + chain.length + " certificate(s):");
350 System.out.println();
351 MessageDigest sha1 = MessageDigest.getInstance("SHA1");
352 MessageDigest md5 = MessageDigest.getInstance("MD5");
353 for (int i = 0; i < chain.length; i++) {
354 X509Certificate cert = chain[i];
355 System.out.println
356 (" " + (i + 1) + " Subject " + cert.getSubjectDN());
357 System.out.println(" Issuer " + cert.getIssuerDN());
358 sha1.update(cert.getEncoded());
359 System.out.println(" Valid from "+cert.getNotBefore());
360 System.out.println(" Valid util "+cert.getNotAfter());
361 System.out.println(" sha1 " + toHexString(sha1.digest()));
362 md5.update(cert.getEncoded());
363 System.out.println(" md5 " + toHexString(md5.digest()));
364 System.out.println();
365 }
366 }
367
368 private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
369
370 private static String toHexString(byte[] bytes) {
371 StringBuilder sb = new StringBuilder(bytes.length * 3);
372 for (int b : bytes) {
373 b &= 0xff;
374 sb.append(HEXDIGITS[b >> 4]);
375 sb.append(HEXDIGITS[b & 15]);
376 sb.append(' ');
377 }
378 return sb.toString();
379 }
380
381 public X509Certificate[] getAcceptedIssuers() {
382 System.out.println("UnsupportedOperationException: getAcceptedIssuers()...");
383 throw new UnsupportedOperationException();
384 }
385
386 public void checkClientTrusted(X509Certificate[] chain, String authType)
387 throws CertificateException {
388 System.out.println("UnsupportedOperationException: checkClientTrusted()...");
389 throw new UnsupportedOperationException();
390 }
391
392 public void checkServerTrusted(X509Certificate[] chain, String authType)
393 throws CertificateException {
394 this.chain = chain;
395 tm.checkServerTrusted(chain, authType);
396 }
397
398 public static void main(String[] args) throws Exception {
399 String host;
400 int port;
401 if (args.length == 1) {
402 String[] c = args[0].split(":");
403 host = c[0];
404 port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
405 } else {
406 System.out.println("--------------------------------------------------------------");
407 System.out.println("Usage: java CertUtils <host>[:port]");
408 System.out.println("--------------------------------------------------------------");
409 System.out.println(" The following java properties are supported:");
410 System.out.println(" -Djavax.net.ssl.trustStore=<TrustStoreFileName>");
411 System.out.println(" -Djavax.net.ssl.trustStorePassword=<TrustStorePassword>");
412 System.out.println(" -Djavax.net.ssl.keyStore=<KeyStoreFileName>");
413 System.out.println(" -Djavax.net.ssl.keyStorePassword=<KeyStorePassword>");
414 System.out.println("--------------------------------------------------------------");
415 return;
416 }
417
418 boolean next = true;
419 while (next) {
420 next = CertUtils.getInstance().installCert(host,port);
421 }
422
423 }
424
425 }