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