001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.console.core.keystore;
019
020 import java.io.ByteArrayInputStream;
021 import java.io.ByteArrayOutputStream;
022 import java.io.File;
023 import java.io.FileInputStream;
024 import java.io.FileOutputStream;
025 import java.io.IOException;
026 import java.io.InputStream;
027 import java.math.BigInteger;
028 import java.security.KeyPair;
029 import java.security.KeyPairGenerator;
030 import java.security.KeyStore;
031 import java.security.KeyStoreException;
032 import java.security.NoSuchAlgorithmException;
033 import java.security.PrivateKey;
034 import java.security.PublicKey;
035 import java.security.cert.Certificate;
036 import java.security.cert.CertificateException;
037 import java.security.cert.CertificateFactory;
038 import java.security.cert.X509Certificate;
039 import java.util.ArrayList;
040 import java.util.Collection;
041 import java.util.Date;
042 import java.util.Enumeration;
043 import java.util.Hashtable;
044 import java.util.Iterator;
045 import java.util.List;
046 import java.util.Vector;
047
048 import org.apache.commons.logging.Log;
049 import org.apache.commons.logging.LogFactory;
050 import org.apache.geronimo.gbean.GBeanInfo;
051 import org.apache.geronimo.gbean.GBeanInfoBuilder;
052 import org.apache.geronimo.gbean.GBeanLifecycle;
053 import org.apache.geronimo.gbean.WaitingException;
054 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
055 import org.apache.geronimo.system.serverinfo.ServerInfo;
056 import org.apache.geronimo.util.asn1.ASN1Set;
057 import org.apache.geronimo.util.asn1.DEROutputStream;
058 import org.apache.geronimo.util.asn1.x509.X509Name;
059 import org.apache.geronimo.util.encoders.Base64;
060 import org.apache.geronimo.util.jce.PKCS10CertificationRequest;
061 import org.apache.geronimo.util.jce.X509Principal;
062 import org.apache.geronimo.util.jce.X509V1CertificateGenerator;
063
064 public class KeyStoreGBean implements GBeanLifecycle {
065
066 private static Log log = LogFactory.getLog(KeyStoreGBean.class);
067
068 private String keyStoreType;
069
070 private String keyStoreProvider;
071
072 private String keyStoreLocation;
073
074 private String keyStorePassword;
075
076 private String keyPassword;
077
078 private KeyStore keystore;
079
080 // Used to resolve keystore path.
081 private ServerInfo serverInfo;
082
083 public KeyStoreGBean() {
084 }
085
086 public void doStart() throws WaitingException, Exception {
087
088 //Security.addProvider(new BouncyCastleProvider());
089
090 this.keystore = KeyStore.getInstance(keyStoreType);
091
092 boolean keystoreExistsFlag = true;
093 InputStream is = null;
094
095 try {
096 File keyStore = serverInfo.resolveServer(this.keyStoreLocation);
097 log.debug("loading keystore from " + keyStore);
098 is = new java.io.FileInputStream(keyStore);
099 this.keystore.load(is, this.keyStorePassword.toCharArray());
100 } catch (java.io.FileNotFoundException e) {
101 keystoreExistsFlag = false;
102 } finally {
103 try {
104 if (is != null) {
105 is.close();
106 }
107 } catch (Exception e) {
108 }
109 }
110
111 if (keystoreExistsFlag == false) {
112 keystore.load(null, keyStorePassword.toCharArray());
113 }
114 }
115
116 public void doStop() throws WaitingException, Exception {
117 }
118
119 public void doFail() {
120 }
121
122 public void setKeyStoreType(String keyStoreType) {
123 this.keyStoreType = keyStoreType;
124 }
125
126 public String getKeyStoreType() {
127 return this.keyStoreType;
128 }
129
130 public void setKeyStoreProvider(String keyStoreProvider) {
131 this.keyStoreProvider = keyStoreProvider;
132 }
133
134 public String getKeyStoreProvider() {
135 return this.keyStoreProvider;
136 }
137
138 public void setKeyStoreLocation(String keyStoreLocation) {
139 this.keyStoreLocation = keyStoreLocation;
140 }
141
142 public ServerInfo getServerInfo() {
143 return serverInfo;
144 }
145
146 public void setServerInfo(ServerInfo serverInfo) {
147 this.serverInfo = serverInfo;
148 }
149
150 public String getKeyStoreLocation() {
151 return this.keyStoreLocation;
152 }
153
154 public void setKeyStorePassword(String keyStorePassword) {
155 this.keyStorePassword = keyStorePassword;
156 }
157
158 public String getKeyStorePassword() {
159 return this.keyStorePassword;
160 }
161
162 public void setKeyPassword(String keyPassword) {
163 this.keyPassword = keyPassword;
164 }
165
166 public String getKeyPassword() {
167 return this.keyPassword;
168 }
169
170 public int getKeyStoreSize() throws KeyStoreException {
171 return this.keystore.size();
172 }
173
174 public KeyEntryInfo getKeyEntryInfo(String alias) throws KeyStoreException {
175 KeyEntryInfo info = null;
176
177 if (this.keystore.isCertificateEntry(alias)) {
178 // certificate entry
179 info = new KeyEntryInfo(alias, "trusted certificate", keystore
180 .getCreationDate(alias));
181 } else if (this.keystore.isKeyEntry(alias)) {
182 // private key entry
183 info = new KeyEntryInfo(alias, "private key", keystore
184 .getCreationDate(alias));
185 } else {
186 throw new KeyStoreException("invalid key entry type");
187 }
188 return info;
189 }
190
191 public List getKeyStoreEntries() throws KeyStoreException {
192 List list = new ArrayList();
193
194 Enumeration aliases = this.keystore.aliases();
195
196 while (aliases.hasMoreElements()) {
197 String alias = (String) aliases.nextElement();
198 list.add(getKeyEntryInfo(alias));
199 }
200 return list;
201 }
202
203 public Certificate[] getCertificateChain(String alias)
204 throws KeyStoreException {
205 Certificate[] certs = null;
206
207 if (keystore.isCertificateEntry(alias)) {
208 Certificate cert = keystore.getCertificate(alias);
209 certs = new Certificate[1];
210 certs[0] = cert;
211 } else if (keystore.isKeyEntry(alias)) {
212 certs = keystore.getCertificateChain(alias);
213 } else if (keystore.containsAlias(alias)) {
214 throw new KeyStoreException("Unsupported key-store-entry, alias = "
215 + alias);
216 } else {
217 throw new KeyStoreException(
218 "Key-store-entry alias not found, alias = " + alias);
219 }
220
221 return certs;
222 }
223
224 public String generateCSR(String alias) throws Exception {
225
226 // find certificate by alias
227 X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
228
229 // find private key by alias
230 PrivateKey key = (PrivateKey) keystore.getKey(alias, keyPassword.toCharArray());
231
232 // generate csr
233 String csr = generateCSR(cert, key);
234 return csr;
235 }
236
237 public String generateCSR(X509Certificate cert, PrivateKey signingKey)
238 throws Exception {
239
240 String sigalg = cert.getSigAlgName();
241 X509Name subject = new X509Name(cert.getSubjectDN().toString());
242 PublicKey publicKey = cert.getPublicKey();
243 ASN1Set attributes = null;
244
245 PKCS10CertificationRequest csr = new PKCS10CertificationRequest(sigalg,
246 subject, publicKey, attributes, signingKey);
247
248 if (!csr.verify()) {
249 throw new KeyStoreException("CSR verification failed");
250 }
251
252 ByteArrayOutputStream os = new ByteArrayOutputStream();
253 DEROutputStream deros = new DEROutputStream(os);
254 deros.writeObject(csr.getDERObject());
255 String b64 = new String(Base64.encode(os.toByteArray()));
256
257 final String BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----";
258 final String END_CERT_REQ = "-----END CERTIFICATE REQUEST-----";
259 final int CERT_REQ_LINE_LENGTH = 70;
260
261 StringBuffer sbuf = new StringBuffer(BEGIN_CERT_REQ).append('\n');
262
263 int idx = 0;
264 while (idx < b64.length()) {
265
266 int len = (idx + CERT_REQ_LINE_LENGTH > b64.length()) ? b64
267 .length()
268 - idx : CERT_REQ_LINE_LENGTH;
269
270 String chunk = b64.substring(idx, idx + len);
271
272 sbuf.append(chunk).append('\n');
273 idx += len;
274 }
275
276 sbuf.append(END_CERT_REQ);
277 return sbuf.toString();
278 }
279
280 public void generateKeyPair(String alias, String keyalg, Integer keysize,
281 String sigalg, Integer validity, String cn, String ou, String o,
282 String l, String st, String c)
283 throws java.security.NoSuchAlgorithmException,
284 java.security.KeyStoreException, java.security.SignatureException,
285 java.security.InvalidKeyException,
286 java.security.cert.CertificateException, java.io.IOException {
287
288 KeyPairGenerator kpgen = KeyPairGenerator.getInstance(keyalg);
289
290 kpgen.initialize(keysize.intValue());
291
292 KeyPair keyPair = kpgen.generateKeyPair();
293
294 X509Certificate cert = generateCert(keyPair.getPublic(), keyPair
295 .getPrivate(), sigalg, validity.intValue(), cn, ou, o, l, st, c);
296
297 keystore.setKeyEntry(alias, keyPair.getPrivate(), keyPassword.toCharArray(), new Certificate[] { cert });
298
299 saveKeyStore();
300 }
301
302 public void saveKeyStore() throws java.io.IOException,
303 java.security.KeyStoreException,
304 java.security.cert.CertificateException,
305 java.security.NoSuchAlgorithmException {
306
307 FileOutputStream os = null;
308
309 try {
310 File keyStore = serverInfo.resolveServer(this.keyStoreLocation);
311 os = new FileOutputStream(keyStore);
312
313 keystore.store(os, keyStorePassword.toCharArray());
314 } finally {
315 if (os != null) {
316 try {
317 os.close();
318 } catch (Exception ex) {
319 }
320 }
321 }
322 }
323
324 public X509Certificate generateCert(PublicKey publicKey,
325 PrivateKey privateKey, String sigalg, int validity, String cn,
326 String ou, String o, String l, String st, String c)
327 throws java.security.SignatureException,
328 java.security.InvalidKeyException {
329 X509V1CertificateGenerator certgen = new X509V1CertificateGenerator();
330
331 // issuer dn
332 Vector order = new Vector();
333 Hashtable attrmap = new Hashtable();
334
335 if (cn != null) {
336 attrmap.put(X509Principal.CN, cn);
337 order.add(X509Principal.CN);
338 }
339
340 if (ou != null) {
341 attrmap.put(X509Principal.OU, ou);
342 order.add(X509Principal.OU);
343 }
344
345 if (o != null) {
346 attrmap.put(X509Principal.O, o);
347 order.add(X509Principal.O);
348 }
349
350 if (l != null) {
351 attrmap.put(X509Principal.L, l);
352 order.add(X509Principal.L);
353 }
354
355 if (st != null) {
356 attrmap.put(X509Principal.ST, st);
357 order.add(X509Principal.ST);
358 }
359
360 if (c != null) {
361 attrmap.put(X509Principal.C, c);
362 order.add(X509Principal.C);
363 }
364
365 X509Principal issuerDN = new X509Principal(order, attrmap);
366 certgen.setIssuerDN(issuerDN);
367
368 // validity
369 long curr = System.currentTimeMillis();
370 long untill = curr + (long) validity * 24 * 60 * 60 * 1000;
371
372 certgen.setNotBefore(new Date(curr));
373 certgen.setNotAfter(new Date(untill));
374
375 // subject dn
376 certgen.setSubjectDN(issuerDN);
377
378 // public key
379 certgen.setPublicKey(publicKey);
380
381 // signature alg
382 certgen.setSignatureAlgorithm(sigalg);
383
384 // serial number
385 certgen.setSerialNumber(new BigInteger(String.valueOf(curr)));
386
387 // make certificate
388 X509Certificate cert = certgen.generateX509Certificate(privateKey);
389 return cert;
390 }
391
392 public void importTrustedX509Certificate(String alias, String certfile)
393 throws java.io.FileNotFoundException,
394 java.security.cert.CertificateException,
395 java.security.KeyStoreException, java.io.IOException,
396 java.security.NoSuchAlgorithmException,
397 java.security.NoSuchProviderException {
398 InputStream is = null;
399
400 try {
401 if (keyStoreProvider.equalsIgnoreCase("Default"))
402 {
403 keyStoreProvider = new String(System.getProperty("java.security.Provider"));
404 }
405 CertificateFactory cf = CertificateFactory.getInstance("X.509", keyStoreProvider);
406
407 is = new FileInputStream(certfile);
408 Certificate cert = cf.generateCertificate(is);
409
410 if(alias == null || alias.equals("")) {
411 // Generate an alias for this certificate
412 X509Certificate xcert = (X509Certificate)cert;
413 alias = xcert.getIssuerDN().toString()+":"+xcert.getSerialNumber();
414 }
415
416 keystore.setCertificateEntry(alias, cert);
417
418 saveKeyStore();
419 } finally {
420 if (is != null) {
421 try {
422 is.close();
423 } catch (Exception e) {
424 }
425 }
426 }
427 }
428
429 public void importPKCS7Certificate(String alias, String certbuf)
430 throws java.security.cert.CertificateException,
431 java.security.NoSuchProviderException,
432 java.security.KeyStoreException,
433 java.security.NoSuchAlgorithmException,
434 java.security.UnrecoverableKeyException, java.io.IOException {
435
436 InputStream is = null;
437
438 try {
439 is = new ByteArrayInputStream(certbuf.getBytes());
440 importPKCS7Certificate(alias, is);
441 } finally {
442 if (is != null) {
443 try {
444 is.close();
445 } catch (Exception e) {
446 }
447 }
448 }
449 }
450
451 public void importPKCS7Certificate(String alias, InputStream is)
452 throws java.security.cert.CertificateException,
453 java.security.NoSuchProviderException,
454 java.security.KeyStoreException,
455 java.security.NoSuchAlgorithmException,
456 java.security.UnrecoverableKeyException, java.io.IOException {
457
458 if (keyStoreProvider.equalsIgnoreCase("Default"))
459 {
460 keyStoreProvider = new String(System.getProperty("java.security.Provider"));
461 }
462 CertificateFactory cf = CertificateFactory.getInstance("X.509",keyStoreProvider);
463 Collection certcoll = cf.generateCertificates(is);
464
465 Certificate[] chain = new Certificate[certcoll.size()];
466
467 Iterator iter = certcoll.iterator();
468 for (int i = 0; iter.hasNext(); i++) {
469 chain[i] = (Certificate) iter.next();
470 }
471
472 char[] password = keyPassword.toCharArray();
473 keystore.setKeyEntry(alias, keystore.getKey(alias, password), password,
474 chain);
475
476 saveKeyStore();
477 }
478
479 public void deleteEntry(String alias)
480 throws KeyStoreException,
481 CertificateException,
482 NoSuchAlgorithmException, IOException {
483
484 keystore.deleteEntry(alias);
485
486 saveKeyStore();
487 }
488
489
490 public static final GBeanInfo GBEAN_INFO;
491
492 static {
493 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(KeyStoreGBean.class);
494
495 infoFactory.addAttribute("keyStoreType", String.class, true);
496 infoFactory.addAttribute("keyStoreProvider", String.class, true);
497 infoFactory.addAttribute("keyStoreLocation", String.class, true);
498 infoFactory.addAttribute("keyStorePassword", String.class, true);
499 infoFactory.addAttribute("keyPassword", String.class, true);
500
501 infoFactory.addReference("serverInfo", ServerInfo.class, NameFactory.GERONIMO_SERVICE);
502
503 infoFactory.addOperation("getKeyEntryInfo",
504 new Class[] { String.class });
505 infoFactory.addOperation("getKeyStoreSize");
506 infoFactory.addOperation("getKeyStoreEntries");
507 infoFactory.addOperation("getCertificateChain",
508 new Class[] { String.class });
509 infoFactory.addOperation("generateCSR", new Class[] { String.class });
510
511 infoFactory.addOperation("generateKeyPair", new Class[] { String.class,
512 String.class, Integer.class, String.class, Integer.class,
513 String.class, String.class, String.class, String.class,
514 String.class, String.class });
515
516 infoFactory.addOperation("importTrustedX509Certificate", new Class[] {
517 String.class, String.class });
518 infoFactory.addOperation("importPKCS7Certificate", new Class[] {
519 String.class, String.class });
520 infoFactory.addOperation("deleteEntry", new Class[] {String.class });
521
522 GBEAN_INFO = infoFactory.getBeanInfo();
523 }
524
525 public static GBeanInfo getGBeanInfo() {
526 return GBEAN_INFO;
527 }
528
529 }