1. /*
  2. * @(#)KeyStoreSpi.java 1.18 04/05/25
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security;
  8. import java.io.*;
  9. import java.util.*;
  10. import java.security.KeyStore.*;
  11. import java.security.cert.Certificate;
  12. import java.security.cert.CertificateException;
  13. import javax.crypto.SecretKey;
  14. import javax.security.auth.callback.*;
  15. /**
  16. * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
  17. * for the <code>KeyStore</code> class.
  18. * All the abstract methods in this class must be implemented by each
  19. * cryptographic service provider who wishes to supply the implementation
  20. * of a keystore for a particular keystore type.
  21. *
  22. * @author Jan Luehe
  23. *
  24. * @version 1.18, 05/25/04
  25. *
  26. * @see KeyStore
  27. *
  28. * @since 1.2
  29. */
  30. public abstract class KeyStoreSpi {
  31. /**
  32. * Returns the key associated with the given alias, using the given
  33. * password to recover it. The key must have been associated with
  34. * the alias by a call to <code>setKeyEntry</code>,
  35. * or by a call to <code>setEntry</code> with a
  36. * <code>PrivateKeyEntry</code> or <code>SecretKeyEntry</code>.
  37. *
  38. * @param alias the alias name
  39. * @param password the password for recovering the key
  40. *
  41. * @return the requested key, or null if the given alias does not exist
  42. * or does not identify a key-related entry.
  43. *
  44. * @exception NoSuchAlgorithmException if the algorithm for recovering the
  45. * key cannot be found
  46. * @exception UnrecoverableKeyException if the key cannot be recovered
  47. * (e.g., the given password is wrong).
  48. */
  49. public abstract Key engineGetKey(String alias, char[] password)
  50. throws NoSuchAlgorithmException, UnrecoverableKeyException;
  51. /**
  52. * Returns the certificate chain associated with the given alias.
  53. * The certificate chain must have been associated with the alias
  54. * by a call to <code>setKeyEntry</code>,
  55. * or by a call to <code>setEntry</code> with a
  56. * <code>PrivateKeyEntry</code>.
  57. *
  58. * @param alias the alias name
  59. *
  60. * @return the certificate chain (ordered with the user's certificate first
  61. * and the root certificate authority last), or null if the given alias
  62. * does not exist or does not contain a certificate chain
  63. */
  64. public abstract Certificate[] engineGetCertificateChain(String alias);
  65. /**
  66. * Returns the certificate associated with the given alias.
  67. *
  68. * <p> If the given alias name identifies an entry
  69. * created by a call to <code>setCertificateEntry</code>,
  70. * or created by a call to <code>setEntry</code> with a
  71. * <code>TrustedCertificateEntry</code>,
  72. * then the trusted certificate contained in that entry is returned.
  73. *
  74. * <p> If the given alias name identifies an entry
  75. * created by a call to <code>setKeyEntry</code>,
  76. * or created by a call to <code>setEntry</code> with a
  77. * <code>PrivateKeyEntry</code>,
  78. * then the first element of the certificate chain in that entry
  79. * (if a chain exists) is returned.
  80. *
  81. * @param alias the alias name
  82. *
  83. * @return the certificate, or null if the given alias does not exist or
  84. * does not contain a certificate.
  85. */
  86. public abstract Certificate engineGetCertificate(String alias);
  87. /**
  88. * Returns the creation date of the entry identified by the given alias.
  89. *
  90. * @param alias the alias name
  91. *
  92. * @return the creation date of this entry, or null if the given alias does
  93. * not exist
  94. */
  95. public abstract Date engineGetCreationDate(String alias);
  96. /**
  97. * Assigns the given key to the given alias, protecting it with the given
  98. * password.
  99. *
  100. * <p>If the given key is of type <code>java.security.PrivateKey</code>,
  101. * it must be accompanied by a certificate chain certifying the
  102. * corresponding public key.
  103. *
  104. * <p>If the given alias already exists, the keystore information
  105. * associated with it is overridden by the given key (and possibly
  106. * certificate chain).
  107. *
  108. * @param alias the alias name
  109. * @param key the key to be associated with the alias
  110. * @param password the password to protect the key
  111. * @param chain the certificate chain for the corresponding public
  112. * key (only required if the given key is of type
  113. * <code>java.security.PrivateKey</code>).
  114. *
  115. * @exception KeyStoreException if the given key cannot be protected, or
  116. * this operation fails for some other reason
  117. */
  118. public abstract void engineSetKeyEntry(String alias, Key key,
  119. char[] password,
  120. Certificate[] chain)
  121. throws KeyStoreException;
  122. /**
  123. * Assigns the given key (that has already been protected) to the given
  124. * alias.
  125. *
  126. * <p>If the protected key is of type
  127. * <code>java.security.PrivateKey</code>,
  128. * it must be accompanied by a certificate chain certifying the
  129. * corresponding public key.
  130. *
  131. * <p>If the given alias already exists, the keystore information
  132. * associated with it is overridden by the given key (and possibly
  133. * certificate chain).
  134. *
  135. * @param alias the alias name
  136. * @param key the key (in protected format) to be associated with the alias
  137. * @param chain the certificate chain for the corresponding public
  138. * key (only useful if the protected key is of type
  139. * <code>java.security.PrivateKey</code>).
  140. *
  141. * @exception KeyStoreException if this operation fails.
  142. */
  143. public abstract void engineSetKeyEntry(String alias, byte[] key,
  144. Certificate[] chain)
  145. throws KeyStoreException;
  146. /**
  147. * Assigns the given certificate to the given alias.
  148. *
  149. * <p> If the given alias identifies an existing entry
  150. * created by a call to <code>setCertificateEntry</code>,
  151. * or created by a call to <code>setEntry</code> with a
  152. * <code>TrustedCertificateEntry</code>,
  153. * the trusted certificate in the existing entry
  154. * is overridden by the given certificate.
  155. *
  156. * @param alias the alias name
  157. * @param cert the certificate
  158. *
  159. * @exception KeyStoreException if the given alias already exists and does
  160. * not identify an entry containing a trusted certificate,
  161. * or this operation fails for some other reason.
  162. */
  163. public abstract void engineSetCertificateEntry(String alias,
  164. Certificate cert)
  165. throws KeyStoreException;
  166. /**
  167. * Deletes the entry identified by the given alias from this keystore.
  168. *
  169. * @param alias the alias name
  170. *
  171. * @exception KeyStoreException if the entry cannot be removed.
  172. */
  173. public abstract void engineDeleteEntry(String alias)
  174. throws KeyStoreException;
  175. /**
  176. * Lists all the alias names of this keystore.
  177. *
  178. * @return enumeration of the alias names
  179. */
  180. public abstract Enumeration<String> engineAliases();
  181. /**
  182. * Checks if the given alias exists in this keystore.
  183. *
  184. * @param alias the alias name
  185. *
  186. * @return true if the alias exists, false otherwise
  187. */
  188. public abstract boolean engineContainsAlias(String alias);
  189. /**
  190. * Retrieves the number of entries in this keystore.
  191. *
  192. * @return the number of entries in this keystore
  193. */
  194. public abstract int engineSize();
  195. /**
  196. * Returns true if the entry identified by the given alias
  197. * was created by a call to <code>setKeyEntry</code>,
  198. * or created by a call to <code>setEntry</code> with a
  199. * <code>PrivateKeyEntry</code> or a <code>SecretKeyEntry</code>.
  200. *
  201. * @param alias the alias for the keystore entry to be checked
  202. *
  203. * @return true if the entry identified by the given alias is a
  204. * key-related, false otherwise.
  205. */
  206. public abstract boolean engineIsKeyEntry(String alias);
  207. /**
  208. * Returns true if the entry identified by the given alias
  209. * was created by a call to <code>setCertificateEntry</code>,
  210. * or created by a call to <code>setEntry</code> with a
  211. * <code>TrustedCertificateEntry</code>.
  212. *
  213. * @param alias the alias for the keystore entry to be checked
  214. *
  215. * @return true if the entry identified by the given alias contains a
  216. * trusted certificate, false otherwise.
  217. */
  218. public abstract boolean engineIsCertificateEntry(String alias);
  219. /**
  220. * Returns the (alias) name of the first keystore entry whose certificate
  221. * matches the given certificate.
  222. *
  223. * <p>This method attempts to match the given certificate with each
  224. * keystore entry. If the entry being considered was
  225. * created by a call to <code>setCertificateEntry</code>,
  226. * or created by a call to <code>setEntry</code> with a
  227. * <code>TrustedCertificateEntry</code>,
  228. * then the given certificate is compared to that entry's certificate.
  229. *
  230. * <p> If the entry being considered was
  231. * created by a call to <code>setKeyEntry</code>,
  232. * or created by a call to <code>setEntry</code> with a
  233. * <code>PrivateKeyEntry</code>,
  234. * then the given certificate is compared to the first
  235. * element of that entry's certificate chain.
  236. *
  237. * @param cert the certificate to match with.
  238. *
  239. * @return the alias name of the first entry with matching certificate,
  240. * or null if no such entry exists in this keystore.
  241. */
  242. public abstract String engineGetCertificateAlias(Certificate cert);
  243. /**
  244. * Stores this keystore to the given output stream, and protects its
  245. * integrity with the given password.
  246. *
  247. * @param stream the output stream to which this keystore is written.
  248. * @param password the password to generate the keystore integrity check
  249. *
  250. * @exception IOException if there was an I/O problem with data
  251. * @exception NoSuchAlgorithmException if the appropriate data integrity
  252. * algorithm could not be found
  253. * @exception CertificateException if any of the certificates included in
  254. * the keystore data could not be stored
  255. */
  256. public abstract void engineStore(OutputStream stream, char[] password)
  257. throws IOException, NoSuchAlgorithmException, CertificateException;
  258. /**
  259. * Stores this keystore using the given
  260. * <code>KeyStore.LoadStoreParmeter</code>.
  261. *
  262. * @param param the <code>KeyStore.LoadStoreParmeter</code>
  263. * that specifies how to store the keystore,
  264. * which may be <code>null</code>
  265. *
  266. * @exception IllegalArgumentException if the given
  267. * <code>KeyStore.LoadStoreParmeter</code>
  268. * input is not recognized
  269. * @exception IOException if there was an I/O problem with data
  270. * @exception NoSuchAlgorithmException if the appropriate data integrity
  271. * algorithm could not be found
  272. * @exception CertificateException if any of the certificates included in
  273. * the keystore data could not be stored
  274. *
  275. * @since 1.5
  276. */
  277. public void engineStore(KeyStore.LoadStoreParameter param)
  278. throws IOException, NoSuchAlgorithmException,
  279. CertificateException {
  280. throw new UnsupportedOperationException();
  281. }
  282. /**
  283. * Loads the keystore from the given input stream.
  284. *
  285. * <p>A password may be given to unlock the keystore
  286. * (e.g. the keystore resides on a hardware token device),
  287. * or to check the integrity of the keystore data.
  288. * If a password is not given for integrity checking,
  289. * then integrity checking is not performed.
  290. *
  291. * @param stream the input stream from which the keystore is loaded,
  292. * or <code>null</code>
  293. * @param password the password used to check the integrity of
  294. * the keystore, the password used to unlock the keystore,
  295. * or <code>null</code>
  296. *
  297. * @exception IOException if there is an I/O or format problem with the
  298. * keystore data, if a password is required but not given,
  299. * or if the given password was incorrect
  300. * @exception NoSuchAlgorithmException if the algorithm used to check
  301. * the integrity of the keystore cannot be found
  302. * @exception CertificateException if any of the certificates in the
  303. * keystore could not be loaded
  304. */
  305. public abstract void engineLoad(InputStream stream, char[] password)
  306. throws IOException, NoSuchAlgorithmException, CertificateException;
  307. /**
  308. * Loads the keystore using the given
  309. * <code>KeyStore.LoadStoreParameter</code>.
  310. *
  311. * <p> Note that if this KeyStore has already been loaded, it is
  312. * reinitialized and loaded again from the given parameter.
  313. *
  314. * @param param the <code>KeyStore.LoadStoreParameter</code>
  315. * that specifies how to load the keystore,
  316. * which may be <code>null</code>
  317. *
  318. * @exception IllegalArgumentException if the given
  319. * <code>KeyStore.LoadStoreParameter</code>
  320. * input is not recognized
  321. * @exception IOException if there is an I/O or format problem with the
  322. * keystore data
  323. * @exception NoSuchAlgorithmException if the algorithm used to check
  324. * the integrity of the keystore cannot be found
  325. * @exception CertificateException if any of the certificates in the
  326. * keystore could not be loaded
  327. *
  328. * @since 1.5
  329. */
  330. public void engineLoad(KeyStore.LoadStoreParameter param)
  331. throws IOException, NoSuchAlgorithmException,
  332. CertificateException {
  333. if (param == null) {
  334. engineLoad((InputStream)null, (char[])null);
  335. return;
  336. }
  337. if (param instanceof KeyStore.SimpleLoadStoreParameter) {
  338. ProtectionParameter protection = param.getProtectionParameter();
  339. char[] password;
  340. if (protection instanceof PasswordProtection) {
  341. password = ((PasswordProtection)param).getPassword();
  342. } else if (protection instanceof CallbackHandlerProtection) {
  343. CallbackHandler handler =
  344. ((CallbackHandlerProtection)param).getCallbackHandler();
  345. PasswordCallback callback =
  346. new PasswordCallback("Password: ", false);
  347. try {
  348. handler.handle(new Callback[] {callback});
  349. } catch (UnsupportedCallbackException e) {
  350. throw new NoSuchAlgorithmException
  351. ("Could not obtain password", e);
  352. }
  353. password = callback.getPassword();
  354. callback.clearPassword();
  355. if (password == null) {
  356. throw new NoSuchAlgorithmException
  357. ("No password provided");
  358. }
  359. } else {
  360. throw new NoSuchAlgorithmException("ProtectionParameter must"
  361. + " be PasswordProtection or CallbackHandlerProtection");
  362. }
  363. engineLoad(null, password);
  364. return;
  365. }
  366. throw new UnsupportedOperationException();
  367. }
  368. /**
  369. * Gets a <code>KeyStore.Entry</code> for the specified alias
  370. * with the specified protection parameter.
  371. *
  372. * @param alias get the <code>KeyStore.Entry</code> for this alias
  373. * @param protParam the <code>ProtectionParameter</code>
  374. * used to protect the <code>Entry</code>,
  375. * which may be <code>null</code>
  376. *
  377. * @return the <code>KeyStore.Entry</code> for the specified alias,
  378. * or <code>null</code> if there is no such entry
  379. *
  380. * @exception KeyStoreException if the operation failed
  381. * @exception NoSuchAlgorithmException if the algorithm for recovering the
  382. * entry cannot be found
  383. * @exception UnrecoverableEntryException if the specified
  384. * <code>protParam</code> were insufficient or invalid
  385. *
  386. * @since 1.5
  387. */
  388. public KeyStore.Entry engineGetEntry(String alias,
  389. KeyStore.ProtectionParameter protParam)
  390. throws KeyStoreException, NoSuchAlgorithmException,
  391. UnrecoverableEntryException {
  392. if (!engineContainsAlias(alias)) {
  393. return null;
  394. }
  395. if (protParam == null) {
  396. if (engineIsCertificateEntry(alias)) {
  397. return new KeyStore.TrustedCertificateEntry
  398. (engineGetCertificate(alias));
  399. } else {
  400. throw new UnrecoverableEntryException
  401. ("requested entry requires a password");
  402. }
  403. }
  404. if (protParam instanceof KeyStore.PasswordProtection) {
  405. if (engineIsCertificateEntry(alias)) {
  406. throw new UnsupportedOperationException
  407. ("trusted certificate entries are not password-protected");
  408. } else if (engineIsKeyEntry(alias)) {
  409. KeyStore.PasswordProtection pp =
  410. (KeyStore.PasswordProtection)protParam;
  411. char[] password = pp.getPassword();
  412. try {
  413. Key key = engineGetKey(alias, password);
  414. if (key instanceof PrivateKey) {
  415. Certificate[] chain = engineGetCertificateChain(alias);
  416. return new KeyStore.PrivateKeyEntry
  417. ((PrivateKey)key, chain);
  418. } else if (key instanceof SecretKey) {
  419. return new KeyStore.SecretKeyEntry((SecretKey)key);
  420. }
  421. } catch (UnrecoverableKeyException uke) {
  422. UnrecoverableEntryException uee =
  423. new UnrecoverableEntryException();
  424. uee.initCause(uke);
  425. throw uee;
  426. }
  427. }
  428. }
  429. throw new UnsupportedOperationException();
  430. }
  431. /**
  432. * Saves a <code>KeyStore.Entry</code> under the specified alias.
  433. * The specified protection parameter is used to protect the
  434. * <code>Entry</code>.
  435. *
  436. * <p> If an entry already exists for the specified alias,
  437. * it is overridden.
  438. *
  439. * @param alias save the <code>KeyStore.Entry</code> under this alias
  440. * @param entry the <code>Entry</code> to save
  441. * @param protParam the <code>ProtectionParameter</code>
  442. * used to protect the <code>Entry</code>,
  443. * which may be <code>null</code>
  444. *
  445. * @exception KeyStoreException if this operation fails
  446. *
  447. * @since 1.5
  448. */
  449. public void engineSetEntry(String alias, KeyStore.Entry entry,
  450. KeyStore.ProtectionParameter protParam)
  451. throws KeyStoreException {
  452. // get password
  453. if (protParam != null &&
  454. !(protParam instanceof KeyStore.PasswordProtection)) {
  455. throw new KeyStoreException("unsupported protection parameter");
  456. }
  457. KeyStore.PasswordProtection pProtect = null;
  458. if (protParam != null) {
  459. pProtect = (KeyStore.PasswordProtection)protParam;
  460. }
  461. // set entry
  462. if (entry instanceof KeyStore.TrustedCertificateEntry) {
  463. if (protParam != null && pProtect.getPassword() != null) {
  464. // pre-1.5 style setCertificateEntry did not allow password
  465. throw new KeyStoreException
  466. ("trusted certificate entries are not password-protected");
  467. } else {
  468. KeyStore.TrustedCertificateEntry tce =
  469. (KeyStore.TrustedCertificateEntry)entry;
  470. engineSetCertificateEntry(alias, tce.getTrustedCertificate());
  471. return;
  472. }
  473. } else if (entry instanceof KeyStore.PrivateKeyEntry) {
  474. if (pProtect == null || pProtect.getPassword() == null) {
  475. // pre-1.5 style setKeyEntry required password
  476. throw new KeyStoreException
  477. ("non-null password required to create PrivateKeyEntry");
  478. } else {
  479. engineSetKeyEntry
  480. (alias,
  481. ((KeyStore.PrivateKeyEntry)entry).getPrivateKey(),
  482. pProtect.getPassword(),
  483. ((KeyStore.PrivateKeyEntry)entry).getCertificateChain());
  484. return;
  485. }
  486. } else if (entry instanceof KeyStore.SecretKeyEntry) {
  487. if (pProtect == null || pProtect.getPassword() == null) {
  488. // pre-1.5 style setKeyEntry required password
  489. throw new KeyStoreException
  490. ("non-null password required to create SecretKeyEntry");
  491. } else {
  492. engineSetKeyEntry
  493. (alias,
  494. ((KeyStore.SecretKeyEntry)entry).getSecretKey(),
  495. pProtect.getPassword(),
  496. (Certificate[])null);
  497. return;
  498. }
  499. }
  500. throw new KeyStoreException
  501. ("unsupported entry type: " + entry.getClass().getName());
  502. }
  503. /**
  504. * Determines if the keystore <code>Entry</code> for the specified
  505. * <code>alias</code> is an instance or subclass of the specified
  506. * <code>entryClass</code>.
  507. *
  508. * @param alias the alias name
  509. * @param entryClass the entry class
  510. *
  511. * @return true if the keystore <code>Entry</code> for the specified
  512. * <code>alias</code> is an instance or subclass of the
  513. * specified <code>entryClass</code>, false otherwise
  514. *
  515. * @since 1.5
  516. */
  517. public boolean
  518. engineEntryInstanceOf(String alias,
  519. Class<? extends KeyStore.Entry> entryClass)
  520. {
  521. if (entryClass == KeyStore.TrustedCertificateEntry.class) {
  522. return engineIsCertificateEntry(alias);
  523. }
  524. if (entryClass == KeyStore.PrivateKeyEntry.class) {
  525. return engineIsKeyEntry(alias) &&
  526. engineGetCertificate(alias) != null;
  527. }
  528. if (entryClass == KeyStore.SecretKeyEntry.class) {
  529. return engineIsKeyEntry(alias) &&
  530. engineGetCertificate(alias) == null;
  531. }
  532. return false;
  533. }
  534. }