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