1
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 package dk.sosi.seal.tool;
30
31 import dk.sosi.seal.ssl.HttpsConnector;
32 import dk.sosi.seal.vault.*;
33 import dk.sosi.seal.vault.renewal.CredentialPairRenewer;
34
35 import java.io.*;
36 import java.security.KeyStore;
37 import java.security.KeyStoreException;
38 import java.security.NoSuchAlgorithmException;
39 import java.security.cert.CertificateException;
40 import java.security.cert.X509Certificate;
41 import java.util.Enumeration;
42 import java.util.Properties;
43 import java.util.jar.*;
44
45
46
47
48
49
50
51
52
53
54 public class SealCommands {
55 private static final String KEYSTORE_FILENAME = "SealKeystore.jks";
56
57 private CredentialPairRenewer credentialPairRenewer;
58 private HttpsConnector httpsConnector;
59 private Properties properties;
60
61 public SealCommands(Properties properties) {
62 this.properties = properties;
63 }
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public void importCertificate(File vaultPath, File certPath, String keystorePassword, String alias, boolean createVault) throws SealToolException {
82
83 if (!vaultPath.exists()) {
84 if (createVault) {
85 System.out.println("The supplied vault file " + vaultPath + " does not exist. Attempts to create it");
86 initKeystore(vaultPath, keystorePassword);
87 } else {
88 throw new SealToolException("The supplied vault file " + vaultPath + " does not exist.");
89 }
90 }
91
92 KeyStore keyStore = getKeyStore(vaultPath, keystorePassword);
93 GenericCredentialVault genericCredentialVault = new GenericCredentialVault(properties, keyStore, keystorePassword);
94 genericCredentialVault.addTrustedCertificate(certPath, alias);
95 saveKeystore(keyStore, vaultPath, keystorePassword);
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public void importPkcs12Keystore(File vaultPath, String keystorePassword, File pkcs12Path, String pkcs12Password) {
112
113 if (!vaultPath.exists()) {
114 System.out.println("The supplied vault file " + vaultPath + " does not exist. Attempts to create it");
115 initKeystore(vaultPath, keystorePassword);
116 }
117
118 KeyStore keyStore = getKeyStore(vaultPath, keystorePassword);
119 GenericCredentialVault genericCredentialVault = new GenericCredentialVault(properties, keyStore, keystorePassword);
120 genericCredentialVault.setSystemCredentialPair(pkcs12Path, pkcs12Password);
121 saveKeystore(keyStore, vaultPath, keystorePassword);
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 @Deprecated
143 public void issueToVault(File vaultPath, String keystorePassword, String referenceNumber, String installationCode, boolean issueTestCertificates) {
144 if (!vaultPath.exists()) {
145 System.out.println("The supplied vault file " + vaultPath + " does not exist. Attempts to create it");
146 initKeystore(vaultPath, keystorePassword);
147 }
148 KeyStore keyStore = getKeyStore(vaultPath, keystorePassword);
149 GenericCredentialVault genericCredentialVault = new GenericCredentialVault(properties, keyStore, keystorePassword);
150
151 TDCCredentialPairIssuer issuer = new TDCCredentialPairIssuer(properties);
152 if(this.httpsConnector != null) {
153 issuer.setHttpsConnector(httpsConnector);
154 }
155 CredentialPair pair = issuer.issue(referenceNumber, installationCode, issueTestCertificates);
156
157 genericCredentialVault.setSystemCredentialPair(pair);
158 saveKeystore(keyStore, vaultPath, keystorePassword);
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173 public void removeAlias(File vaultPath, String keystorePassword, String alias) throws SealToolException {
174
175 if (!vaultPath.exists()) {
176 System.out.println("The supplied vault file " + vaultPath + " does not exist. Attempts to create it");
177 initKeystore(vaultPath, keystorePassword);
178 }
179 KeyStore keyStore = getKeyStore(vaultPath, keystorePassword);
180 try {
181 if (!keyStore.containsAlias(alias)) {
182 throw new SealToolException("No such alias in keystore '" + alias + "'");
183 }
184 keyStore.deleteEntry(alias);
185 } catch (KeyStoreException e) {
186 throw new SealToolException("Unable to delete alias " + alias, e);
187 }
188 saveKeystore(keyStore, vaultPath, keystorePassword);
189 }
190
191
192
193
194
195
196
197
198
199
200
201 public void list(File vaultPath, String password) throws SealToolException {
202 KeyStore keyStore = getKeyStore(vaultPath, password);
203 list(keyStore);
204 }
205
206
207
208
209
210
211
212
213
214
215 public void list(String keyStorePath, String password) throws SealToolException {
216 KeyStore keyStore = getKeyStore(keyStorePath, password);
217 list(keyStore);
218 }
219
220
221 public void setCredentialPairRenewer(CredentialPairRenewer renewer) {
222 this.credentialPairRenewer = renewer;
223 }
224
225 public void setHttpsConnector(HttpsConnector httpsConnector) {
226 this.httpsConnector = httpsConnector;
227 }
228
229
230
231
232
233
234
235
236
237
238
239 @Deprecated
240 public void renewSystemCredentials(File keyStoreFile, String keyStorePassword) throws SealToolException {
241 RenewableFileBasedCredentialVault vault = new RenewableFileBasedCredentialVault(properties, keyStoreFile, keyStorePassword);
242 if(this.credentialPairRenewer != null) {
243 vault.setCredentialPairRenewer(credentialPairRenewer);
244 }
245
246 if(!vault.isRenewalChargeable() || userAcceptsChargeableRenewal()) {
247 vault.renewSystemCredentials();
248 }
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262 @Deprecated
263 public void renewVaultedSystemCredentials(File vaultPath, String password) throws SealToolException {
264
265 if (!vaultPath.exists()) {
266 throw new SealToolException("The supplied vault file " + vaultPath + " does not exist.");
267 }
268 KeyStore keyStore = getKeyStore(vaultPath, password);
269 ArchivableCredentialVault vault = new ArchivableCredentialVault(properties, keyStore, password);
270
271 CredentialPairRenewer renewer = getRenewer(vault.getSystemCredentialPair().getCertificate());
272
273 if(!renewer.isRenewalChargeable(vault.getSystemCredentialPair().getCertificate()) || userAcceptsChargeableRenewal()) {
274 CredentialPair renewedPair = renewer.renew(vault.getSystemCredentialPair());
275 vault.archiveSystemCredentials(renewedPair);
276 keyStore = vault.getKeyStore();
277 saveKeystore(keyStore, vaultPath, password);
278 }
279 }
280
281
282
283
284
285 private CredentialPairRenewer getRenewer(X509Certificate certificate) {
286 if(this.credentialPairRenewer != null) {
287 return this.credentialPairRenewer;
288 } else {
289 return CredentialPairRenewer.createInstance(certificate, properties);
290 }
291 }
292
293 private boolean userAcceptsChargeableRenewal() throws SealToolException {
294 System.out.println("Renewal of the system certificate will not be free of charge.\n\n" +
295 "Do you wish to renew the system certificate? (y/n)");
296 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
297 try {
298 String line = reader.readLine();
299 while(!(line.equals("y") || line.equals("n"))) {
300 System.out.println("You must reply by typing either \"y\" or \"n\":");
301 line = reader.readLine();
302 }
303 return line.equals("y");
304 } catch (IOException e) {
305 throw new SealToolException("Failed to read user input", e);
306 }
307 }
308
309
310 private void list(KeyStore keyStore) throws SealToolException {
311
312 Enumeration<String> aliases;
313
314 try {
315 aliases = keyStore.aliases();
316 } catch (KeyStoreException e) {
317 throw new SealToolException("Unable to list content of keystore", e);
318 }
319
320 System.out.println("Listing contents:\n");
321
322 int count = 1;
323 while (aliases.hasMoreElements()) {
324 String alias = aliases.nextElement();
325 String type;
326
327 try {
328 if (keyStore.isCertificateEntry(alias)) {
329 type = "trusted certificate";
330 } else if (keyStore.isKeyEntry(alias)) {
331 int days = getDaysToExpiry((X509Certificate) keyStore.getCertificate(alias));
332 type = "private key, " + days + " days to expiry";
333 } else {
334 type = "unknown";
335 }
336 } catch (KeyStoreException e) {
337 throw new SealToolException("Unable to read keystore entry " + alias, e);
338 }
339
340 System.out.println(count++ + " : " + alias + " (" + type + ")");
341 }
342 }
343
344 private int getDaysToExpiry(X509Certificate cert) {
345 return (int) ((cert.getNotAfter().getTime() - System.currentTimeMillis()) / (24*60*60*1000));
346
347 }
348
349 private KeyStore getKeyStore(File vaultPath, String password) throws SealToolException {
350
351 KeyStore keyStore;
352 try {
353 keyStore = KeyStore.getInstance("JKS");
354 } catch (KeyStoreException e) {
355 throw new SealToolException("Unable to get JKS instance!", e);
356 }
357 JarInputStream jarInputStream = getJarInputStream(vaultPath);
358
359 try {
360 JarEntry jarEntry = jarInputStream.getNextJarEntry();
361 while (jarEntry != null) {
362 if (KEYSTORE_FILENAME.equals(jarEntry.getName())) {
363 try {
364 keyStore.load(jarInputStream, password.toCharArray());
365 } catch (NoSuchAlgorithmException e) {
366 throw new SealToolException("Unable to load keystore from .jar file " + vaultPath, e);
367 } catch (CertificateException e) {
368 throw new SealToolException("Unable to load keystore from .jar file " + vaultPath, e);
369 }
370 }
371 jarEntry = jarInputStream.getNextJarEntry();
372 }
373 } catch (IOException e) {
374 throw new SealToolException("Unable to read from .jar file " + vaultPath, e);
375 } finally {
376 try {
377 jarInputStream.close();
378 } catch (IOException e) {
379 e.printStackTrace();
380 }
381 }
382
383 return keyStore;
384 }
385
386 private KeyStore getKeyStore(String keyStorePath, String password) throws SealToolException {
387
388 KeyStore keyStore;
389 try {
390 keyStore = KeyStore.getInstance("JKS");
391 } catch (KeyStoreException e) {
392 throw new SealToolException("Unable to get JKS instance!", e);
393 }
394
395 try {
396 FileInputStream is = new FileInputStream(new File(keyStorePath));
397 keyStore.load(is, password.toCharArray());
398 is.close();
399 } catch (NoSuchAlgorithmException e) {
400 throw new SealToolException("Unable to load keystore from file " + keyStorePath, e);
401 } catch (CertificateException e) {
402 throw new SealToolException("Unable to load keystore from file " + keyStorePath, e);
403 } catch (IOException e) {
404 throw new SealToolException("Unable to load keystore from file " + keyStorePath, e);
405 }
406
407 return keyStore;
408 }
409
410 private JarInputStream getJarInputStream(File vaultPath) throws SealToolException {
411
412 JarInputStream jarInputStream;
413
414 try {
415 jarInputStream = new JarInputStream(new FileInputStream(vaultPath));
416 } catch (IOException e) {
417 throw new SealToolException("Unable to open .jar file " + vaultPath, e);
418 }
419
420 return jarInputStream;
421 }
422
423 private JarOutputStream getJarOutputStream(File vaultPath) throws SealToolException {
424
425 JarOutputStream jarOutputStream;
426 try {
427 jarOutputStream = new JarOutputStream(new FileOutputStream(vaultPath));
428 } catch (IOException e) {
429 throw new SealToolException("Unable to open .jar file " + vaultPath, e);
430 }
431
432 return jarOutputStream;
433 }
434
435 private void saveKeystore(KeyStore keyStore, File vaultPath, String keystorePassword) {
436
437 JarOutputStream jos = getJarOutputStream(vaultPath);
438 JarEntry entry = new JarEntry(ClasspathCredentialVault.KEYSTORE_FILENAME);
439 try {
440 jos.putNextEntry(entry);
441 } catch (IOException e) {
442 throw new SealToolException("Unable to add jar entry", e);
443 }
444
445 try {
446 keyStore.store(jos, keystorePassword.toCharArray());
447 } catch (KeyStoreException e) {
448 throw new SealToolException("Unable to save keystore back to file", e);
449 } catch (IOException e) {
450 throw new SealToolException("Unable to save keystore back to file", e);
451 } catch (NoSuchAlgorithmException e) {
452 throw new SealToolException("Unable to save keystore back to file", e);
453 } catch (CertificateException e) {
454 throw new SealToolException("Unable to save keystore back to file", e);
455 } finally {
456 try {
457 jos.close();
458 } catch (IOException e) {
459 e.printStackTrace();
460 }
461 }
462 }
463
464
465
466
467
468
469
470
471
472
473
474 private void initKeystore(File vaultPath, String keystorePassword) throws SealToolException {
475
476 KeyStore keyStore;
477 try {
478 keyStore = KeyStore.getInstance("JKS");
479 keyStore.load(null, keystorePassword.toCharArray());
480 } catch (KeyStoreException e) {
481 throw new SealToolException("Unable to create empty keystore", e);
482 } catch (IOException e) {
483 throw new SealToolException("Unable to create empty keystore", e);
484 } catch (NoSuchAlgorithmException e) {
485 throw new SealToolException("Unable to create empty keystore", e);
486 } catch (CertificateException e) {
487 throw new SealToolException("Unable to create empty keystore", e);
488 }
489
490 JarOutputStream jarOutputStream = null;
491 try {
492 Manifest manifest = new Manifest();
493 Attributes attrCreatedBy = new Attributes();
494 attrCreatedBy.putValue("Created-By", "SOSI Seal");
495 manifest.getEntries().put("Created-By", attrCreatedBy);
496
497 Attributes attrSpecTitle = new Attributes();
498 attrSpecTitle.putValue("Specification-Title", "Seal Certificates");
499 manifest.getEntries().put("Specification-Title", attrSpecTitle);
500
501 try {
502 jarOutputStream = new JarOutputStream(new FileOutputStream(vaultPath, true), manifest);
503 } catch (IOException e) {
504 throw new SealToolException("Unable create a jar file for the supplied path " + vaultPath, e);
505 }
506
507 JarEntry jarEntry = new JarEntry(ClasspathCredentialVault.KEYSTORE_FILENAME);
508 jarEntry.setComment("SOSI Seal Keystore");
509 try {
510 jarOutputStream.putNextEntry(jarEntry);
511 } catch (IOException e) {
512 throw new SealToolException("Unable to write keystore to jarfile " + vaultPath, e);
513 }
514 try {
515 keyStore.store(jarOutputStream, keystorePassword.toCharArray());
516 } catch (KeyStoreException e) {
517 throw new SealToolException("Unable to write keystore to jarfile " + vaultPath, e);
518 } catch (IOException e) {
519 throw new SealToolException("Unable to write keystore to jarfile " + vaultPath, e);
520 } catch (NoSuchAlgorithmException e) {
521 throw new SealToolException("Unable to write keystore to jarfile " + vaultPath, e);
522 } catch (CertificateException e) {
523 throw new SealToolException("Unable to write keystore to jarfile " + vaultPath, e);
524 }
525 } finally {
526 try {
527 if (jarOutputStream != null)
528 jarOutputStream.close();
529 } catch (IOException e) {
530 e.printStackTrace();
531 }
532 }
533 }
534
535 }