001: // ========================================================================
002: // Copyright (c) 1999 Jason Gilbert
003: // ========================================================================
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.jetty.security;
016:
017: import java.io.File;
018: import java.io.FileInputStream;
019: import java.io.FileOutputStream;
020: import java.io.IOException;
021: import java.io.InputStreamReader;
022: import java.io.OutputStream;
023: import java.security.Key;
024: import java.security.KeyStore;
025: import java.security.cert.Certificate;
026: import java.security.cert.X509Certificate;
027: import java.util.Enumeration;
028:
029: /**
030: * This class can be used to import a key/certificate pair from a pkcs12 file
031: * into a regular JKS format keystore for use with jetty and other java based
032: * SSL applications, etc.
033: *<PRE>
034: * usage: java PKCS12Import {pkcs12file} [newjksfile]
035: *</PRE>
036: *
037: * If you don't supply newjksfile, newstore.jks will be used. This can be an
038: * existing JKS keystore.
039: * <P>
040: * Upon execution, you will be prompted for the password for the pkcs12 keystore
041: * as well as the password for the jdk file. After execution you should have a
042: * JKS keystore file that contains the private key and certificate that were in
043: * the pkcs12
044: * <P>
045: * You can generate a pkcs12 file from PEM encoded certificate and key files
046: * using the following openssl command:
047: * <PRE>
048: * openssl pkcs12 -export -out keystore.pkcs12 -in www.crt -inkey www.key
049: * </PRE>
050: * then run:
051: * <PRE>
052: * java PKCS12Import keystore.pkcs12 keytore.jks
053: * </PRE>
054: *
055: * @author Jason Gilbert <jason@doozer.com>
056: */
057: public class PKCS12Import {
058: public static void main(String[] args) throws Exception {
059: if (args.length < 1) {
060: System.err
061: .println("usage: java PKCS12Import {pkcs12file} [newjksfile]");
062: System.exit(1);
063: }
064:
065: File fileIn = new File(args[0]);
066: File fileOut;
067: if (args.length > 1) {
068: fileOut = new File(args[1]);
069: } else {
070: fileOut = new File("newstore.jks");
071: }
072:
073: if (!fileIn.canRead()) {
074: System.err.println("Unable to access input keystore: "
075: + fileIn.getPath());
076: System.exit(2);
077: }
078:
079: if (fileOut.exists() && !fileOut.canWrite()) {
080: System.err.println("Output file is not writable: "
081: + fileOut.getPath());
082: System.exit(2);
083: }
084:
085: KeyStore kspkcs12 = KeyStore.getInstance("pkcs12");
086: KeyStore ksjks = KeyStore.getInstance("jks");
087:
088: System.out.print("Enter input keystore passphrase: ");
089: char[] inphrase = readPassphrase();
090: System.out.print("Enter output keystore passphrase: ");
091: char[] outphrase = readPassphrase();
092:
093: kspkcs12.load(new FileInputStream(fileIn), inphrase);
094:
095: ksjks.load((fileOut.exists()) ? new FileInputStream(fileOut)
096: : null, outphrase);
097:
098: Enumeration eAliases = kspkcs12.aliases();
099: int n = 0;
100: while (eAliases.hasMoreElements()) {
101: String strAlias = (String) eAliases.nextElement();
102: System.err.println("Alias " + n++ + ": " + strAlias);
103:
104: if (kspkcs12.isKeyEntry(strAlias)) {
105: System.err.println("Adding key for alias " + strAlias);
106: Key key = kspkcs12.getKey(strAlias, inphrase);
107:
108: Certificate[] chain = kspkcs12
109: .getCertificateChain(strAlias);
110:
111: ksjks.setKeyEntry(strAlias, key, outphrase, chain);
112: }
113: }
114:
115: OutputStream out = new FileOutputStream(fileOut);
116: ksjks.store(out, outphrase);
117: out.close();
118: }
119:
120: static void dumpChain(Certificate[] chain) {
121: for (int i = 0; i < chain.length; i++) {
122: Certificate cert = chain[i];
123: if (cert instanceof X509Certificate) {
124: X509Certificate x509 = (X509Certificate) chain[i];
125: System.err.println("subject: " + x509.getSubjectDN());
126: System.err.println("issuer: " + x509.getIssuerDN());
127: }
128: }
129: }
130:
131: static char[] readPassphrase() throws IOException {
132: InputStreamReader in = new InputStreamReader(System.in);
133:
134: char[] cbuf = new char[256];
135: int i = 0;
136:
137: readchars: while (i < cbuf.length) {
138: char c = (char) in.read();
139: switch (c) {
140: case '\r':
141: break readchars;
142: case '\n':
143: break readchars;
144: default:
145: cbuf[i++] = c;
146: }
147: }
148:
149: char[] phrase = new char[i];
150: System.arraycopy(cbuf, 0, phrase, 0, i);
151: return phrase;
152: }
153: }
|