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