diff options
Diffstat (limited to 'src/org/noreply/fancydress/directory/Directory.java')
-rw-r--r-- | src/org/noreply/fancydress/directory/Directory.java | 156 |
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; + } +} |