KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > boot > KeyStoreManager


1 /*
2  * SSL-Explorer
3  *
4  * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */

19             
20 package com.sslexplorer.boot;
21
22 import java.io.ByteArrayInputStream JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.FileInputStream JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.io.OutputStream JavaDoc;
29 import java.security.Key JavaDoc;
30 import java.security.KeyPair JavaDoc;
31 import java.security.KeyStore JavaDoc;
32 import java.security.KeyStoreException JavaDoc;
33 import java.security.Principal JavaDoc;
34 import java.security.PrivateKey JavaDoc;
35 import java.security.PublicKey JavaDoc;
36 import java.security.cert.Certificate JavaDoc;
37 import java.security.cert.X509Certificate JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.Arrays JavaDoc;
40 import java.util.Date JavaDoc;
41 import java.util.Enumeration JavaDoc;
42 import java.util.HashMap JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.List JavaDoc;
45 import java.util.StringTokenizer JavaDoc;
46 import java.util.Vector JavaDoc;
47
48 import org.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50
51 import com.maverick.crypto.asn1.ASN1Sequence;
52 import com.maverick.crypto.asn1.DERInputStream;
53 import com.maverick.crypto.asn1.x509.X509CertificateStructure;
54 import com.maverick.ssl.TrustedCACertStore;
55
56 /**
57  * <p>
58  * Manages one or more keystores. SSL-Explorer currently uses two keystores, one
59  * for the SSL server certificate and one for storing all of the client
60  * certificates.
61  * </p>
62  *
63  * <p>
64  * Before a keystore manager may be used, it must be registered using
65  * {@link #registerKeyStore(String, String, boolean, String, KeyStoreType)}
66  *
67  * <p>
68  * To obtain a keystore, use {@link #getInstance(String)}, passing the keystore
69  * name. If the named keystore has not yet been initialised then it is created
70  * and initialised, otherwise the last used instance is returned.
71  * </p>
72  *
73  * <p>
74  * The key store files are held and manipulated in the <i>conf</i> directory.
75  * All key stores are also updated to the
76  * {@link com.sslexplorer.boot.Repository} which is loaded at start up,
77  * replacing all the files.
78  * </p>
79  *
80  * @author Brett Smith <a HREF="mailto: brett@3sp.com">&lt;brett@3sp.com&gt;</a>
81  * @author Lee David Painter <a HREF="mailto: brett@3sp.com">&lt;lee@3sp.com&gt;</a>
82  * @see com.sslexplorer.boot.Repository
83  */

84 public class KeyStoreManager {
85
86     // Public statics
87

88     /**
89      * The default key store name. Used to store SSL-Explorers own server
90      * certificate
91      */

92     public static final String JavaDoc DEFAULT_KEY_STORE = "default";
93
94     /**
95      * Key store name for Server authentication certificates used to store
96      * certificates to use to connect to other servers
97      */

98     public static final String JavaDoc SERVER_AUTHENTICATION_CERTIFICATES_KEY_STORE = "serverAuthentication";
99
100     /**
101      * Key Store name for Server certificates that are trusted by SSL-Explorer
102      * making outgoing connections to it.
103      */

104     public static final String JavaDoc TRUSTED_SERVER_CERTIFICATES_KEY_STORE = "trustedServer";
105
106     /**
107      * Default password used for storing the untrusted key
108      */

109     public static final String JavaDoc DEFAULT_KEY_PASSWORD = "sslexplorer";
110
111     /**
112      * Repository name
113      */

114     public static final String JavaDoc KEYSTORE_REPOSITORY = "keystore";
115
116     // Private instance variables
117

118     private boolean keyStoreExists;
119     private Date JavaDoc keystoreLastModified;
120     private KeyStore JavaDoc keyStore;
121     private boolean keyStoreEmpty;
122     private File JavaDoc keyStoreFile;
123     private Throwable JavaDoc keyStoreException;
124     private String JavaDoc keyStoreName;
125     private KeyStoreType keyStoreType;
126     private String JavaDoc bundle;
127     private boolean removeable;
128     private String JavaDoc storePassword;
129
130     // Private statics
131
final static Log log = LogFactory.getLog(KeyStoreManager.class);
132     static String JavaDoc KEY_TOOL = System.getProperty("java.home") + File.separator + "bin" + File.separator + "keytool";
133     private static HashMap JavaDoc<String JavaDoc,KeyStoreManager> instances = new HashMap JavaDoc<String JavaDoc,KeyStoreManager>();
134
135     /**
136      * Constant for jks keystore
137      */

138     public static final KeyStoreType TYPE_JKS = new KeyStoreType("JKS", "jks");
139     
140     /**
141      * Constant for pkcs12 keystore
142      */

143     public static final KeyStoreType TYPE_PKCS12 = new KeyStoreType("PKCS12", "p12");
144     
145     private static final List JavaDoc keyStoreTypes = Arrays.asList(new KeyStoreType[] { TYPE_JKS, TYPE_PKCS12 });
146     /**
147      * Constructor. Private to prevent direct instantiation
148      *
149      * @param keyStoreName name of key store
150      * @param bundle bundle key from which to get key store messages (title,
151      * description etc)
152      * @param removeable admin may remove certificates manually in the key store
153      * management page
154      * @param storePassword the keystore password
155      * @param type
156      */

157     private KeyStoreManager(String JavaDoc keyStoreName, String JavaDoc bundle, boolean removeable, String JavaDoc storePassword, KeyStoreType type) {
158         super();
159
160         this.keyStoreName = keyStoreName;
161         this.bundle = bundle;
162         this.removeable = removeable;
163         this.storePassword = storePassword;
164         this.keyStoreType = type;
165         
166         initKeyStoreFile();
167
168         // Make sure that this keystore is synchronized with the repository
169

170         try {
171             synchronizeWithRepository();
172         } catch (IOException JavaDoc ex) {
173             log.error("The keystore could not be synchornized with the repository", ex);
174         }
175     }
176
177     
178     /**
179      * Get an instance of a keystore manager given the keystore name
180      *
181      * @param keyStoreName
182      * @return keyStore instance
183      */

184     public static KeyStoreManager getInstance(String JavaDoc keyStoreName) {
185         KeyStoreManager mgr = (KeyStoreManager) instances.get(keyStoreName);
186         if (mgr == null) {
187             throw new IllegalArgumentException JavaDoc("No keystore named " + keyStoreName);
188         }
189         return mgr;
190     }
191     
192     /**
193      * @return InputStream
194      * @throws IOException
195      */

196     public InputStream JavaDoc getInputStream() throws IOException JavaDoc {
197         return RepositoryFactory.getRepository().getStore(KEYSTORE_REPOSITORY).getEntryInputStream(keyStoreFile.getName());
198     }
199
200     /**
201      * Get a list of registered {@link KeyStoreManager}s.
202      *
203      * @return key stores
204      */

205     public static List JavaDoc<KeyStoreManager> getKeyStores() {
206         List JavaDoc<KeyStoreManager> keyStoreList = new ArrayList JavaDoc<KeyStoreManager>();
207         for (KeyStoreManager manager : instances.values()) {
208             keyStoreList.add(manager);
209         }
210         return keyStoreList;
211     }
212
213     /**
214      * Register a new keystore
215      *
216      * @param name name of keystore
217      * @param bundle bundle for messages
218      * @param removeable <code>true</code> if certificates may manually be
219      * removed
220      * @param storePassword key store password
221      * @param type
222      */

223     public static void registerKeyStore(String JavaDoc name, String JavaDoc bundle, boolean removeable, String JavaDoc storePassword, KeyStoreType type) {
224         if (log.isInfoEnabled())
225             log.info("Registering keystore " + name);
226         KeyStoreManager mgr = new KeyStoreManager(name, bundle, removeable, storePassword, type);
227         instances.put(name, mgr);
228     }
229
230     /**
231      * Set the new store password. Note, this only sets the password to use for
232      * reading the key store. It does not change the password of the key store
233      * itself.
234      *
235      * @param storePassword store password
236      */

237     public void setStorePassword(String JavaDoc storePassword) {
238         this.storePassword = storePassword;
239         reloadKeystore();
240     }
241
242     /**
243      * Get if certificates are removeable by the administrator
244      *
245      * @return removeable
246      */

247     public boolean getRemoveable() {
248         return removeable;
249     }
250
251     /**
252      * Get the bundle that contains messages for this key store
253      *
254      * @return bundle
255      */

256     public String JavaDoc getBundle() {
257         return bundle;
258     }
259
260     /**
261      * Get the name that this key store was registered with
262      *
263      * @return name
264      */

265     public String JavaDoc getName() {
266         return keyStoreName;
267     }
268
269     /**
270      * Get if the keystore currently exists
271      *
272      * @return keystore exists
273      */

274     public boolean isKeyStoreExists() {
275         try {
276             checkKeyStore();
277         } catch (Exception JavaDoc e) {
278             log.error("Could not determine if key store exists.");
279         }
280         return keyStoreExists;
281     }
282
283     /**
284      * Get if the keystore is empty.
285      *
286      * @return keystore is empty
287      */

288     public boolean isKeyStoreEmpty() {
289         try {
290             checkKeyStore();
291         } catch (Exception JavaDoc e) {
292             log.error("Could not determine if key store exists.");
293         }
294         return keyStoreEmpty;
295     }
296
297     /**
298      * Determine whether the certificate with the supplied alias is trusted or
299      * not.
300      *
301      * @param alias certificiate name
302      * @return trust certificate
303      */

304     public boolean isCertificateTrusted(String JavaDoc alias) {
305         try {
306             checkKeyStore();
307             if (isKeyStoreExists() && !isKeyStoreEmpty()) {
308                 return doIsCertificateTrused(alias, keyStore);
309             }
310         } catch (Exception JavaDoc e) {
311             log.error("Could not determine if certificate " + alias + " is trusted.", e);
312         }
313         return false;
314     }
315
316     /**
317      * If there were any errors loading or iniatilising the keystore, this
318      * method will a non-null exception object detailing the error. If the
319      * keystore was loaded successfully then <code>null</code> will be
320      * returned.
321      *
322      * @return exception caught whilst initialising the keystore
323      */

324     public Throwable JavaDoc getKeyStoreException() {
325         checkKeyStore();
326         return keyStoreException;
327     }
328
329     /**
330      * Get the {@link KeyStore} this keystore manager is managing.
331      *
332      * @return keystore
333      */

334     public KeyStore JavaDoc getKeyStore() {
335         if(keyStore==null)
336             this.reloadKeystore();
337         
338         return keyStore;
339     }
340     
341     /**
342      * Get a certificate given its alias.
343      *
344      * @param alias certificate alias.
345      * @return certificate
346      */

347     public Certificate JavaDoc getCertificate(String JavaDoc alias) {
348         try {
349             checkKeyStore();
350             if (isKeyStoreExists() && !isKeyStoreEmpty()) {
351                 return keyStore.getCertificate(alias);
352             }
353         } catch (Exception JavaDoc e) {
354             log.error("Could not get certificate with alias " + alias + ".", e);
355         }
356         return null;
357     }
358
359     /**
360      * Return an enumeration of {@link String} objects aliases or
361      * <code>null</code> if the key store is not loaded.
362      *
363      * @return enumeration of {@link Certificate} objects.
364      */

365     public Enumeration JavaDoc getCertificateAliases() {
366         checkKeyStore();
367         try {
368             if (keyStore != null) {
369                 return keyStore.aliases();
370             }
371         } catch (Exception JavaDoc e) {
372             log.error("Could not get certificates.", e);
373         }
374         return null;
375     }
376
377     /**
378      * Get the number of keys / certificates in this key store
379      *
380      * @return number of keys / certificates in this key store
381      */

382     public int getSize() {
383         checkKeyStore();
384         try {
385             return keyStore != null ? keyStore.size() : 0;
386         } catch (KeyStoreException JavaDoc e) {
387             log.error("Failed to determine size of key store.", e);
388         }
389         return 0;
390     }
391
392     /**
393      * Change the password used to encrypt this key store.
394      *
395      * @param oldPassword old password
396      * @param password new password
397      * @throws Exception on any error
398      */

399     public void changeKeystorePassword(String JavaDoc oldPassword, String JavaDoc password) throws Exception JavaDoc {
400         checkKeyStore();
401         if (!isKeyStoreExists()) {
402             throw new Exception JavaDoc("Key store doesn't exists. Password cannot be changed.");
403         }
404         CommandRunner runner = null;
405         try {
406             Vector JavaDoc<String JavaDoc> v = new Vector JavaDoc<String JavaDoc>();
407             v.add(KEY_TOOL);
408             v.add("-storepasswd");
409             v.add("-new");
410             v.add(password);
411             v.add("-keystore");
412             v.add(getKeyStoreFile().getAbsolutePath());
413             v.add("-storepass");
414             v.add(oldPassword);
415             runner = new CommandRunner(v);
416             runner.runCommand();
417             this.storePassword = password;
418         } catch (Exception JavaDoc e) {
419             log.error("Failed to change keystore password.", e);
420             throw new Exception JavaDoc(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
421         }
422
423     }
424
425     /**
426      * Get a key pair from this key store
427      *
428      * @param alias alias under which the pair is stored
429      * @param password password protecting the keys if any
430      * @return key pair
431      */

432     public KeyPair JavaDoc getKeyPair(String JavaDoc alias, char[] password) {
433         try {
434             checkKeyStore();
435             if (isKeyStoreExists() && !isKeyStoreEmpty()) {
436                 Key JavaDoc key = keyStore.getKey(alias, password);
437                 if (key instanceof PrivateKey JavaDoc) {
438                     Certificate JavaDoc cert = keyStore.getCertificate(alias);
439                     PublicKey JavaDoc publicKey = cert.getPublicKey();
440                     return new KeyPair JavaDoc(publicKey, (PrivateKey JavaDoc) key);
441                 }
442             }
443         } catch (Exception JavaDoc e) {
444             log.error("Could not get key pair with alias " + alias + ".", e);
445         }
446         return null;
447     }
448
449     /**
450      * Get a private key from this key store
451      *
452      * @param alias alias under which the key is stored
453      * @param password password protecting the key if any
454      * @return key
455      */

456     public PrivateKey JavaDoc getPrivateKey(String JavaDoc alias, char[] password) {
457         try {
458             checkKeyStore();
459             if (isKeyStoreExists() && !isKeyStoreEmpty()) {
460                 return (PrivateKey JavaDoc) keyStore.getKey(alias, password);
461             }
462         } catch (Exception JavaDoc e) {
463             log.error("Could not get private key with alias " + alias + ".", e);
464         }
465         return null;
466     }
467
468     /**
469      * Get the chain of certificates from the specified alias up to the root CA
470      * certificate
471      *
472      * @param alias alias
473      * @return certificate chain
474      */

475
476     public Certificate JavaDoc[] getCertificateChain(String JavaDoc alias) {
477         Certificate JavaDoc[] chain = null;
478         try {
479             checkKeyStore();
480             if (isKeyStoreExists() && !isKeyStoreEmpty()) {
481                 chain = keyStore.getCertificateChain(alias);
482             }
483         } catch (Exception JavaDoc e) {
484             log.error(e);
485         }
486         if (chain == null) {
487             log.error("Could not get private key with alias " + alias + ".");
488         }
489         return chain;
490     }
491
492     /**
493      * Utility method to extract an entity from a certificates subject DN
494      *
495      * @param c certificate
496      * @param entity entity to extract
497      * @return entity value
498      */

499     public static String JavaDoc getX509CertificateEntity(X509Certificate JavaDoc c, String JavaDoc entity) {
500         // This assumes the keystore returns the last certificate in the chain
501
// the actual certifcate that is signed by a CA or untrusted cert
502
Principal JavaDoc subjectPrincipal = c.getSubjectDN();
503         StringTokenizer JavaDoc t = new StringTokenizer JavaDoc(subjectPrincipal.getName(), ",");
504         while (t.hasMoreTokens()) {
505             String JavaDoc e = t.nextToken().trim();
506             String JavaDoc f = entity.trim() + "=";
507             if (e.toLowerCase().startsWith(f.toLowerCase())) {
508                 return e.substring(f.length()).trim();
509             }
510         }
511         return "";
512     }
513
514     /**
515      * Reload the key store this manager is managing
516      */

517     public void reloadKeystore() {
518         keyStoreExists = false;
519         keyStoreException = null;
520         keyStoreEmpty = true;
521         keyStore = null;
522         try {
523             File JavaDoc keystoreFile = getKeyStoreFile();
524             InputStream JavaDoc in = null;
525             if (keystoreFile.exists() && keystoreFile.canRead()) {
526                 keyStoreExists = true;
527                 keyStoreException = null;
528                 keyStoreEmpty = true;
529                 keyStore = null;
530                 try {
531                     keyStore = KeyStore.getInstance(keyStoreType.getName());
532                     String JavaDoc keystorePassword = getKeyStorePassword();
533                     if (keystoreFile.length() != 0) {
534                         in = new FileInputStream JavaDoc(keystoreFile);
535                         keyStore.load(in, keystorePassword.toCharArray());
536                         keyStoreEmpty = keyStore.size() == 0;
537                     }
538                 } finally {
539                     Util.closeStream(in);
540                 }
541             } else {
542                 // No change
543
}
544         } catch (Exception JavaDoc e) {
545             log.error("Failed to check key store.", e);
546             keyStoreException = e;
547         }
548     }
549     
550
551     /**
552      * Check the check store to see if it has been modified since it was last
553      * loaded, loading it if it has changed
554      */

555     public void checkKeyStore() {
556         initKeyStoreFile();
557         try {
558             File JavaDoc keystoreFile = getKeyStoreFile();
559             if (keystoreFile.exists() && keystoreFile.canRead()) {
560                 Date JavaDoc fileLastModified = new Date JavaDoc(keystoreFile.lastModified());
561                 if (keystoreLastModified == null || !keystoreLastModified.equals(fileLastModified)) {
562                     keystoreLastModified = fileLastModified;
563                     reloadKeystore();
564                 } else {
565                     // No change
566
}
567             } else {
568                 keyStore = null;
569                 keyStoreExists = false;
570                 keyStoreEmpty = true;
571                 keyStoreException = null;
572             }
573         } catch (Exception JavaDoc e) {
574             log.error("Failed to check key store.", e);
575             keyStoreException = e;
576         }
577     }
578
579     /**
580      * Import a key in PKCS12 key format
581      *
582      * @param keyFile file to import
583      * @param password password for key
584      * @param alias alias for key
585      * @param newAlias
586      * @throws Exception on any error
587      * @return the alias of the key imported
588      */

589     public String JavaDoc importPKCS12Key(File JavaDoc keyFile, String JavaDoc password, String JavaDoc alias, String JavaDoc newAlias) throws Exception JavaDoc {
590         KeyStore JavaDoc kspkcs12 = KeyStore.getInstance("PKCS12");
591         kspkcs12.load(new FileInputStream JavaDoc(keyFile), password == null ? null : password.toCharArray());
592         boolean hasTemp = false;
593         if(isKeyStoreEmpty()) {
594             if(isKeyStoreExists()) {
595                 deleteKeyStore();
596             }
597             createKeyStore();
598             String JavaDoc dname = "cn=tmp, ou=tmp, o=tmp, l=tmp, st=tmp, c=GB";
599             createKey("temporary-key", dname);
600             hasTemp = true;
601             reloadKeystore();
602         }
603         try {
604         
605             String JavaDoc firstAlias = (String JavaDoc) kspkcs12.aliases().nextElement();
606             
607             if(Util.isNullOrTrimmedBlank(alias)) {
608                 log.info("Alias not specified, importing first alias " + firstAlias);
609                 alias = firstAlias;
610             }
611
612             if(Util.isNullOrTrimmedBlank(newAlias)) {
613                 log.info("New alias not specified, using imported alias " + alias);
614                 newAlias = alias;
615             }
616             
617             Certificate JavaDoc c[] = kspkcs12.getCertificateChain(alias);
618             // Make sure we don't have a null chain
619
if (c == null)
620                 c = new Certificate JavaDoc[] {};
621             Key JavaDoc key = kspkcs12.getKey(alias, password == null ? null : password.toCharArray());
622             if(key == null) {
623                 throw new Exception JavaDoc("No alias of '" + alias + "' in imported PKCS12 key file.");
624             }
625             this.keyStore.setKeyEntry(newAlias, key, getKeyStorePassword().toCharArray(), c);
626         } finally {
627             if(hasTemp || keyStore.containsAlias("temporary-key"))
628                 this.keyStore.deleteEntry("temporary-key");
629             OutputStream JavaDoc out = null;
630             try {
631                 out = new FileOutputStream JavaDoc(keyStoreFile.getAbsolutePath());
632                 getKeyStore().store(out, getKeyStorePassword().toCharArray());
633             } finally {
634                 Util.closeStream(out);
635             }
636             updateRepository(false);
637         }
638         
639         return newAlias;
640     }
641
642     /**
643      * Get the key store file this manager is managing
644      *
645      * @return file
646      */

647     public File JavaDoc getKeyStoreFile() {
648         return keyStoreFile;
649     }
650
651     /**
652      * Create a new private key given an alias an DN. Note that the
653      * DN will be escaped as required by RFC2253
654      *
655      * @param alias alias
656      * @param dname DN
657      * @throws Exception on any error
658      */

659     public void createKey(String JavaDoc alias, String JavaDoc dname) throws Exception JavaDoc {
660         checkKeyStore();
661         if (!isKeyStoreExists()) {
662             throw new Exception JavaDoc("Key store doesn't exists. Key cannot be created.");
663         }
664         /*
665          * Because an empty keystore file is not valid, delete the key first
666          * then let genkey create a new keystore
667          */

668         if (isKeyStoreEmpty()) {
669             if (!getKeyStoreFile().delete()) {
670                 throw new Exception JavaDoc("Could not delete key store.");
671             }
672         }
673         CommandRunner runner = null;
674         try {
675             String JavaDoc keyStorePassword = getKeyStorePassword();
676             Vector JavaDoc<String JavaDoc> v = new Vector JavaDoc<String JavaDoc>();
677             v.add(KEY_TOOL);
678             v.add("-genkey");
679             v.add("-alias");
680             v.add(alias);
681             v.add("-keyalg");
682             v.add("RSA");
683             v.add("-keystore");
684             v.add(keyStoreFile.getAbsolutePath());
685             v.add("-dname");
686             v.add(dname);
687             v.add("-storetype");
688             v.add(keyStoreType.getName());
689             v.add("-storepass");
690             v.add(keyStorePassword);
691             v.add("-keypass");
692             v.add(keyStorePassword);
693             v.add("-validity");
694             v.add("365");
695             runner = new CommandRunner(v);
696             runner.runCommand();
697
698             updateRepository(false);
699         } catch (Exception JavaDoc e) {
700             log.error("Failed to create key.", e);
701             throw new Exception JavaDoc(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
702         }
703     }
704
705     /**
706      * Import a certificate from a file and store with the specified a alias.
707      * File must be X509 and Base 64 or DER encoded.
708      *
709      * @param alias alias to store cert. under
710      * @param certFile file contain certificate
711      * @param keyPass key password or <code>null</code> for default
712      * @throws Exception on any error
713      */

714     public void importCert(String JavaDoc alias, File JavaDoc certFile, String JavaDoc keyPass) throws Exception JavaDoc {
715         checkKeyStore();
716         if (!isKeyStoreExists()) {
717             createKeyStore();
718         }
719         /*
720          * Because an empty keystore file is not valid, delete the key first
721          * then let genkey create a new keystore
722          */

723         if (isKeyStoreEmpty()) {
724             if (!getKeyStoreFile().delete()) {
725                 throw new Exception JavaDoc("Could not delete key store.");
726             }
727         }
728         CommandRunner runner = null;
729         try {
730             if (log.isInfoEnabled())
731                 log.info("Importing certificate for " + alias + " from " + certFile.getAbsolutePath());
732             String JavaDoc keyPassword = getKeyStorePassword();
733             Vector JavaDoc<String JavaDoc> v = new Vector JavaDoc<String JavaDoc>();
734             v.add(KEY_TOOL);
735             v.add("-import");
736             v.add("-trustcacerts");
737             
738             v.add("-noprompt");
739             v.add("-file");
740             v.add(certFile.getAbsolutePath());
741             v.add("-alias");
742             v.add(alias);
743             v.add("-keystore");
744             v.add(keyStoreFile.getAbsolutePath());
745             v.add("-storepass");
746             v.add(keyPassword);
747             v.add("-keypass");
748             
749             v.add(keyPass == null ? DEFAULT_KEY_PASSWORD : keyPass);
750             v.add("-storetype");
751             v.add(keyStoreType.getName().toLowerCase());
752             runner = new CommandRunner(v);
753             runner.runCommand();
754
755             updateRepository(false);
756         } catch (Exception JavaDoc e) {
757             log.error("Failed to import certficate.", e);
758             throw new Exception JavaDoc(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
759         }
760         if (log.isInfoEnabled())
761             log.info("Certificate for " + alias + " imported from " + certFile.getAbsolutePath());
762     }
763
764     /**
765      * Generate a certificate sigining request for the key with the specfied
766      * alias.
767      *
768      * @param alias alias to generate CSR for
769      * @param keyPass
770      * @return CSR as a string
771      * @throws Exception on any error
772      */

773     public String JavaDoc generateCSR(String JavaDoc alias, String JavaDoc keyPass) throws Exception JavaDoc {
774         checkKeyStore();
775         if (!isKeyStoreExists()) {
776             throw new Exception JavaDoc("Key store doesn't exists. CSR cannot be generated.");
777         }
778         CommandRunner runner = null;
779         InputStream JavaDoc in = null;
780         try {
781             String JavaDoc keyPassword = getKeyStorePassword();
782             Vector JavaDoc<String JavaDoc> v = new Vector JavaDoc<String JavaDoc>();
783             v.add(KEY_TOOL);
784             v.add("-certreq");
785             v.add("-alias");
786             v.add(alias);
787             v.add("-keyalg");
788             v.add("RSA");
789             v.add("-keystore");
790             v.add(keyStoreFile.getAbsolutePath());
791             v.add("-storepass");
792             v.add(keyPassword);
793             v.add("-file");
794             File JavaDoc csrFile = new File JavaDoc(ContextHolder.getContext().getConfDirectory(), "sslexplorer.csr");
795             v.add(csrFile.getAbsolutePath());
796             v.add("-keypass");
797             v.add(keyPass == null ? DEFAULT_KEY_PASSWORD : keyPass);
798             runner = new CommandRunner(v);
799             runner.runCommand();
800             in = new FileInputStream JavaDoc(csrFile);
801             return Util.loadStreamToString(in, null);
802         } catch (Exception JavaDoc e) {
803             log.error("Failed to create key.", e);
804             throw new Exception JavaDoc(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
805         } finally {
806             Util.closeStream(in);
807         }
808     }
809
810     /**
811      * Create a new key store.
812      * <p>
813      * We dont actually create a keystore, we just create a zero length file as
814      * there doesnt seem to be a way of creating an empty keystore using
815      * keytool.
816      *
817      * @throws IOException on any error
818      */

819     public void createKeyStore() throws IOException JavaDoc {
820         if (isKeyStoreExists()) {
821             throw new IOException JavaDoc("Key store already exists.");
822         }
823         FileOutputStream JavaDoc out = null;
824         try {
825             out = new FileOutputStream JavaDoc(getKeyStoreFile());
826         } finally {
827             Util.closeStream(out);
828         }
829     }
830
831
832     /**
833      * Delete the key store.
834      *
835      * @throws IOException
836      */

837     public void deleteKeyStore() throws IOException JavaDoc {
838         if (!isKeyStoreExists()) {
839             throw new IOException JavaDoc("Key store does not exist.");
840         }
841         if (!getKeyStoreFile().delete()) {
842             throw new IOException JavaDoc("Failed to delete " + getKeyStoreFile().getAbsolutePath() + ".");
843         }
844
845         updateRepository(true);
846     }
847
848     /**
849      * Delete a certificate from the key store given its alias.
850      *
851      * @param alias alias to remove
852      * @throws Exception on any error
853      */

854     public void deleteCertificate(String JavaDoc alias) throws Exception JavaDoc {
855         checkKeyStore();
856         if (!isKeyStoreExists()) {
857             throw new Exception JavaDoc("Key store doesn't exists. Certificate cannot be deleted.");
858         }
859         CommandRunner runner = null;
860         try {
861             if (log.isInfoEnabled())
862                 log.info("Deleting certificate for " + alias);
863             String JavaDoc keyPassword = getKeyStorePassword();
864             Vector JavaDoc<String JavaDoc> v = new Vector JavaDoc<String JavaDoc>();
865             v.add(KEY_TOOL);
866             v.add("-delete");
867             v.add("-alias");
868             v.add(alias);
869             v.add("-keystore");
870             v.add(keyStoreFile.getAbsolutePath());
871             v.add("-storepass");
872             v.add(keyPassword);
873             runner = new CommandRunner(v);
874             runner.runCommand();
875
876             updateRepository(false);
877         } catch (Exception JavaDoc e) {
878             log.error("Failed to delete certificate.", e);
879             throw new Exception JavaDoc(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
880         }
881         if (log.isInfoEnabled())
882             log.info("Deleted certificate for " + alias);
883
884     }
885
886     /**
887      * Get a {@link KeyStoreType} given its name.
888      *
889      * @param name key store type name
890      * @return key store type
891      */

892     public static KeyStoreType getKeyStoreType(String JavaDoc name) {
893         for (Iterator JavaDoc i = keyStoreTypes.iterator(); i.hasNext();) {
894             KeyStoreType t = (KeyStoreType) i.next();
895             if (t.getName().equals(name)) {
896                 return t;
897             }
898         }
899         return null;
900     }
901
902     /**
903      * Get a list of supported {@link KeyStoreType} objects.
904      *
905      * @return list of support key store types
906      */

907     public List JavaDoc getSupportedKeyStoreTypes() {
908         return keyStoreTypes;
909     }
910
911     /**
912      * Set the key store type for this key store manager.
913      *
914      * @param keyStoreType key store type
915      */

916     public void setKeyStoreType(KeyStoreType keyStoreType) {
917         this.keyStoreType = keyStoreType;
918         initKeyStoreFile();
919     }
920
921     /**
922      * Get the key store type for this key store manager.
923      *
924      * @return key store type
925      */

926     public KeyStoreType getKeyStoreType() {
927         return keyStoreType;
928     }
929
930     // Supporting methods
931

932     void initKeyStoreFile() {
933         this.keyStoreFile = new File JavaDoc(ContextHolder.getContext().getConfDirectory(), keyStoreName + ".keystore." + keyStoreType.getExtension());
934     }
935
936     void synchronizeWithRepository() throws IOException JavaDoc {
937
938         RepositoryStore store = RepositoryFactory.getRepository().getStore(KEYSTORE_REPOSITORY);
939
940         if (!store.hasEntry(keyStoreFile.getName())) {
941             keyStoreFile.createNewFile();
942         } else {
943             InputStream JavaDoc in = null;
944             OutputStream JavaDoc out = null;
945             try {
946                 in = store.getEntryInputStream(keyStoreFile.getName());
947                 out = new FileOutputStream JavaDoc(keyStoreFile);
948                 Util.copy(in, out);
949             } finally {
950                 Util.closeStream(in);
951                 Util.closeStream(out);
952             }
953         }
954     }
955     
956     
957
958     void updateRepository(boolean remove) throws IOException JavaDoc {
959
960         RepositoryStore store = RepositoryFactory.getRepository().getStore(KEYSTORE_REPOSITORY);
961
962         if (remove) {
963             store.removeEntry(keyStoreFile.getName());
964         } else {
965             OutputStream JavaDoc out = null;
966             InputStream JavaDoc in = null;
967             try {
968                 out = store.getEntryOutputStream(keyStoreFile.getName());
969                 in = new FileInputStream JavaDoc(keyStoreFile);
970
971                 Util.copy(in, out);
972             } finally {
973                 Util.closeStream(in);
974                 Util.closeStream(out);
975             }
976         }
977
978     }
979
980     /**
981      * Get the key store passwords
982      *
983      * @return keystore password
984      * @throws Exception
985      */

986     public String JavaDoc getKeyStorePassword() throws Exception JavaDoc {
987         return storePassword;
988     }
989
990     boolean doIsCertificateTrused(String JavaDoc alias, KeyStore JavaDoc keyStore) throws Exception JavaDoc {
991
992         Certificate JavaDoc[] certs = keyStore.getCertificateChain(alias);
993         
994         
995 // try {
996
// ((CustomSSLSocketFactory)CustomSSLSocketFactory.getDefault()).checkServerTrusted((X509Certificate[])certs, "");
997
// return true;
998
// } catch(CertificateException ex) {
999
if (certs == null) {
1000            if (log.isInfoEnabled())
1001                log.info("No certs for " + alias + ", untrusted.");
1002        } else if (certs.length > 1) {
1003            X509Certificate JavaDoc x509cert = (X509Certificate JavaDoc) certs[certs.length - 1];
1004            TrustedCACertStore store = new TrustedCACertStore();
1005            ByteArrayInputStream JavaDoc bin = new ByteArrayInputStream JavaDoc(x509cert.getEncoded());
1006            DERInputStream der = null;
1007            try {
1008                der = new DERInputStream(bin);
1009
1010                ASN1Sequence certificate = (ASN1Sequence) der.readObject();
1011                com.maverick.crypto.asn1.x509.X509Certificate x509 = new com.maverick.crypto.asn1.x509.X509Certificate(
1012                    X509CertificateStructure.getInstance(certificate));
1013                return store.isTrustedCertificate(x509, false, false);
1014            } finally {
1015                Util.closeStream(der);
1016            }
1017        }
1018// }
1019
return false;
1020
1021    }
1022
1023    String JavaDoc parseKeytoolOutput(String JavaDoc output) {
1024        if (output.startsWith("keytool error: ")) {
1025            int idx = output.indexOf(':', 14);
1026            if (idx != -1) {
1027                output = output.substring(idx + 1);
1028            }
1029        }
1030        return output;
1031    }
1032
1033    /**
1034     * Deregister a keystore
1035     *
1036     * @param name name of keystore
1037     */

1038    public static void deregisterKeyStore(String JavaDoc name) {
1039        if (log.isInfoEnabled())
1040            log.info("Deregistering keystore " + name);
1041        instances.remove(name);
1042    }
1043    
1044    
1045    
1046}
1047
Popular Tags