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