KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > appserv > management > client > TrustStoreTrustManager


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.appserv.management.client;
24
25 import java.io.File JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.FileOutputStream JavaDoc;
28 import java.io.FileInputStream JavaDoc;
29 import java.io.FileNotFoundException JavaDoc;
30
31 import java.util.Date JavaDoc;
32 import java.text.DateFormat JavaDoc;
33
34 import java.security.KeyStore JavaDoc;
35 import java.security.cert.X509Certificate JavaDoc;
36 import java.security.cert.Certificate JavaDoc;
37 import java.security.cert.CertificateException JavaDoc;
38 import java.security.KeyStoreException JavaDoc;
39 import java.security.NoSuchAlgorithmException JavaDoc;
40 import java.security.UnrecoverableKeyException JavaDoc;
41
42 import javax.net.ssl.X509TrustManager;
43
44 import com.sun.appserv.management.util.misc.LineReaderImpl;
45
46
47 /**
48     This X509TrustManager implementation supports a trust-store file and allows
49     adding new certificates to it. It is designed to allow a subclass to
50     override a variety of protected methods including those of TrustManager:
51     <ul>
52     <li>checkClientTrusted</li>
53     <li>checkServerTrusted</li>
54     <li>getAcceptedIssuers</li>
55     </ul>
56     
57     as well as:
58     
59     <ul>
60     <li>#checkCertificate</li>
61     <li>#getTrustStorePassword</li>
62     <li>#shouldAddToTrustStore</li>
63     <li>#askShouldAddToTrustStore</li>
64     <li>#getCertificateAlias</li>
65     <li>#addCertificateToTrustStore</li>
66     <li>#writeStore</li>
67     <li>#certificateNotInTrustStore</li>
68     <li>#getTrustStore</li>
69     </ul>
70     <p>
71     For convenience, if setPrompt( true ) is called, then when a new Certificate
72     is encountered, askShouldAddToTrustStore( c ) prompts the user
73     via System.in as to whether to accept this new Certificate as trusted.
74     Subclasses can of course override this behavior any any desired way.
75  */

76 public class TrustStoreTrustManager
77     implements X509TrustManager // do NOT make Serializable
78
{
79     private final File JavaDoc mTrustStoreFile;
80     private final char[] mTrustStorePassword;
81     private final String JavaDoc mKeyStoreType;
82     private KeyStore JavaDoc mTrustStore;
83     private boolean mPrompt;
84     
85     /**
86         Create a new instance with the specified File and password
87         The trustStoreFile must exist.
88         
89         @param trustStoreFile (not required to exist)
90         @param keyStoreType keystore (truststore) type, eg "JKS"
91         @param trustStorePassword (may be null)
92      */

93         public
94     TrustStoreTrustManager(
95         final File JavaDoc trustStoreFile,
96         final String JavaDoc keyStoreType,
97         final char[] trustStorePassword )
98     {
99         if ( trustStoreFile == null || keyStoreType == null )
100         {
101             throw new IllegalArgumentException JavaDoc();
102         }
103         
104         mTrustStoreFile = trustStoreFile;
105         mKeyStoreType = keyStoreType;
106         mTrustStorePassword = trustStorePassword;
107         mTrustStore = null;
108         mPrompt = false;
109         
110         try
111         {
112             getTrustStore(); // force initialization now
113
}
114         catch( Exception JavaDoc e )
115         {
116             throw new RuntimeException JavaDoc( e );
117         }
118     }
119     
120     /**
121         calls this( trustStoreFile,"JKS", trustStorePassword )
122      */

123         public
124     TrustStoreTrustManager(
125         final File JavaDoc trustStoreFile,
126         final char[] trustStorePassword )
127     {
128         this( trustStoreFile, "JKS", trustStorePassword );
129     }
130     
131     /**
132         If set to true, then when a new Certificate is encountered, the user
133         will be prompted via System.in as to whether it should be trusted.
134         
135         @param prompt
136      */

137         public void
138     setPrompt( final boolean prompt )
139     {
140         mPrompt = prompt;
141     }
142     
143     /**
144         Create an instance using the system trust-store as returned by
145         getSystemTrustStoreFile().
146         
147         @return an instance or null if not possible
148      */

149         public static TrustStoreTrustManager
150     getSystemInstance()
151     {
152         final File JavaDoc trustStore = getSystemTrustStoreFile();
153         final char[] trustStorePassword = getSystemTrustStorePassword();
154         
155         TrustStoreTrustManager mgr = null;
156         
157         if ( trustStore != null && trustStorePassword != null )
158         {
159             return( new TrustStoreTrustManager( trustStore, trustStorePassword ) );
160         }
161         
162         return( mgr );
163     }
164     
165         private static char[]
166     toCharArray( final String JavaDoc s )
167     {
168         return( s == null ? null : s.toCharArray() );
169     }
170     
171     
172     /**
173         Standard system property denoting the trust-store.
174      */

175     public static final String JavaDoc TRUSTSTORE_FILE_SPROP = "javax.net.ssl.trustStore";
176     
177     /**
178         Standard system property denoting the trust-store password.
179      */

180     public static final String JavaDoc TRUSTSTORE_PASSWORD_SPROP= "javax.net.ssl.trustStorePassword";
181     
182     /**
183         Use System.getProperty( "javax.net.ssl.trustStore" ) to find a trust-store.
184      */

185         public static File JavaDoc
186     getSystemTrustStoreFile()
187     {
188         final String JavaDoc prop = System.getProperty( TRUSTSTORE_FILE_SPROP );
189         final File JavaDoc trustStore = prop == null ? null : new File JavaDoc( prop );
190         return( trustStore );
191     }
192     
193     /**
194         Use System.getProperty( "javax.net.ssl.trustStorePassword" ) to find the
195         trust-store password.
196      */

197         public static char[]
198     getSystemTrustStorePassword()
199     {
200         return( toCharArray( System.getProperty( TRUSTSTORE_PASSWORD_SPROP ) ) );
201     }
202     
203     
204     /**
205         Return the trust-store that was initially passed in.
206         
207         @return File
208      */

209         public final File JavaDoc
210     getTrustStoreFile()
211     {
212         return( mTrustStoreFile );
213     }
214     
215     /**
216         Subclass may choose to override this method to get the password from any
217         desired source. Otherwise, the password used to create this instance is
218         returned.
219         
220         @return char[]
221      */

222         protected char[]
223     getTrustStorePassword()
224     {
225         return( mTrustStorePassword );
226     }
227     
228         public void
229     checkClientTrusted( X509Certificate JavaDoc[] chain, String JavaDoc authType)
230         throws CertificateException JavaDoc
231     {
232         throw new UnsupportedOperationException JavaDoc( "checkClientTrusted() not supported" );
233     }
234     
235         public void
236     checkServerTrusted( X509Certificate JavaDoc[] chain, String JavaDoc authType)
237         throws CertificateException JavaDoc
238     {
239         if (chain == null || chain.length == 0)
240         {
241             throw new IllegalArgumentException JavaDoc();
242         }
243         
244         checkCertificate(chain);
245     }
246     
247     /**
248         By default, no issuers are trusted. It is better to trust specific
249         Certificates explicitly.
250         
251         @return X509Certificate[]
252      */

253         public X509Certificate JavaDoc[]
254     getAcceptedIssuers()
255     {
256         // none, by default
257
return( new X509Certificate JavaDoc[ 0 ] );
258     }
259     
260     /**
261         Prompts via System.in to ask whether the Certificate should be added.
262         
263         @param c
264         @return true if the response is yes.
265      */

266         protected boolean
267     askShouldAddToTrustStore( final Certificate JavaDoc c )
268         throws IOException JavaDoc
269     {
270         final LineReaderImpl reader = new LineReaderImpl( System.in );
271         
272         final String JavaDoc prompt = c.toString() +
273             "\n\nAdd the above certificate to the truststore [y/n]?";
274             
275         final String JavaDoc result = reader.readLine( prompt );
276         
277         return( result.equalsIgnoreCase( "y" ) || result.equalsIgnoreCase( "yes" ) );
278     }
279     
280     /**
281         Subclass may wish to override this routine and call defaultShouldAddToTrustStore( c );
282         
283         @param c
284         @return true if the Certificate should be trusted and added to the trust-store
285      */

286         protected boolean
287     shouldAddToTrustStore( final Certificate JavaDoc c )
288         throws IOException JavaDoc
289     {
290         return( mPrompt ? askShouldAddToTrustStore( c ) : false );
291     }
292     
293     /**
294         Return an alias for a Certificate to be added to the TrustStore.
295         @param c
296         @return an alias to be used for adding the Certificate to the trust-store
297      */

298         protected String JavaDoc
299     getCertificateAlias( final Certificate JavaDoc c )
300     {
301         final DateFormat JavaDoc f = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
302         
303         return( "cert" + f.format( new Date JavaDoc() ) );
304     }
305     
306     
307     /**
308         Add the Certificate with the specified alias to the trust-store.
309         
310         @param alias
311         @param c
312      */

313         protected void
314     addCertificateToTrustStore(
315         final String JavaDoc alias,
316         final Certificate JavaDoc c )
317         throws IOException JavaDoc,
318         KeyStoreException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc
319     {
320         mTrustStore.setCertificateEntry( alias, c );
321         writeStore();
322     }
323     
324     
325     /**
326         Add the Certificate to the trust-store, using the alias returned by
327         getCertificateAlias( c ).
328         
329         @param c
330      */

331         protected void
332     addCertificateToTrustStore( final Certificate JavaDoc c )
333         throws IOException JavaDoc,
334         KeyStoreException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc
335     {
336         final String JavaDoc aliasName = getCertificateAlias( c );
337         
338         addCertificateToTrustStore( aliasName, c );
339     }
340     
341         private void
342     writeStore(
343         final KeyStore JavaDoc trustStore,
344         final char[] trustStorePassword,
345         final File JavaDoc f )
346         throws IOException JavaDoc,
347         KeyStoreException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc
348     {
349         FileOutputStream JavaDoc out = new FileOutputStream JavaDoc( f );
350         
351         try
352         {
353             trustStore.store( out, trustStorePassword );
354         }
355         catch( Throwable JavaDoc t )
356         {
357             t.printStackTrace();
358         }
359         finally
360         {
361             out.close();
362         }
363     }
364     
365     /**
366         Write the store to disk. Results are undefined if an error occurs while
367         writing the file.
368      */

369         protected void
370     writeStore()
371         throws IOException JavaDoc,
372         KeyStoreException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc
373     {
374         writeStore( getTrustStore(), getTrustStorePassword(), getTrustStoreFile() );
375         // NOTE: any exception thrown from here is squelched by calling JDK code
376
// if in the middle of a SSL negotiation
377
}
378     
379     
380     /**
381         The Certificate is not found in the trust-store.
382         If shouldAddToTrustStore( c ) returns false, then a CertificateException
383         is thrown. Otherwise, addCertificateToTrustStore( c ) is called.
384         
385         @param c
386      */

387         protected void
388     certificateNotInTrustStore( final Certificate JavaDoc c )
389         throws IOException JavaDoc,
390         KeyStoreException JavaDoc, NoSuchAlgorithmException JavaDoc, CertificateException JavaDoc
391     {
392         if ( shouldAddToTrustStore( c ) )
393         {
394             addCertificateToTrustStore( c );
395         }
396         else
397         {
398             throw new CertificateException JavaDoc( "Certificate not trusted:\n" + c );
399         }
400     }
401     
402         private void
403     createTrustStoreFile(
404         final KeyStore JavaDoc keyStore,
405         final char[] pw,
406         final File JavaDoc f )
407         throws IOException JavaDoc,
408             CertificateException JavaDoc, NoSuchAlgorithmException JavaDoc,
409             KeyStoreException JavaDoc, FileNotFoundException JavaDoc
410     {
411         f.createNewFile();
412         writeStore( keyStore, pw, f );
413     }
414
415     /**
416         Get the KeyStore containing the Certificates to be trusted. This should
417         be a KeyStore corresponding to the file that was specified. The same
418         KeyStore should be returned each time.
419         
420         @return KeyStore
421      */

422         protected synchronized KeyStore JavaDoc
423     getTrustStore()
424         throws IOException JavaDoc,
425             CertificateException JavaDoc, NoSuchAlgorithmException JavaDoc, KeyStoreException JavaDoc, FileNotFoundException JavaDoc
426     {
427         if ( mTrustStore == null )
428         {
429             mTrustStore = KeyStore.getInstance( mKeyStoreType );
430             final File JavaDoc f = getTrustStoreFile();
431             final char[] pw = getTrustStorePassword();
432             if ( (! f.exists()) || f.length() == 0 )
433             {
434                 f.delete();
435                 mTrustStore.load( null, pw );
436                 createTrustStoreFile( mTrustStore, pw, f);
437             }
438             else
439             {
440                 final FileInputStream JavaDoc is = new FileInputStream JavaDoc( f );
441                 try
442                 {
443                     mTrustStore.load( is, pw );
444                 }
445                 finally
446                 {
447                     is.close();
448                 }
449             }
450         }
451         
452         return( mTrustStore );
453     }
454     
455     /**
456         @param chain
457         @throws RuntimeException
458         @throws CertificateException
459      */

460         protected void
461     checkCertificate( final X509Certificate JavaDoc[] chain)
462         throws RuntimeException JavaDoc, CertificateException JavaDoc
463     {
464         try
465         {
466             //First ensure that the certificate is valid.
467
for (int i = 0 ; i < chain.length ; i ++)
468             {
469                 chain[i].checkValidity();
470             }
471             
472             mTrustStore = getTrustStore();
473             
474             final Certificate JavaDoc cert = chain[ 0 ];
475             
476             //if the certificate already exists in the truststore, it is implicitly trusted
477
if ( mTrustStore.getCertificateAlias( cert ) == null )
478             {
479                 certificateNotInTrustStore( cert );
480             }
481         }
482         catch (CertificateException JavaDoc e)
483         {
484             throw e;
485         }
486         catch (Exception JavaDoc e)
487         {
488             throw new RuntimeException JavaDoc( e );
489         }
490     }
491
492     
493         public String JavaDoc
494     toString()
495     {
496         return( "TrustStoreTrustManager--trusts certificates found in truststore: " + mTrustStore );
497     }
498 }
499
500
501
502
Popular Tags