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