View Javadoc

1   // ========================================================================
2   // Copyright (c) 1999 Jason Gilbert
3   // ========================================================================
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.jetty.security;
16  
17  import java.io.File;
18  import java.io.FileInputStream;
19  import java.io.FileOutputStream;
20  import java.io.IOException;
21  import java.io.InputStreamReader;
22  import java.io.OutputStream;
23  import java.security.Key;
24  import java.security.KeyStore;
25  import java.security.cert.Certificate;
26  import java.security.cert.X509Certificate;
27  import java.util.Enumeration;
28  
29  /**
30   * This class can be used to import a key/certificate pair from a pkcs12 file
31   * into a regular JKS format keystore for use with jetty and other java based
32   * SSL applications, etc. 
33   *<PRE>
34   *    usage: java PKCS12Import {pkcs12file} [newjksfile]
35   *</PRE>
36   *
37   * If you don't supply newjksfile, newstore.jks will be used.  This can be an
38   * existing JKS keystore.
39   * <P>
40   * Upon execution, you will be prompted for the password for the pkcs12 keystore
41   * as well as the password for the jdk file.  After execution you should have a
42   * JKS keystore file that contains the private key and certificate that were in
43   * the pkcs12
44   * <P>
45   * You can generate a pkcs12 file from PEM encoded certificate and key files
46   * using the following openssl command:
47   * <PRE>
48   *    openssl pkcs12 -export -out keystore.pkcs12 -in www.crt -inkey www.key
49   * </PRE>
50   * then run:
51   * <PRE>
52   *    java PKCS12Import keystore.pkcs12 keystore.jks
53   * </PRE>
54   *
55   * @author Jason Gilbert &lt;jason@doozer.com&gt;
56   */
57  public class PKCS12Import
58  {
59     public static void main(String[] args) throws Exception
60     {
61        if (args.length < 1) {
62           System.err.println(
63                 "usage: java PKCS12Import {pkcs12file} [newjksfile]");
64           System.exit(1);
65        }
66  
67        File fileIn = new File(args[0]);
68        File fileOut;
69        if (args.length > 1) {
70           fileOut = new File(args[1]);
71        } else {
72           fileOut = new File("newstore.jks");
73        }
74  
75        if (!fileIn.canRead()) {
76           System.err.println(
77                 "Unable to access input keystore: " + fileIn.getPath());
78           System.exit(2);
79        }
80  
81        if (fileOut.exists() && !fileOut.canWrite()) {
82           System.err.println(
83                 "Output file is not writable: " + fileOut.getPath());
84           System.exit(2);
85        }
86  
87        KeyStore kspkcs12 = KeyStore.getInstance("pkcs12");
88        KeyStore ksjks = KeyStore.getInstance("jks");
89  
90        System.out.print("Enter input keystore passphrase: ");
91        char[] inphrase = readPassphrase();
92        System.out.print("Enter output keystore passphrase: ");
93        char[] outphrase = readPassphrase();
94  
95        kspkcs12.load(new FileInputStream(fileIn), inphrase);
96  
97        ksjks.load(
98              (fileOut.exists())
99              ? new FileInputStream(fileOut) : null, outphrase);
100 
101       Enumeration eAliases = kspkcs12.aliases();
102       int n = 0;
103       while (eAliases.hasMoreElements()) {
104          String strAlias = (String)eAliases.nextElement();
105          System.err.println("Alias " + n++ + ": " + strAlias);
106 
107          if (kspkcs12.isKeyEntry(strAlias)) {
108             System.err.println("Adding key for alias " + strAlias);
109             Key key = kspkcs12.getKey(strAlias, inphrase);
110 
111             Certificate[] chain = kspkcs12.getCertificateChain(strAlias);
112 
113             ksjks.setKeyEntry(strAlias, key, outphrase, chain);
114          }
115       }
116 
117       OutputStream out = new FileOutputStream(fileOut);
118       ksjks.store(out, outphrase);
119       out.close();
120    }
121 
122    static void dumpChain(Certificate[] chain)
123    {
124       for (int i = 0; i < chain.length; i++) {
125          Certificate cert = chain[i];
126          if (cert instanceof X509Certificate) {
127             X509Certificate x509 = (X509Certificate)chain[i];
128             System.err.println("subject: " + x509.getSubjectDN());
129             System.err.println("issuer: " + x509.getIssuerDN());
130          }
131       }
132    }
133 
134    static char[] readPassphrase() throws IOException
135    {
136       InputStreamReader in = new InputStreamReader(System.in);
137 
138       char[] cbuf = new char[256];
139       int i = 0;
140 
141 readchars:
142       while (i < cbuf.length) {
143          char c = (char)in.read();
144          switch (c) {
145             case '\r':
146                break readchars;
147             case '\n':
148                break readchars;
149             default:
150                cbuf[i++] = c;
151          }
152       }
153 
154       char[] phrase = new char[i];
155       System.arraycopy(cbuf, 0, phrase, 0, i);
156       return phrase;
157    }
158 }
159