1 13 14 package org.ejbca.util; 15 16 import java.io.ByteArrayInputStream ; 17 import java.io.IOException ; 18 import java.security.InvalidAlgorithmParameterException ; 19 import java.security.KeyFactory ; 20 import java.security.KeyPair ; 21 import java.security.KeyPairGenerator ; 22 import java.security.KeyStore ; 23 import java.security.KeyStoreException ; 24 import java.security.NoSuchAlgorithmException ; 25 import java.security.NoSuchProviderException ; 26 import java.security.PrivateKey ; 27 import java.security.PublicKey ; 28 import java.security.SecureRandom ; 29 import java.security.cert.Certificate ; 30 import java.security.cert.CertificateException ; 31 import java.security.cert.CertificateFactory ; 32 import java.security.cert.X509Certificate ; 33 import java.security.interfaces.ECPublicKey ; 34 import java.security.interfaces.RSAPublicKey ; 35 import java.security.spec.InvalidKeySpecException ; 36 import java.security.spec.PKCS8EncodedKeySpec ; 37 import java.util.ArrayList ; 38 import java.util.Collection ; 39 40 import org.apache.commons.lang.StringUtils; 41 import org.apache.log4j.Logger; 42 import org.bouncycastle.asn1.ASN1InputStream; 43 import org.bouncycastle.asn1.ASN1Sequence; 44 import org.bouncycastle.asn1.DERBMPString; 45 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 46 import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; 47 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 48 import org.bouncycastle.jce.ECNamedCurveTable; 49 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; 50 import org.bouncycastle.jce.provider.JCEECPublicKey; 51 import org.ejbca.core.model.ca.catoken.CATokenConstants; 52 53 54 59 public class KeyTools { 60 private static Logger log = Logger.getLogger(KeyTools.class); 61 62 65 private KeyTools() { 66 } 67 68 82 public static KeyPair genKeys(String keySpec, String keyAlg) 83 throws NoSuchAlgorithmException , NoSuchProviderException , InvalidAlgorithmParameterException { 84 if (log.isDebugEnabled()) { 85 log.debug(">genKeys("+keySpec+", "+keyAlg+")"); 86 } 87 88 KeyPairGenerator keygen = KeyPairGenerator.getInstance(keyAlg, "BC"); 89 if (StringUtils.equals(keyAlg, CATokenConstants.KEYALGORITHM_ECDSA)) { 90 org.bouncycastle.jce.spec.ECParameterSpec ecSpec = null; 91 if ( (keySpec == null) || StringUtils.equals(keySpec,"implicitlyCA") ) { 92 log.debug("Generating implicitlyCA encoded ECDSA key pair"); 93 } else { 97 log.debug("Generating named curve ECDSA key pair"); 98 ecSpec = ECNamedCurveTable.getParameterSpec(keySpec); 100 } 101 keygen.initialize(ecSpec, new SecureRandom ()); 102 } else { 103 int keysize = Integer.parseInt(keySpec); 105 keygen.initialize(keysize); 106 } 107 108 KeyPair keys = keygen.generateKeyPair(); 109 110 if (log.isDebugEnabled()) { 111 PublicKey pk = keys.getPublic(); 112 int len = getKeyLength(pk); 113 log.debug("Generated " + keys.getPublic().getAlgorithm() + " keys with length " + len); 114 log.debug("<genKeys()"); 115 } 116 117 return keys; 118 } 120 126 public static int getKeyLength(PublicKey pk) { 127 int len = -1; 128 if (pk instanceof RSAPublicKey ) { 129 RSAPublicKey rsapub = (RSAPublicKey ) pk; 130 len = rsapub.getModulus().bitLength(); 131 } else if (pk instanceof JCEECPublicKey) { 132 JCEECPublicKey ecpriv = (JCEECPublicKey) pk; 133 org.bouncycastle.jce.spec.ECParameterSpec spec = ecpriv.getParameters(); 134 if (spec != null) { 135 len = spec.getN().bitLength(); 136 } else { 137 len = 0; 139 } 140 } else if (pk instanceof ECPublicKey ) { 141 ECPublicKey ecpriv = (ECPublicKey ) pk; 142 java.security.spec.ECParameterSpec spec = ecpriv.getParams(); 143 if (spec != null) { 144 len = spec.getOrder().bitLength(); } else { 146 len = 0; 148 } 149 } 150 return len; 151 } 152 153 166 public static KeyStore createP12(String alias, PrivateKey privKey, X509Certificate cert, X509Certificate cacert) 167 throws IOException , KeyStoreException , CertificateException , NoSuchProviderException , NoSuchAlgorithmException , InvalidKeySpecException { 168 Certificate [] chain; 169 170 if (cacert == null) { 171 chain = null; 172 } else { 173 chain = new Certificate [1]; 174 chain[0] = cacert; 175 } 176 177 return createP12(alias, privKey, cert, chain); 178 } 180 192 public static KeyStore createP12(String alias, PrivateKey privKey, X509Certificate cert, Collection cacerts) 193 throws IOException , KeyStoreException , CertificateException , NoSuchProviderException , NoSuchAlgorithmException , InvalidKeySpecException { 194 Certificate [] chain; 195 if (cacerts == null) 196 chain = null; 197 else { 198 chain = new Certificate [cacerts.size()]; 199 chain = (Certificate [])cacerts.toArray(chain); 200 } 201 return createP12(alias, privKey, cert, chain); 202 } 204 215 public static KeyStore createP12(String alias, PrivateKey privKey, X509Certificate cert, Certificate [] cachain) 216 throws IOException , KeyStoreException , CertificateException , NoSuchProviderException , NoSuchAlgorithmException , InvalidKeySpecException { 217 log.debug(">createP12: alias=" + alias + ", privKey, cert=" + CertTools.getSubjectDN(cert) +", cachain.length=" + ((cachain == null) ? 0 : cachain.length)); 218 219 if (cert == null) { 221 throw new IllegalArgumentException ("Parameter cert cannot be null."); 222 } 223 int len = 1; 224 if (cachain != null) { 225 len += cachain.length; 226 } 227 Certificate [] chain = new Certificate [len]; 228 CertificateFactory cf = CertTools.getCertificateFactory(); 230 chain[0] = cf.generateCertificate(new ByteArrayInputStream (cert.getEncoded())); 231 232 if (cachain != null) { 233 for (int i = 0; i < cachain.length; i++) { 234 X509Certificate tmpcert = (X509Certificate ) cf.generateCertificate(new ByteArrayInputStream ( 235 cachain[i].getEncoded())); 236 chain[i + 1] = tmpcert; 237 } 238 } 239 if (chain.length > 1) { 240 for (int i = 1; i < chain.length; i++) { 241 X509Certificate cacert = (X509Certificate ) cf.generateCertificate(new ByteArrayInputStream ( 242 chain[i].getEncoded())); 243 PKCS12BagAttributeCarrier caBagAttr = (PKCS12BagAttributeCarrier) chain[i]; 245 String cafriendly = CertTools.getPartFromDN(CertTools.getSubjectDN(cacert), "CN"); 247 if (cafriendly == null) { 249 cafriendly = CertTools.getPartFromDN(CertTools.getSubjectDN(cacert), "O")+i; 250 } 251 if (cafriendly == null) { 252 cafriendly = CertTools.getPartFromDN(CertTools.getSubjectDN(cacert), "OU"+i); 253 } 254 if (cafriendly == null) { 255 cafriendly = "CA_unknown"+i; 256 } 257 caBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, 258 new DERBMPString(cafriendly)); 259 } 260 } 261 262 PKCS12BagAttributeCarrier certBagAttr = (PKCS12BagAttributeCarrier) chain[0]; 264 certBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString(alias)); 265 certBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, createSubjectKeyId(chain[0].getPublicKey())); 267 KeyFactory keyfact = KeyFactory.getInstance(privKey.getAlgorithm(), "BC"); 269 PrivateKey pk = keyfact.generatePrivate(new PKCS8EncodedKeySpec (privKey.getEncoded())); 270 PKCS12BagAttributeCarrier keyBagAttr = (PKCS12BagAttributeCarrier) pk; 272 keyBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString(alias)); 274 keyBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, createSubjectKeyId(chain[0].getPublicKey())); 275 KeyStore store = KeyStore.getInstance("PKCS12", "BC"); 277 store.load(null, null); 278 store.setKeyEntry(alias, pk, null, chain); 279 log.debug("<createP12: alias=" + alias + ", privKey, cert=" + CertTools.getSubjectDN(cert) + ", cachain.length=" + ((cachain == null) ? 0 : cachain.length)); 280 281 return store; 282 } 284 299 public static KeyStore createJKS(String alias, PrivateKey privKey, String password, 300 X509Certificate cert, Certificate [] cachain) throws Exception { 301 log.debug(">createJKS: alias=" + alias + ", privKey, cert=" + CertTools.getSubjectDN(cert) + 302 ", cachain.length=" + ((cachain == null) ? 0 : cachain.length)); 303 304 String caAlias = "cacert"; 305 306 if (cert == null) { 308 throw new IllegalArgumentException ("Parameter cert cannot be null."); 309 } 310 int len = 1; 311 if (cachain != null) { 312 len += cachain.length; 313 } 314 Certificate [] chain = new Certificate [len]; 315 chain[0] = cert; 316 if (cachain != null) { 317 for (int i = 0; i < cachain.length; i++) { 318 chain[i + 1] = cachain[i]; 319 } 320 } 321 322 KeyStore store = KeyStore.getInstance("JKS"); 324 store.load(null, null); 325 326 X509Certificate [] usercert = new X509Certificate [1]; 328 usercert[0] = cert; 329 store.setKeyEntry(alias, privKey, password.toCharArray(), usercert); 330 331 if (cachain != null) { 333 if (!CertTools.isSelfSigned((X509Certificate ) cachain[cachain.length - 1])) { 334 throw new IllegalArgumentException ("Root cert is not self-signed."); 335 } 336 store.setCertificateEntry(caAlias, cachain[cachain.length - 1]); 337 } 338 339 log.debug("Storing cert chain of length " + chain.length); 341 store.setKeyEntry(alias, privKey, password.toCharArray(), chain); 342 log.debug("<createJKS: alias=" + alias + ", privKey, cert=" + CertTools.getSubjectDN(cert) + 343 ", cachain.length=" + ((cachain == null) ? 0 : cachain.length)); 344 345 return store; 346 } 348 356 public static Certificate [] getCertChain(KeyStore keyStore, String privateKeyAlias) 357 throws KeyStoreException { 358 log.debug(">getCertChain: alias='" + privateKeyAlias + "'"); 359 360 Certificate [] certchain = keyStore.getCertificateChain(privateKeyAlias); 361 if (certchain == null) { 362 return null; 363 } 364 log.debug("Certchain retrieved from alias '" + privateKeyAlias + "' has length " + 365 certchain.length); 366 367 if (certchain.length < 1) { 368 log.error("Cannot load certificate chain with alias '" + privateKeyAlias + 369 "' from keystore."); 370 log.debug("<getCertChain: alias='" + privateKeyAlias + "', retlength=" + 371 certchain.length); 372 373 return certchain; 374 } else if (certchain.length > 0) { 375 if (CertTools.isSelfSigned((X509Certificate ) certchain[certchain.length - 1])) { 376 log.debug("Issuer='" + 377 CertTools.getIssuerDN((X509Certificate ) certchain[certchain.length - 1]) + 378 "'."); 379 log.debug("Subject='" + 380 CertTools.getSubjectDN((X509Certificate ) certchain[certchain.length - 1]) + 381 "'."); 382 log.debug("<getCertChain: alias='" + privateKeyAlias + "', retlength=" + 383 certchain.length); 384 385 return certchain; 386 } 387 } 388 389 ArrayList array = new ArrayList (); 391 392 for (int i = 0; i < certchain.length; i++) { 393 array.add(certchain[i]); 394 } 395 396 boolean stop = false; 397 398 while (!stop) { 399 X509Certificate cert = (X509Certificate ) array.get(array.size() - 1); 400 String ialias = CertTools.getPartFromDN(CertTools.getIssuerDN(cert), "CN"); 401 Certificate [] chain1 = keyStore.getCertificateChain(ialias); 402 403 if (chain1 == null) { 404 stop = true; 405 } else { 406 log.debug("Loaded certificate chain with length " + chain1.length + 407 " with alias '" + ialias + "'."); 408 409 if (chain1.length == 0) { 410 log.error("No RootCA certificate found!"); 411 stop = true; 412 } 413 414 for (int j = 0; j < chain1.length; j++) { 415 array.add(chain1[j]); 416 417 if (CertTools.isSelfSigned((X509Certificate ) chain1[j])) { 419 stop = true; 420 } 421 } 422 } 423 } 424 425 Certificate [] ret = new Certificate [array.size()]; 426 427 for (int i = 0; i < ret.length; i++) { 428 ret[i] = (X509Certificate ) array.get(i); 429 log.debug("Issuer='" + CertTools.getIssuerDN((X509Certificate ) ret[i]) + "'."); 430 log.debug("Subject='" + CertTools.getSubjectDN((X509Certificate ) ret[i]) + "'."); 431 } 432 433 log.debug("<getCertChain: alias='" + privateKeyAlias + "', retlength=" + ret.length); 434 435 return ret; 436 } 438 445 public static SubjectKeyIdentifier createSubjectKeyId(PublicKey pubKey) { 446 try { 447 ByteArrayInputStream bIn = new ByteArrayInputStream (pubKey.getEncoded()); 448 SubjectPublicKeyInfo info = new SubjectPublicKeyInfo((ASN1Sequence) new ASN1InputStream( 449 bIn).readObject()); 450 451 return new SubjectKeyIdentifier(info); 452 } catch (Exception e) { 453 throw new RuntimeException ("error creating key"); 454 } 455 } 457 } | Popular Tags |