summaryrefslogtreecommitdiff
path: root/src/org/noreply/fancydress/directory/Directory.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/noreply/fancydress/directory/Directory.java')
-rw-r--r--src/org/noreply/fancydress/directory/Directory.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/org/noreply/fancydress/directory/Directory.java b/src/org/noreply/fancydress/directory/Directory.java
new file mode 100644
index 0000000..d5f940b
--- /dev/null
+++ b/src/org/noreply/fancydress/directory/Directory.java
@@ -0,0 +1,156 @@
+package org.noreply.fancydress.directory;
+
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.noreply.fancydress.directory.parser.*;
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.crypto.*;
+import org.noreply.fancydress.status.*;
+import java.util.*;
+
+/**
+ * This class represents a type III Directory.
+ *
+ * A directory holds information about the state of a type III network, like
+ * recommended servers, which servers exist, their keys, etc.
+ *
+ * FIXME:
+ * This whole flex and cup thing was just a nice way to try these tools.
+ * Eventually this should be rewritten to a simple parser in Java itself.
+ * Writing it should be pretty straight forward and cut down the
+ * dependencies.
+ *
+ * @see Server
+ */
+public class Directory {
+ /**
+ * Hash holding all Servers.
+ *
+ * This hash holds all Servers. Since nickname are to be treaded case
+ * insensitive the hash's keys are the lowercased nicknames of the Servers.
+ *
+ * All values in this hash are instances of Server.
+ *
+ * @see Server
+ */
+ private Hashtable byName;
+
+ /**
+ * Possibly add a new server descriptor to the directory.
+ *
+ * This method adds a server desccriptor to the directory if it
+ * - conforms to the syntax specified.
+ * - the server is not yet known or it's identity key matches the key of the already known ServerDescriptor.
+ *
+ * @param server a DirectoryMessage consisting of one of more sections. At 'Server' section needs to be present.
+ * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored.
+ * @throws Mix3BadServerSignatureException if the server descriptor's signature is invalid.
+ */
+ private void addServerDescriptor(DirectoryMessage server) throws Mix3BadServerFormatException, Mix3BadServerSignatureException {
+ try {
+ ServerDescriptor sd = new ServerDescriptor(server);
+ String key = sd.getNickname().toLowerCase();
+ if (byName.containsKey(key)) {
+ Server s = (Server) byName.get(key);
+ try {
+ s.addDescriptor(sd);
+ } catch (Mix3BadServerFormatException e) {
+ System.err.println("Ignoring Descriptor with different identity for "+key);
+ }
+ } else {
+ Server s = new Server(sd);
+ byName.put(key, s);
+ }
+ } catch (Mix3BadServerUnrecognizedVersionException e) {
+ System.err.println("Ignoring unregonized version");
+ }
+ }
+
+ /**
+ * Create a directory from an entire DirectoryMessage.
+ *
+ * This constructor builds up the directory from the message
+ * <code>m</code>. It optionally checks the directory's signature and
+ * splits the message into single server descriptors to load them.
+ *
+ * @param m the directory message
+ * @param checkDirectorySignature whether or not to check the directory's signature
+ * @throws Mix3BadDirectorySignatureException if the directory's signature is invalid.
+ * @throws Mix3BadServerSignatureException if a server descriptor's signature is invalid.
+ * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored.
+ */
+ public Directory(DirectoryMessage m, boolean checkDirectorySignature) throws
+ Mix3BadDirectorySignatureException,
+ Mix3BadServerFormatException,
+ Mix3BadServerSignatureException
+ {
+ byName = new Hashtable();
+
+ if (checkDirectorySignature)
+ checkSignature(m);
+ DirectoryMessage server = null;
+ for (Iterator i = m.getSectionsIterator(); i.hasNext(); ) {
+ DirectorySection section = (DirectorySection) i.next();
+ if (section.getName().equals("Server")) {
+ if (server != null)
+ addServerDescriptor(server);
+ server = new DirectoryMessage();
+ }
+ if (server != null)
+ server.addSection(section);
+ }
+ if (server != null)
+ addServerDescriptor(server);
+
+ System.out.println(byName);
+ }
+
+ /* FIXME: known directory servers should be passed as arguments */
+ /**
+ * Check the signature of a type III directory.
+ */
+ private void checkSignature(DirectoryMessage m) throws Mix3BadDirectorySignatureException {
+ /* FIXME: handle more than one signature block,
+ */
+
+ DirectorySection signatureSection = m.getSection("Signature");
+ if (signatureSection == null)
+ throw new Mix3BadDirectorySignatureException("No Signature section found.");
+
+ DirectoryEntry signatureEntry = signatureSection.getEntry("DirectorySignature");
+ if (signatureEntry == null)
+ throw new Mix3BadDirectorySignatureException("No DirectorySignature in Signature section found.");
+
+ DirectoryEntry identityEntry = signatureSection.getEntry("DirectoryIdentity");
+ if (identityEntry == null)
+ throw new Mix3BadDirectorySignatureException("No DirectoryIdentity in Signature section found.");
+
+ byte[] signature = Base64.decode(signatureEntry.getValue());
+ byte[] identity = Base64.decode(identityEntry.getValue());
+
+ DirectoryMessage cleanedDirectory = new DirectoryMessage(m);
+ cleanedDirectory.blindValue("Signature","DirectoryDigest");
+ cleanedDirectory.blindValue("Signature","DirectorySignature");
+
+ /* FIXME: what if identity is no valid key? */
+ RSAPublicKey identityKey = new RSAPublicKey(identity);
+ boolean verifies;
+ try {
+ verifies = identityKey.verify(signature, Util.toOctets(cleanedDirectory.toString()));
+ } catch (InvalidCipherTextException e) {
+ throw new Mix3BadDirectorySignatureException("Directory signature has invalid format.", e);
+ };
+ if (!verifies)
+ throw new Mix3BadDirectorySignatureException("Directory signature does not verify.");
+ }
+
+ /**
+ * Get a server by nickname.
+ */
+ public Server getServer(String name) {
+ String key = name.toLowerCase();
+ if (byName.containsKey(key))
+ return (Server) byName.get(key);
+ return null;
+ }
+}