001/* 002 * Copyright 2008-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2024 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-2024 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.NotNull; 053import com.unboundid.util.Nullable; 054import com.unboundid.util.StaticUtils; 055import com.unboundid.util.ThreadSafety; 056import com.unboundid.util.ThreadSafetyLevel; 057 058 059 060/** 061 * This class provides an SSL key manager that may be used to wrap a provided 062 * set of key managers. It provides the ability to select the desired 063 * certificate based on a given nickname. 064 */ 065@NotExtensible() 066@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 067public abstract class WrapperKeyManager 068 extends X509ExtendedKeyManager 069{ 070 // The nickname of the certificate that should be selected. 071 @Nullable private final String certificateAlias; 072 073 // The set of key managers that will be used to perform the processing. 074 @NotNull private final X509KeyManager[] keyManagers; 075 076 077 078 /** 079 * Creates a new instance of this wrapper key manager with the provided 080 * information. 081 * 082 * @param keyManagers The set of key managers to be wrapped. It must 083 * not be {@code null} or empty, and it must contain 084 * only X509KeyManager instances. 085 * @param certificateAlias The nickname of the certificate that should be 086 * selected. It may be {@code null} if any 087 * acceptable certificate found may be used. 088 */ 089 protected WrapperKeyManager(@NotNull final KeyManager[] keyManagers, 090 @Nullable final String certificateAlias) 091 { 092 this.certificateAlias = certificateAlias; 093 094 this.keyManagers = new X509KeyManager[keyManagers.length]; 095 for (int i=0; i < keyManagers.length; i++) 096 { 097 this.keyManagers[i] = (X509KeyManager) keyManagers[i]; 098 } 099 } 100 101 102 103 /** 104 * Creates a new instance of this wrapper key manager with the provided 105 * information. 106 * 107 * @param keyManagers The set of key managers to be wrapped. It must 108 * not be {@code null} or empty. 109 * @param certificateAlias The nickname of the certificate that should be 110 * selected. It may be {@code null} if any 111 * acceptable certificate found may be used. 112 */ 113 protected WrapperKeyManager(@NotNull final X509KeyManager[] keyManagers, 114 @Nullable final String certificateAlias) 115 { 116 this.keyManagers = keyManagers; 117 this.certificateAlias = certificateAlias; 118 } 119 120 121 122 /** 123 * Retrieves the nickname of the certificate that should be selected. 124 * 125 * @return The nickname of the certificate that should be selected, or 126 * {@code null} if any acceptable certificate found in the key store 127 * may be used. 128 */ 129 @Nullable() 130 public String getCertificateAlias() 131 { 132 return certificateAlias; 133 } 134 135 136 137 /** 138 * Retrieves the nicknames of the client certificates of the specified type 139 * contained in the key store. 140 * 141 * @param keyType The key algorithm name for which to retrieve the available 142 * certificate nicknames. 143 * @param issuers The list of acceptable issuer certificate subjects. It 144 * may be {@code null} if any issuer may be used. 145 * 146 * @return The nicknames of the client certificates, or {@code null} if none 147 * were found in the key store. 148 */ 149 @Override() 150 @Nullable() 151 public final synchronized String[] getClientAliases( 152 @NotNull final String keyType, 153 @Nullable final Principal[] issuers) 154 { 155 final LinkedHashSet<String> clientAliases = 156 new LinkedHashSet<>(StaticUtils.computeMapCapacity(10)); 157 158 for (final X509KeyManager m : keyManagers) 159 { 160 final String[] aliases = m.getClientAliases(keyType, issuers); 161 if (aliases != null) 162 { 163 clientAliases.addAll(Arrays.asList(aliases)); 164 } 165 } 166 167 if (clientAliases.isEmpty()) 168 { 169 return null; 170 } 171 else 172 { 173 final String[] aliases = new String[clientAliases.size()]; 174 return clientAliases.toArray(aliases); 175 } 176 } 177 178 179 180 /** 181 * Retrieves the nickname of the certificate that a client should use to 182 * authenticate to a server. 183 * 184 * @param keyType The list of key algorithm names that may be used. 185 * @param issuers The list of acceptable issuer certificate subjects. It 186 * may be {@code null} if any issuer may be used. 187 * @param socket The socket to be used. It may be {@code null} if the 188 * certificate may be for any socket. 189 * 190 * @return The nickname of the certificate to use, or {@code null} if no 191 * appropriate certificate is found. 192 */ 193 @Override() 194 @Nullable() 195 public final synchronized String chooseClientAlias( 196 @NotNull final String[] keyType, 197 @Nullable final Principal[] issuers, 198 @Nullable final Socket socket) 199 { 200 if (certificateAlias == null) 201 { 202 for (final X509KeyManager m : keyManagers) 203 { 204 final String alias = m.chooseClientAlias(keyType, issuers, socket); 205 if (alias != null) 206 { 207 return alias; 208 } 209 } 210 211 return null; 212 } 213 else 214 { 215 for (final String s : keyType) 216 { 217 for (final X509KeyManager m : keyManagers) 218 { 219 final String[] aliases = m.getClientAliases(s, issuers); 220 if (aliases != null) 221 { 222 for (final String alias : aliases) 223 { 224 if (alias.equals(certificateAlias)) 225 { 226 return certificateAlias; 227 } 228 } 229 } 230 } 231 } 232 233 return null; 234 } 235 } 236 237 238 239 /** 240 * Retrieves the nickname of the certificate that a client should use to 241 * authenticate to a server. 242 * 243 * @param keyType The list of key algorithm names that may be used. 244 * @param issuers The list of acceptable issuer certificate subjects. It 245 * may be {@code null} if any issuer may be used. 246 * @param engine The SSL engine to be used. It may be {@code null} if the 247 * certificate may be for any engine. 248 * 249 * @return The nickname of the certificate to use, or {@code null} if no 250 * appropriate certificate is found. 251 */ 252 @Override() 253 @Nullable() 254 public final synchronized String chooseEngineClientAlias( 255 @NotNull final String[] keyType, 256 @Nullable final Principal[] issuers, 257 @Nullable final SSLEngine engine) 258 { 259 if (certificateAlias == null) 260 { 261 for (final X509KeyManager m : keyManagers) 262 { 263 if (m instanceof X509ExtendedKeyManager) 264 { 265 final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m; 266 final String alias = 267 em.chooseEngineClientAlias(keyType, issuers, engine); 268 if (alias != null) 269 { 270 return alias; 271 } 272 } 273 else 274 { 275 final String alias = m.chooseClientAlias(keyType, issuers, null); 276 if (alias != null) 277 { 278 return alias; 279 } 280 } 281 } 282 283 return null; 284 } 285 else 286 { 287 for (final String s : keyType) 288 { 289 for (final X509KeyManager m : keyManagers) 290 { 291 final String[] aliases = m.getClientAliases(s, issuers); 292 if (aliases != null) 293 { 294 for (final String alias : aliases) 295 { 296 if (alias.equals(certificateAlias)) 297 { 298 return certificateAlias; 299 } 300 } 301 } 302 } 303 } 304 305 return null; 306 } 307 } 308 309 310 311 /** 312 * Retrieves the nicknames of the server certificates of the specified type 313 * contained in the key store. 314 * 315 * @param keyType The key algorithm name for which to retrieve the available 316 * certificate nicknames. 317 * @param issuers The list of acceptable issuer certificate subjects. It 318 * may be {@code null} if any issuer may be used. 319 * 320 * @return The nicknames of the server certificates, or {@code null} if none 321 * were found in the key store. 322 */ 323 @Override() 324 @Nullable() 325 public final synchronized String[] getServerAliases( 326 @NotNull final String keyType, 327 @Nullable final Principal[] issuers) 328 { 329 final LinkedHashSet<String> serverAliases = 330 new LinkedHashSet<>(StaticUtils.computeMapCapacity(10)); 331 332 for (final X509KeyManager m : keyManagers) 333 { 334 final String[] aliases = m.getServerAliases(keyType, issuers); 335 if (aliases != null) 336 { 337 serverAliases.addAll(Arrays.asList(aliases)); 338 } 339 } 340 341 if (serverAliases.isEmpty()) 342 { 343 return null; 344 } 345 else 346 { 347 final String[] aliases = new String[serverAliases.size()]; 348 return serverAliases.toArray(aliases); 349 } 350 } 351 352 353 354 /** 355 * Retrieves the nickname of the certificate that a server should use to 356 * authenticate to a client. 357 * 358 * @param keyType The key algorithm name that may be used. 359 * @param issuers The list of acceptable issuer certificate subjects. It 360 * may be {@code null} if any issuer may be used. 361 * @param socket The socket to be used. It may be {@code null} if the 362 * certificate may be for any socket. 363 * 364 * @return The nickname of the certificate to use, or {@code null} if no 365 * appropriate certificate is found. 366 */ 367 @Override() 368 @Nullable() 369 public final synchronized String chooseServerAlias( 370 @NotNull final String keyType, 371 @Nullable final Principal[] issuers, 372 @Nullable final Socket socket) 373 { 374 if (certificateAlias == null) 375 { 376 for (final X509KeyManager m : keyManagers) 377 { 378 final String alias = m.chooseServerAlias(keyType, issuers, socket); 379 if (alias != null) 380 { 381 return alias; 382 } 383 } 384 385 return null; 386 } 387 else 388 { 389 for (final X509KeyManager m : keyManagers) 390 { 391 final String[] aliases = m.getServerAliases(keyType, issuers); 392 if (aliases != null) 393 { 394 for (final String alias : aliases) 395 { 396 if (alias.equals(certificateAlias)) 397 { 398 return certificateAlias; 399 } 400 } 401 } 402 } 403 404 return null; 405 } 406 } 407 408 409 410 /** 411 * Retrieves the nickname of the certificate that a server should use to 412 * authenticate to a client. 413 * 414 * @param keyType The key algorithm name that may be used. 415 * @param issuers The list of acceptable issuer certificate subjects. It 416 * may be {@code null} if any issuer may be used. 417 * @param engine The SSL engine to be used. It may be {@code null} if the 418 * certificate may be for any engine. 419 * 420 * @return The nickname of the certificate to use, or {@code null} if no 421 * appropriate certificate is found. 422 */ 423 @Override() 424 @Nullable() 425 public final synchronized String chooseEngineServerAlias( 426 @NotNull final String keyType, 427 @Nullable final Principal[] issuers, 428 @Nullable final SSLEngine engine) 429 { 430 if (certificateAlias == null) 431 { 432 for (final X509KeyManager m : keyManagers) 433 { 434 if (m instanceof X509ExtendedKeyManager) 435 { 436 final X509ExtendedKeyManager em = (X509ExtendedKeyManager) m; 437 final String alias = 438 em.chooseEngineServerAlias(keyType, issuers, engine); 439 if (alias != null) 440 { 441 return alias; 442 } 443 } 444 else 445 { 446 final String alias = m.chooseServerAlias(keyType, issuers, null); 447 if (alias != null) 448 { 449 return alias; 450 } 451 } 452 } 453 454 return null; 455 } 456 else 457 { 458 for (final X509KeyManager m : keyManagers) 459 { 460 final String[] aliases = m.getServerAliases(keyType, issuers); 461 if (aliases != null) 462 { 463 for (final String alias : aliases) 464 { 465 if (alias.equals(certificateAlias)) 466 { 467 return certificateAlias; 468 } 469 } 470 } 471 } 472 473 return null; 474 } 475 } 476 477 478 479 /** 480 * Retrieves the certificate chain for the certificate with the given 481 * nickname. 482 * 483 * @param alias The nickname of the certificate for which to retrieve the 484 * certificate chain. 485 * 486 * @return The certificate chain for the certificate with the given nickname, 487 * or {@code null} if the requested certificate cannot be found. 488 */ 489 @Override() 490 @Nullable() 491 public final synchronized X509Certificate[] getCertificateChain( 492 @NotNull final String alias) 493 { 494 for (final X509KeyManager m : keyManagers) 495 { 496 final X509Certificate[] chain = m.getCertificateChain(alias); 497 if (chain != null) 498 { 499 return chain; 500 } 501 } 502 503 return null; 504 } 505 506 507 508 /** 509 * Retrieves the private key for the specified certificate. 510 * 511 * @param alias The nickname of the certificate for which to retrieve the 512 * private key. 513 * 514 * @return The private key for the requested certificate, or {@code null} if 515 * the requested certificate cannot be found. 516 */ 517 @Override() 518 @Nullable() 519 public final synchronized PrivateKey getPrivateKey( 520 @NotNull final String alias) 521 { 522 for (final X509KeyManager m : keyManagers) 523 { 524 final PrivateKey key = m.getPrivateKey(alias); 525 if (key != null) 526 { 527 return key; 528 } 529 } 530 531 return null; 532 } 533}