EnvelopeEntry.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /* EnvelopeEntry.java --
  2. Copyright (C) 2003, 2006, 2010 Free Software Foundation, Inc.
  3. This file is a part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or (at
  7. your option) any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  15. USA
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.javax.crypto.keyring;
  32. import gnu.java.security.Configuration;
  33. import java.io.ByteArrayOutputStream;
  34. import java.io.DataInputStream;
  35. import java.io.DataOutputStream;
  36. import java.io.IOException;
  37. import java.util.ArrayList;
  38. import java.util.Iterator;
  39. import java.util.LinkedList;
  40. import java.util.List;
  41. import java.util.StringTokenizer;
  42. import java.util.logging.Logger;
  43. /**
  44. * An envelope entry is a generic container for some number of primitive and
  45. * other envelope entries.
  46. */
  47. public abstract class EnvelopeEntry
  48. extends Entry
  49. {
  50. private static final Logger log = Configuration.DEBUG ?
  51. Logger.getLogger(EnvelopeEntry.class.getName()) : null;
  52. /** The envelope that contains this one (if any). */
  53. protected EnvelopeEntry containingEnvelope;
  54. /** The contained entries. */
  55. protected List entries;
  56. public EnvelopeEntry(int type, Properties properties)
  57. {
  58. super(type, properties);
  59. entries = new LinkedList();
  60. if (this.properties.get("alias-list") != null)
  61. this.properties.remove("alias-list");
  62. }
  63. protected EnvelopeEntry(int type)
  64. {
  65. super(type);
  66. entries = new LinkedList();
  67. }
  68. /**
  69. * Adds an entry to this envelope.
  70. *
  71. * @param entry The entry to add.
  72. */
  73. public void add(Entry entry)
  74. {
  75. if (Configuration.DEBUG)
  76. log.entering(this.getClass().getName(), "add", entry);
  77. if (! containsEntry(entry))
  78. {
  79. if (entry instanceof EnvelopeEntry)
  80. ((EnvelopeEntry) entry).setContainingEnvelope(this);
  81. entries.add(entry);
  82. if (Configuration.DEBUG)
  83. log.fine("Payload is " + (payload == null ? "" : "not ") + "null");
  84. makeAliasList();
  85. }
  86. if (Configuration.DEBUG)
  87. log.exiting(this.getClass().getName(), "add");
  88. }
  89. /**
  90. * Tests if this envelope contains a primitive entry with the given alias.
  91. *
  92. * @param alias The alias to test.
  93. * @return True if this envelope (or one of the contained envelopes) contains
  94. * a primitive entry with the given alias.
  95. */
  96. public boolean containsAlias(String alias)
  97. {
  98. if (Configuration.DEBUG)
  99. log.entering(this.getClass().getName(), "containsAlias", alias);
  100. String aliases = getAliasList();
  101. if (Configuration.DEBUG)
  102. log.fine("aliases = [" + aliases + "]");
  103. boolean result = false;
  104. if (aliases != null)
  105. {
  106. StringTokenizer tok = new StringTokenizer(aliases, ";");
  107. while (tok.hasMoreTokens())
  108. if (tok.nextToken().equals(alias))
  109. {
  110. result = true;
  111. break;
  112. }
  113. }
  114. if (Configuration.DEBUG)
  115. log.exiting(this.getClass().getName(), "containsAlias",
  116. Boolean.valueOf(result));
  117. return result;
  118. }
  119. /**
  120. * Tests if this envelope contains the given entry.
  121. *
  122. * @param entry The entry to test.
  123. * @return True if this envelope contains the given entry.
  124. */
  125. public boolean containsEntry(Entry entry)
  126. {
  127. if (entry instanceof EnvelopeEntry)
  128. return entries.contains(entry);
  129. if (entry instanceof PrimitiveEntry)
  130. for (Iterator it = entries.iterator(); it.hasNext();)
  131. {
  132. Entry e = (Entry) it.next();
  133. if (e.equals(entry))
  134. return true;
  135. if ((e instanceof EnvelopeEntry)
  136. && ((EnvelopeEntry) e).containsEntry(entry))
  137. return true;
  138. }
  139. return false;
  140. }
  141. /**
  142. * Returns a copy of all entries this envelope contains.
  143. *
  144. * @return All contained entries.
  145. */
  146. public List getEntries()
  147. {
  148. return new ArrayList(entries);
  149. }
  150. /**
  151. * Gets all primitive entries that have the given alias. If there are any
  152. * masked entries that contain the given alias, they will be returned as well.
  153. *
  154. * @param alias The alias of the entries to get.
  155. * @return A list of all primitive entries that have the given alias.
  156. */
  157. public List get(String alias)
  158. {
  159. if (Configuration.DEBUG)
  160. log.entering(this.getClass().getName(), "get", alias);
  161. List result = new LinkedList();
  162. for (Iterator it = entries.iterator(); it.hasNext();)
  163. {
  164. Entry e = (Entry) it.next();
  165. if (e instanceof EnvelopeEntry)
  166. {
  167. EnvelopeEntry ee = (EnvelopeEntry) e;
  168. if (! ee.containsAlias(alias))
  169. continue;
  170. if (ee instanceof MaskableEnvelopeEntry)
  171. {
  172. MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee;
  173. if (mee.isMasked())
  174. {
  175. if (Configuration.DEBUG)
  176. log.fine("Processing masked entry: " + mee);
  177. result.add(mee);
  178. continue;
  179. }
  180. }
  181. if (Configuration.DEBUG)
  182. log.fine("Processing unmasked entry: " + ee);
  183. result.addAll(ee.get(alias));
  184. }
  185. else if (e instanceof PrimitiveEntry)
  186. {
  187. PrimitiveEntry pe = (PrimitiveEntry) e;
  188. if (pe.getAlias().equals(alias))
  189. result.add(e);
  190. }
  191. }
  192. if (Configuration.DEBUG)
  193. log.exiting(this.getClass().getName(), "get", result);
  194. return result;
  195. }
  196. /**
  197. * Returns the list of all aliases contained by this envelope, separated by a
  198. * semicolon (';').
  199. *
  200. * @return The list of aliases.
  201. */
  202. public String getAliasList()
  203. {
  204. String list = properties.get("alias-list");
  205. if (list == null)
  206. return "";
  207. else
  208. return list;
  209. }
  210. /**
  211. * Removes the specified entry.
  212. *
  213. * @param entry The entry.
  214. * @return True if an entry was removed.
  215. */
  216. public boolean remove(Entry entry)
  217. {
  218. if (Configuration.DEBUG)
  219. log.entering(this.getClass().getName(), "remove", entry);
  220. boolean ret = false;
  221. for (Iterator it = entries.iterator(); it.hasNext();)
  222. {
  223. Entry e = (Entry) it.next();
  224. if (e instanceof EnvelopeEntry)
  225. {
  226. if (e == entry)
  227. {
  228. it.remove();
  229. ret = true;
  230. break;
  231. }
  232. if (((EnvelopeEntry) e).remove(entry))
  233. {
  234. ret = true;
  235. break;
  236. }
  237. }
  238. else if (e instanceof PrimitiveEntry)
  239. {
  240. if (((PrimitiveEntry) e).equals(entry))
  241. {
  242. it.remove();
  243. ret = true;
  244. break;
  245. }
  246. }
  247. }
  248. if (ret)
  249. {
  250. if (Configuration.DEBUG)
  251. log.fine("State before: " + this);
  252. payload = null;
  253. makeAliasList();
  254. if (Configuration.DEBUG)
  255. log.fine("State after: " + this);
  256. }
  257. if (Configuration.DEBUG)
  258. log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret));
  259. return ret;
  260. }
  261. /**
  262. * Removes all primitive entries that have the specified alias.
  263. *
  264. * @param alias The alias of the entries to remove.
  265. * @return <code>true</code> if <code>alias</code> was present and was
  266. * successfully trmoved. Returns <code>false</code> if
  267. * <code>alias</code> was not present in the list of aliases in this
  268. * envelope.
  269. */
  270. public boolean remove(String alias)
  271. {
  272. if (Configuration.DEBUG)
  273. log.entering(this.getClass().getName(), "remove", alias);
  274. boolean result = false;
  275. for (Iterator it = entries.iterator(); it.hasNext();)
  276. {
  277. Entry e = (Entry) it.next();
  278. if (e instanceof EnvelopeEntry)
  279. {
  280. EnvelopeEntry ee = (EnvelopeEntry) e;
  281. result = ee.remove(alias) || result;
  282. }
  283. else if (e instanceof PrimitiveEntry)
  284. {
  285. PrimitiveEntry pe = (PrimitiveEntry) e;
  286. if (pe.getAlias().equals(alias))
  287. {
  288. it.remove();
  289. result = true;
  290. }
  291. }
  292. }
  293. if (result)
  294. {
  295. if (Configuration.DEBUG)
  296. log.fine("State before: " + this);
  297. payload = null;
  298. makeAliasList();
  299. if (Configuration.DEBUG)
  300. log.fine("State after: " + this);
  301. }
  302. if (Configuration.DEBUG)
  303. log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result));
  304. return result;
  305. }
  306. public String toString()
  307. {
  308. return new StringBuilder("Envelope{")
  309. .append(super.toString())
  310. .append(", entries=").append(entries)
  311. .append("}")
  312. .toString();
  313. }
  314. // Protected methods.
  315. // ------------------------------------------------------------------------
  316. protected void encodePayload() throws IOException
  317. {
  318. ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
  319. DataOutputStream out = new DataOutputStream(bout);
  320. for (Iterator it = entries.iterator(); it.hasNext();)
  321. ((Entry) it.next()).encode(out);
  322. }
  323. protected void setContainingEnvelope(EnvelopeEntry e)
  324. {
  325. if (containingEnvelope != null)
  326. throw new IllegalArgumentException("envelopes may not be shared");
  327. containingEnvelope = e;
  328. }
  329. protected void decodeEnvelope(DataInputStream in) throws IOException
  330. {
  331. this.entries.clear();
  332. while (true)
  333. {
  334. int type = in.read();
  335. switch (type)
  336. {
  337. case EncryptedEntry.TYPE:
  338. add(EncryptedEntry.decode(in));
  339. break;
  340. case PasswordEncryptedEntry.TYPE:
  341. add(PasswordEncryptedEntry.decode(in));
  342. break;
  343. case PasswordAuthenticatedEntry.TYPE:
  344. add(PasswordAuthenticatedEntry.decode(in));
  345. break;
  346. case AuthenticatedEntry.TYPE:
  347. add(AuthenticatedEntry.decode(in));
  348. break;
  349. case CompressedEntry.TYPE:
  350. add(CompressedEntry.decode(in));
  351. break;
  352. case CertificateEntry.TYPE:
  353. add(CertificateEntry.decode(in));
  354. break;
  355. case PublicKeyEntry.TYPE:
  356. add(PublicKeyEntry.decode(in));
  357. break;
  358. case PrivateKeyEntry.TYPE:
  359. add(PrivateKeyEntry.decode(in));
  360. break;
  361. case CertPathEntry.TYPE:
  362. add(CertPathEntry.decode(in));
  363. break;
  364. case BinaryDataEntry.TYPE:
  365. add(BinaryDataEntry.decode(in));
  366. break;
  367. case -1:
  368. return;
  369. default:
  370. throw new MalformedKeyringException("unknown type " + type);
  371. }
  372. }
  373. }
  374. private void makeAliasList()
  375. {
  376. if (Configuration.DEBUG)
  377. log.entering(this.getClass().getName(), "makeAliasList");
  378. if (! entries.isEmpty())
  379. {
  380. StringBuilder buf = new StringBuilder();
  381. String aliasOrList;
  382. for (Iterator it = entries.iterator(); it.hasNext();)
  383. {
  384. Entry entry = (Entry) it.next();
  385. aliasOrList = null;
  386. if (entry instanceof EnvelopeEntry)
  387. aliasOrList = ((EnvelopeEntry) entry).getAliasList();
  388. else if (entry instanceof PrimitiveEntry)
  389. aliasOrList = ((PrimitiveEntry) entry).getAlias();
  390. else if (Configuration.DEBUG)
  391. log.fine("Entry with no Alias. Ignored: " + entry);
  392. if (aliasOrList != null)
  393. {
  394. aliasOrList = aliasOrList.trim();
  395. if (aliasOrList.trim().length() > 0)
  396. {
  397. buf.append(aliasOrList);
  398. if (it.hasNext())
  399. buf.append(';');
  400. }
  401. }
  402. }
  403. String aliasList = buf.toString();
  404. properties.put("alias-list", aliasList);
  405. if (Configuration.DEBUG)
  406. log.fine("alias-list=[" + aliasList + "]");
  407. if (containingEnvelope != null)
  408. containingEnvelope.makeAliasList();
  409. }
  410. if (Configuration.DEBUG)
  411. log.exiting(this.getClass().getName(), "makeAliasList");
  412. }
  413. }