001 /* 002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/src/java/org/apache/commons/ssl/KeyStoreBuilder.java $ 003 * $Revision: 154 $ 004 * $Date: 2009-09-16 22:18:47 -0700 (Wed, 16 Sep 2009) $ 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 032 package org.apache.commons.ssl; 033 034 import org.apache.commons.ssl.asn1.ASN1EncodableVector; 035 import org.apache.commons.ssl.asn1.DERInteger; 036 import org.apache.commons.ssl.asn1.DERSequence; 037 038 import java.io.ByteArrayInputStream; 039 import java.io.File; 040 import java.io.FileInputStream; 041 import java.io.FileOutputStream; 042 import java.io.IOException; 043 import java.math.BigInteger; 044 import java.security.GeneralSecurityException; 045 import java.security.InvalidKeyException; 046 import java.security.Key; 047 import java.security.KeyStore; 048 import java.security.KeyStoreException; 049 import java.security.NoSuchAlgorithmException; 050 import java.security.NoSuchProviderException; 051 import java.security.PrivateKey; 052 import java.security.PublicKey; 053 import java.security.UnrecoverableKeyException; 054 import java.security.cert.Certificate; 055 import java.security.cert.CertificateException; 056 import java.security.cert.CertificateFactory; 057 import java.security.cert.X509Certificate; 058 import java.security.interfaces.DSAParams; 059 import java.security.interfaces.DSAPrivateKey; 060 import java.security.interfaces.RSAPrivateCrtKey; 061 import java.security.interfaces.RSAPublicKey; 062 import java.util.Arrays; 063 import java.util.Collection; 064 import java.util.Collections; 065 import java.util.Enumeration; 066 import java.util.Iterator; 067 import java.util.LinkedList; 068 import 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 */ 080 public 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 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 320 Key key = null; 321 Certificate[] chain = null; 322 try { 323 PKCS8Key pkcs8Key = new PKCS8Key(stuff, jksPass); 324 key = pkcs8Key.getPrivateKey(); 325 } 326 catch (ProbablyBadPasswordException pbpe) { 327 throw pbpe; 328 } 329 catch (GeneralSecurityException gse) { 330 // no luck 331 } 332 333 List pemItems = PEMUtil.decode(stuff); 334 Iterator it = pemItems.iterator(); 335 LinkedList certificates = new LinkedList(); 336 while (it.hasNext()) { 337 PEMItem item = (PEMItem) it.next(); 338 byte[] derBytes = item.getDerBytes(); 339 String type = item.pemType.trim().toUpperCase(); 340 if (type.startsWith("CERT") || 341 type.startsWith("X509") || 342 type.startsWith("PKCS7")) { 343 ByteArrayInputStream in = new ByteArrayInputStream(derBytes); 344 X509Certificate c = (X509Certificate) cf.generateCertificate(in); 345 certificates.add(c); 346 } 347 chain = toChain(certificates); 348 } 349 350 if (chain != null || key != null) { 351 List chains = chain != null ? Collections.singletonList(chain) : null; 352 List keys = key != null ? Collections.singletonList(key) : null; 353 return new BuildResult(keys, chains, null); 354 } 355 356 boolean isProbablyPKCS12 = false; 357 boolean isASN = false; 358 ASN1Structure asn1 = null; 359 try { 360 asn1 = ASN1Util.analyze(stuff); 361 isASN = true; 362 isProbablyPKCS12 = asn1.oids.contains(PKCS7_ENCRYPTED); 363 if (!isProbablyPKCS12 && asn1.bigPayload != null) { 364 asn1 = ASN1Util.analyze(asn1.bigPayload); 365 isProbablyPKCS12 = asn1.oids.contains(PKCS7_ENCRYPTED); 366 } 367 } 368 catch (Exception e) { 369 // isProbablyPKCS12 and isASN are set properly by now. 370 } 371 372 ByteArrayInputStream stuffStream = new ByteArrayInputStream(stuff); 373 // Try default keystore... then try others. 374 BuildResult br = tryJKS(KeyStore.getDefaultType(), stuffStream, jksPass, keyPass); 375 if (br == null) { 376 br = tryJKS("jks", stuffStream, jksPass, keyPass); 377 if (br == null) { 378 br = tryJKS("jceks", stuffStream, jksPass, keyPass); 379 if (br == null) { 380 br = tryJKS("BKS", stuffStream, jksPass, keyPass); 381 if (br == null) { 382 br = tryJKS("UBER", stuffStream, jksPass, keyPass); 383 } 384 } 385 } 386 } 387 if (br != null) { 388 return br; 389 } 390 if (isASN) { 391 if (isProbablyPKCS12) { 392 return tryJKS("pkcs12", stuffStream, jksPass, null); 393 } 394 } else { 395 // Okay, it's ASN.1, but it's not PKCS12. Only one possible 396 // interesting things remains: X.509. 397 stuffStream.reset(); 398 399 try { 400 certificates = new LinkedList(); 401 Collection certs = cf.generateCertificates(stuffStream); 402 it = certs.iterator(); 403 while (it.hasNext()) { 404 X509Certificate x509 = (X509Certificate) it.next(); 405 certificates.add(x509); 406 } 407 chain = toChain(certificates); 408 if (chain != null && chain.length > 0) { 409 List chains = Collections.singletonList(chain); 410 return new BuildResult(null, chains, null); 411 } 412 } 413 catch (CertificateException ce) { 414 // oh well 415 } 416 417 stuffStream.reset(); 418 // Okay, still no luck. Maybe it's an ASN.1 DER stream 419 // containing only a single certificate? (I don't completely 420 // trust CertificateFactory.generateCertificates). 421 try { 422 Certificate c = cf.generateCertificate(stuffStream); 423 X509Certificate x509 = (X509Certificate) c; 424 chain = toChain(Collections.singleton(x509)); 425 if (chain != null && chain.length > 0) { 426 List chains = Collections.singletonList(chain); 427 return new BuildResult(null, chains, null); 428 } 429 } 430 catch (CertificateException ce) { 431 // oh well 432 } 433 } 434 435 br = tryJKS("pkcs12", stuffStream, jksPass, null); 436 if (br != null) { 437 // no exception thrown, so must be PKCS12. 438 System.out.println("Please report bug!"); 439 System.out.println("PKCS12 detection failed to realize this was PKCS12!"); 440 System.out.println(asn1); 441 return br; 442 } 443 throw new KeyStoreException("failed to extract any certificates or private keys - maybe bad password?"); 444 } 445 446 private static BuildResult tryJKS(String keystoreType, 447 ByteArrayInputStream in, 448 char[] jksPassword, char[] keyPassword) 449 throws ProbablyBadPasswordException { 450 in.reset(); 451 if (keyPassword == null || keyPassword.length <= 0) { 452 keyPassword = jksPassword; 453 } 454 455 keystoreType = keystoreType.trim().toLowerCase(); 456 boolean isPKCS12 = "pkcs12".equalsIgnoreCase(keystoreType); 457 try { 458 Key key = null; 459 Certificate[] chain = null; 460 UnrecoverableKeyException uke = null; 461 KeyStore jksKeyStore = KeyStore.getInstance(keystoreType); 462 jksKeyStore.load(in, jksPassword); 463 Enumeration en = jksKeyStore.aliases(); 464 while (en.hasMoreElements()) { 465 String alias = (String) en.nextElement(); 466 if (jksKeyStore.isKeyEntry(alias)) { 467 try { 468 key = jksKeyStore.getKey(alias, keyPassword); 469 if (key != null && key instanceof PrivateKey) { 470 chain = jksKeyStore.getCertificateChain(alias); 471 break; 472 } 473 } catch (UnrecoverableKeyException e) { 474 uke = e; // We might throw this one later. 475 } catch (GeneralSecurityException gse) { 476 // Swallow... keep looping. 477 } 478 } 479 if (isPKCS12 && en.hasMoreElements()) { 480 System.out.println("what kind of weird pkcs12 file has more than one alias?"); 481 } 482 } 483 if (key == null && uke != null) { 484 throw new ProbablyBadPasswordException("Probably bad JKS-Key password: " + uke); 485 } 486 if (isPKCS12) { 487 // PKCS12 is supposed to be just a key and a chain, anyway. 488 jksKeyStore = null; 489 } 490 491 List keys = Collections.singletonList(key); 492 List chains = Collections.singletonList(chain); 493 return new BuildResult(keys, chains, jksKeyStore); 494 } 495 catch (ProbablyBadPasswordException pbpe) { 496 throw pbpe; 497 } 498 catch (GeneralSecurityException gse) { 499 // swallow it, return null 500 return null; 501 } 502 catch (IOException ioe) { 503 String msg = ioe.getMessage(); 504 msg = msg != null ? msg.trim().toLowerCase() : ""; 505 if (isPKCS12) { 506 int x = msg.indexOf("failed to decrypt"); 507 int y = msg.indexOf("verify mac"); 508 x = Math.max(x, y); 509 if (x >= 0) { 510 throw new ProbablyBadPasswordException("Probably bad PKCS12 password: " + ioe); 511 } 512 } else { 513 int x = msg.indexOf("password"); 514 if (x >= 0) { 515 throw new ProbablyBadPasswordException("Probably bad JKS password: " + ioe); 516 } 517 } 518 // swallow it, return null. 519 return null; 520 } 521 } 522 523 private static X509Certificate[] toChain(Collection certs) { 524 if (certs != null && !certs.isEmpty()) { 525 X509Certificate[] x509Chain = new X509Certificate[certs.size()]; 526 certs.toArray(x509Chain); 527 return x509Chain; 528 } else { 529 return null; 530 } 531 } 532 533 534 public static void main(String[] args) throws Exception { 535 if (args.length < 2) { 536 System.out.println("KeyStoreBuilder: creates '[alias].jks' (Java Key Store)"); 537 System.out.println(" -topk8 mode: creates '[alias].pem' (x509 chain + unencrypted pkcs8)"); 538 System.out.println("[alias] will be set to the first CN value of the X509 certificate."); 539 System.out.println("-------------------------------------------------------------------"); 540 System.out.println("Usage1: [password] [file:pkcs12]"); 541 System.out.println("Usage2: [password] [file:private-key] [file:certificate-chain]"); 542 System.out.println("Usage3: -topk8 [password] [file:jks]"); 543 System.out.println("-------------------------------------------------------------------"); 544 System.out.println("[private-key] can be openssl format, or pkcs8."); 545 System.out.println("[password] decrypts [private-key], and also encrypts outputted JKS file."); 546 System.out.println("All files can be PEM or DER."); 547 System.exit(1); 548 } 549 char[] password = args[0].toCharArray(); 550 boolean toPKCS8 = false; 551 if ("-topk8".equalsIgnoreCase(args[0])) { 552 toPKCS8 = true; 553 password = args[1].toCharArray(); 554 args[1] = args[2]; 555 args[2] = null; 556 } 557 558 FileInputStream fin1 = new FileInputStream(args[1]); 559 byte[] bytes1 = Util.streamToBytes(fin1); 560 byte[] bytes2 = null; 561 if (args.length > 2 && args[2] != null) { 562 FileInputStream fin2 = new FileInputStream(args[2]); 563 bytes2 = Util.streamToBytes(fin2); 564 } 565 566 KeyStore ks = build(bytes1, bytes2, password); 567 Enumeration en = ks.aliases(); 568 String alias = "keystorebuilder"; 569 570 // We're going to assume that the biggest key is the one we want 571 // to convert to PKCS8 (PEM). That's until someone figures out a 572 // better way to deal with this annoying situation (more than 1 573 // key in the KeyStore). 574 int biggestKey = 0; 575 while (en.hasMoreElements()) { 576 String s = (String) en.nextElement(); 577 try { 578 PrivateKey pk = (PrivateKey) ks.getKey(s, password); 579 byte[] encoded = pk.getEncoded(); 580 int len = encoded != null ? encoded.length : 0; 581 if (len >= biggestKey) { 582 biggestKey = len; 583 alias = s; 584 } 585 } catch (Exception e) { 586 // oh well, try next one. 587 } 588 } 589 590 String suffix = toPKCS8 ? ".pem" : ".jks"; 591 String fileName = alias; 592 Certificate[] chain = ks.getCertificateChain(alias); 593 if (chain != null && chain[0] != null) { 594 String cn = Certificates.getCN((X509Certificate) chain[0]); 595 cn = cn != null ? cn.trim() : ""; 596 if (!"".equals(cn)) { 597 fileName = cn; 598 } 599 } 600 601 File f = new File(fileName + suffix); 602 int count = 1; 603 while (f.exists()) { 604 f = new File(alias + "_" + count + suffix); 605 count++; 606 } 607 608 FileOutputStream fout = new FileOutputStream(f); 609 if (toPKCS8) { 610 List pemItems = new LinkedList(); 611 PrivateKey key = (PrivateKey) ks.getKey(alias, password); 612 chain = ks.getCertificateChain(alias); 613 byte[] pkcs8DerBytes = null; 614 if (key instanceof RSAPrivateCrtKey) { 615 RSAPrivateCrtKey rsa = (RSAPrivateCrtKey) key; 616 ASN1EncodableVector vec = new ASN1EncodableVector(); 617 vec.add(new DERInteger(BigInteger.ZERO)); 618 vec.add(new DERInteger(rsa.getModulus())); 619 vec.add(new DERInteger(rsa.getPublicExponent())); 620 vec.add(new DERInteger(rsa.getPrivateExponent())); 621 vec.add(new DERInteger(rsa.getPrimeP())); 622 vec.add(new DERInteger(rsa.getPrimeQ())); 623 vec.add(new DERInteger(rsa.getPrimeExponentP())); 624 vec.add(new DERInteger(rsa.getPrimeExponentQ())); 625 vec.add(new DERInteger(rsa.getCrtCoefficient())); 626 DERSequence seq = new DERSequence(vec); 627 byte[] derBytes = PKCS8Key.encode(seq); 628 PKCS8Key pkcs8 = new PKCS8Key(derBytes, null); 629 pkcs8DerBytes = pkcs8.getDecryptedBytes(); 630 } else if (key instanceof DSAPrivateKey) { 631 DSAPrivateKey dsa = (DSAPrivateKey) key; 632 DSAParams params = dsa.getParams(); 633 BigInteger g = params.getG(); 634 BigInteger p = params.getP(); 635 BigInteger q = params.getQ(); 636 BigInteger x = dsa.getX(); 637 BigInteger y = q.modPow(x, p); 638 639 ASN1EncodableVector vec = new ASN1EncodableVector(); 640 vec.add(new DERInteger(BigInteger.ZERO)); 641 vec.add(new DERInteger(p)); 642 vec.add(new DERInteger(q)); 643 vec.add(new DERInteger(g)); 644 vec.add(new DERInteger(y)); 645 vec.add(new DERInteger(x)); 646 DERSequence seq = new DERSequence(vec); 647 byte[] derBytes = PKCS8Key.encode(seq); 648 PKCS8Key pkcs8 = new PKCS8Key(derBytes, null); 649 pkcs8DerBytes = pkcs8.getDecryptedBytes(); 650 } 651 if (chain != null && chain.length > 0) { 652 for (int i = 0; i < chain.length; i++) { 653 X509Certificate x509 = (X509Certificate) chain[i]; 654 byte[] derBytes = x509.getEncoded(); 655 PEMItem item = new PEMItem(derBytes, "CERTIFICATE"); 656 pemItems.add(item); 657 } 658 } 659 if (pkcs8DerBytes != null) { 660 PEMItem item = new PEMItem(pkcs8DerBytes, "PRIVATE KEY"); 661 pemItems.add(item); 662 } 663 byte[] pem = PEMUtil.encode(pemItems); 664 fout.write(pem); 665 } else { 666 // If we're not converting to unencrypted PKCS8 style PEM, 667 // then we are converting to Sun JKS. It happens right here: 668 KeyStore jks = KeyStore.getInstance(KeyStore.getDefaultType()); 669 jks.load(null, password); 670 jks.setKeyEntry(alias, ks.getKey(alias, password), password, ks.getCertificateChain(alias)); 671 jks.store(fout, password); 672 } 673 fout.flush(); 674 fout.close(); 675 System.out.println("Successfuly wrote: [" + f.getPath() + "]"); 676 } 677 678 679 }