From 566d17f731637df6828bdf32502a0fb123882dbe Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Thu, 9 Oct 2003 11:41:45 +0000 Subject: Initial import --- .../fancydress/directory/ServerDescriptor.java | 319 +++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 src/org/noreply/fancydress/directory/ServerDescriptor.java (limited to 'src/org/noreply/fancydress/directory/ServerDescriptor.java') diff --git a/src/org/noreply/fancydress/directory/ServerDescriptor.java b/src/org/noreply/fancydress/directory/ServerDescriptor.java new file mode 100644 index 0000000..06cf2d6 --- /dev/null +++ b/src/org/noreply/fancydress/directory/ServerDescriptor.java @@ -0,0 +1,319 @@ +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 org.noreply.fancydress.type3.*; +import java.util.*; +import java.text.ParseException; + +/** + * A single Server Descriptor of a type III node. + * + * This class holds all information of a single server descriptor. It may also + * hold subsections like Incoming/MMTP or Delivery/MBOX if such sections exist + * in this server descriptor. + * + * An instance of Server pools ServerDescriptors of a single node. + * + * @see Server + */ +public class ServerDescriptor { + /* Required */ + private String descriptorVersion; + private String nickname; + private byte[] identity; + private RSAPublicKey identityKey; + private byte[] identityDigest; + private byte[] digest; + private byte[] signature; + private Date published; + private Date validAfter; + private Date validUntil; + private RSAPublicKey packetKey; + private String[] packetVersions; + + /* Optional */ + private String contact; + private String contactFingerprint; + private String comments; + private String software; + private Boolean secureConfiguration; + private String whyInsecure; + + private IncomingMMTPSection IncomingMMTPSection; + private Object OutgoingMMTPSection; + private DeliveryMBOXSection DeliveryMBOXSection; + private DeliverySMTPSection DeliverySMTPSection; + private Object DeliveryFragmentedSection; + + + /** + * Construct a ServerDescriptor instance from the message in m. + * + * This constructor builds up a ServerDescriptor from the message + * m which contains a single server descriptor. + * + * The DirectoryMessage needs to have a 'Server' section. + * + * @param server a DirectoryMessage consisting of one of more sections. + * @throws Mix3BadServerFormatException if a section is syntactially invalid and the error cannot be ignored. + * @throws Mix3BadServerSignatureException if the server descriptor's signature is invalid. + */ + public ServerDescriptor(DirectoryMessage m) + throws Mix3BadServerFormatException, Mix3BadServerSignatureException + { + DirectorySection serverSection = m.getSection("Server"); + if (serverSection == null) + throw new Mix3BadServerFormatException("No Server section found."); + + parseServerSection(serverSection); + identityKey = new RSAPublicKey(identity); + identityDigest = CryptoPrimitives.hash(identity); + checkSignature(m); + + DirectorySection section; + section = m.getSection("Incoming/MMTP"); + try { + IncomingMMTPSection = section == null ? null : new IncomingMMTPSection(section); + } catch (Mix3BadServerFormatException e) { System.err.println(e); }; + + section = m.getSection("Delivery/MBOX"); + try { + DeliveryMBOXSection = section == null ? null : new DeliveryMBOXSection(section); + } catch (Mix3BadServerFormatException e) { System.err.println(e); }; + + section = m.getSection("Delivery/SMTP"); + try { + DeliverySMTPSection = section == null ? null : new DeliverySMTPSection(section); + } catch (Mix3BadServerFormatException e) { System.err.println(e); }; + } + + + /** + * Check if s is a valid nickname. + * + * @throws Mix3BadServerFormatException if s is not a valid nickame + */ + private static void checkSyntaxNickname(String s) throws Mix3BadServerFormatException { + for (int i=0; i= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '_' || c == '@' || c == '-')) + throw new Mix3BadServerFormatException("Illegal characters in nickname: "+c); + } + } + + /** + * Tokenize a Packet-Versions string into single Packet-Versions. + * + * The Packet-Versions is a comma separated list of Packet-Versions. + * This method parses a Packet-Versions value and returns an array of + * Strings, holding one Packet-Version each. + * + * Whitespace is trimmed off each Packet-Version. + * + * @param s the comma separated list of Packet-Versions + * @param onlySupported only include Packet-Versions that we can handle + * @return array of Packet-Versions. + */ + public static String[] parsePacketVersions(String s, boolean onlySupported) { + ArrayList versions = new ArrayList(); + int indexFrom = 0; + int indexOf; + + while ((indexOf = s.indexOf(',', indexFrom)) != -1) { + String v = s.substring(indexFrom, indexOf).trim(); + if (Packet.isPacketVersionSupported(v) || !onlySupported ) + versions.add( v ); + indexFrom = indexOf + 1; + } + String v = s.substring(indexFrom).trim(); + if (Packet.isPacketVersionSupported(v) || !onlySupported ) + versions.add( v ); + + String[] result = new String[versions.size()]; + for (int i=0; i 128) + throw new Mix3BadServerFormatException("Contact is too long for "+nickname); + + contactFingerprint = entryContactFingerprint == null ? null : entryContactFingerprint.getValue(); + if (contactFingerprint != null && contactFingerprint.length() > 128) + throw new Mix3BadServerFormatException("Contact-Fingerprint is too long for "+nickname); + + comments = entryComments == null ? null : entryComments.getValue(); + if (comments != null && comments.length() >= 1024) + throw new Mix3BadServerFormatException("Comments is too long for "+nickname); + + software = entrySoftware == null ? null : entrySoftware.getValue(); + try { + secureConfiguration = entrySecureConfiguration == null ? null : + new Boolean(Util.parseBoolean(entrySecureConfiguration.getValue())); + } catch (ParseException e) { + throw new Mix3BadServerFormatException("Cannot parse SecureConfiguration for "+nickname, e); + }; + whyInsecure = entryWhyInsecure == null ? null : entryWhyInsecure.getValue(); + } + + /** + * Check the signature of the server descriptor in m. + * + * @param m the ServerDescriptor to check + * @throws Mix3BadServerSignatureException if the signature is invalid. + */ + private void checkSignature(DirectoryMessage m) throws Mix3BadServerSignatureException { + DirectoryMessage cleanedDescriptor = new DirectoryMessage(m); + cleanedDescriptor.blindValue("Server","Digest"); + cleanedDescriptor.blindValue("Server","Signature"); + + boolean verifies; + try { + verifies = identityKey.verify(signature, Util.toOctets(cleanedDescriptor.toString())); + } catch (InvalidCipherTextException e) { + throw new Mix3BadServerSignatureException("Server signature has invalid format.", e); + }; + if (!verifies) + throw new Mix3BadServerSignatureException("Server signature does not verify."); + } + + /** + * Get this server descriptor's nickname. + * + * @return nickname of the server + */ + public String getNickname() { + return nickname; + } + + /** + * Get this server descriptor's identity key. + * + * @return asn1 encoded identity key of the server + */ + public byte[] getIdentity() { + return identity; + } + + /** + * Get this server descriptor's identity key. + * + * @return identity key of the server + */ + public RSAPublicKey getIdentityKey() { + return identityKey; + } + + /** + * Get this server descriptor's packet key. + * + * @return packet key of this server descriptor + */ + public RSAPublicKey getPacketKey() { + return packetKey; + } +} -- cgit v1.2.3