1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.geronimo.security.keystore;
19
20 import java.io.BufferedInputStream;
21 import java.io.BufferedOutputStream;
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileNotFoundException;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.math.BigInteger;
31 import java.net.URI;
32 import java.security.InvalidKeyException;
33 import java.security.KeyPair;
34 import java.security.KeyPairGenerator;
35 import java.security.KeyStore;
36 import java.security.KeyStoreException;
37 import java.security.NoSuchAlgorithmException;
38 import java.security.NoSuchProviderException;
39 import java.security.PrivateKey;
40 import java.security.PublicKey;
41 import java.security.SignatureException;
42 import java.security.UnrecoverableKeyException;
43 import java.security.cert.Certificate;
44 import java.security.cert.CertificateEncodingException;
45 import java.security.cert.CertificateException;
46 import java.security.cert.CertificateFactory;
47 import java.security.cert.X509Certificate;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.Date;
51 import java.util.Enumeration;
52 import java.util.HashMap;
53 import java.util.Hashtable;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.Vector;
58 import javax.net.ssl.KeyManager;
59 import javax.net.ssl.KeyManagerFactory;
60 import javax.net.ssl.TrustManager;
61 import javax.net.ssl.TrustManagerFactory;
62 import org.apache.commons.logging.Log;
63 import org.apache.commons.logging.LogFactory;
64 import org.apache.geronimo.gbean.GBeanInfo;
65 import org.apache.geronimo.gbean.GBeanInfoBuilder;
66 import org.apache.geronimo.gbean.GBeanLifecycle;
67 import org.apache.geronimo.gbean.AbstractName;
68 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
69 import org.apache.geronimo.kernel.Kernel;
70 import org.apache.geronimo.management.geronimo.KeyNotFoundException;
71 import org.apache.geronimo.management.geronimo.KeystoreException;
72 import org.apache.geronimo.management.geronimo.KeystoreInstance;
73 import org.apache.geronimo.management.geronimo.KeystoreIsLocked;
74 import org.apache.geronimo.system.serverinfo.ServerInfo;
75 import org.apache.geronimo.util.asn1.ASN1InputStream;
76 import org.apache.geronimo.util.asn1.ASN1Sequence;
77 import org.apache.geronimo.util.asn1.ASN1Set;
78 import org.apache.geronimo.util.asn1.DEROutputStream;
79 import org.apache.geronimo.util.asn1.x509.X509CertificateStructure;
80 import org.apache.geronimo.util.asn1.x509.X509Name;
81 import org.apache.geronimo.util.encoders.Base64;
82 import org.apache.geronimo.util.jce.PKCS10CertificationRequest;
83 import org.apache.geronimo.util.jce.X509Principal;
84 import org.apache.geronimo.util.jce.X509V1CertificateGenerator;
85
86 /**
87 * Implementation of KeystoreInstance that accesses a keystore file on the
88 * local filesystem, identified by the file's name (the last component of
89 * the name only, not the full path).
90 *
91 * @version $Rev: 472514 $ $Date: 2006-11-08 07:07:46 -0800 (Wed, 08 Nov 2006) $
92 */
93 public class FileKeystoreInstance implements KeystoreInstance, GBeanLifecycle {
94 private static final Log log = LogFactory.getLog(FileKeystoreInstance.class);
95 final static String JKS = "JKS";
96 private URI keystorePath;
97 private ServerInfo serverInfo;
98 private File keystoreFile;
99 private String keystoreName;
100 private char[] keystorePassword;
101 private Map keyPasswords = new HashMap();
102 private Kernel kernel;
103 private AbstractName abstractName;
104 private char[] openPassword;
105
106 private List privateKeys = new ArrayList();
107 private List trustCerts = new ArrayList();
108 private KeyStore keystore;
109 private long keystoreReadDate = Long.MIN_VALUE;
110
111 public FileKeystoreInstance(ServerInfo serverInfo, URI keystorePath, String keystoreName, String keystorePassword, String keyPasswords, Kernel kernel, AbstractName abstractName) {
112 this.serverInfo = serverInfo;
113 this.keystorePath = keystorePath;
114 this.keystoreName = keystoreName;
115 this.kernel = kernel;
116 this.abstractName = abstractName;
117 this.keystorePassword = keystorePassword == null ? null : keystorePassword.toCharArray();
118 if(keyPasswords != null) {
119 String[] keys = keyPasswords.split("\\]\\!\\[");
120 for (int i = 0; i < keys.length; i++) {
121 String key = keys[i];
122 int pos = key.indexOf('=');
123 this.keyPasswords.put(key.substring(0, pos), key.substring(pos+1).toCharArray());
124 }
125 }
126 }
127
128 public void doStart() throws Exception {
129 keystoreFile = new File(serverInfo.resolveServer(keystorePath));
130 if(!keystoreFile.exists() || !keystoreFile.canRead()) {
131 throw new IllegalArgumentException("Invalid keystore file ("+keystorePath+" = "+keystoreFile.getAbsolutePath()+")");
132 }
133 }
134
135 public void doStop() throws Exception {
136 }
137
138 public void doFail() {
139 }
140
141 public static final GBeanInfo GBEAN_INFO;
142
143 static {
144 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(FileKeystoreInstance.class, NameFactory.KEYSTORE_INSTANCE);
145 infoFactory.addAttribute("keystorePath", URI.class, true, false);
146 infoFactory.addAttribute("keystoreName", String.class, true, false);
147 infoFactory.addAttribute("keystorePassword", String.class, true, true);
148 infoFactory.addAttribute("keyPasswords", String.class, true, true);
149 infoFactory.addAttribute("kernel", Kernel.class, false);
150 infoFactory.addAttribute("abstractName", AbstractName.class, false);
151 infoFactory.addReference("ServerInfo", ServerInfo.class, NameFactory.GERONIMO_SERVICE);
152 infoFactory.addInterface(KeystoreInstance.class);
153 infoFactory.setConstructor(new String[]{"ServerInfo","keystorePath", "keystoreName", "keystorePassword", "keyPasswords", "kernel", "abstractName"});
154
155 GBEAN_INFO = infoFactory.getBeanInfo();
156 }
157
158 public static GBeanInfo getGBeanInfo() {
159 return GBEAN_INFO;
160 }
161
162
163
164
165 public String getKeystoreName() {
166 return keystoreName;
167 }
168
169 public void unlockKeystore(char[] password) throws KeystoreException {
170 if (password == null) {
171 throw new NullPointerException("password is null");
172 }
173 ensureLoaded(password);
174 try {
175 kernel.setAttribute(abstractName, "keystorePassword", new String(password));
176 } catch (Exception e) {
177 throw new KeystoreException("Unable to set attribute keystorePassword on myself!", e);
178 }
179 }
180
181 public void setKeystorePassword(String password) {
182 keystorePassword = password == null ? null : password.toCharArray();
183 }
184
185 public void lockKeystore(char[] password) throws KeystoreException {
186 if (password == null) {
187 throw new NullPointerException("password is null");
188 }
189 ensureLoaded(password);
190 try {
191 kernel.setAttribute(abstractName, "keystorePassword", null);
192 keyPasswords.clear();
193 storePasswords();
194 } catch (Exception e) {
195 throw new KeystoreException("Unable to set attribute keystorePassword on myself!", e);
196 }
197 }
198
199 public boolean isKeystoreLocked() {
200 return keystorePassword == null;
201 }
202
203 public String[] listPrivateKeys(char[] storePassword) throws KeystoreException {
204 ensureLoaded(storePassword);
205 return (String[]) privateKeys.toArray(new String[privateKeys.size()]);
206 }
207
208 public void unlockPrivateKey(String alias, char[] storePassword, char[] password) throws KeystoreException {
209 if (storePassword == null) {
210 throw new NullPointerException("storePassword is null");
211 }
212 getPrivateKey(alias, storePassword, password);
213 keyPasswords.put(alias, password);
214 storePasswords();
215 }
216
217 public String[] getUnlockedKeys(char[] storePassword) throws KeystoreException {
218 ensureLoaded(storePassword);
219 return (String[]) keyPasswords.keySet().toArray(new String[keyPasswords.size()]);
220 }
221
222 public boolean isTrustStore(char[] storePassword) throws KeystoreException {
223 ensureLoaded(storePassword);
224 return trustCerts.size() > 0;
225 }
226
227 public void lockPrivateKey(String alias, char[] storePassword) throws KeystoreException {
228 if (storePassword == null) {
229 throw new NullPointerException("storePassword is null");
230 }
231 ensureLoaded(storePassword);
232 keyPasswords.remove(alias);
233 storePasswords();
234 }
235
236 private void storePasswords() throws KeystoreException {
237 StringBuffer buf = new StringBuffer();
238 for (Iterator it = keyPasswords.entrySet().iterator(); it.hasNext();) {
239 if(buf.length() > 0) {
240 buf.append("]![");
241 }
242 Map.Entry entry = (Map.Entry) it.next();
243 buf.append(entry.getKey()).append("=").append((char[])entry.getValue());
244 }
245 try {
246 kernel.setAttribute(abstractName, "keyPasswords", buf.length() == 0 ? null : buf.toString());
247 } catch (Exception e) {
248 throw new KeystoreException("Unable to save key passwords in keystore '"+keystoreName+"'", e);
249 }
250 }
251
252 public void setKeyPasswords(String passwords) {}
253
254 /**
255 * Checks whether the specified private key is locked, which is to say,
256 * available for other components to use to generate socket factories.
257 * Does not check whether the unlock password is actually correct.
258 */
259 public boolean isKeyLocked(String alias) {
260 return keyPasswords.get(alias) == null;
261 }
262
263 public String[] listTrustCertificates(char[] storePassword) throws KeystoreException {
264 ensureLoaded(storePassword);
265 return (String[]) trustCerts.toArray(new String[trustCerts.size()]);
266 }
267
268 public void importTrustCertificate(Certificate cert, String alias, char[] storePassword) throws KeystoreException {
269 if (storePassword == null) {
270 throw new NullPointerException("storePassword is null");
271 }
272 ensureLoaded(storePassword);
273 try {
274 keystore.setCertificateEntry(alias, cert);
275 } catch (KeyStoreException e) {
276 throw new KeystoreException("Unable to set certificate entry in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
277 }
278 trustCerts.add(alias);
279 saveKeystore(storePassword);
280 }
281
282 public void generateKeyPair(String alias, char[] storePassword, char[] keyPassword, String keyAlgorithm, int keySize, String signatureAlgorithm, int validity, String commonName, String orgUnit, String organization, String locality, String state, String country) throws KeystoreException {
283 if (storePassword == null) {
284 throw new NullPointerException("storePassword is null");
285 }
286 ensureLoaded(storePassword);
287 try {
288 KeyPairGenerator kpgen = KeyPairGenerator.getInstance(keyAlgorithm);
289 kpgen.initialize(keySize);
290 KeyPair keyPair = kpgen.generateKeyPair();
291 X509Certificate cert = generateCertificate(keyPair.getPublic(), keyPair.getPrivate(), signatureAlgorithm,
292 validity, commonName, orgUnit, organization, locality, state, country);
293
294 keystore.setKeyEntry(alias, keyPair.getPrivate(), keyPassword, new Certificate[] { cert });
295 privateKeys.add(alias);
296 } catch (KeyStoreException e) {
297 throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'");
298 } catch (InvalidKeyException e) {
299 throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'");
300 } catch (SignatureException e) {
301 throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'");
302 } catch (NoSuchAlgorithmException e) {
303 throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'");
304 }
305 saveKeystore(storePassword);
306 }
307
308
309 public String generateCSR(String alias, char[] storePassword) throws KeystoreException {
310 ensureLoaded(storePassword);
311 try {
312
313 X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
314
315 PrivateKey key = (PrivateKey) keystore.getKey(alias, (char[])keyPasswords.get(alias));
316
317 String csr = generateCSR(cert, key);
318 return csr;
319 } catch (KeyStoreException e) {
320 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
321 } catch (NoSuchAlgorithmException e) {
322 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
323 } catch (UnrecoverableKeyException e) {
324 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
325 } catch (InvalidKeyException e) {
326 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
327 } catch (NoSuchProviderException e) {
328 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
329 } catch (SignatureException e) {
330 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
331 } catch (IOException e) {
332 throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
333 }
334 }
335
336 private String generateCSR(X509Certificate cert, PrivateKey signingKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, KeyStoreException, IOException {
337 String sigalg = cert.getSigAlgName();
338 X509Name subject;
339 try{
340 ASN1InputStream ais = new ASN1InputStream(cert.getEncoded());
341 X509CertificateStructure x509Struct = new X509CertificateStructure((ASN1Sequence)ais.readObject());
342 ais.close();
343 subject = x509Struct.getSubject();
344 } catch(CertificateEncodingException e) {
345 log.warn(e.toString()+" while retrieving subject from certificate to create CSR. Using subjectDN instead.");
346 subject = new X509Name(cert.getSubjectDN().toString());
347 }
348 PublicKey publicKey = cert.getPublicKey();
349 ASN1Set attributes = null;
350
351 PKCS10CertificationRequest csr = new PKCS10CertificationRequest(sigalg,
352 subject, publicKey, attributes, signingKey);
353
354 if (!csr.verify()) {
355 throw new KeyStoreException("CSR verification failed");
356 }
357
358 ByteArrayOutputStream os = new ByteArrayOutputStream();
359 DEROutputStream deros = new DEROutputStream(os);
360 deros.writeObject(csr.getDERObject());
361 String b64 = new String(Base64.encode(os.toByteArray()));
362
363 final String BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----";
364 final String END_CERT_REQ = "-----END CERTIFICATE REQUEST-----";
365 final int CERT_REQ_LINE_LENGTH = 70;
366
367 StringBuffer sbuf = new StringBuffer(BEGIN_CERT_REQ).append('\n');
368
369 int idx = 0;
370 while (idx < b64.length()) {
371
372 int len = (idx + CERT_REQ_LINE_LENGTH > b64.length()) ? b64
373 .length()
374 - idx : CERT_REQ_LINE_LENGTH;
375
376 String chunk = b64.substring(idx, idx + len);
377
378 sbuf.append(chunk).append('\n');
379 idx += len;
380 }
381
382 sbuf.append(END_CERT_REQ);
383 return sbuf.toString();
384 }
385
386 public void importPKCS7Certificate(String alias, String certbuf, char[] storePassword) throws KeystoreException {
387 if (storePassword == null) {
388 throw new NullPointerException("storePassword is null");
389 }
390 ensureLoaded(storePassword);
391 InputStream is = null;
392 try {
393 is = new ByteArrayInputStream(certbuf.getBytes());
394 CertificateFactory cf = CertificateFactory.getInstance("X.509");
395 Collection certcoll = cf.generateCertificates(is);
396 Certificate[] chain = new Certificate[certcoll.size()];
397 Iterator iter = certcoll.iterator();
398 for (int i = 0; iter.hasNext(); i++) {
399 chain[i] = (Certificate) iter.next();
400 }
401 if(keystore.getCertificate(alias).getPublicKey().equals(chain[0].getPublicKey())) {
402 char[] keyPassword = (char[])keyPasswords.get(alias);
403 keystore.setKeyEntry(alias, keystore.getKey(alias, keyPassword), keyPassword, chain);
404 saveKeystore(keystorePassword);
405 } else {
406 log.error("Error in importPKCS7Certificate. PublicKey in the certificate received is not related to the PrivateKey in the keystore. keystore = "+keystoreName+", alias = "+alias);
407 }
408 } catch (CertificateException e) {
409 throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
410 } catch (KeyStoreException e) {
411 throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
412 } catch (NoSuchAlgorithmException e) {
413 throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
414 } catch (UnrecoverableKeyException e) {
415 throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
416 } finally {
417 if (is != null) {
418 try {
419 is.close();
420 } catch (Exception e) {
421 }
422 }
423 }
424 }
425
426 public void deleteEntry(String alias, char[] storePassword) throws KeystoreException {
427 if (storePassword == null) {
428 throw new NullPointerException("storePassword is null");
429 }
430 ensureLoaded(storePassword);
431 try {
432 keystore.deleteEntry(alias);
433 } catch (KeyStoreException e) {
434 throw new KeystoreException("Unable to delete key in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
435 }
436 privateKeys.remove(alias);
437 trustCerts.remove(alias);
438 if (keyPasswords.containsKey(alias)) {
439 keyPasswords.remove(alias);
440 storePasswords();
441 }
442 saveKeystore(storePassword);
443 }
444
445 public KeyManager[] getKeyManager(String algorithm, String alias, char[] storePassword) throws KeystoreException {
446 ensureLoaded(storePassword);
447 try {
448 KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm);
449 if(privateKeys.size() == 1) {
450 keyFactory.init(keystore, (char[]) keyPasswords.get(alias));
451 } else {
452
453
454 KeyStore subKeystore = KeyStore.getInstance(keystore.getType(), keystore.getProvider());
455 try {
456 subKeystore.load(null, null);
457 } catch (NoSuchAlgorithmException e) {
458
459 } catch (CertificateException e) {
460
461 } catch (IOException e) {
462
463 }
464 subKeystore.setKeyEntry(alias, keystore.getKey(alias, (char[]) keyPasswords.get(alias)),
465 (char[]) keyPasswords.get(alias), keystore.getCertificateChain(alias));
466 keyFactory.init(subKeystore, (char[]) keyPasswords.get(alias));
467 }
468 return keyFactory.getKeyManagers();
469 } catch (KeyStoreException e) {
470 throw new KeystoreException("Unable to retrieve key manager in keystore '" + keystoreName + "' for alias '" + alias + "'");
471 } catch (NoSuchAlgorithmException e) {
472 throw new KeystoreException("Unable to retrieve key manager in keystore '" + keystoreName + "' for alias '" + alias + "'");
473 } catch (UnrecoverableKeyException e) {
474 throw new KeystoreException("Unable to retrieve key manager in keystore '" + keystoreName + "' for alias '" + alias + "'");
475 }
476 }
477
478 public TrustManager[] getTrustManager(String algorithm, char[] storePassword) throws KeystoreException {
479 ensureLoaded(storePassword);
480 try {
481 TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm);
482 trustFactory.init(keystore);
483 return trustFactory.getTrustManagers();
484 } catch (KeyStoreException e) {
485 throw new KeystoreException("Unable to retrieve trust manager in keystore '" + keystoreName + "'");
486 } catch (NoSuchAlgorithmException e) {
487 throw new KeystoreException("Unable to retrieve trust manager in keystore '" + keystoreName + "'");
488 }
489 }
490
491 /**
492 * Gets the private key with the specified alias.
493 * @param alias The alias of the private key to be retrieved
494 * @param storePassword The password used to access the keystore
495 * @param keyPassword The password to use to protect the new key
496 * @return PrivateKey with the alias specified
497 */
498 public PrivateKey getPrivateKey(String alias, char[] storePassword, char[] keyPassword) throws KeyNotFoundException, KeystoreException, KeystoreIsLocked {
499 ensureLoaded(storePassword);
500 try {
501 PrivateKey key = (PrivateKey) keystore.getKey(alias, keyPassword);
502 if (key == null) {
503 throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain a private key with alias'"+alias+"'.");
504 }
505 return key;
506 } catch (KeyStoreException e) {
507 throw new KeystoreException("Unable to retrieve private key from keystore", e);
508 } catch (NoSuchAlgorithmException e) {
509 throw new KeystoreException("Unable to retrieve private key from keystore", e);
510 } catch (UnrecoverableKeyException e) {
511 throw new KeystoreException("Unable to retrieve private key from keystore", e);
512 }
513 }
514
515 /**
516 * Gets a particular certificate from the keystore. This may be a trust
517 * certificate or the certificate corresponding to a particular private
518 * key.
519 * This only works if the keystore is unlocked.
520 * @param alias The certificate to look at
521 * @throws KeyNotFoundException
522 * @throws KeyStoreException
523 */
524 public Certificate getCertificate(String alias, char[] storePassword) throws KeystoreIsLocked, KeyNotFoundException, KeystoreException {
525 ensureLoaded(storePassword);
526 try {
527 Certificate cert = keystore.getCertificate(alias);
528 if (cert == null) {
529 throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain a certificate with alias'"+alias+"'.");
530 }
531 return cert;
532 } catch (KeyStoreException e) {
533 throw new KeystoreException("Unable to retrieve certificate from keystore", e);
534 }
535 }
536
537 public String getCertificateAlias(Certificate cert, char[] storePassword) throws KeystoreException {
538 ensureLoaded(storePassword);
539 try {
540 String alias = keystore.getCertificateAlias(cert);
541 if (alias == null) {
542 throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain an alias corresponding to the given certificate.");
543 }
544 return alias;
545 } catch (KeyStoreException e) {
546 throw new KeystoreException("Unable to read certificate alias from keystore", e);
547 }
548 }
549
550 public Certificate[] getCertificateChain(String alias, char[] storePassword) throws KeystoreException {
551 ensureLoaded(storePassword);
552 try {
553 Certificate[] certs = keystore.getCertificateChain(alias);
554 if (certs == null) {
555 throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain a certificate chain with alias'"+alias+"'.");
556 }
557 return certs;
558 } catch (KeyStoreException e) {
559 throw new KeystoreException("Unable to read certificate chain from keystore", e);
560 }
561 }
562
563
564
565 private void loadKeystoreData(char[] password) throws KeystoreException {
566 try {
567 keystoreReadDate = System.currentTimeMillis();
568 privateKeys.clear();
569 trustCerts.clear();
570 if(keystore == null) {
571 keystore = KeyStore.getInstance(JKS);
572 }
573 InputStream in = new BufferedInputStream(new FileInputStream(keystoreFile));
574 keystore.load(in, password);
575 in.close();
576 openPassword = password;
577 Enumeration aliases = keystore.aliases();
578 while (aliases.hasMoreElements()) {
579 String alias = (String) aliases.nextElement();
580 if(keystore.isKeyEntry(alias)) {
581 privateKeys.add(alias);
582 } else if(keystore.isCertificateEntry(alias)) {
583 trustCerts.add(alias);
584 }
585 }
586 } catch (KeyStoreException e) {
587 throw new KeystoreException("Unable to open keystore with provided password", e);
588 } catch (IOException e) {
589 throw new KeystoreException("Unable to open keystore with provided password", e);
590 } catch (NoSuchAlgorithmException e) {
591 throw new KeystoreException("Unable to open keystore with provided password", e);
592 } catch (CertificateException e) {
593 throw new KeystoreException("Unable to open keystore with provided password", e);
594 }
595 }
596
597 private boolean isLoaded(char[] password) {
598 if(openPassword == null || openPassword.length != password.length) {
599 return false;
600 }
601 if(keystoreReadDate < keystoreFile.lastModified()) {
602 return false;
603 }
604 for (int i = 0; i < password.length; i++) {
605 if(password[i] != openPassword[i]) {
606 return false;
607 }
608 }
609 return true;
610 }
611
612 private void ensureLoaded(char[] storePassword) throws KeystoreException {
613 char[] password;
614 if (storePassword == null) {
615 if (isKeystoreLocked()) {
616 throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked; please unlock it in the console.");
617 }
618 password = keystorePassword;
619 } else {
620 password = storePassword;
621 }
622 if (!isLoaded(password)) {
623 loadKeystoreData(password);
624 }
625 }
626
627 private X509Certificate generateCertificate(PublicKey publicKey, PrivateKey privateKey, String algorithm, int validity, String commonName, String orgUnit, String organization, String locality, String state, String country) throws SignatureException, InvalidKeyException {
628 X509V1CertificateGenerator certgen = new X509V1CertificateGenerator();
629 Vector order = new Vector();
630 Hashtable attrmap = new Hashtable();
631
632 if (commonName != null) {
633 attrmap.put(X509Principal.CN, commonName);
634 order.add(X509Principal.CN);
635 }
636
637 if (orgUnit != null) {
638 attrmap.put(X509Principal.OU, orgUnit);
639 order.add(X509Principal.OU);
640 }
641
642 if (organization != null) {
643 attrmap.put(X509Principal.O, organization);
644 order.add(X509Principal.O);
645 }
646
647 if (locality != null) {
648 attrmap.put(X509Principal.L, locality);
649 order.add(X509Principal.L);
650 }
651
652 if (state != null) {
653 attrmap.put(X509Principal.ST, state);
654 order.add(X509Principal.ST);
655 }
656
657 if (country != null) {
658 attrmap.put(X509Principal.C, country);
659 order.add(X509Principal.C);
660 }
661
662 X509Principal issuerDN = new X509Principal(order, attrmap);
663
664
665 long curr = System.currentTimeMillis();
666 long untill = curr + (long) validity * 24 * 60 * 60 * 1000;
667
668 certgen.setNotBefore(new Date(curr));
669 certgen.setNotAfter(new Date(untill));
670 certgen.setIssuerDN(issuerDN);
671 certgen.setSubjectDN(issuerDN);
672 certgen.setPublicKey(publicKey);
673 certgen.setSignatureAlgorithm(algorithm);
674 certgen.setSerialNumber(new BigInteger(String.valueOf(curr)));
675
676
677 return certgen.generateX509Certificate(privateKey);
678 }
679
680 private void saveKeystore(char[] password) throws KeystoreException {
681 try {
682 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(keystoreFile));
683 keystore.store(out, password);
684 out.flush();
685 out.close();
686 keystoreReadDate = System.currentTimeMillis();
687 } catch (KeyStoreException e) {
688 throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
689 } catch (FileNotFoundException e) {
690 throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
691 } catch (IOException e) {
692 throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
693 } catch (NoSuchAlgorithmException e) {
694 throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
695 } catch (CertificateException e) {
696 throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
697 }
698 }
699
700 }