Source code: net/jxta/impl/membership/pse/URIKeyStoreManager.java
1 /************************************************************************
2 *
3 * $Id: URIKeyStoreManager.java,v 1.2 2004/05/05 01:29:38 bondolo Exp $
4 *
5 * Copyright (c) 2001 Sun Microsystems, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Sun Microsystems, Inc. for Project JXTA."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
27 * must not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact Project JXTA at http://www.jxta.org.
30 *
31 * 5. Products derived from this software may not be called "JXTA",
32 * nor may "JXTA" appear in their name, without prior written
33 * permission of Sun.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 *
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of Project JXTA. For more
52 * information on Project JXTA, please see
53 * <http://www.jxta.org/>.
54 *
55 * This license is based on the BSD license adopted by the Apache Foundation.
56 *********************************************************************************/
57
58 package net.jxta.impl.membership.pse;
59
60 import java.io.File;
61 import java.io.FileOutputStream;
62 import java.io.OutputStream;
63 import java.net.URI;
64 import java.security.KeyStore;
65
66 import java.io.IOException;
67 import java.security.KeyStoreException;
68 import java.security.NoSuchProviderException;
69 import java.security.NoSuchAlgorithmException;
70 import java.security.cert.CertificateException;
71
72 import org.apache.log4j.Level;
73 import org.apache.log4j.Logger;
74
75 /**
76 * Manages a Keystore located at at URI. This version precludes KeyStores which
77 * are built from multiple URIs.
78 **/
79 public class URIKeyStoreManager implements KeyStoreManager {
80
81 /**
82 * Log4J Logger
83 **/
84 private final static transient Logger LOG = Logger.getLogger( PSEConfig.class.getName() );
85
86 /**
87 * The default keystore type we will use.
88 **/
89 private final static String DEFAULT_KEYSTORE_TYPE = "jks";
90
91 /**
92 * The keystore type
93 **/
94 private String keystore_type;
95
96 /**
97 * The keystore type
98 **/
99 private String keystore_provider;
100
101 /**
102 * The file where the keystore lives
103 **/
104 private URI keystore_location;
105
106 /**
107 * Default constructor.
108 **/
109 public URIKeyStoreManager( String type, String provider, URI location ) throws NoSuchProviderException, KeyStoreException {
110 if( null == type ) {
111 type = DEFAULT_KEYSTORE_TYPE;
112 provider = null;
113 }
114
115 // special case for forcing bc provider for jdk < 1.5 since jdk 1.4.x
116 // jsse pkcs12 is readonly.
117 if ( "pkcs12".equalsIgnoreCase( type ) ) {
118 if( "BC".equals( provider ) ) {
119 provider = null;
120 }
121
122 boolean hasJDK15 = System.getProperty( "java.specification.version", "0.0" ).compareTo( "1.5" ) >= 0;
123
124 provider = hasJDK15 ? null : "BC";
125 }
126
127 if( !location.isAbsolute() ) {
128 throw new IllegalArgumentException( "location must be an absolute URI" );
129 }
130
131 if( "file".equalsIgnoreCase( location.getScheme() ) ) {
132 File asFile = new File( location );
133
134 if( asFile.exists() && !asFile.isFile() ) {
135 throw new IllegalArgumentException( "location must refer to a file" );
136 }
137 }
138
139 if ( LOG.isEnabledFor(Level.INFO) ) {
140 LOG.info( "pse location = " + location );
141 }
142
143 keystore_type = type;
144
145 keystore_provider = provider;
146
147 keystore_location = location;
148
149 // check if we can get an instance.
150 if( null == keystore_provider ) {
151 KeyStore.getInstance( keystore_type );
152 } else {
153 KeyStore.getInstance( keystore_type, keystore_provider );
154 }
155 }
156
157 /**
158 * {@inheritDoc}
159 **/
160 public boolean isInitialized() {
161 return isInitialized( null );
162 }
163
164 /**
165 * {@inheritDoc}
166 **/
167 public boolean isInitialized(char[] store_password ) {
168 try {
169 KeyStore store;
170 if( null == keystore_provider ) {
171 store = KeyStore.getInstance( keystore_type );
172 } else {
173 store = KeyStore.getInstance( keystore_type, keystore_provider );
174 }
175
176 store.load( keystore_location.toURL().openStream(), store_password );
177
178 return true;
179 } catch( Exception failed ) {
180 return false;
181 }
182 }
183
184 /**
185 * {@inheritDoc}
186 **/
187 public void createKeyStore(char[] store_password ) throws KeyStoreException, IOException {
188 try {
189 KeyStore store;
190 if( null == keystore_provider ) {
191 store = KeyStore.getInstance( keystore_type );
192 } else {
193 store = KeyStore.getInstance( keystore_type, keystore_provider );
194 }
195
196 store.load( null, store_password );
197
198 saveKeyStore( store, store_password );
199 } catch( NoSuchProviderException failed ) {
200 KeyStoreException failure = new KeyStoreException( "NoSuchProviderException during keystore processing" );
201 failure.initCause( failed );
202 throw failure;
203 } catch( NoSuchAlgorithmException failed ) {
204 KeyStoreException failure = new KeyStoreException( "NoSuchAlgorithmException during keystore processing" );
205 failure.initCause( failed );
206 throw failure;
207 } catch( CertificateException failed ) {
208 KeyStoreException failure = new KeyStoreException( "CertificateException during keystore processing" );
209 failure.initCause( failed );
210 throw failure;
211 }
212 }
213
214 /**
215 * {@inheritDoc}
216 **/
217 public KeyStore loadKeyStore(char[] password) throws KeyStoreException, IOException {
218
219 if ( LOG.isEnabledFor(Level.DEBUG) ) {
220 LOG.debug( "Loading (" + keystore_type + "," + keystore_provider + ") store from " + keystore_location );
221 }
222
223 try {
224 KeyStore store;
225 if( null == keystore_provider ) {
226 store = KeyStore.getInstance( keystore_type );
227 } else {
228 store = KeyStore.getInstance( keystore_type, keystore_provider );
229 }
230
231 store.load( keystore_location.toURL().openStream(), password );
232
233 return store;
234 } catch( NoSuchAlgorithmException failed ) {
235 KeyStoreException failure = new KeyStoreException( "NoSuchAlgorithmException during keystore processing" );
236 failure.initCause( failed );
237 throw failure;
238 } catch( CertificateException failed ) {
239 KeyStoreException failure = new KeyStoreException( "CertificateException during keystore processing" );
240 failure.initCause( failed );
241 throw failure;
242 } catch( NoSuchProviderException failed ) {
243 KeyStoreException failure = new KeyStoreException( "NoSuchProviderException during keystore processing" );
244 failure.initCause( failed );
245 throw failure;
246 }
247 }
248
249 /**
250 * {@inheritDoc}
251 **/
252 public void saveKeyStore(KeyStore store, char[] password) throws KeyStoreException, IOException {
253
254 if ( LOG.isEnabledFor(Level.DEBUG) ) {
255 LOG.debug( "Writing " + store + " to " + keystore_location );
256 }
257
258 try {
259 OutputStream os = null;
260
261 if( "file".equalsIgnoreCase( keystore_location.getScheme() ) ){
262 os = new FileOutputStream( new File( keystore_location ) );
263 } else {
264 os = keystore_location.toURL().openConnection().getOutputStream();
265 }
266 store.store( os, password );
267 } catch( NoSuchAlgorithmException failed ) {
268 KeyStoreException failure = new KeyStoreException( "NoSuchAlgorithmException during keystore processing" );
269 failure.initCause( failed );
270 throw failure;
271 } catch( CertificateException failed ) {
272 KeyStoreException failure = new KeyStoreException( "CertificateException during keystore processing" );
273 failure.initCause( failed );
274 throw failure;
275 }
276 }
277
278 /**
279 * {@inheritDoc}
280 **/
281 public void eraseKeyStore() {
282
283 if( "file".equalsIgnoreCase( keystore_location.getScheme() ) ) {
284 File asFile = new File( keystore_location );
285
286 if( asFile.exists() && asFile.isFile() && asFile.canWrite() ) {
287 asFile.delete();
288 }
289 } else {
290 throw new UnsupportedOperationException( "Unable to delete non-file URI" );
291 }
292 }
293 }