Source code: net/jxta/impl/membership/pse/CMKeyStoreManager.java
1 /************************************************************************
2 *
3 * $Id: CMKeyStoreManager.java,v 1.3 2004/11/02 00:59:45 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.ByteArrayOutputStream;
61 import java.io.InputStream;
62 import java.security.KeyStore;
63
64 import java.io.IOException;
65 import java.security.KeyStoreException;
66 import java.security.NoSuchProviderException;
67 import java.security.NoSuchAlgorithmException;
68 import java.security.cert.CertificateException;
69
70 import org.apache.log4j.Level;
71 import org.apache.log4j.Logger;
72
73 import net.jxta.id.ID;
74 import net.jxta.peergroup.PeerGroup;
75
76 import net.jxta.impl.cm.Cm;
77 import net.jxta.impl.peergroup.StdPeerGroup;
78
79 /**
80 * Manages a Keystore located within the JXTA CM.
81 **/
82 public class CMKeyStoreManager implements KeyStoreManager {
83
84 /**
85 * Log4J Logger
86 **/
87 private final static transient Logger LOG = Logger.getLogger( CMKeyStoreManager.class.getName() );
88
89 private final static String DEFAULT_KEYSTORE_TYPE = "jks";
90
91 /**
92 * The keystore type
93 **/
94 private final String keystore_type;
95
96 /**
97 * The keystore type
98 **/
99 private final String keystore_provider;
100
101 /**
102 * The file where the keystore lives
103 **/
104 private final Cm keystore_cm;
105
106 /**
107 * The file where the keystore lives
108 **/
109 private final ID keystore_location;
110
111 /**
112 * Default constructor.
113 **/
114 public CMKeyStoreManager( String type, String provider, PeerGroup group, ID location ) throws NoSuchProviderException, KeyStoreException {
115
116 if( null == type ) {
117 type = DEFAULT_KEYSTORE_TYPE;
118 provider = null;
119 }
120
121 // special case for forcing bc provider for jdk < 1.5 since jdk 1.4.x
122 // jsse pkcs12 is readonly.
123 if ( "pkcs12".equalsIgnoreCase( type ) ) {
124 if( "BC".equals( provider ) ) {
125 provider = null;
126 }
127
128 boolean hasJDK15 = System.getProperty( "java.specification.version", "0.0" ).compareTo( "1.5" ) >= 0;
129
130 if( hasJDK15 ) {
131 provider = null;
132 } else {
133 provider = "BC";
134 }
135 }
136
137 keystore_type = type;
138
139 keystore_provider = provider;
140
141 keystore_cm = ((StdPeerGroup)group).getCacheManager();
142
143 keystore_location = location;
144
145 // check if we can get an instance.
146 if( null == keystore_provider ) {
147 KeyStore.getInstance( keystore_type );
148 } else {
149 KeyStore.getInstance( keystore_type, keystore_provider );
150 }
151
152 if ( LOG.isEnabledFor(Level.INFO) ) {
153 LOG.info( "pse location = " + keystore_location + " in " + keystore_cm );
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 InputStream is = keystore_cm.getInputStream( "Raw", keystore_location.toString() );
177
178 if( null == is ) {
179 return false;
180 }
181
182 store.load( is, store_password );
183
184 return true;
185 } catch( Exception failed ) {
186 return false;
187 }
188 }
189
190 /**
191 * {@inheritDoc}
192 **/
193 public void createKeyStore( char[] store_password ) throws KeyStoreException, IOException {
194 try {
195 KeyStore store;
196 if( null == keystore_provider ) {
197 store = KeyStore.getInstance( keystore_type );
198 } else {
199 store = KeyStore.getInstance( keystore_type, keystore_provider );
200 }
201
202 store.load( null, store_password );
203
204 saveKeyStore( store, store_password );
205 } catch( NoSuchProviderException failed ) {
206 KeyStoreException failure = new KeyStoreException( "NoSuchProviderException during keystore processing" );
207 failure.initCause( failed );
208 throw failure;
209 } catch( NoSuchAlgorithmException failed ) {
210 KeyStoreException failure = new KeyStoreException( "NoSuchAlgorithmException during keystore processing" );
211 failure.initCause( failed );
212 throw failure;
213 } catch( CertificateException failed ) {
214 KeyStoreException failure = new KeyStoreException( "CertificateException during keystore processing" );
215 failure.initCause( failed );
216 throw failure;
217 }
218 }
219
220 /**
221 * Return the keystore instance we are using. i
222 **/
223 public KeyStore loadKeyStore(char[] password) throws KeyStoreException, IOException {
224
225 if ( LOG.isEnabledFor(Level.DEBUG) ) {
226 LOG.debug( "Loading (" + keystore_type + "," + keystore_provider + ") store from " + keystore_location );
227 }
228
229 try {
230 KeyStore store;
231 if( null == keystore_provider ) {
232 store = KeyStore.getInstance( keystore_type );
233 } else {
234 store = KeyStore.getInstance( keystore_type, keystore_provider );
235 }
236
237 InputStream is = keystore_cm.getInputStream( "Raw", keystore_location.toString() );
238
239 store.load( is, password );
240
241 return store;
242 } catch( NoSuchAlgorithmException failed ) {
243 KeyStoreException failure = new KeyStoreException( "NoSuchAlgorithmException during keystore processing" );
244 failure.initCause( failed );
245 throw failure;
246 } catch( CertificateException failed ) {
247 KeyStoreException failure = new KeyStoreException( "CertificateException during keystore processing" );
248 failure.initCause( failed );
249 throw failure;
250 } catch( NoSuchProviderException failed ) {
251 KeyStoreException failure = new KeyStoreException( "NoSuchProviderException during keystore processing" );
252 failure.initCause( failed );
253 throw failure;
254 }
255 }
256
257 /**
258 * Return the keystore instance we are using. includes compatibility code
259 * to force using Bouncy Castle for < JDK 1.5. The JCE 1.4.X PCKS#12
260 * keystore is read only.
261 **/
262 public void saveKeyStore(KeyStore store, char[] password) throws IOException, KeyStoreException {
263
264 if ( LOG.isEnabledFor(Level.DEBUG) ) {
265 LOG.debug( "Writing " + store + " to " + keystore_location );
266 }
267
268 try {
269 ByteArrayOutputStream bos = new ByteArrayOutputStream();
270
271 store.store( bos, password );
272 bos.close();
273
274 keystore_cm.save( "Raw", keystore_location.toString(), bos.toByteArray(), 0, Long.MAX_VALUE );
275 } catch( NoSuchAlgorithmException failed ) {
276 KeyStoreException failure = new KeyStoreException( "NoSuchAlgorithmException during keystore processing" );
277 failure.initCause( failed );
278 throw failure;
279 } catch( CertificateException failed ) {
280 KeyStoreException failure = new KeyStoreException( "CertificateException during keystore processing" );
281 failure.initCause( failed );
282 throw failure;
283 }
284 }
285
286 /**
287 * {@inheritDoc}
288 **/
289 public void eraseKeyStore() throws IOException {
290
291 keystore_cm.remove( "Raw", keystore_location.toString() );
292 }
293 }