    001/*
    002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/src/java/org/apache/commons/ssl/KeyMaterial.java $
    003 * $Revision: 138 $
    004 * $Date: 2008-03-03 23:50:07 -0800 (Mon, 03 Mar 2008) $
    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
    032package org.apache.commons.ssl;
    033
    034import java.io.File;
    035import java.io.FileInputStream;
    036import java.io.IOException;
    037import java.io.InputStream;
    038import java.net.URL;
    039import java.security.GeneralSecurityException;
    040import java.security.KeyStore;
    041import java.security.KeyStoreException;
    042import java.security.cert.Certificate;
    043import java.security.cert.CertificateEncodingException;
    044import java.security.cert.X509Certificate;
    045import java.util.Collections;
    046import java.util.Enumeration;
    047import java.util.Iterator;
    048import java.util.LinkedList;
    049import java.util.List;
    050
    051/**
    052 * @author Credit Union Central of British Columbia
    053 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
    054 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
    055 * @since 27-Feb-2006
    056 */
    057public class KeyMaterial extends TrustMaterial {
    058    private final Object keyManagerFactory;
    059    private final List aliases;
    060    private final List associatedChains;
    061
    062    public KeyMaterial(InputStream jks, char[] password)
    063        throws GeneralSecurityException, IOException {
    064        this(Util.streamToBytes(jks), password);
    065    }
    066
    067    public KeyMaterial(InputStream jks, char[] jksPass, char[] keyPass)
    068        throws GeneralSecurityException, IOException {
    069        this(Util.streamToBytes(jks), jksPass, keyPass);
    070    }
    071
    072    public KeyMaterial(InputStream jks, InputStream key, char[] password)
    073        throws GeneralSecurityException, IOException {
    074        this(jks != null ? Util.streamToBytes(jks) : null,
    075            key != null ? Util.streamToBytes(key) : null,
    076            password);
    077    }
    078
    079    public KeyMaterial(InputStream jks, InputStream key, char[] jksPass,
    080                       char[] keyPass)
    081        throws GeneralSecurityException, IOException {
    082        this(jks != null ? Util.streamToBytes(jks) : null,
    083            key != null ? Util.streamToBytes(key) : null,
    084            jksPass, keyPass);
    085    }
    086
    087    public KeyMaterial(String pathToJksFile, char[] password)
    088        throws GeneralSecurityException, IOException {
    089        this(new File(pathToJksFile), password);
    090    }
    091
    092    public KeyMaterial(String pathToJksFile, char[] jksPass, char[] keyPass)
    093        throws GeneralSecurityException, IOException {
    094        this(new File(pathToJksFile), jksPass, keyPass);
    095    }
    096
    097    public KeyMaterial(String pathToCerts, String pathToKey, char[] password)
    098        throws GeneralSecurityException, IOException {
    099        this(pathToCerts != null ? new File(pathToCerts) : null,
    100            pathToKey != null ? new File(pathToKey) : null,
    101            password);
    102    }
    103
    104    public KeyMaterial(String pathToCerts, String pathToKey, char[] jksPass,
    105                       char[] keyPass)
    106        throws GeneralSecurityException, IOException {
    107        this(pathToCerts != null ? new File(pathToCerts) : null,
    108            pathToKey != null ? new File(pathToKey) : null,
    109            jksPass, keyPass);
    110    }
    111
    112    public KeyMaterial(File jksFile, char[] password)
    113        throws GeneralSecurityException, IOException {
    114        this(new FileInputStream(jksFile), password);
    115    }
    116
    117    public KeyMaterial(File jksFile, char[] jksPass, char[] keyPass)
    118        throws GeneralSecurityException, IOException {
    119        this(new FileInputStream(jksFile), jksPass, keyPass);
    120    }
    121
    122    public KeyMaterial(File certsFile, File keyFile, char[] password)
    123        throws GeneralSecurityException, IOException {
    124        this(certsFile != null ? new FileInputStream(certsFile) : null,
    125            keyFile != null ? new FileInputStream(keyFile) : null,
    126            password);
    127    }
    128
    129    public KeyMaterial(File certsFile, File keyFile, char[] jksPass,
    130                       char[] keyPass)
    131        throws GeneralSecurityException, IOException {
    132        this(certsFile != null ? new FileInputStream(certsFile) : null,
    133            keyFile != null ? new FileInputStream(keyFile) : null,
    134            jksPass, keyPass);
    135    }
    136
    137    public KeyMaterial(URL urlToJKS, char[] password)
    138        throws GeneralSecurityException, IOException {
    139        this(urlToJKS.openStream(), password);
    140    }
    141
    142    public KeyMaterial(URL urlToJKS, char[] jksPass, char[] keyPass)
    143        throws GeneralSecurityException, IOException {
    144        this(urlToJKS.openStream(), jksPass, keyPass);
    145    }
    146
    147    public KeyMaterial(URL urlToCerts, URL urlToKey, char[] password)
    148        throws GeneralSecurityException, IOException {
    149        this(urlToCerts.openStream(), urlToKey.openStream(), password);
    150    }
    151
    152    public KeyMaterial(URL urlToCerts, URL urlToKey, char[] jksPass,
    153                       char[] keyPass)
    154        throws GeneralSecurityException, IOException {
    155        this(urlToCerts.openStream(), urlToKey.openStream(), jksPass, keyPass);
    156    }
    157
    158    public KeyMaterial(byte[] jks, char[] password)
    159        throws GeneralSecurityException, IOException {
    160        this(jks, (byte[]) null, password);
    161    }
    162
    163    public KeyMaterial(byte[] jks, char[] jksPass, char[] keyPass)
    164        throws GeneralSecurityException, IOException {
    165        this(jks, null, jksPass, keyPass);
    166    }
    167
    168    public KeyMaterial(byte[] jksOrCerts, byte[] key, char[] password)
    169        throws GeneralSecurityException, IOException {
    170        this(jksOrCerts, key, password, password);
    171    }
    172
    173
    174    public KeyMaterial(byte[] jksOrCerts, byte[] key, char[] jksPass,
    175                       char[] keyPass)
    176        throws GeneralSecurityException, IOException {
    177        // We're not a simple trust type, so set "simpleTrustType" value to 0.
    178        // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types.
    179        super(KeyStoreBuilder.build(jksOrCerts, key, jksPass, keyPass), 0);
    180        KeyStore ks = getKeyStore();
    181        Enumeration en = ks.aliases();
    182        List myAliases = new LinkedList();
    183        List myChains = new LinkedList();
    184        while (en.hasMoreElements()) {
    185            X509Certificate[] c; // chain
    186            String alias = (String) en.nextElement();
    187            if (ks.isKeyEntry(alias)) {
    188                try {
    189                    ks.getKey(alias, keyPass);
    190                    // No Exception thrown, so we're good!
    191                    myAliases.add(alias);
    192                    Certificate[] chain = ks.getCertificateChain(alias);
    193                    if (chain != null) {
    194                        c = Certificates.x509ifyChain(chain);
    195                        // Cleanup chain to remove any spurious entries.
    196                        if (c != null) {
    197                            X509Certificate l = c[0]; // The leaf node.
    198                            c = X509CertificateChainBuilder.buildPath(l, c);
    199                        }
    200                        myChains.add(c);
    201                    } else {
    202                        throw new KeyStoreException("Could not find KeyMaterial's associated certificate chain with alis=[" + alias + "]");
    203                    }
    204
    205                } catch (GeneralSecurityException gse) {
    206                    // oh well, we can't use that KeyStore alias.
    207                }
    208            }
    209        }
    210        if (myAliases.isEmpty()) {
    211            throw new KeyStoreException("KeyMaterial provided does not contain any keys!");
    212        }
    213        this.aliases = Collections.unmodifiableList(myAliases);
    214        this.associatedChains = Collections.unmodifiableList(myChains);
    215        this.keyManagerFactory = JavaImpl.newKeyManagerFactory(ks, keyPass);
    216    }
    217
    218    public Object[] getKeyManagers() {
    219        return JavaImpl.getKeyManagers(keyManagerFactory);
    220    }
    221
    222    public List getAssociatedCertificateChains() {
    223        return associatedChains;
    224    }
    225
    226    public KeyStore getKeyStore() {
    227        return super.getKeyStore();
    228    }
    229
    230    public List getAliases() {
    231        return aliases;
    232    }
    233
    234    public static void main(String[] args) throws Exception {
    235        if (args.length < 2) {
    236            System.out.println("Usage1:  java org.apache.commons.ssl.KeyMaterial [password] [pkcs12 or jks]");
    237            System.out.println("Usage2:  java org.apache.commons.ssl.KeyMaterial [password] [private-key] [cert-chain]");
    238            System.exit(1);
    239        }
    240        char[] jksPass = args[0].toCharArray();
    241        char[] keyPass = jksPass;
    242        String path1 = args[1];
    243        String path2 = null;
    244        if (args.length >= 3) {
    245            path2 = args[2];
    246        }
    247        if (args.length >= 4) {
    248            keyPass = args[3].toCharArray();
    249        } else if (path2 != null) {
    250            File f = new File(path2);
    251            if (!f.exists()) {
    252                // Hmmm... maybe it's a password.
    253                keyPass = path2.toCharArray();
    254                path2 = null;
    255            }
    256        }
    257
    258        KeyMaterial km = new KeyMaterial(path1, path2, jksPass, keyPass);
    259        System.out.println(km);
    260    }
    261
    262    public String toString() {
    263        List chains = getAssociatedCertificateChains();
    264        List aliases = getAliases();
    265        Iterator it = chains.iterator();
    266        Iterator aliasesIt = aliases.iterator();
    267        StringBuffer buf = new StringBuffer(8192);
    268        while (it.hasNext()) {
    269            X509Certificate[] certs = (X509Certificate[]) it.next();
    270            String alias = (String) aliasesIt.next();
    271            buf.append("Alias: ");
    272            buf.append(alias);
    273            buf.append('\n');
    274            if (certs != null) {
    275                for (int i = 0; i < certs.length; i++) {
    276                    buf.append(Certificates.toString(certs[i]));
    277                    try {
    278                        buf.append(Certificates.toPEMString(certs[i]));
    279                    }
    280                    catch (CertificateEncodingException cee) {
    281                        buf.append(cee.toString());
    282                        buf.append('\n');
    283                    }
    284                }
    285            }
    286        }
    287        return buf.toString();
    288    }
    289}