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 }