001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.admin.ads.util; 029 030 import java.net.Socket; 031 import java.security.KeyStore; 032 import java.security.KeyStoreException; 033 import java.security.NoSuchAlgorithmException; 034 import java.security.NoSuchProviderException; 035 import java.security.Principal; 036 import java.security.PrivateKey; 037 import java.security.UnrecoverableKeyException; 038 import java.security.cert.X509Certificate; 039 import java.util.logging.Level; 040 import java.util.logging.Logger; 041 042 import javax.net.ssl.KeyManager; 043 import javax.net.ssl.KeyManagerFactory; 044 import javax.net.ssl.X509KeyManager; 045 046 047 /** 048 * This class is in charge of checking whether the certificates that are 049 * presented are trusted or not. 050 * This implementation tries to check also that the subject DN of the 051 * certificate corresponds to the host passed using the setHostName method. 052 * 053 * The constructor tries to use a default TrustManager from the system and if 054 * it cannot be retrieved this class will only accept the certificates 055 * explicitly accepted by the user (and specified by calling acceptCertificate). 056 * 057 * NOTE: this class is not aimed to be used when we have connections in paralel. 058 */ 059 public class ApplicationKeyManager implements X509KeyManager 060 { 061 static private final Logger LOG = 062 Logger.getLogger(ApplicationKeyManager.class.getName()); 063 064 /** 065 * The default keyManager. 066 */ 067 private X509KeyManager sunJSSEX509KeyManager = null ; 068 069 /** 070 * The default constructor. 071 * @param keystore The keystore to use for this keymanager. 072 * @param password The keystore password to use for this keymanager. 073 */ 074 public ApplicationKeyManager(KeyStore keystore, char[] password) 075 { 076 KeyManagerFactory kmf = null; 077 String algo = "SunX509"; 078 String provider = "SunJSSE"; 079 try 080 { 081 kmf = KeyManagerFactory.getInstance(algo, provider); 082 kmf.init(keystore, password); 083 KeyManager kms[] = kmf.getKeyManagers(); 084 085 /* 086 * Iterate over the returned keymanagers, look for an instance 087 * of X509KeyManager. If found, use that as our "default" key 088 * manager. 089 */ 090 for (int i = 0; i < kms.length; i++) 091 { 092 if (kms[i] instanceof X509KeyManager) 093 { 094 sunJSSEX509KeyManager = (X509KeyManager) kms[i]; 095 break; 096 } 097 } 098 099 } 100 catch (NoSuchAlgorithmException e) 101 { 102 // Nothing to do. Maybe we should avoid this and be strict, but we are 103 // in a best effor mode. 104 LOG.log(Level.WARNING, "Error with the algorithm", e); 105 } 106 catch (NoSuchProviderException e) 107 { 108 // Nothing to do. Maybe we should avoid this and be strict, but we are 109 // in a best effor mode. 110 LOG.log(Level.WARNING, "Error with the provider", e); 111 } 112 catch (KeyStoreException e) 113 { 114 // Nothing to do. Maybe we should avoid this and be strict, but we are 115 // in a best effor mode.. 116 LOG.log(Level.WARNING, "Error with the keystore", e); 117 } 118 catch (UnrecoverableKeyException e) 119 { 120 // Nothing to do. Maybe we should avoid this and be strict, but we are 121 // in a best effor mode. 122 LOG.log(Level.WARNING, "Error with the key", e); 123 } 124 } 125 126 127 /** 128 * Choose an alias to authenticate the client side of a secure 129 * socket given the public key type and the list of certificate 130 * issuer authorities recognized by the peer (if any). 131 * 132 * @param keyType 133 * the key algorithm type name(s), ordered with the 134 * most-preferred key type first. 135 * @param issuers 136 * the list of acceptable CA issuer subject names or null 137 * if it does not matter which issuers are used. 138 * @param socket 139 * the socket to be used for this connection. This 140 * parameter can be null, in which case this method will 141 * return the most generic alias to use. 142 * @return the alias name for the desired key, or null if there are 143 * no matches. 144 */ 145 public String chooseClientAlias(String[] keyType, Principal[] issuers, 146 Socket socket) 147 { 148 if (sunJSSEX509KeyManager != null) 149 { 150 return sunJSSEX509KeyManager.chooseClientAlias(keyType, issuers, socket); 151 } 152 else 153 { 154 return null ; 155 } 156 } 157 158 /** 159 * Choose an alias to authenticate the client side of a secure 160 * socket given the public key type and the list of certificate 161 * issuer authorities recognized by the peer (if any). 162 * 163 * @param keyType 164 * the key algorithm type name(s), ordered with the 165 * most-preferred key type first. 166 * @param issuers 167 * the list of acceptable CA issuer subject names or null 168 * if it does not matter which issuers are used. 169 * @param socket 170 * the socket to be used for this connection. This 171 * parameter can be null, in which case this method will 172 * return the most generic alias to use. 173 * @return the alias name for the desired key, or null if there are 174 * no matches. 175 */ 176 public String chooseServerAlias(String keyType, Principal[] issuers, 177 Socket socket) 178 { 179 if (sunJSSEX509KeyManager != null) 180 { 181 return sunJSSEX509KeyManager.chooseServerAlias(keyType, issuers, socket); 182 } 183 else 184 { 185 return null; 186 } 187 } 188 189 /** 190 * Returns the certificate chain associated with the given alias. 191 * 192 * @param alias 193 * the alias name 194 * @return the certificate chain (ordered with the user's 195 * certificate first and the root certificate authority 196 * last), or null if the alias can't be found. 197 */ 198 public X509Certificate[] getCertificateChain(String alias) 199 { 200 if (sunJSSEX509KeyManager != null) 201 { 202 return sunJSSEX509KeyManager.getCertificateChain(alias); 203 } 204 else 205 { 206 return null; 207 } 208 } 209 210 /** 211 * Get the matching aliases for authenticating the server side of a 212 * secure socket given the public key type and the list of 213 * certificate issuer authorities recognized by the peer (if any). 214 * 215 * @param keyType 216 * the key algorithm type name 217 * @param issuers 218 * the list of acceptable CA issuer subject names or null 219 * if it does not matter which issuers are used. 220 * @return an array of the matching alias names, or null if there 221 * were no matches. 222 */ 223 public String[] getClientAliases(String keyType, Principal[] issuers) 224 { 225 if (sunJSSEX509KeyManager != null) 226 { 227 return sunJSSEX509KeyManager.getClientAliases(keyType, issuers); 228 } 229 else 230 { 231 return null; 232 } 233 } 234 235 /** 236 * Returns the key associated with the given alias. 237 * 238 * @param alias 239 * the alias name 240 * @return the requested key, or null if the alias can't be found. 241 */ 242 public PrivateKey getPrivateKey(String alias) 243 { 244 if (sunJSSEX509KeyManager != null) 245 { 246 return sunJSSEX509KeyManager.getPrivateKey(alias); 247 } 248 else 249 { 250 return null; 251 } 252 } 253 254 /** 255 * Get the matching aliases for authenticating the server side of a 256 * secure socket given the public key type and the list of 257 * certificate issuer authorities recognized by the peer (if any). 258 * 259 * @param keyType 260 * the key algorithm type name 261 * @param issuers 262 * the list of acceptable CA issuer subject names or null 263 * if it does not matter which issuers are used. 264 * @return an array of the matching alias names, or null if there 265 * were no matches. 266 */ 267 public String[] getServerAliases(String keyType, Principal[] issuers) 268 { 269 if (sunJSSEX509KeyManager != null) 270 { 271 return sunJSSEX509KeyManager.getServerAliases(keyType, issuers); 272 } 273 else 274 { 275 return null; 276 } 277 } 278 }