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 keytore.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