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 }