KeyManagerImpl.java revision f33eae7e84eb6d3b0f4e86b59605bb3de73009f3
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17package org.apache.harmony.xnet.provider.jsse;
18
19import java.net.Socket;
20import java.security.KeyStore;
21import java.security.KeyStoreException;
22import java.security.NoSuchAlgorithmException;
23import java.security.Principal;
24import java.security.PrivateKey;
25import java.security.UnrecoverableEntryException;
26import java.security.KeyStore.PrivateKeyEntry;
27import java.security.cert.Certificate;
28import java.security.cert.X509Certificate;
29import java.util.Enumeration;
30import java.util.Hashtable;
31import java.util.Vector;
32
33import javax.net.ssl.SSLEngine;
34import javax.net.ssl.X509ExtendedKeyManager;
35import javax.security.auth.x500.X500Principal;
36
37/**
38 * KeyManager implementation.
39 *
40 * This implementation uses hashed key store information. It works faster than retrieving all of the
41 * data from the key store. Any key store changes, that happen after key manager was created, have
42 * no effect. The implementation does not use peer information (host, port) that may be obtained
43 * from socket or engine.
44 *
45 * @see javax.net.ssl.KeyManager
46 *
47 */
48public class KeyManagerImpl extends X509ExtendedKeyManager {
49
50    // hashed key store information
51    private final Hashtable<String, PrivateKeyEntry> hash;
52
53    /**
54     * Creates Key manager
55     *
56     * @param keyStore
57     * @param pwd
58     */
59    public KeyManagerImpl(KeyStore keyStore, char[] pwd) {
60        super();
61        this.hash = new Hashtable<String, PrivateKeyEntry>();
62        final Enumeration<String> aliases;
63        try {
64            aliases = keyStore.aliases();
65        } catch (KeyStoreException e) {
66            return;
67        }
68        for (; aliases.hasMoreElements();) {
69            final String alias = aliases.nextElement();
70            try {
71                if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
72                    final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore
73                            .getEntry(alias, new KeyStore.PasswordProtection(pwd));
74                    hash.put(alias, entry);
75                }
76            } catch (KeyStoreException e) {
77                continue;
78            } catch (UnrecoverableEntryException e) {
79                continue;
80            } catch (NoSuchAlgorithmException e) {
81                continue;
82            }
83        }
84    }
85
86    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
87        final String[] al = chooseAlias(keyType, issuers);
88        return (al == null ? null : al[0]);
89    }
90
91    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
92        final String[] al = chooseAlias(new String[] { keyType }, issuers);
93        return (al == null ? null : al[0]);
94    }
95
96    public X509Certificate[] getCertificateChain(String alias) {
97        // BEGIN android-changed
98        if (alias == null) {
99            return null;
100        }
101        // END android-changed
102        if (hash.containsKey(alias)) {
103            Certificate[] certs = hash.get(alias).getCertificateChain();
104            if (certs[0] instanceof X509Certificate) {
105                X509Certificate[] xcerts = new X509Certificate[certs.length];
106                for (int i = 0; i < certs.length; i++) {
107                    xcerts[i] = (X509Certificate) certs[i];
108                }
109                return xcerts;
110            }
111        }
112        return null;
113
114    }
115
116    public String[] getClientAliases(String keyType, Principal[] issuers) {
117        return chooseAlias(new String[] { keyType }, issuers);
118    }
119
120    public String[] getServerAliases(String keyType, Principal[] issuers) {
121        return chooseAlias(new String[] { keyType }, issuers);
122    }
123
124    public PrivateKey getPrivateKey(String alias) {
125        // BEGIN android-changed
126        if (alias == null) {
127            return null;
128        }
129        // END android-changed
130        if (hash.containsKey(alias)) {
131            return hash.get(alias).getPrivateKey();
132        }
133        return null;
134    }
135
136    @Override
137    public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
138        final String[] al = chooseAlias(keyType, issuers);
139        return (al == null ? null : al[0]);
140    }
141
142    @Override
143    public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
144        final String[] al = chooseAlias(new String[] { keyType }, issuers);
145        return (al == null ? null : al[0]);
146    }
147
148    private String[] chooseAlias(String[] keyType, Principal[] issuers) {
149        if (keyType == null || keyType.length == 0) {
150            return null;
151        }
152        Vector<String> found = new Vector<String>();
153        for (Enumeration<String> aliases = hash.keys(); aliases.hasMoreElements();) {
154            final String alias = aliases.nextElement();
155            final KeyStore.PrivateKeyEntry entry = hash.get(alias);
156            final Certificate[] certs = entry.getCertificateChain();
157            final String alg = certs[0].getPublicKey().getAlgorithm();
158            for (int i = 0; i < keyType.length; i++) {
159                if (alg.equals(keyType[i])) {
160                    if (issuers != null && issuers.length != 0) {
161                        // check that certificate was issued by specified issuer
162                        loop: for (int ii = 0; ii < certs.length; ii++) {
163                            if (certs[ii] instanceof X509Certificate) {
164                                X500Principal issuer = ((X509Certificate) certs[ii])
165                                        .getIssuerX500Principal();
166                                for (int iii = 0; iii < issuers.length; iii++) {
167                                    if (issuer.equals(issuers[iii])) {
168                                        found.add(alias);
169                                        break loop;
170                                    }
171                                }
172                            }
173
174                        }
175                    } else {
176                        found.add(alias);
177                    }
178                }
179            }
180        }
181        if (!found.isEmpty()) {
182            return found.toArray(new String[found.size()]);
183        }
184        return null;
185    }
186}
187