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