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-2016 ForgeRock AS. 017 */ 018package org.opends.admin.ads.util; 019 020import java.net.Socket; 021import java.security.KeyStore; 022import java.security.KeyStoreException; 023import java.security.NoSuchAlgorithmException; 024import java.security.NoSuchProviderException; 025import java.security.Principal; 026import java.security.PrivateKey; 027import java.security.UnrecoverableKeyException; 028import java.security.cert.X509Certificate; 029 030import javax.net.ssl.KeyManager; 031import javax.net.ssl.KeyManagerFactory; 032import javax.net.ssl.TrustManagerFactory; 033import javax.net.ssl.X509KeyManager; 034 035import org.forgerock.i18n.LocalizableMessage; 036import org.forgerock.i18n.slf4j.LocalizedLogger; 037import org.opends.server.util.Platform; 038 039/** 040 * This class is in charge of checking whether the certificates that are 041 * presented are trusted or not. 042 * This implementation tries to check also that the subject DN of the 043 * certificate corresponds to the host passed using the setHostName method. 044 * 045 * The constructor tries to use a default TrustManager from the system and if 046 * it cannot be retrieved this class will only accept the certificates 047 * explicitly accepted by the user (and specified by calling acceptCertificate). 048 * 049 * NOTE: this class is not aimed to be used when we have connections in parallel. 050 */ 051public class ApplicationKeyManager implements X509KeyManager 052{ 053 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 054 055 /** The default keyManager. */ 056 private X509KeyManager keyManager; 057 058 /** 059 * The default constructor. 060 * @param keystore The keystore to use for this keymanager. 061 * @param password The keystore password to use for this keymanager. 062 */ 063 public ApplicationKeyManager(KeyStore keystore, char[] password) 064 { 065 KeyManagerFactory kmf = null; 066 String userSpecifiedAlgo = 067 System.getProperty("org.opends.admin.keymanageralgo"); 068 String userSpecifiedProvider = 069 System.getProperty("org.opends.admin.keymanagerprovider"); 070 071 //Handle IBM specific cases if the user did not specify a algorithm and/or 072 //provider. 073 if(userSpecifiedAlgo == null && Platform.isVendor("IBM")) 074 { 075 userSpecifiedAlgo = "IbmX509"; 076 } 077 if(userSpecifiedProvider == null && Platform.isVendor("IBM")) 078 { 079 userSpecifiedProvider = "IBMJSSE2"; 080 } 081 082 // Have some fallbacks to choose the provider and algorith of the key 083 // manager. First see if the user wanted to use something specific, 084 // then try with the SunJSSE provider and SunX509 algorithm. Finally, 085 // fallback to the default algorithm of the JVM. 086 String[] preferredProvider = 087 { userSpecifiedProvider, "SunJSSE", null, null }; 088 String[] preferredAlgo = 089 { userSpecifiedAlgo, "SunX509", "SunX509", 090 TrustManagerFactory.getDefaultAlgorithm() }; 091 092 for (int i=0; i<preferredProvider.length && keyManager == null; i++) 093 { 094 String provider = preferredProvider[i]; 095 String algo = preferredAlgo[i]; 096 if (algo == null) 097 { 098 continue; 099 } 100 try 101 { 102 if (provider != null) 103 { 104 kmf = KeyManagerFactory.getInstance(algo, provider); 105 } 106 else 107 { 108 kmf = KeyManagerFactory.getInstance(algo); 109 } 110 kmf.init(keystore, password); 111 KeyManager kms[] = kmf.getKeyManagers(); 112 /* 113 * Iterate over the returned keymanagers, look for an instance 114 * of X509KeyManager. If found, use that as our "default" key manager. 115 */ 116 for (KeyManager km : kms) 117 { 118 if (kms[i] instanceof X509KeyManager) 119 { 120 keyManager = (X509KeyManager) km; 121 break; 122 } 123 } 124 } 125 catch (NoSuchAlgorithmException e) 126 { 127 // Nothing to do. Maybe we should avoid this and be strict, but we are 128 // in a best effort mode. 129 logger.warn(LocalizableMessage.raw("Error with the algorithm", e)); 130 } 131 catch (KeyStoreException 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 keystore", e)); 136 } 137 catch (UnrecoverableKeyException 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 key", e)); 142 } 143 catch (NoSuchProviderException 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 provider", e)); 148 } 149 } 150 } 151 152 @Override 153 public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) 154 { 155 return keyManager != null ? keyManager.chooseClientAlias(keyType, issuers, socket) : null; 156 } 157 158 @Override 159 public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) 160 { 161 return keyManager != null ? keyManager.chooseServerAlias(keyType, issuers, socket) : null; 162 } 163 164 @Override 165 public X509Certificate[] getCertificateChain(String alias) 166 { 167 return keyManager != null ? keyManager.getCertificateChain(alias) : null; 168 } 169 170 @Override 171 public String[] getClientAliases(String keyType, Principal[] issuers) 172 { 173 return keyManager != null ? keyManager.getClientAliases(keyType, issuers) : null; 174 } 175 176 @Override 177 public PrivateKey getPrivateKey(String alias) 178 { 179 return keyManager != null ? keyManager.getPrivateKey(alias) : null; 180 } 181 182 @Override 183 public String[] getServerAliases(String keyType, Principal[] issuers) 184 { 185 return keyManager != null ? keyManager.getServerAliases(keyType, issuers) : null; 186 } 187}