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.crypto.asn1.ASN1Set; 057 import org.apache.geronimo.crypto.asn1.DEROutputStream; 058 import org.apache.geronimo.crypto.asn1.x509.X509Name; 059 import org.apache.geronimo.crypto.encoders.Base64; 060 import org.apache.geronimo.crypto.jce.PKCS10CertificationRequest; 061 import org.apache.geronimo.crypto.jce.X509Principal; 062 import org.apache.geronimo.crypto.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 }