]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/membership/pse/PSEConfig.java
b578083dd703f712da237614dcaac07ac1e0d32b
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / membership / pse / PSEConfig.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56
57 package net.jxta.impl.membership.pse;
58
59
60 import net.jxta.id.ID;
61 import net.jxta.id.IDFactory;
62 import net.jxta.logging.Logging;
63
64 import java.io.IOException;
65 import java.net.URI;
66 import java.net.URISyntaxException;
67 import java.security.*;
68 import java.security.cert.Certificate;
69 import java.security.cert.X509Certificate;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Enumeration;
73 import java.util.List;
74 import java.util.logging.Level;
75 import java.util.logging.Logger;
76
77
78 /**
79  * Manages the state of a Personal Security Enviroment.
80  */
81 public final class PSEConfig {
82
83     /**
84      * Log4J Logger
85      */
86     private final static transient Logger LOG = Logger.getLogger(PSEConfig.class.getName());
87
88     /**
89      * Manager for the keystore we are using.
90      */
91     private final KeyStoreManager keystore_manager;
92
93     /**
94      * The keystore passphrase.
95      */
96     private char[] keystore_password = null;
97
98     /**
99      * Standard constructor.
100      *
101      * @param storeManager   The StoreManager to be used for this PSEConfig
102      *                       instance.
103      * @param store_password The passphrase for the keystore or <tt>null</tt>.
104      *                       The passphrase may be set independantly via
105      *                       {@link #setKeyStorePassword(char[])}.
106      */
107     PSEConfig(KeyStoreManager storeManager, char[] store_password) {
108         this.keystore_manager = storeManager;
109         setKeyStorePassword(store_password);
110     }
111
112     /**
113      * Sets the passphrase to be used when unlocking the keystore.
114      *
115      * @param store_password The passphrase used to unlock the keystore may be
116      *                       {@code null} for keystores with no passphrase.
117      */
118     public final void setKeyStorePassword(char[] store_password) {
119         if (null != this.keystore_password) {
120             Arrays.fill(this.keystore_password, '\0');
121         }
122
123         if (null == store_password) {
124             this.keystore_password = null;
125         } else {
126             this.keystore_password = store_password.clone();
127         }
128     }
129
130     /**
131      * {@inheritDoc}
132      */
133     @Override
134     protected void finalize() throws Throwable {
135         if (null != keystore_password) {
136             Arrays.fill(keystore_password, '\0');
137         }
138
139         super.finalize();
140     }
141
142     /**
143      * Returns {@code true} if the PSE has been initialized (created). Some
144      * keystore formats may not require initialization and may always return
145      * {@code true}. {@code false} may also be returned if the keystore passphrase is
146      * incorrect.
147      *
148      * @return {@code true} if the PSE has been previously initialized
149      *         otherwise {@code false}.
150      */
151     public boolean isInitialized() {
152         try {
153             if (keystore_password != null) {
154                 return keystore_manager.isInitialized(keystore_password);
155             } else {
156                 return keystore_manager.isInitialized();
157             }
158         } catch (Exception ignored) {
159             return false;
160         }
161     }
162
163     /**
164      * Initializes the PSE environment.
165      *
166      * @throws KeyStoreException When the wrong keystore has been provided.
167      * @throws IOException       For errors related to processing the keystore.
168      */
169     public void initialize() throws KeyStoreException, IOException {
170
171         if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
172             LOG.info("Initializing new PSE keystore...");
173         }
174
175         synchronized (keystore_manager) {
176             try {
177                 if (keystore_manager.isInitialized(keystore_password)) {
178                     return;
179                 }
180
181                 keystore_manager.createKeyStore(keystore_password);
182             } catch (KeyStoreException failed) {
183                 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
184                     LOG.log(Level.SEVERE, "Failure accessing or creating keystore.", failed);
185                 }
186
187                 keystore_manager.eraseKeyStore();
188
189                 throw failed;
190             }
191         }
192     }
193
194     /**
195      * Removes an existing PSE enviroment.
196      *
197      * @throws IOException If the PSE cannot be successfully deleted.
198      */
199     public void erase() throws IOException {
200         synchronized (keystore_manager) {
201             keystore_manager.eraseKeyStore();
202         }
203     }
204
205     /**
206      * Gets a copy of the KeyStore associated with this PSE instance. The
207      * returned KeyStore is a copy and not tied to the instance maintained by
208      * the PSE. Changing the returned keystore will not result in changes to
209      * the PSE.
210      *
211      * @return The keystore or {@code null} if it cannot be retrieved.
212      */
213     public KeyStore getKeyStore() {
214         Throwable failure;
215
216         try {
217             return getKeyStore(keystore_password);
218         } catch (KeyStoreException failed) {
219             failure = failed;
220         } catch (IOException failed) {
221             failure = failed;
222         }
223
224         if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
225             LOG.warning("Failure recovering keystore : " + failure);
226         }
227
228         return null;
229     }
230
231     /**
232      * Gets a copy of the KeyStore associated with this PSE instance. The
233      * returned KeyStore is a copy and not tied to the instance maintained by
234      * the PSE. Changing the returned keystore will not result in changes to
235      * the PSE.
236      *
237      * @param store_password The passphrase used to unlock the keystore may be
238      *                       {@code null} for keystores with no passphrase.
239      * @return The keystore.
240      * @throws KeyStoreException When the wrong keystore has been provided.
241      * @throws IOException       For errors related to processing the keystore.
242      * @since JXTA 2.4
243      */
244     public KeyStore getKeyStore(char[] store_password) throws KeyStoreException, IOException {
245         synchronized (keystore_manager) {
246             KeyStore store = keystore_manager.loadKeyStore(store_password);
247
248             return store;
249         }
250     }
251
252     /**
253      * Check if the provided passwords are correct for the specified identity.
254      *
255      * @param id             The identity to be validated.
256      * @param store_password The passphrase used to unlock the keystore may be
257      *                       {@code null} for keystores with no passphrase.
258      * @param key_password   The passphrase associated with the private key or
259      *                       {@code null} if the key has no passphrase.
260      * @return {@code true} if the passwords were valid for the given id
261      *         otherwise {@code false}.
262      */
263     boolean validPasswd(ID id, char[] store_password, char[] key_password) {
264
265         if (null == id) {
266             return false;
267         }
268
269         Throwable failure;
270
271         try {
272             synchronized (keystore_manager) {
273                 KeyStore store;
274
275                 if (null != store_password) {
276                     store = keystore_manager.loadKeyStore(store_password);
277                 } else {
278                     if (null != keystore_password) {
279                         store = keystore_manager.loadKeyStore(keystore_password);
280                     } else {
281                         throw new UnrecoverableKeyException("KeyStore passphrase not initialized");
282                     }
283                 }
284
285                 String alias = id.toString();
286
287                 Key key = store.getKey(alias, key_password);
288
289                 return (null != key);
290             }
291         } catch (UnrecoverableKeyException failed) {
292             failure = failed;
293         } catch (NoSuchAlgorithmException failed) {
294             failure = failed;
295         } catch (KeyStoreException failed) {
296             failure = failed;
297         } catch (IOException failed) {
298             failure = failed;
299         }
300
301         if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
302             LOG.warning("Failure checking passphrase : " + failure);
303         }
304
305         return false;
306     }
307
308     /**
309      * Returns the list of the trusted certificates available in this keystore.
310      *
311      * @return an array of the IDs of the available trusted certificates.
312      * @throws KeyStoreException When the wrong keystore has been provided.
313      * @throws IOException       For errors related to processing the keystore.
314      */
315     public ID[] getTrustedCertsList() throws KeyStoreException, IOException {
316         List<ID> trustedCertsList = new ArrayList<ID>();
317
318         synchronized (keystore_manager) {
319             KeyStore store = keystore_manager.loadKeyStore(keystore_password);
320
321             Enumeration<String> eachAlias = store.aliases();
322
323             while (eachAlias.hasMoreElements()) {
324                 String anAlias = eachAlias.nextElement();
325
326                 if (store.isCertificateEntry(anAlias) || store.isKeyEntry(anAlias)) {
327                     try {
328                         URI id = new URI(anAlias);
329
330                         trustedCertsList.add(IDFactory.fromURI(id));
331                     } catch (URISyntaxException badID) {// ignored
332                     }
333                 }
334             }
335
336             return trustedCertsList.toArray(new ID[trustedCertsList.size()]);
337         }
338     }
339
340     /**
341      * Returns the list of root certificates for which there is an associated
342      * local private key.
343      *
344      * @return an array of the available keys. May be an empty array.
345      * @throws KeyStoreException When the wrong keystore has been provided.
346      * @throws IOException       For errors related to processing the keystore.
347      */
348     public ID[] getKeysList() throws KeyStoreException, IOException {
349         return getKeysList(keystore_password);
350     }
351
352     /**
353      * Returns the list of root certificates for which there is an associated
354      * local private key.
355      *
356      * @param store_password The passphrase used to unlock the keystore may be
357      *                       {@code null} for keystores with no passphrase.
358      * @return an array of the available keys. May be an empty array.
359      * @throws KeyStoreException When the wrong keystore has been provided.
360      * @throws IOException       For errors related to processing the keystore.
361      */
362     ID[] getKeysList(char[] store_password) throws KeyStoreException, IOException {
363         List<ID> keyedRootsList = new ArrayList<ID>();
364
365         synchronized (keystore_manager) {
366             KeyStore store = keystore_manager.loadKeyStore(store_password);
367
368             Enumeration<String> eachAlias = store.aliases();
369
370             while (eachAlias.hasMoreElements()) {
371                 String anAlias = eachAlias.nextElement();
372
373                 if (store.isKeyEntry(anAlias)) {
374                     try {
375                         URI id = new URI(anAlias);
376
377                         keyedRootsList.add(IDFactory.fromURI(id));
378                     } catch (URISyntaxException badID) {// ignored
379                     }
380                 }
381             }
382
383             return keyedRootsList.toArray(new ID[keyedRootsList.size()]);
384         }
385     }
386
387     /**
388      * Returns the ID of the provided certificate or null if the certificate is
389      * not found in the keystore.
390      *
391      * @param cert The certificate who's ID is desired.
392      * @return The ID of the certificate or <tt>null</tt> if no matching
393      *         Certificate was found.
394      * @throws KeyStoreException When the wrong keystore has been provided.
395      * @throws IOException       For errors related to processing the keystore.
396      */
397     public ID getTrustedCertificateID(X509Certificate cert) throws KeyStoreException, IOException {
398
399         String anAlias = null;
400
401         synchronized (keystore_manager) {
402             KeyStore store = keystore_manager.loadKeyStore(keystore_password);
403
404             anAlias = store.getCertificateAlias(cert);
405         }
406
407         // not found.
408         if (null == anAlias) {
409             return null;
410         }
411
412         try {
413             URI id = new URI(anAlias);
414
415             return IDFactory.fromURI(id);
416         } catch (URISyntaxException badID) {
417             return null;
418         }
419     }
420
421     /**
422      * Returns the trusted cert for the specified id.
423      *
424      * @param id The id of the Certificate to retrieve.
425      * @return Certificate for the specified ID or null if the store does not
426      *         contain the specified certificate.
427      * @throws KeyStoreException When the wrong keystore key has been provided.
428      * @throws IOException       For errors related to processing the keystore.
429      */
430     public X509Certificate getTrustedCertificate(ID id) throws KeyStoreException, IOException {
431
432         return getTrustedCertificate(id, keystore_password);
433     }
434
435     /**
436      * Returns the trusted cert for the specified id.
437      *
438      * @param id             The id of the Certificate to retrieve.
439      * @param store_password The passphrase used to unlock the keystore may be
440      *                       {@code null} for keystores with no passphrase.
441      * @return Certificate for the specified ID or null if the store does not
442      *         contain the specified certificate.
443      * @throws KeyStoreException When the wrong keystore has been provided.
444      * @throws IOException       For errors related to processing the keystore.
445      */
446     X509Certificate getTrustedCertificate(ID id, char[] store_password) throws KeyStoreException, IOException {
447
448         String alias = id.toString();
449
450         synchronized (keystore_manager) {
451             KeyStore store = keystore_manager.loadKeyStore(store_password);
452
453             if (!store.containsAlias(alias)) {
454                 return null;
455             }
456
457             return (X509Certificate) store.getCertificate(alias);
458         }
459     }
460
461     /**
462      * Returns the trusted cert chain for the specified id.
463      *
464      * @param id The ID of the certificate who's certificate chain is desired.
465      * @return Certificate chain for the specified ID or null if the PSE does
466      *         not contain the specified certificate.
467      * @throws KeyStoreException When the wrong keystore has been provided.
468      * @throws IOException       For errors related to processing the keystore.
469      */
470     public X509Certificate[] getTrustedCertificateChain(ID id) throws KeyStoreException, IOException {
471
472         String alias = id.toString();
473
474         synchronized (keystore_manager) {
475             KeyStore store = keystore_manager.loadKeyStore(keystore_password);
476
477             if (!store.containsAlias(alias)) {
478                 return null;
479             }
480
481             Certificate certs[] = store.getCertificateChain(alias);
482
483             if (null == certs) {
484                 return null;
485             }
486
487             X509Certificate x509certs[] = new X509Certificate[certs.length];
488
489             System.arraycopy(certs, 0, x509certs, 0, certs.length);
490
491             return x509certs;
492         }
493     }
494
495     /**
496      * Returns the private key for the specified ID.
497      *
498      * @param id           The ID of the requested private key.
499      * @param key_password The passphrase associated with the private key or
500      *                     {@code null} if the key has no passphrase.
501      * @return PrivateKey for the specified ID.
502      * @throws KeyStoreException When the wrong keystore has been provided.
503      * @throws IOException       For errors related to processing the keystore.
504      */
505     public PrivateKey getKey(ID id, char[] key_password) throws KeyStoreException, IOException {
506
507         String alias = id.toString();
508
509         try {
510             synchronized (keystore_manager) {
511                 KeyStore store = keystore_manager.loadKeyStore(keystore_password);
512
513                 if (!store.containsAlias(alias) || !store.isKeyEntry(alias)) {
514                     return null;
515                 }
516
517                 return (PrivateKey) store.getKey(alias, key_password);
518             }
519         } catch (NoSuchAlgorithmException failed) {
520             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
521                 LOG.log(Level.SEVERE, "Something failed", failed);
522             }
523
524             KeyStoreException failure = new KeyStoreException("Something Failed");
525
526             failure.initCause(failed);
527             throw failure;
528         } catch (UnrecoverableKeyException failed) {
529             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
530                 LOG.log(Level.SEVERE, "Key passphrase failure", failed);
531             }
532
533             KeyStoreException failure = new KeyStoreException("Key passphrase failure");
534
535             failure.initCause(failed);
536             throw failure;
537         }
538     }
539
540     /**
541      * Returns <tt>true</tt> if the specified id is associated with a private
542      * key.
543      *
544      * @param id The ID of the requested private key.
545      * @return <tt>true</tt> if a private key with the specified ID is present
546      *         otherwise <tt>false</tt>
547      * @throws KeyStoreException When the wrong keystore has been provided.
548      * @throws IOException       For errors related to processing the keystore.
549      */
550     public boolean isKey(ID id) throws KeyStoreException, IOException {
551         return isKey(id, keystore_password);
552     }
553
554     /**
555      * Returns <tt>true</tt> if the specified id is associated with a private
556      * key.
557      *
558      * @param id             The ID of the requested private key.
559      * @param store_password The passphrase used to unlock the keystore may be
560      *                       {@code null} for keystores with no passphrase.
561      * @return <tt>true</tt> if a private key with the specified ID is present
562      *         otherwise <tt>false</tt>
563      * @throws KeyStoreException When the wrong keystore has been provided.
564      * @throws IOException       For errors related to processing the keystore.
565      */
566     public boolean isKey(ID id, char[] store_password) throws KeyStoreException, IOException {
567         String alias = id.toString();
568
569         synchronized (keystore_manager) {
570             KeyStore store = keystore_manager.loadKeyStore(store_password);
571
572             return store.containsAlias(alias) & store.isKeyEntry(alias);
573         }
574     }
575
576     /**
577      * Adds a trusted certificate with the specified id to the key store. The
578      * certificate replaces any existing certificate or private key stored at
579      * this ID.
580      *
581      * @param id   The ID under which the certificate will be stored.
582      * @param cert Certificate for the specified ID.
583      * @throws KeyStoreException When the wrong keystore has been provided.
584      * @throws IOException       For errors related to processing the keystore.
585      */
586     public void setTrustedCertificate(ID id, X509Certificate cert) throws KeyStoreException, IOException {
587         String alias = id.toString();
588
589         synchronized (keystore_manager) {
590             KeyStore store = keystore_manager.loadKeyStore(keystore_password);
591
592             store.deleteEntry(alias);
593
594             store.setCertificateEntry(alias, cert);
595
596             keystore_manager.saveKeyStore(store, keystore_password);
597         }
598     }
599
600     /**
601      * Adds a private key to the PSE using the specified ID. The key replaces
602      * any existing certificate or private key stored at this ID. The key is
603      * stored using the provided key passphrase.
604      *
605      * @param id           The ID under which the certificate chain and private key will be stored.
606      * @param certchain    The certificate chain matching the private key.
607      * @param key          The private key to be stored in the kestore.
608      * @param key_password The passphrase associated with the private key or
609      *                     {@code null} if the key has no passphrase.
610      * @throws KeyStoreException When the wrong keystore key has been provided.
611      * @throws IOException       For errors related to processing the keystore.
612      */
613     public void setKey(ID id, Certificate[] certchain, PrivateKey key, char[] key_password) throws KeyStoreException, IOException {
614
615         String alias = id.toString();
616
617         synchronized (keystore_manager) {
618             KeyStore store = keystore_manager.loadKeyStore(keystore_password);
619
620             // Remove any existing entry.
621             store.deleteEntry(alias);
622
623             store.setKeyEntry(alias, key, key_password, certchain);
624
625             keystore_manager.saveKeyStore(store, keystore_password);
626         }
627     }
628
629     /**
630      * Erases the specified id from the keystore.
631      *
632      * @param id The ID of the key or certificate to be deleted.
633      * @throws KeyStoreException When the wrong keystore password has been
634      *                           provided.
635      * @throws IOException       For errors related to processing the keystore.
636      */
637     public void erase(ID id) throws KeyStoreException, IOException {
638         String alias = id.toString();
639
640         synchronized (keystore_manager) {
641             KeyStore store = keystore_manager.loadKeyStore(keystore_password);
642
643             store.deleteEntry(alias);
644
645             keystore_manager.saveKeyStore(store, keystore_password);
646         }
647     }
648 }