001/* 002 * Copyright 2021-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2021-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) 2021-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.ldap.sdk.unboundidds.extensions; 037 038 039 040import java.io.File; 041import java.io.IOException; 042import java.util.ArrayList; 043import java.util.List; 044 045import com.unboundid.asn1.ASN1Element; 046import com.unboundid.asn1.ASN1OctetString; 047import com.unboundid.asn1.ASN1Sequence; 048import com.unboundid.ldap.sdk.LDAPException; 049import com.unboundid.ldap.sdk.ResultCode; 050import com.unboundid.util.Debug; 051import com.unboundid.util.NotMutable; 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; 057import com.unboundid.util.Validator; 058 059import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 060 061 062 063/** 064 * This class provides a {@link ReplaceCertificateKeyStoreContent} 065 * implementation to indicate that the server should use a certificate key store 066 * whose content (that is, the bytes that comprise the key store file) is 067 * provided directly in the extended request. 068 * <BR> 069 * <BLOCKQUOTE> 070 * <B>NOTE:</B> This class, and other classes within the 071 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 072 * supported for use against Ping Identity, UnboundID, and 073 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 074 * for proprietary functionality or for external specifications that are not 075 * considered stable or mature enough to be guaranteed to work in an 076 * interoperable way with other types of LDAP servers. 077 * </BLOCKQUOTE> 078 */ 079@NotMutable() 080@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 081public final class KeyStoreDataReplaceCertificateKeyStoreContent 082 extends ReplaceCertificateKeyStoreContent 083{ 084 /** 085 * The BER type to use for the ASN.1 element containing an encoded 086 * representation of this key store content object. 087 */ 088 static final byte TYPE_KEY_STORE_CONTENT = (byte) 0xA1; 089 090 091 092 /** 093 * The BER type to use for the ASN.1 element that holds the raw data that 094 * comprises the key store. 095 */ 096 private static final byte TYPE_KEY_STORE_DATA = (byte) 0x88; 097 098 099 100 /** 101 * The BER type to use for the ASN.1 element that holds raw data that 102 * comprises the key store. 103 */ 104 private static final byte TYPE_KEY_STORE_PIN = (byte) 0x89; 105 106 107 108 /** 109 * The BER type to use for the ASN.1 element that holds the PIN needed to 110 * access the private key in the key store. 111 */ 112 private static final byte TYPE_PRIVATE_KEY_PIN = (byte) 0x8A; 113 114 115 116 /** 117 * The BER type to use for the ASN.1 element that holds the key store type. 118 */ 119 private static final byte TYPE_KEY_STORE_TYPE = (byte) 0x8B; 120 121 122 123 /** 124 * The BER type to use for the ASN.1 element that holds the source certificate 125 * alias. 126 */ 127 private static final byte TYPE_SOURCE_CERTIFICATE_ALIAS = (byte) 0x8C; 128 129 130 131 /** 132 * The serial version UID for this serializable class. 133 */ 134 private static final long serialVersionUID = -8068834762688653001L; 135 136 137 138 // The raw data that comprises the key store. 139 @NotNull private final byte[] keyStoreData; 140 141 // The PIN needed to access the contents of the key store. 142 @NotNull private final String keyStorePIN; 143 144 // The key store type for the key store. 145 @Nullable private final String keyStoreType; 146 147 // The PIN needed to access the private key. 148 @Nullable private final String privateKeyPIN; 149 150 // The alias of the certificate to use in the key store. 151 @Nullable private final String sourceCertificateAlias; 152 153 154 155 /** 156 * Creates a new instance of this key store content object with the provided 157 * information. 158 * 159 * @param keyStoreData The raw bytes that comprises the key store 160 * with the new certificate to use. It must 161 * not be {@code null} or empty. 162 * @param keyStorePIN The PIN needed to access protected content 163 * in the key store. It must not be 164 * {@code null} or empty. 165 * @param privateKeyPIN The PIN needed to access private key 166 * information in the key store. It may be 167 * {@code null} if the key store PIN should 168 * also be used as the private key PIN. 169 * @param keyStoreType The key store type for the target key 170 * store. If provided, its value will likely 171 * be one of JKS, PKCS12, or BCFKS. If this 172 * is {@code null}, then the server will 173 * attempt to automatically determine the 174 * appropriate key store type. 175 * @param sourceCertificateAlias The alias of the private key entry in the 176 * key store that contains the new certificate 177 * chain to be used. It may optionally be 178 * {@code null} if and only if the key store 179 * has only a single private key entry. 180 */ 181 public KeyStoreDataReplaceCertificateKeyStoreContent( 182 @NotNull final byte[] keyStoreData, 183 @NotNull final String keyStorePIN, 184 @Nullable final String privateKeyPIN, 185 @Nullable final String keyStoreType, 186 @Nullable final String sourceCertificateAlias) 187 { 188 Validator.ensureNotNullOrEmpty(keyStoreData, 189 "KeyStoreDataReplaceCertificateKeyStoreContent.keyStoreData must " + 190 "not be null or empty."); 191 Validator.ensureNotNullOrEmpty(keyStorePIN, 192 "KeyStoreDataReplaceCertificateKeyStoreContent.keyStorePIN must " + 193 "not be null or empty."); 194 195 this.keyStoreData = keyStoreData; 196 this.keyStorePIN = keyStorePIN; 197 this.privateKeyPIN = privateKeyPIN; 198 this.keyStoreType = keyStoreType; 199 this.sourceCertificateAlias = sourceCertificateAlias; 200 } 201 202 203 204 /** 205 * Creates a new instance of this key store content object with the provided 206 * information. 207 * 208 * @param keyStoreFile The local (client-side) file from which the 209 * certificate data should be read. It must 210 * not be {@code null}. and the file must 211 * exist. 212 * @param keyStorePIN The PIN needed to access protected content 213 * in the key store. It must not be 214 * {@code null} or empty. 215 * @param privateKeyPIN The PIN needed to access private key 216 * information in the key store. It may be 217 * {@code null} if the key store PIN should 218 * also be used as the private key PIN. 219 * @param keyStoreType The key store type for the target key 220 * store. If provided, its value will likely 221 * be one of JKS, PKCS12, or BCFKS. If this 222 * is {@code null}, then the server will 223 * attempt to automatically determine the 224 * appropriate key store type. 225 * @param sourceCertificateAlias The alias of the private key entry in the 226 * key store that contains the new certificate 227 * chain to be used. It may optionally be 228 * {@code null} if and only if the key store 229 * has only a single private key entry. 230 * 231 * @throws IOException If a problem occurs while attempting to read from the 232 * key store file. 233 */ 234 public KeyStoreDataReplaceCertificateKeyStoreContent( 235 @NotNull final File keyStoreFile, 236 @NotNull final String keyStorePIN, 237 @Nullable final String privateKeyPIN, 238 @Nullable final String keyStoreType, 239 @Nullable final String sourceCertificateAlias) 240 throws IOException 241 { 242 this(StaticUtils.readFileBytes(keyStoreFile), keyStorePIN, privateKeyPIN, 243 keyStoreType, sourceCertificateAlias); 244 } 245 246 247 248 /** 249 * Retrieves the raw data that comprises the key store with the new 250 * certificate to use. 251 * 252 * @return The raw data that comprises the key store with the new certificate 253 * to use. 254 */ 255 @NotNull() 256 public byte[] getKeyStoreData() 257 { 258 return keyStoreData; 259 } 260 261 262 263 /** 264 * Retrieves the PIN needed to access protected content in the key store. 265 * 266 * @return The PIN needed to access protected content in the key store. 267 */ 268 @NotNull() 269 public String getKeyStorePIN() 270 { 271 return keyStorePIN; 272 } 273 274 275 276 /** 277 * Retrieves the PIN needed to access private key information in the key 278 * store, if available. 279 * 280 * @return The PIN needed to access private key information in the key store, 281 * or {@code null} if the key store PIN should also be used as the 282 * private key PIN. 283 */ 284 @Nullable() 285 public String getPrivateKeyPIN() 286 { 287 return privateKeyPIN; 288 } 289 290 291 292 /** 293 * Retrieves the key store type for the target key store, if available. 294 * 295 * @return The key store type for the target key store, or {@code null} if 296 * the key store type is not available and the server should attempt 297 * to automatically determine the appropriate key store type. 298 */ 299 @Nullable() 300 public String getKeyStoreType() 301 { 302 return keyStoreType; 303 } 304 305 306 307 /** 308 * Retrieves the alias of the private key entry in the key store that contains 309 * the new certificate chain to be used, if available. 310 * 311 * @return The alias of the private key entry in the key store that contains 312 * the new certificate chain to be used, or {@code null} if no source 313 * certificate alias was provided and the key store is expected to 314 * have only a single private key entry. 315 */ 316 @Nullable() 317 public String getSourceCertificateAlias() 318 { 319 return sourceCertificateAlias; 320 } 321 322 323 324 /** 325 * Decodes a key store file replace certificate key store content object from 326 * the provided ASN.1 element. 327 * 328 * @param element The ASN.1 element containing the encoded representation of 329 * the key store file replace certificate key store content 330 * object. It must not be {@code null}. 331 * 332 * @return The decoded key store content object. 333 * 334 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 335 * a key store file replace certificate key store 336 * content object. 337 */ 338 @NotNull() 339 static KeyStoreDataReplaceCertificateKeyStoreContent decodeInternal( 340 @NotNull final ASN1Element element) 341 throws LDAPException 342 { 343 try 344 { 345 final ASN1Element[] elements = element.decodeAsSequence().elements(); 346 final byte[] keyStoreData = 347 elements[0].decodeAsOctetString().getValue(); 348 final String keyStorePIN = 349 elements[1].decodeAsOctetString().stringValue(); 350 351 String privateKeyPIN = null; 352 String keyStoreType = null; 353 String sourceCertificateAlias = null; 354 for (int i=2; i < elements.length; i++) 355 { 356 switch (elements[i].getType()) 357 { 358 case TYPE_PRIVATE_KEY_PIN: 359 privateKeyPIN = elements[i].decodeAsOctetString().stringValue(); 360 break; 361 case TYPE_KEY_STORE_TYPE: 362 keyStoreType = elements[i].decodeAsOctetString().stringValue(); 363 break; 364 case TYPE_SOURCE_CERTIFICATE_ALIAS: 365 sourceCertificateAlias = 366 elements[i].decodeAsOctetString().stringValue(); 367 break; 368 } 369 } 370 371 return new KeyStoreDataReplaceCertificateKeyStoreContent(keyStoreData, 372 keyStorePIN, privateKeyPIN, keyStoreType, sourceCertificateAlias); 373 } 374 catch (final Exception e) 375 { 376 Debug.debugException(e); 377 throw new LDAPException(ResultCode.DECODING_ERROR, 378 ERR_KSD_KSC_DECODE_ERROR.get(StaticUtils.getExceptionMessage(e)), 379 e); 380 } 381 } 382 383 384 385 /** 386 * {@inheritDoc} 387 */ 388 @Override() 389 @NotNull() 390 public ASN1Element encode() 391 { 392 final List<ASN1Element> elements = new ArrayList<>(5); 393 elements.add(new ASN1OctetString(TYPE_KEY_STORE_DATA, keyStoreData)); 394 elements.add(new ASN1OctetString(TYPE_KEY_STORE_PIN, keyStorePIN)); 395 396 if (privateKeyPIN != null) 397 { 398 elements.add(new ASN1OctetString(TYPE_PRIVATE_KEY_PIN, privateKeyPIN)); 399 } 400 401 if (keyStoreType != null) 402 { 403 elements.add(new ASN1OctetString(TYPE_KEY_STORE_TYPE, keyStoreType)); 404 } 405 406 if (sourceCertificateAlias != null) 407 { 408 elements.add(new ASN1OctetString(TYPE_SOURCE_CERTIFICATE_ALIAS, 409 sourceCertificateAlias)); 410 } 411 412 return new ASN1Sequence(TYPE_KEY_STORE_CONTENT, elements); 413 } 414 415 416 417 /** 418 * {@inheritDoc} 419 */ 420 @Override() 421 public void toString(@NotNull final StringBuilder buffer) 422 { 423 buffer.append("KeyStoreDataReplaceCertificateKeyStoreContent(" + 424 "keyStoreDataSizeBytes="); 425 buffer.append(keyStoreData.length); 426 buffer.append(", privateKeyPINProvided="); 427 buffer.append(privateKeyPIN != null); 428 429 if (keyStoreType != null) 430 { 431 buffer.append(", keyStoreType='"); 432 buffer.append(keyStoreType); 433 buffer.append('\''); 434 } 435 436 if (sourceCertificateAlias != null) 437 { 438 buffer.append(", sourceCertificateAlias='"); 439 buffer.append(sourceCertificateAlias); 440 buffer.append('\''); 441 } 442 443 buffer.append(')'); 444 } 445}