1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security; 19 20import java.io.IOException; 21import java.io.InputStream; 22import java.io.OutputStream; 23import java.security.cert.Certificate; 24import java.security.cert.CertificateException; 25import java.util.Date; 26import java.util.Enumeration; 27import javax.crypto.SecretKey; 28import javax.security.auth.callback.CallbackHandler; 29import javax.security.auth.callback.PasswordCallback; 30 31/** 32 * {@code KeyStoreSpi} is the Service Provider Interface (SPI) definition for 33 * {@link KeyStore}. 34 * 35 * @see KeyStore 36 */ 37public abstract class KeyStoreSpi { 38 39 /** 40 * Returns the key with the given alias, using the password to recover the 41 * key from the store. 42 * 43 * @param alias 44 * the alias for the entry. 45 * @param password 46 * the password used to recover the key. 47 * @return the key with the specified alias, or {@code null} if the 48 * specified alias is not bound to an entry. 49 * @throws NoSuchAlgorithmException 50 * if the algorithm for recovering the key is not available. 51 * @throws UnrecoverableKeyException 52 * if the key can not be recovered. 53 */ 54 public abstract Key engineGetKey(String alias, char[] password) 55 throws NoSuchAlgorithmException, UnrecoverableKeyException; 56 57 /** 58 * Returns the certificate chain for the entry with the given alias. 59 * 60 * @param alias 61 * the alias for the entry 62 * @return the certificate chain for the entry with the given alias, or 63 * {@code null} if the specified alias is not bound to an entry. 64 */ 65 public abstract Certificate[] engineGetCertificateChain(String alias); 66 67 /** 68 * Returns the trusted certificate for the entry with the given alias. 69 * 70 * @param alias 71 * the alias for the entry. 72 * @return the trusted certificate for the entry with the given alias, or 73 * {@code null} if the specified alias is not bound to an entry. 74 */ 75 public abstract Certificate engineGetCertificate(String alias); 76 77 /** 78 * Returns the creation date of the entry with the given alias. 79 * 80 * @param alias 81 * the alias for the entry. 82 * @return the creation date, or {@code null} if the specified alias is not 83 * bound to an entry. 84 */ 85 public abstract Date engineGetCreationDate(String alias); 86 87 /** 88 * Associates the given alias with the key, password and certificate chain. 89 * <p> 90 * If the specified alias already exists, it will be reassigned. 91 * 92 * @param alias 93 * the alias for the key. 94 * @param key 95 * the key. 96 * @param password 97 * the password. 98 * @param chain 99 * the certificate chain. 100 * @throws KeyStoreException 101 * if the specified key can not be protected, or if this 102 * operation fails for another reason. 103 * @throws IllegalArgumentException 104 * if {@code key} is a {@code PrivateKey} and {@code chain} does 105 * not contain any certificates. 106 */ 107 public abstract void engineSetKeyEntry(String alias, Key key, 108 char[] password, Certificate[] chain) throws KeyStoreException; 109 110 /** 111 * Associates the given alias with a key and a certificate chain. 112 * <p> 113 * If the specified alias already exists, it will be reassigned. 114 * 115 * @param alias 116 * the alias for the key. 117 * @param key 118 * the key in an encoded format. 119 * @param chain 120 * the certificate chain. 121 * @throws KeyStoreException 122 * if this operation fails. 123 * @throws IllegalArgumentException 124 * if {@code key} is a {@code PrivateKey} and {@code chain} 125 * does. 126 */ 127 public abstract void engineSetKeyEntry(String alias, byte[] key, 128 Certificate[] chain) throws KeyStoreException; 129 130 /** 131 * Associates the given alias with a certificate. 132 * <p> 133 * If the specified alias already exists, it will be reassigned. 134 * 135 * @param alias 136 * the alias for the certificate. 137 * @param cert 138 * the certificate. 139 * @throws KeyStoreException 140 * if an existing alias is not associated to an entry containing 141 * a trusted certificate, or this method fails for any other 142 * reason. 143 */ 144 public abstract void engineSetCertificateEntry(String alias, 145 Certificate cert) throws KeyStoreException; 146 147 /** 148 * Deletes the entry identified with the given alias from this {@code 149 * KeyStoreSpi}. 150 * 151 * @param alias 152 * the alias for the entry. 153 * @throws KeyStoreException 154 * if the entry can not be deleted. 155 */ 156 public abstract void engineDeleteEntry(String alias) 157 throws KeyStoreException; 158 159 /** 160 * Returns an {@code Enumeration} over all alias names stored in this 161 * {@code KeyStoreSpi}. 162 * 163 * @return an {@code Enumeration} over all alias names stored in this 164 * {@code KeyStoreSpi}. 165 */ 166 public abstract Enumeration<String> engineAliases(); 167 168 /** 169 * Indicates whether the given alias is present in this {@code KeyStoreSpi}. 170 * 171 * @param alias 172 * the alias of an entry. 173 * @return {@code true} if the alias exists, {@code false} otherwise. 174 */ 175 public abstract boolean engineContainsAlias(String alias); 176 177 /** 178 * Returns the number of entries stored in this {@code KeyStoreSpi}. 179 * 180 * @return the number of entries stored in this {@code KeyStoreSpi}. 181 */ 182 public abstract int engineSize(); 183 184 /** 185 * Indicates whether the specified alias is associated with either a 186 * {@link KeyStore.PrivateKeyEntry} or a {@link KeyStore.SecretKeyEntry}. 187 * 188 * @param alias 189 * the alias of an entry. 190 * @return {@code true} if the given alias is associated with a key entry. 191 */ 192 public abstract boolean engineIsKeyEntry(String alias); 193 194 /** 195 * Indicates whether the specified alias is associated with a 196 * {@link KeyStore.TrustedCertificateEntry}. 197 * 198 * @param alias 199 * the alias of an entry. 200 * @return {@code true} if the given alias is associated with a certificate 201 * entry. 202 */ 203 public abstract boolean engineIsCertificateEntry(String alias); 204 205 /** 206 * Returns the alias associated with the first entry whose certificate 207 * matches the specified certificate. 208 * 209 * @param cert 210 * the certificate to find the associated entry's alias for. 211 * @return the alias or {@code null} if no entry with the specified 212 * certificate can be found. 213 */ 214 public abstract String engineGetCertificateAlias(Certificate cert); 215 216 /** 217 * Writes this {@code KeyStoreSpi} to the specified {@code OutputStream}. 218 * The data written to the {@code OutputStream} is protected by the 219 * specified password. 220 * 221 * @param stream 222 * the {@code OutputStream} to write the store's data to. 223 * @param password 224 * the password to protect the data. 225 * @throws IOException 226 * if a problem occurred while writing to the stream. 227 * @throws NoSuchAlgorithmException 228 * if the required algorithm is not available. 229 * @throws CertificateException 230 * if the an exception occurred while storing the certificates 231 * of this code {@code KeyStoreSpi}. 232 */ 233 public abstract void engineStore(OutputStream stream, char[] password) 234 throws IOException, NoSuchAlgorithmException, CertificateException; 235 236 /** 237 * Stores this {@code KeyStoreSpi} using the specified {@code 238 * LoadStoreParameter}. 239 * 240 * @param param 241 * the {@code LoadStoreParameter} that specifies how to store 242 * this {@code KeyStoreSpi}, maybe {@code null}. 243 * @throws IOException 244 * if a problem occurred while writing to the stream. 245 * @throws NoSuchAlgorithmException 246 * if the required algorithm is not available. 247 * @throws CertificateException 248 * if the an exception occurred while storing the certificates 249 * of this code {@code KeyStoreSpi}. 250 * @throws IllegalArgumentException 251 * if the given {@link KeyStore.LoadStoreParameter} is not 252 * recognized. 253 */ 254 public void engineStore(KeyStore.LoadStoreParameter param) 255 throws IOException, NoSuchAlgorithmException, CertificateException { 256 throw new UnsupportedOperationException(); 257 } 258 259 /** 260 * Loads this {@code KeyStoreSpi} from the given {@code InputStream}. 261 * Utilizes the given password to verify the stored data. 262 * 263 * @param stream 264 * the {@code InputStream} to load this {@code KeyStoreSpi}'s 265 * data from. 266 * @param password 267 * the password to verify the stored data, maybe {@code null}. 268 * @throws IOException 269 * if a problem occurred while reading from the stream. 270 * @throws NoSuchAlgorithmException 271 * if the required algorithm is not available. 272 * @throws CertificateException 273 * if the an exception occurred while loading the certificates 274 * of this code {@code KeyStoreSpi}. 275 */ 276 public abstract void engineLoad(InputStream stream, char[] password) 277 throws IOException, NoSuchAlgorithmException, CertificateException; 278 279 /** 280 * Loads this {@code KeyStoreSpi} using the specified {@code 281 * LoadStoreParameter}. 282 * 283 * @param param 284 * the {@code LoadStoreParameter} that specifies how to load this 285 * {@code KeyStoreSpi}, maybe {@code null}. 286 * @throws IOException 287 * if a problem occurred while reading from the stream. 288 * @throws NoSuchAlgorithmException 289 * if the required algorithm is not available. 290 * @throws CertificateException 291 * if the an exception occurred while loading the certificates 292 * of this code {@code KeyStoreSpi}. 293 * @throws IllegalArgumentException 294 * if the given {@link KeyStore.LoadStoreParameter} is not 295 * recognized. 296 */ 297 public void engineLoad(KeyStore.LoadStoreParameter param) 298 throws IOException, NoSuchAlgorithmException, CertificateException { 299 if (param == null) { 300 engineLoad(null, null); 301 return; 302 } 303 char[] pwd; 304 KeyStore.ProtectionParameter pp = param.getProtectionParameter(); 305 if (pp instanceof KeyStore.PasswordProtection) { 306 try { 307 pwd = ((KeyStore.PasswordProtection) pp).getPassword(); 308 engineLoad(null, pwd); 309 return; 310 } catch (IllegalStateException e) { 311 throw new IllegalArgumentException(e); 312 } 313 } 314 if (pp instanceof KeyStore.CallbackHandlerProtection) { 315 try { 316 pwd = getPasswordFromCallBack(pp); 317 engineLoad(null, pwd); 318 return; 319 } catch (UnrecoverableEntryException e) { 320 throw new IllegalArgumentException(e); 321 } 322 } 323 throw new UnsupportedOperationException("protectionParameter is neither PasswordProtection " 324 + "nor CallbackHandlerProtection instance"); 325 } 326 327 /** 328 * Returns the {@code Entry} with the given alias, using the specified 329 * {@code ProtectionParameter}. 330 * 331 * @param alias 332 * the alias of the requested entry. 333 * @param protParam 334 * the {@code ProtectionParameter}, used to protect the requested 335 * entry, maybe {@code null}. 336 * @return he {@code Entry} with the given alias, using the specified 337 * {@code ProtectionParameter}. 338 * @throws NoSuchAlgorithmException 339 * if the required algorithm is not available. 340 * @throws UnrecoverableEntryException 341 * if the entry can not be recovered. 342 * @throws KeyStoreException 343 * if this operation fails 344 */ 345 public KeyStore.Entry engineGetEntry(String alias, 346 KeyStore.ProtectionParameter protParam) throws KeyStoreException, 347 NoSuchAlgorithmException, UnrecoverableEntryException { 348 if (!engineContainsAlias(alias)) { 349 return null; 350 } 351 if (engineIsCertificateEntry(alias)) { 352 return new KeyStore.TrustedCertificateEntry( 353 engineGetCertificate(alias)); 354 } 355 char[] passW = null; 356 if (protParam != null) { 357 if (protParam instanceof KeyStore.PasswordProtection) { 358 try { 359 passW = ((KeyStore.PasswordProtection) protParam) 360 .getPassword(); 361 } catch (IllegalStateException ee) { 362 throw new KeyStoreException("Password was destroyed", ee); 363 } 364 } else if (protParam instanceof KeyStore.CallbackHandlerProtection) { 365 passW = getPasswordFromCallBack(protParam); 366 } else { 367 throw new UnrecoverableEntryException("ProtectionParameter object is not " 368 + "PasswordProtection: " + protParam); 369 } 370 } 371 if (engineIsKeyEntry(alias)) { 372 Key key = engineGetKey(alias, passW); 373 if (key instanceof PrivateKey) { 374 return new KeyStore.PrivateKeyEntry((PrivateKey) key, 375 engineGetCertificateChain(alias)); 376 } 377 if (key instanceof SecretKey) { 378 return new KeyStore.SecretKeyEntry((SecretKey) key); 379 } 380 } 381 throw new NoSuchAlgorithmException("Unknown KeyStore.Entry object"); 382 } 383 384 /** 385 * Stores the given {@code Entry} in this {@code KeyStoreSpi} and associates 386 * the entry with the given {@code alias}. The entry is protected by the 387 * specified {@code ProtectionParameter}. 388 * <p> 389 * If the specified alias already exists, it will be reassigned. 390 * 391 * @param alias 392 * the alias for the entry. 393 * @param entry 394 * the entry to store. 395 * @param protParam 396 * the {@code ProtectionParameter} to protect the entry. 397 * @throws KeyStoreException 398 * if this operation fails. 399 */ 400 public void engineSetEntry(String alias, KeyStore.Entry entry, 401 KeyStore.ProtectionParameter protParam) throws KeyStoreException { 402 if (entry == null) { 403 throw new KeyStoreException("entry == null"); 404 } 405 406 if (engineContainsAlias(alias)) { 407 engineDeleteEntry(alias); 408 } 409 410 if (entry instanceof KeyStore.TrustedCertificateEntry) { 411 KeyStore.TrustedCertificateEntry trE = (KeyStore.TrustedCertificateEntry) entry; 412 engineSetCertificateEntry(alias, trE.getTrustedCertificate()); 413 return; 414 } 415 416 char[] passW = null; 417 if (protParam != null) { 418 if (protParam instanceof KeyStore.PasswordProtection) { 419 try { 420 passW = ((KeyStore.PasswordProtection) protParam).getPassword(); 421 } catch (IllegalStateException ee) { 422 throw new KeyStoreException("Password was destroyed", ee); 423 } 424 } else if (protParam instanceof KeyStore.CallbackHandlerProtection) { 425 try { 426 passW = getPasswordFromCallBack(protParam); 427 } catch (Exception e) { 428 throw new KeyStoreException(e); 429 } 430 } else { 431 throw new KeyStoreException("protParam should be PasswordProtection or " 432 + "CallbackHandlerProtection"); 433 } 434 } 435 436 if (entry instanceof KeyStore.PrivateKeyEntry) { 437 KeyStore.PrivateKeyEntry prE = (KeyStore.PrivateKeyEntry) entry; 438 engineSetKeyEntry(alias, prE.getPrivateKey(), passW, prE 439 .getCertificateChain()); 440 return; 441 } 442 443 if (entry instanceof KeyStore.SecretKeyEntry) { 444 KeyStore.SecretKeyEntry skE = (KeyStore.SecretKeyEntry) entry; 445 engineSetKeyEntry(alias, skE.getSecretKey(), passW, null); 446 // engineSetKeyEntry(alias, skE.getSecretKey().getEncoded(), null); 447 return; 448 } 449 450 throw new KeyStoreException("Entry object is neither PrivateKeyObject nor SecretKeyEntry " 451 + "nor TrustedCertificateEntry: " + entry); 452 } 453 454 /** 455 * Indicates whether the entry for the given alias is assignable to the 456 * provided {@code Class}. 457 * 458 * @param alias 459 * the alias for the entry. 460 * @param entryClass 461 * the type of the entry. 462 * @return {@code true} if the {@code Entry} for the alias is assignable to 463 * the specified {@code entryClass}. 464 */ 465 public boolean engineEntryInstanceOf(String alias, 466 Class<? extends KeyStore.Entry> entryClass) { 467 if (!engineContainsAlias(alias)) { 468 return false; 469 } 470 471 try { 472 if (engineIsCertificateEntry(alias)) { 473 return entryClass 474 .isAssignableFrom(Class 475 .forName("java.security.KeyStore$TrustedCertificateEntry")); 476 } 477 478 if (engineIsKeyEntry(alias)) { 479 if (entryClass.isAssignableFrom(Class 480 .forName("java.security.KeyStore$PrivateKeyEntry"))) { 481 return engineGetCertificate(alias) != null; 482 } 483 484 if (entryClass.isAssignableFrom(Class 485 .forName("java.security.KeyStore$SecretKeyEntry"))) { 486 return engineGetCertificate(alias) == null; 487 } 488 } 489 } catch (ClassNotFoundException ignore) {} 490 491 return false; 492 } 493 494 /* 495 * This method returns password which is encapsulated in 496 * CallbackHandlerProtection object If there is no implementation of 497 * CallbackHandler then this method returns null 498 */ 499 static char[] getPasswordFromCallBack(KeyStore.ProtectionParameter protParam) 500 throws UnrecoverableEntryException { 501 502 if (protParam == null) { 503 return null; 504 } 505 506 if (!(protParam instanceof KeyStore.CallbackHandlerProtection)) { 507 throw new UnrecoverableEntryException("Incorrect ProtectionParameter"); 508 } 509 510 String clName = Security.getProperty("auth.login.defaultCallbackHandler"); 511 if (clName == null) { 512 throw new UnrecoverableEntryException("Default CallbackHandler was not defined"); 513 514 } 515 516 try { 517 Class<?> cl = Class.forName(clName); 518 CallbackHandler cbHand = (CallbackHandler) cl.newInstance(); 519 PasswordCallback[] pwCb = { new PasswordCallback("password: ", true) }; 520 cbHand.handle(pwCb); 521 return pwCb[0].getPassword(); 522 } catch (Exception e) { 523 throw new UnrecoverableEntryException(e.toString()); 524 } 525 } 526} 527