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-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027 028package org.opends.quicksetup.util; 029 030import java.io.File; 031import java.io.FileInputStream; 032import java.io.FileOutputStream; 033import java.io.IOException; 034import java.security.KeyStore; 035import java.security.KeyStoreException; 036import java.security.NoSuchAlgorithmException; 037import java.security.cert.Certificate; 038import java.security.cert.CertificateException; 039import java.security.cert.X509Certificate; 040import java.util.Enumeration; 041 042import org.forgerock.i18n.LocalizableMessage; 043import org.forgerock.i18n.slf4j.LocalizedLogger; 044 045/** 046 * Class used to get the KeyStore that the graphical utilities use. 047 * 048 */ 049public class UIKeyStore extends KeyStore 050{ 051 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 052 private static KeyStore keyStore; 053 054 /** 055 * This should never be called. 056 */ 057 private UIKeyStore() 058 { 059 super(null, null, null); 060 } 061 /** 062 * Returns the KeyStore to be used by graphical applications. 063 * @return the KeyStore to be used by graphical applications. 064 * @throws IOException if there was a file system access error. 065 * @throws KeyStoreException if there was a problem while reading the key 066 * store. 067 * @throws CertificateException if an error with a certificate occurred. 068 * @throws NoSuchAlgorithmException if the used algorithm is not supported 069 * by the system. 070 */ 071 public static KeyStore getInstance() throws IOException, KeyStoreException, 072 CertificateException, NoSuchAlgorithmException 073 { 074 if (keyStore == null) 075 { 076 keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 077 String keyStorePath = getKeyStorePath(); 078 079 File f = new File(keyStorePath); 080 if (!f.exists()) 081 { 082 logger.info(LocalizableMessage.raw("Path "+keyStorePath+ " does not exist")); 083 keyStorePath = null; 084 } 085 else if (f.isDirectory()) 086 { 087 logger.error(LocalizableMessage.raw("Path "+keyStorePath+ " is a directory")); 088 keyStorePath = null; 089 } 090 else if (!f.canRead()) 091 { 092 logger.error(LocalizableMessage.raw("Path "+keyStorePath+ " is not readable")); 093 keyStorePath = null; 094 } 095 else if (!f.canWrite()) 096 { 097 logger.error(LocalizableMessage.raw("Path "+keyStorePath+ " is not writable")); 098 keyStorePath = null; 099 } 100 101 102 if (keyStorePath != null) 103 { 104 FileInputStream fos = new FileInputStream(keyStorePath); 105 try 106 { 107 keyStore.load(fos, null); 108 } 109 catch (Throwable t) 110 { 111 logger.error(LocalizableMessage.raw("Error reading key store on "+keyStorePath, t)); 112 keyStore.load(null, null); 113 } 114 fos.close(); 115 } 116 else 117 { 118 keyStore.load(null, null); 119 } 120 loadLocalAdminTrustStore(keyStore); 121 } 122 return keyStore; 123 } 124 125 /** 126 * Updates the Key Store with the provided certificate chain. 127 * @param chain the certificate chain to be accepted. 128 * @throws IOException if there was a file system access error. 129 * @throws KeyStoreException if there was a problem while reading or writing 130 * to the key store. 131 * @throws CertificateException if an error with a certificate occurred. 132 * @throws NoSuchAlgorithmException if the used algorithm is not supported 133 * by the system. 134 */ 135 public static void acceptCertificate(X509Certificate[] chain) 136 throws IOException,KeyStoreException, CertificateException, 137 NoSuchAlgorithmException 138 { 139 logger.info(LocalizableMessage.raw("Accepting certificate chain.")); 140 KeyStore k = getInstance(); 141 for (X509Certificate aChain : chain) { 142 if (!containsCertificate(aChain, k)) { 143 String alias = aChain.getSubjectDN().getName(); 144 int j = 1; 145 while (k.containsAlias(alias)) { 146 alias = aChain.getSubjectDN().getName() + "-" + j; 147 j++; 148 } 149 k.setCertificateEntry(alias, aChain); 150 } 151 } 152 String keyStorePath = getKeyStorePath(); 153 File f = new File(keyStorePath); 154 if (!f.exists()) 155 { 156 Utils.createFile(f); 157 } 158 FileOutputStream fos = new FileOutputStream(getKeyStorePath(), false); 159 k.store(fos, new char[]{}); 160 fos.close(); 161 } 162 163 /** 164 * Returns the path where we store the keystore for the graphical 165 * applications. 166 * @return the path where we store the keystore for the graphical 167 * applications. 168 */ 169 private static String getKeyStorePath() 170 { 171 return System.getProperty("user.home") + File.separator + 172 ".opendj" + File.separator + "gui-keystore"; 173 } 174 175 /** 176 * Loads the local admin truststore. 177 * @param keyStore the keystore where the admin truststore will be loaded. 178 */ 179 private static void loadLocalAdminTrustStore(KeyStore keyStore) 180 { 181 String adminTrustStorePath = getLocalAdminTrustStorePath(); 182 File f = new File(adminTrustStorePath); 183 if (!f.exists()) 184 { 185 logger.info(LocalizableMessage.raw("Path "+adminTrustStorePath+ " does not exist")); 186 adminTrustStorePath = null; 187 } 188 else if (f.isDirectory()) 189 { 190 logger.error(LocalizableMessage.raw("Path "+adminTrustStorePath+ " is a directory")); 191 adminTrustStorePath = null; 192 } 193 else if (!f.canRead()) 194 { 195 logger.error(LocalizableMessage.raw("Path "+adminTrustStorePath+ " is not readable")); 196 adminTrustStorePath = null; 197 } 198 199 if (adminTrustStorePath != null) 200 { 201 FileInputStream fos = null; 202 try 203 { 204 fos = new FileInputStream(adminTrustStorePath); 205 KeyStore adminKeyStore = 206 KeyStore.getInstance(KeyStore.getDefaultType()); 207 adminKeyStore.load(fos, null); 208 Enumeration<String> aliases = adminKeyStore.aliases(); 209 while (aliases.hasMoreElements()) 210 { 211 String alias = aliases.nextElement(); 212 if (adminKeyStore.isCertificateEntry(alias)) 213 { 214 keyStore.setCertificateEntry(alias, 215 adminKeyStore.getCertificate(alias)); 216 } 217 else 218 { 219 keyStore.setEntry(alias, adminKeyStore.getEntry(alias, null), null); 220 } 221 } 222 } 223 catch (Throwable t) 224 { 225 logger.error(LocalizableMessage.raw("Error reading admin key store on "+ 226 adminTrustStorePath, t)); 227 } 228 finally 229 { 230 try 231 { 232 if (fos != null) 233 { 234 fos.close(); 235 } 236 } 237 catch (Throwable t) 238 { 239 logger.error(LocalizableMessage.raw("Error closing admin key store on "+ 240 adminTrustStorePath, t)); 241 } 242 } 243 } 244 } 245 246 /** 247 * Returns the path where the local admin trust store is. 248 * @return the path where the local admin trust store is. 249 */ 250 private static String getLocalAdminTrustStorePath() 251 { 252 String instancePath = 253 Utils.getInstancePathFromInstallPath(Utils.getInstallPathFromClasspath()); 254 return instancePath + File.separator + "config" + 255 File.separator + "admin-truststore"; 256 } 257 258 /** 259 * Returns whether the key store contains the provided certificate or not. 260 * @param cert the certificate. 261 * @param keyStore the key store. 262 * @return whether the key store contains the provided certificate or not. 263 * @throws KeyStoreException if an error occurs reading the contents of the 264 * key store. 265 */ 266 private static boolean containsCertificate(X509Certificate cert, 267 KeyStore keyStore) throws KeyStoreException 268 { 269 boolean found = false; 270 Enumeration<String> aliases = keyStore.aliases(); 271 while (aliases.hasMoreElements() && !found) 272 { 273 String alias = aliases.nextElement(); 274 if (keyStore.isCertificateEntry(alias)) 275 { 276 Certificate c = keyStore.getCertificate(alias); 277 found = c.equals(cert); 278 } 279 } 280 return found; 281 } 282}