001 /*
002 * Copyright 2008-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.util.ssl;
022
023
024
025 import java.net.Socket;
026 import java.security.Principal;
027 import java.security.PrivateKey;
028 import java.security.cert.X509Certificate;
029 import java.util.Arrays;
030 import java.util.LinkedHashSet;
031 import javax.net.ssl.KeyManager;
032 import javax.net.ssl.SSLEngine;
033 import javax.net.ssl.X509ExtendedKeyManager;
034 import javax.net.ssl.X509KeyManager;
035
036
037
038
039 /**
040 * This class provides an SSL key manager that may be used to wrap a provided
041 * set of key managers. It provides the ability to select the desired
042 * certificate based on a given nickname.
043 */
044 public abstract class WrapperKeyManager
045 extends X509ExtendedKeyManager
046 {
047 // The nickname of the certificate that should be selected.
048 private final String certificateAlias;
049
050 // The set of key managers that will be used to perform the processing.
051 private final X509KeyManager[] keyManagers;
052
053
054
055 /**
056 * Creates a new instance of this wrapper key manager with the provided
057 * information.
058 *
059 * @param keyManagers The set of key managers to be wrapped. It must
060 * not be {@code null} or empty, and it must contain
061 * only X509KeyManager instances.
062 * @param certificateAlias The nickname of the certificate that should be
063 * selected. It may be {@code null} if any
064 * acceptable certificate found may be used.
065 */
066 protected WrapperKeyManager(final KeyManager[] keyManagers,
067 final String certificateAlias)
068 {
069 this.certificateAlias = certificateAlias;
070
071 this.keyManagers = new X509KeyManager[keyManagers.length];
072 for (int i=0; i < keyManagers.length; i++)
073 {
074 this.keyManagers[i] = (X509KeyManager) keyManagers[i];
075 }
076 }
077
078
079
080 /**
081 * Creates a new instance of this wrapper key manager with the provided
082 * information.
083 *
084 * @param keyManagers The set of key managers to be wrapped. It must
085 * not be {@code null} or empty.
086 * @param certificateAlias The nickname of the certificate that should be
087 * selected. It may be {@code null} if any
088 * acceptable certificate found may be used.
089 */
090 protected WrapperKeyManager(final X509KeyManager[] keyManagers,
091 final String certificateAlias)
092 {
093 this.keyManagers = keyManagers;
094 this.certificateAlias = certificateAlias;
095 }
096
097
098
099 /**
100 * Retrieves the nickname of the certificate that should be selected.
101 *
102 * @return The nickname of the certificate that should be selected, or
103 * {@code null} if any acceptable certificate found in the key store
104 * may be used.
105 */
106 public String getCertificateAlias()
107 {
108 return certificateAlias;
109 }
110
111
112
113 /**
114 * Retrieves the nicknames of the client certificates of the specified type
115 * contained in the key store.
116 *
117 * @param keyType The key algorithm name for which to retrieve the available
118 * certificate nicknames.
119 * @param issuers The list of acceptable issuer certificate subjects. It
120 * may be {@code null} if any issuer may be used.
121 *
122 * @return The nicknames of the client certificates, or {@code null} if none
123 * were found in the key store.
124 */
125 public final synchronized String[] getClientAliases(final String keyType,
126 final Principal[] issuers)
127 {
128 final LinkedHashSet<String> clientAliases = new LinkedHashSet<String>();
129
130 for (final X509KeyManager m : keyManagers)
131 {
132 final String[] aliases = m.getClientAliases(keyType, issuers);
133 if (aliases != null)
134 {
135 clientAliases.addAll(Arrays.asList(aliases));
136 }
137 }
138
139 if (clientAliases.isEmpty())
140 {
141 return null;
142 }
143 else
144 {
145 final String[] aliases = new String[clientAliases.size()];
146 return clientAliases.toArray(aliases);
147 }
148 }
149
150
151
152 /**
153 * Retrieves the nickname of the certificate that a client should use to
154 * authenticate to a server.
155 *
156 * @param keyType The list of key algorithm names that may be used.
157 * @param issuers The list of acceptable issuer certificate subjects. It
158 * may be {@code null} if any issuer may be used.
159 * @param socket The socket to be used. It may be {@code null} if the
160 * certificate may be for any socket.
161 *
162 * @return The nickname of the certificate to use, or {@code null} if no
163 * appropriate certificate is found.
164 */
165 public final synchronized String chooseClientAlias(final String[] keyType,
166 final Principal[] issuers,
167 final Socket socket)
168 {
169 if (certificateAlias == null)
170 {
171 for (final X509KeyManager m : keyManagers)
172 {
173 final String alias = m.chooseClientAlias(keyType, issuers, socket);
174 if (alias != null)
175 {
176 return alias;
177 }
178 }
179
180 return null;
181 }
182 else
183 {
184 for (final String s : keyType)
185 {
186 for (final X509KeyManager m : keyManagers)
187 {
188 final String[] aliases = m.getClientAliases(s, issuers);
189 if (aliases != null)
190 {
191 for (final String alias : aliases)
192 {
193 if (alias.equals(certificateAlias))
194 {
195 return certificateAlias;
196 }
197 }
198 }
199 }
200 }
201
202 return null;
203 }
204 }
205
206
207
208 /**
209 * Retrieves the nickname of the certificate that a client should use to
210 * authenticate to a server.
211 *
212 * @param keyType The list of key algorithm names that may be used.
213 * @param issuers The list of acceptable issuer certificate subjects. It
214 * may be {@code null} if any issuer may be used.
215 * @param engine The SSL engine to be used. It may be {@code null} if the
216 * certificate may be for any engine.
217 *
218 * @return The nickname of the certificate to use, or {@code null} if no
219 * appropriate certificate is found.
220 */
221 @Override()
222 public final synchronized String chooseEngineClientAlias(
223 final String[] keyType,
224 final Principal[] issuers,
225 final SSLEngine engine)
226 {
227 if (certificateAlias == null)
228 {
229 for (final X509KeyManager m : keyManagers)
230 {
231 if (m instanceof X509ExtendedKeyManager)
232 {
233 final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m;
234 final String alias =
235 em.chooseEngineClientAlias(keyType, issuers, engine);
236 if (alias != null)
237 {
238 return alias;
239 }
240 }
241 else
242 {
243 final String alias = m.chooseClientAlias(keyType, issuers, null);
244 if (alias != null)
245 {
246 return alias;
247 }
248 }
249 }
250
251 return null;
252 }
253 else
254 {
255 for (final String s : keyType)
256 {
257 for (final X509KeyManager m : keyManagers)
258 {
259 final String[] aliases = m.getClientAliases(s, issuers);
260 if (aliases != null)
261 {
262 for (final String alias : aliases)
263 {
264 if (alias.equals(certificateAlias))
265 {
266 return certificateAlias;
267 }
268 }
269 }
270 }
271 }
272
273 return null;
274 }
275 }
276
277
278
279 /**
280 * Retrieves the nicknames of the server certificates of the specified type
281 * contained in the key store.
282 *
283 * @param keyType The key algorithm name for which to retrieve the available
284 * certificate nicknames.
285 * @param issuers The list of acceptable issuer certificate subjects. It
286 * may be {@code null} if any issuer may be used.
287 *
288 * @return The nicknames of the server certificates, or {@code null} if none
289 * were found in the key store.
290 */
291 public final synchronized String[] getServerAliases(final String keyType,
292 final Principal[] issuers)
293 {
294 final LinkedHashSet<String> serverAliases = new LinkedHashSet<String>();
295
296 for (final X509KeyManager m : keyManagers)
297 {
298 final String[] aliases = m.getServerAliases(keyType, issuers);
299 if (aliases != null)
300 {
301 serverAliases.addAll(Arrays.asList(aliases));
302 }
303 }
304
305 if (serverAliases.isEmpty())
306 {
307 return null;
308 }
309 else
310 {
311 final String[] aliases = new String[serverAliases.size()];
312 return serverAliases.toArray(aliases);
313 }
314 }
315
316
317
318 /**
319 * Retrieves the nickname of the certificate that a server should use to
320 * authenticate to a client.
321 *
322 * @param keyType The key algorithm name that may be used.
323 * @param issuers The list of acceptable issuer certificate subjects. It
324 * may be {@code null} if any issuer may be used.
325 * @param socket The socket to be used. It may be {@code null} if the
326 * certificate may be for any socket.
327 *
328 * @return The nickname of the certificate to use, or {@code null} if no
329 * appropriate certificate is found.
330 */
331 public final synchronized String chooseServerAlias(final String keyType,
332 final Principal[] issuers,
333 final Socket socket)
334 {
335 if (certificateAlias == null)
336 {
337 for (final X509KeyManager m : keyManagers)
338 {
339 final String alias = m.chooseServerAlias(keyType, issuers, socket);
340 if (alias != null)
341 {
342 return alias;
343 }
344 }
345
346 return null;
347 }
348 else
349 {
350 for (final X509KeyManager m : keyManagers)
351 {
352 final String[] aliases = m.getServerAliases(keyType, issuers);
353 if (aliases != null)
354 {
355 for (final String alias : aliases)
356 {
357 if (alias.equals(certificateAlias))
358 {
359 return certificateAlias;
360 }
361 }
362 }
363 }
364
365 return null;
366 }
367 }
368
369
370
371 /**
372 * Retrieves the nickname of the certificate that a server should use to
373 * authenticate to a client.
374 *
375 * @param keyType The key algorithm name that may be used.
376 * @param issuers The list of acceptable issuer certificate subjects. It
377 * may be {@code null} if any issuer may be used.
378 * @param engine The SSL engine to be used. It may be {@code null} if the
379 * certificate may be for any engine.
380 *
381 * @return The nickname of the certificate to use, or {@code null} if no
382 * appropriate certificate is found.
383 */
384 @Override()
385 public final synchronized String chooseEngineServerAlias(final String keyType,
386 final Principal[] issuers,
387 final SSLEngine engine)
388 {
389 if (certificateAlias == null)
390 {
391 for (final X509KeyManager m : keyManagers)
392 {
393 if (m instanceof X509ExtendedKeyManager)
394 {
395 final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m;
396 final String alias =
397 em.chooseEngineServerAlias(keyType, issuers, engine);
398 if (alias != null)
399 {
400 return alias;
401 }
402 }
403 else
404 {
405 final String alias = m.chooseServerAlias(keyType, issuers, null);
406 if (alias != null)
407 {
408 return alias;
409 }
410 }
411 }
412
413 return null;
414 }
415 else
416 {
417 for (final X509KeyManager m : keyManagers)
418 {
419 final String[] aliases = m.getServerAliases(keyType, issuers);
420 if (aliases != null)
421 {
422 for (final String alias : aliases)
423 {
424 if (alias.equals(certificateAlias))
425 {
426 return certificateAlias;
427 }
428 }
429 }
430 }
431
432 return null;
433 }
434 }
435
436
437
438 /**
439 * Retrieves the certificate chain for the certificate with the given
440 * nickname.
441 *
442 * @param alias The nickname of the certificate for which to retrieve the
443 * certificate chain.
444 *
445 * @return The certificate chain for the certificate with the given nickname,
446 * or {@code null} if the requested certificate cannot be found.
447 */
448 public final synchronized X509Certificate[] getCertificateChain(
449 final String alias)
450 {
451 for (final X509KeyManager m : keyManagers)
452 {
453 final X509Certificate[] chain = m.getCertificateChain(alias);
454 if (chain != null)
455 {
456 return chain;
457 }
458 }
459
460 return null;
461 }
462
463
464
465 /**
466 * Retrieves the private key for the specified certificate.
467 *
468 * @param alias The nickname of the certificate for which to retrieve the
469 * private key.
470 *
471 * @return The private key for the requested certificate, or {@code null} if
472 * the requested certificate cannot be found.
473 */
474 public final synchronized PrivateKey getPrivateKey(final String alias)
475 {
476 for (final X509KeyManager m : keyManagers)
477 {
478 final PrivateKey key = m.getPrivateKey(alias);
479 if (key != null)
480 {
481 return key;
482 }
483 }
484
485 return null;
486 }
487 }