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