001/* 002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/src/java/org/apache/commons/ssl/KeyStoreBuilder.java $ 003 * $Revision: 176 $ 004 * $Date: 2014-09-07 11:36:28 -0700 (Sun, 07 Sep 2014) $ 005 * 006 * ==================================================================== 007 * Licensed to the Apache Software Foundation (ASF) under one 008 * or more contributor license agreements. See the NOTICE file 009 * distributed with this work for additional information 010 * regarding copyright ownership. The ASF licenses this file 011 * to you under the Apache License, Version 2.0 (the 012 * "License"); you may not use this file except in compliance 013 * with the License. You may obtain a copy of the License at 014 * 015 * http://www.apache.org/licenses/LICENSE-2.0 016 * 017 * Unless required by applicable law or agreed to in writing, 018 * software distributed under the License is distributed on an 019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 020 * KIND, either express or implied. See the License for the 021 * specific language governing permissions and limitations 022 * under the License. 023 * ==================================================================== 024 * 025 * This software consists of voluntary contributions made by many 026 * individuals on behalf of the Apache Software Foundation. For more 027 * information on the Apache Software Foundation, please see 028 * <http://www.apache.org/>. 029 * 030 */ 031 032package org.apache.commons.ssl; 033 034import org.apache.commons.ssl.asn1.ASN1EncodableVector; 035import org.apache.commons.ssl.asn1.DERInteger; 036import org.apache.commons.ssl.asn1.DERSequence; 037 038import java.io.ByteArrayInputStream; 039import java.io.File; 040import java.io.FileInputStream; 041import java.io.FileOutputStream; 042import java.io.IOException; 043import java.math.BigInteger; 044import java.security.GeneralSecurityException; 045import java.security.InvalidKeyException; 046import java.security.Key; 047import java.security.KeyStore; 048import java.security.KeyStoreException; 049import java.security.NoSuchAlgorithmException; 050import java.security.NoSuchProviderException; 051import java.security.PrivateKey; 052import java.security.PublicKey; 053import java.security.UnrecoverableKeyException; 054import java.security.cert.Certificate; 055import java.security.cert.CertificateException; 056import java.security.cert.CertificateFactory; 057import java.security.cert.X509Certificate; 058import java.security.interfaces.DSAParams; 059import java.security.interfaces.DSAPrivateKey; 060import java.security.interfaces.RSAPrivateCrtKey; 061import java.security.interfaces.RSAPublicKey; 062import java.util.Arrays; 063import java.util.Collection; 064import java.util.Collections; 065import java.util.Enumeration; 066import java.util.Iterator; 067import java.util.LinkedList; 068import java.util.List; 069 070/** 071 * Builds Java Key Store files out of pkcs12 files, or out of pkcs8 files + 072 * certificate chains. Also supports OpenSSL style private keys (encrypted or 073 * unencrypted). 074 * 075 * @author Credit Union Central of British Columbia 076 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a> 077 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a> 078 * @since 4-Nov-2006 079 */ 080public class KeyStoreBuilder { 081 private final static String PKCS7_ENCRYPTED = "1.2.840.113549.1.7.6"; 082 083 public static KeyStore build(byte[] jksOrCerts, char[] password) 084 throws IOException, CertificateException, KeyStoreException, 085 NoSuchAlgorithmException, InvalidKeyException, 086 NoSuchProviderException, ProbablyBadPasswordException, 087 UnrecoverableKeyException { 088 return build(jksOrCerts, null, password); 089 } 090 091 public static KeyStore build(byte[] jksOrCerts, byte[] privateKey, 092 char[] password) 093 throws IOException, CertificateException, KeyStoreException, 094 NoSuchAlgorithmException, InvalidKeyException, 095 NoSuchProviderException, ProbablyBadPasswordException, 096 UnrecoverableKeyException { 097 return build(jksOrCerts, privateKey, password, null); 098 } 099 100 101 public static KeyStore build(byte[] jksOrCerts, byte[] privateKey, 102 char[] jksPassword, char[] keyPassword) 103 throws IOException, CertificateException, KeyStoreException, 104 NoSuchAlgorithmException, InvalidKeyException, 105 NoSuchProviderException, ProbablyBadPasswordException, 106 UnrecoverableKeyException { 107 108 if (keyPassword == null || keyPassword.length <= 0) { 109 keyPassword = jksPassword; 110 } 111 112 BuildResult br1 = parse(jksOrCerts, jksPassword, keyPassword); 113 BuildResult br2 = null; 114 KeyStore jks = null; 115 if (br1.jks != null) { 116 jks = br1.jks; 117 } else if (privateKey != null && privateKey.length > 0) { 118 br2 = parse(privateKey, jksPassword, keyPassword); 119 if (br2.jks != null) { 120 jks = br2.jks; 121 } 122 } 123 124 // If we happened to find a JKS file, let's just return that. 125 // JKS files get priority (in case some weirdo specifies both a PKCS12 126 // and a JKS file!). 127 if (jks != null) { 128 // Make sure the keystore we found is not corrupt. 129 br1 = validate(jks, keyPassword); 130 if (br1 == null) { 131 return jks; 132 } 133 } 134 135 List keys = br1.keys; 136 List chains = br1.chains; 137 boolean atLeastOneNotSet = keys == null || chains == null || keys.isEmpty() || chains.isEmpty(); 138 if (atLeastOneNotSet && br2 != null) { 139 if (br2.keys != null && !br2.keys.isEmpty()) { 140 // Notice that the key from build-result-2 gets priority over the 141 // key from build-result-1 (if both had valid keys). 142 keys = br2.keys; 143 } 144 if (chains == null || chains.isEmpty()) { 145 chains = br2.chains; 146 } 147 } 148 149 atLeastOneNotSet = keys == null || chains == null || keys.isEmpty() || chains.isEmpty(); 150 if (atLeastOneNotSet) { 151 String missing = ""; 152 if (keys == null) { 153 missing = " [Private key missing (bad password?)]"; 154 } 155 if (chains == null) { 156 missing += " [Certificate chain missing]"; 157 } 158 throw new KeyStoreException("Can't build keystore:" + missing); 159 } else { 160 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 161 ks.load(null, jksPassword); 162 Iterator keysIt = keys.iterator(); 163 Iterator chainsIt = chains.iterator(); 164 int i = 1; 165 while (keysIt.hasNext() && chainsIt.hasNext()) { 166 Key key = (Key) keysIt.next(); 167 Certificate[] c = (Certificate[]) chainsIt.next(); 168 X509Certificate theOne = buildChain(key, c); 169 String alias = "alias_" + i++; 170 // The theOne is not null, then our chain was probably altered. 171 // Need to trim out the newly introduced null entries at the end of 172 // our chain. 173 if (theOne != null) { 174 c = Certificates.trimChain(c); 175 alias = Certificates.getCN(theOne); 176 alias = alias.replace(' ', '_'); 177 } 178 ks.setKeyEntry(alias, key, keyPassword, c); 179 } 180 return ks; 181 } 182 } 183 184 /** 185 * Builds the chain up such that chain[ 0 ] contains the public key 186 * corresponding to the supplied private key. 187 * 188 * @param key private key 189 * @param chain array of certificates to build chain from 190 * @return theOne! 191 * @throws KeyStoreException no certificates correspond to private key 192 * @throws CertificateException java libraries complaining 193 * @throws NoSuchAlgorithmException java libraries complaining 194 * @throws InvalidKeyException java libraries complaining 195 * @throws NoSuchProviderException java libraries complaining 196 */ 197 public static X509Certificate buildChain(Key key, Certificate[] chain) 198 throws CertificateException, KeyStoreException, 199 NoSuchAlgorithmException, InvalidKeyException, 200 NoSuchProviderException { 201 X509Certificate theOne = null; 202 if (key instanceof RSAPrivateCrtKey) { 203 final RSAPrivateCrtKey rsa = (RSAPrivateCrtKey) key; 204 BigInteger publicExponent = rsa.getPublicExponent(); 205 BigInteger modulus = rsa.getModulus(); 206 for (int i = 0; i < chain.length; i++) { 207 X509Certificate c = (X509Certificate) chain[i]; 208 PublicKey pub = c.getPublicKey(); 209 if (pub instanceof RSAPublicKey) { 210 RSAPublicKey certKey = (RSAPublicKey) pub; 211 BigInteger pe = certKey.getPublicExponent(); 212 BigInteger mod = certKey.getModulus(); 213 if (publicExponent.equals(pe) && modulus.equals(mod)) { 214 theOne = c; 215 } 216 } 217 } 218 if (theOne == null) { 219 throw new KeyStoreException("Can't build keystore: [No certificates belong to the private-key]"); 220 } 221 X509Certificate[] newChain; 222 newChain = X509CertificateChainBuilder.buildPath(theOne, chain); 223 Arrays.fill(chain, null); 224 System.arraycopy(newChain, 0, chain, 0, newChain.length); 225 } 226 return theOne; 227 } 228 229 public static BuildResult validate(KeyStore jks, char[] keyPass) 230 throws CertificateException, KeyStoreException, 231 NoSuchAlgorithmException, InvalidKeyException, 232 NoSuchProviderException, UnrecoverableKeyException { 233 Enumeration en = jks.aliases(); 234 boolean atLeastOneSuccess = false; 235 boolean atLeastOneFailure = false; 236 237 List keys = new LinkedList(); 238 List chains = new LinkedList(); 239 while (en.hasMoreElements()) { 240 String alias = (String) en.nextElement(); 241 if (jks.isKeyEntry(alias)) { 242 try { 243 PrivateKey key = (PrivateKey) jks.getKey(alias, keyPass); 244 // No Exception thrown, so we're good! 245 atLeastOneSuccess = true; 246 Certificate[] chain = jks.getCertificateChain(alias); 247 X509Certificate[] c; 248 if (chain != null) { 249 c = Certificates.x509ifyChain(chain); 250 X509Certificate theOne = buildChain(key, c); 251 // The theOne is not null, then our chain was probably 252 // altered. Need to trim out the newly introduced null 253 // entries at the end of our chain. 254 if (theOne != null) { 255 c = (X509Certificate[]) Certificates.trimChain(c); 256 jks.deleteEntry(alias); 257 jks.setKeyEntry(alias, key, keyPass, c); 258 } 259 keys.add(key); 260 chains.add(c); 261 } 262 } catch (GeneralSecurityException gse) { 263 atLeastOneFailure = true; 264 // This is not the key you're looking for. 265 } 266 } 267 } 268 if (!atLeastOneSuccess) { 269 throw new KeyStoreException("No private keys found in keystore!"); 270 } 271 // The idea is a bit hacky: if we return null, all is cool. If 272 // we return a list, we're telling upstairs to abandon the JKS and 273 // build a new one from the BuildResults we provide. 274 // (Sun's builtin SSL refuses to deal with keystores where not all 275 // keys can be decrypted). 276 return atLeastOneFailure ? new BuildResult(keys, chains, null) : null; 277 } 278 279 public static class BuildResult { 280 protected final List keys; 281 protected final List chains; 282 protected final KeyStore jks; 283 284 protected BuildResult(List keys, List chains, KeyStore jks) { 285 if (keys == null || keys.isEmpty()) { 286 this.keys = null; 287 } else { 288 this.keys = Collections.unmodifiableList(keys); 289 } 290 this.jks = jks; 291 List x509Chains = new LinkedList(); 292 if (chains != null) { 293 Iterator it = chains.iterator(); 294 while (it.hasNext()) { 295 Certificate[] chain = (Certificate[]) it.next(); 296 if (chain != null && chain.length > 0) { 297 int len = chain.length; 298 X509Certificate[] x509 = new X509Certificate[len]; 299 for (int i = 0; i < x509.length; i++) { 300 x509[i] = (X509Certificate) chain[i]; 301 } 302 x509Chains.add(x509); 303 } 304 } 305 } 306 if (x509Chains == null || x509Chains.isEmpty()) { 307 this.chains = null; 308 } else { 309 this.chains = Collections.unmodifiableList(x509Chains); 310 } 311 } 312 } 313 314 315 public static BuildResult parse(byte[] stuff, char[] jksPass, 316 char[] keyPass) 317 throws IOException, CertificateException, KeyStoreException, 318 ProbablyBadPasswordException { 319 320 return parse(stuff, jksPass, keyPass, false); 321 } 322 323 static BuildResult parse(byte[] stuff, char[] jksPass, 324 char[] keyPass, boolean forTrustMaterial) 325 throws IOException, CertificateException, KeyStoreException, 326 ProbablyBadPasswordException { 327 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 328 Key key = null; 329 Certificate[] chain = null; 330 try { 331 PKCS8Key pkcs8Key = new PKCS8Key(stuff, jksPass); 332 key = pkcs8Key.getPrivateKey(); 333 } 334 catch (ProbablyBadPasswordException pbpe) { 335 throw pbpe; 336 } 337 catch (GeneralSecurityException gse) { 338 // no luck 339 } 340 341 List pemItems = PEMUtil.decode(stuff); 342 Iterator it = pemItems.iterator(); 343 LinkedList certificates = new LinkedList(); 344 while (it.hasNext()) { 345 PEMItem item = (PEMItem) it.next(); 346 byte[] derBytes = item.getDerBytes(); 347 String type = item.pemType.trim().toUpperCase(); 348 if (type.startsWith("CERT") || 349 type.startsWith("X509") || 350 type.startsWith("PKCS7")) { 351 ByteArrayInputStream in = new ByteArrayInputStream(derBytes); 352 X509Certificate c = (X509Certificate) cf.generateCertificate(in); 353 certificates.add(c); 354 } 355 chain = toChain(certificates); 356 } 357 358 if (chain != null || key != null) { 359 List chains = chain != null ? Collections.singletonList(chain) : null; 360 List keys = key != null ? Collections.singletonList(key) : null; 361 return new BuildResult(keys, chains, null); 362 } 363 364 boolean isProbablyPKCS12 = false; 365 boolean isASN = false; 366 ASN1Structure asn1 = null; 367 try { 368 asn1 = ASN1Util.analyze(stuff); 369 isASN = true; 370 isProbablyPKCS12 = asn1.oids.contains(PKCS7_ENCRYPTED); 371 if (!isProbablyPKCS12 && asn1.bigPayload != null) { 372 asn1 = ASN1Util.analyze(asn1.bigPayload); 373 isProbablyPKCS12 = asn1.oids.contains(PKCS7_ENCRYPTED); 374 } 375 } 376 catch (Exception e) { 377 // isProbablyPKCS12 and isASN are set properly by now. 378 } 379 380 ByteArrayInputStream stuffStream = new ByteArrayInputStream(stuff); 381 // Try default keystore... then try others. 382 BuildResult br = tryJKS(KeyStore.getDefaultType(), stuffStream, jksPass, keyPass, forTrustMaterial); 383 if (br == null) { 384 br = tryJKS("jks", stuffStream, jksPass, keyPass, forTrustMaterial); 385 if (br == null) { 386 br = tryJKS("jceks", stuffStream, jksPass, keyPass, forTrustMaterial); 387 if (br == null) { 388 br = tryJKS("BKS", stuffStream, jksPass, keyPass, forTrustMaterial); 389 if (br == null) { 390 br = tryJKS("UBER", stuffStream, jksPass, keyPass, forTrustMaterial); 391 } 392 } 393 } 394 } 395 if (br != null) { 396 return br; 397 } 398 if (isASN) { 399 if (isProbablyPKCS12) { 400 return tryJKS("pkcs12", stuffStream, jksPass, null, forTrustMaterial); 401 } 402 } else { 403 // Okay, it's ASN.1, but it's not PKCS12. Only one possible 404 // interesting things remains: X.509. 405 stuffStream.reset(); 406 407 try { 408 certificates = new LinkedList(); 409 Collection certs = cf.generateCertificates(stuffStream); 410 it = certs.iterator(); 411 while (it.hasNext()) { 412 X509Certificate x509 = (X509Certificate) it.next(); 413 certificates.add(x509); 414 } 415 chain = toChain(certificates); 416 if (chain != null && chain.length > 0) { 417 List chains = Collections.singletonList(chain); 418 return new BuildResult(null, chains, null); 419 } 420 } 421 catch (CertificateException ce) { 422 // oh well 423 } 424 425 stuffStream.reset(); 426 // Okay, still no luck. Maybe it's an ASN.1 DER stream 427 // containing only a single certificate? (I don't completely 428 // trust CertificateFactory.generateCertificates). 429 try { 430 Certificate c = cf.generateCertificate(stuffStream); 431 X509Certificate x509 = (X509Certificate) c; 432 chain = toChain(Collections.singleton(x509)); 433 if (chain != null && chain.length > 0) { 434 List chains = Collections.singletonList(chain); 435 return new BuildResult(null, chains, null); 436 } 437 } 438 catch (CertificateException ce) { 439 // oh well 440 } 441 } 442 443 br = tryJKS("pkcs12", stuffStream, jksPass, null, forTrustMaterial); 444 if (br != null) { 445 // no exception thrown, so must be PKCS12. 446 /* 447 Hmm, well someone finally reported this bug! And they want the library to be quiet.... 448 Commenting out for now, maybe investigate why it's happening one day.... 449 450 System.out.println("Please report bug!"); 451 System.out.println("PKCS12 detection failed to realize this was PKCS12!"); 452 System.out.println(asn1); 453 */ 454 return br; 455 } 456 throw new KeyStoreException("failed to extract any certificates or private keys - maybe bad password?"); 457 } 458 459 private static BuildResult tryJKS( 460 String keystoreType, ByteArrayInputStream in, char[] jksPassword, char[] keyPassword, 461 boolean forTrustMaterial 462 ) throws ProbablyBadPasswordException { 463 in.reset(); 464 if (keyPassword == null || keyPassword.length <= 0) { 465 keyPassword = jksPassword; 466 } 467 468 keystoreType = keystoreType.trim().toLowerCase(); 469 boolean isPKCS12 = "pkcs12".equalsIgnoreCase(keystoreType); 470 try { 471 Key key = null; 472 Certificate[] chain = null; 473 UnrecoverableKeyException uke = null; 474 KeyStore jksKeyStore = KeyStore.getInstance(keystoreType); 475 jksKeyStore.load(in, jksPassword); 476 Enumeration en = jksKeyStore.aliases(); 477 while (en.hasMoreElements()) { 478 String alias = (String) en.nextElement(); 479 if (jksKeyStore.isKeyEntry(alias)) { 480 try { 481 if (keyPassword != null) { 482 key = jksKeyStore.getKey(alias, keyPassword); 483 } 484 if (key instanceof PrivateKey) { 485 chain = jksKeyStore.getCertificateChain(alias); 486 break; 487 } 488 } catch (UnrecoverableKeyException e) { 489 uke = e; // We might throw this one later. 490 } catch (GeneralSecurityException gse) { 491 // Swallow... keep looping. 492 } 493 } 494 if (isPKCS12 && en.hasMoreElements()) { 495 System.out.println("what kind of weird pkcs12 file has more than one alias?"); 496 } 497 } 498 if (key == null && uke != null) { 499 // If we're trying to load KeyMaterial, then we *need* that key we spotted. 500 // But if we're trying to load TrustMaterial, then we're fine, and we can ignore the key. 501 if (!forTrustMaterial) { 502 throw new ProbablyBadPasswordException("Probably bad JKS-Key password: " + uke); 503 } 504 } 505 if (isPKCS12) { 506 // PKCS12 is supposed to be just a key and a chain, anyway. 507 jksKeyStore = null; 508 } 509 510 List keys = Collections.singletonList(key); 511 List chains = Collections.singletonList(chain); 512 return new BuildResult(keys, chains, jksKeyStore); 513 } 514 catch (ProbablyBadPasswordException pbpe) { 515 throw pbpe; 516 } 517 catch (GeneralSecurityException gse) { 518 // swallow it, return null 519 return null; 520 } 521 catch (IOException ioe) { 522 String msg = ioe.getMessage(); 523 msg = msg != null ? msg.trim().toLowerCase() : ""; 524 if (isPKCS12) { 525 int x = msg.indexOf("failed to decrypt"); 526 int y = msg.indexOf("verify mac"); 527 x = Math.max(x, y); 528 if (x >= 0) { 529 throw new ProbablyBadPasswordException("Probably bad PKCS12 password: " + ioe); 530 } 531 } else { 532 int x = msg.indexOf("password"); 533 if (x >= 0) { 534 throw new ProbablyBadPasswordException("Probably bad JKS password: " + ioe); 535 } 536 } 537 // swallow it, return null. 538 return null; 539 } 540 } 541 542 private static X509Certificate[] toChain(Collection certs) { 543 if (certs != null && !certs.isEmpty()) { 544 X509Certificate[] x509Chain = new X509Certificate[certs.size()]; 545 certs.toArray(x509Chain); 546 return x509Chain; 547 } else { 548 return null; 549 } 550 } 551 552 553 public static void main(String[] args) throws Exception { 554 if (args.length < 2) { 555 System.out.println("KeyStoreBuilder: creates '[alias].jks' (Java Key Store)"); 556 System.out.println(" -topk8 mode: creates '[alias].pem' (x509 chain + unencrypted pkcs8)"); 557 System.out.println("[alias] will be set to the first CN value of the X509 certificate."); 558 System.out.println("-------------------------------------------------------------------"); 559 System.out.println("Usage1: [password] [file:pkcs12]"); 560 System.out.println("Usage2: [password] [file:private-key] [file:certificate-chain]"); 561 System.out.println("Usage3: -topk8 [password] [file:jks]"); 562 System.out.println("-------------------------------------------------------------------"); 563 System.out.println("[private-key] can be openssl format, or pkcs8."); 564 System.out.println("[password] decrypts [private-key], and also encrypts outputted JKS file."); 565 System.out.println("All files can be PEM or DER."); 566 System.exit(1); 567 } 568 char[] password = args[0].toCharArray(); 569 boolean toPKCS8 = false; 570 if ("-topk8".equalsIgnoreCase(args[0])) { 571 toPKCS8 = true; 572 password = args[1].toCharArray(); 573 args[1] = args[2]; 574 args[2] = null; 575 } 576 577 FileInputStream fin1 = new FileInputStream(args[1]); 578 byte[] bytes1 = Util.streamToBytes(fin1); 579 byte[] bytes2 = null; 580 if (args.length > 2 && args[2] != null) { 581 FileInputStream fin2 = new FileInputStream(args[2]); 582 bytes2 = Util.streamToBytes(fin2); 583 } 584 585 KeyStore ks = build(bytes1, bytes2, password); 586 Enumeration en = ks.aliases(); 587 String alias = "keystorebuilder"; 588 589 // We're going to assume that the biggest key is the one we want 590 // to convert to PKCS8 (PEM). That's until someone figures out a 591 // better way to deal with this annoying situation (more than 1 592 // key in the KeyStore). 593 int biggestKey = 0; 594 while (en.hasMoreElements()) { 595 String s = (String) en.nextElement(); 596 try { 597 PrivateKey pk = (PrivateKey) ks.getKey(s, password); 598 byte[] encoded = pk.getEncoded(); 599 int len = encoded != null ? encoded.length : 0; 600 if (len >= biggestKey) { 601 biggestKey = len; 602 alias = s; 603 } 604 } catch (Exception e) { 605 // oh well, try next one. 606 } 607 } 608 609 String suffix = toPKCS8 ? ".pem" : ".jks"; 610 String fileName = alias; 611 Certificate[] chain = ks.getCertificateChain(alias); 612 if (chain != null && chain[0] != null) { 613 String cn = Certificates.getCN((X509Certificate) chain[0]); 614 cn = cn != null ? cn.trim() : ""; 615 if (!"".equals(cn)) { 616 fileName = cn; 617 } 618 } 619 620 File f = new File(fileName + suffix); 621 int count = 1; 622 while (f.exists()) { 623 f = new File(alias + "_" + count + suffix); 624 count++; 625 } 626 627 FileOutputStream fout = new FileOutputStream(f); 628 if (toPKCS8) { 629 List pemItems = new LinkedList(); 630 PrivateKey key = (PrivateKey) ks.getKey(alias, password); 631 chain = ks.getCertificateChain(alias); 632 byte[] pkcs8DerBytes = null; 633 if (key instanceof RSAPrivateCrtKey) { 634 RSAPrivateCrtKey rsa = (RSAPrivateCrtKey) key; 635 ASN1EncodableVector vec = new ASN1EncodableVector(); 636 vec.add(new DERInteger(BigInteger.ZERO)); 637 vec.add(new DERInteger(rsa.getModulus())); 638 vec.add(new DERInteger(rsa.getPublicExponent())); 639 vec.add(new DERInteger(rsa.getPrivateExponent())); 640 vec.add(new DERInteger(rsa.getPrimeP())); 641 vec.add(new DERInteger(rsa.getPrimeQ())); 642 vec.add(new DERInteger(rsa.getPrimeExponentP())); 643 vec.add(new DERInteger(rsa.getPrimeExponentQ())); 644 vec.add(new DERInteger(rsa.getCrtCoefficient())); 645 DERSequence seq = new DERSequence(vec); 646 byte[] derBytes = PKCS8Key.encode(seq); 647 PKCS8Key pkcs8 = new PKCS8Key(derBytes, null); 648 pkcs8DerBytes = pkcs8.getDecryptedBytes(); 649 } else if (key instanceof DSAPrivateKey) { 650 DSAPrivateKey dsa = (DSAPrivateKey) key; 651 DSAParams params = dsa.getParams(); 652 BigInteger g = params.getG(); 653 BigInteger p = params.getP(); 654 BigInteger q = params.getQ(); 655 BigInteger x = dsa.getX(); 656 BigInteger y = q.modPow(x, p); 657 658 ASN1EncodableVector vec = new ASN1EncodableVector(); 659 vec.add(new DERInteger(BigInteger.ZERO)); 660 vec.add(new DERInteger(p)); 661 vec.add(new DERInteger(q)); 662 vec.add(new DERInteger(g)); 663 vec.add(new DERInteger(y)); 664 vec.add(new DERInteger(x)); 665 DERSequence seq = new DERSequence(vec); 666 byte[] derBytes = PKCS8Key.encode(seq); 667 PKCS8Key pkcs8 = new PKCS8Key(derBytes, null); 668 pkcs8DerBytes = pkcs8.getDecryptedBytes(); 669 } 670 if (chain != null && chain.length > 0) { 671 for (int i = 0; i < chain.length; i++) { 672 X509Certificate x509 = (X509Certificate) chain[i]; 673 byte[] derBytes = x509.getEncoded(); 674 PEMItem item = new PEMItem(derBytes, "CERTIFICATE"); 675 pemItems.add(item); 676 } 677 } 678 if (pkcs8DerBytes != null) { 679 PEMItem item = new PEMItem(pkcs8DerBytes, "PRIVATE KEY"); 680 pemItems.add(item); 681 } 682 byte[] pem = PEMUtil.encode(pemItems); 683 fout.write(pem); 684 } else { 685 // If we're not converting to unencrypted PKCS8 style PEM, 686 // then we are converting to Sun JKS. It happens right here: 687 KeyStore jks = KeyStore.getInstance(KeyStore.getDefaultType()); 688 jks.load(null, password); 689 jks.setKeyEntry(alias, ks.getKey(alias, password), password, ks.getCertificateChain(alias)); 690 jks.store(fout, password); 691 } 692 fout.flush(); 693 fout.close(); 694 System.out.println("Successfuly wrote: [" + f.getPath() + "]"); 695 } 696 697 698}