From: megacz Date: Fri, 30 Jan 2004 06:51:14 +0000 (+0000) Subject: 2003/02/12 06:21:04 X-Git-Tag: RC3~1491 X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=commitdiff_plain;h=d70f271afd972a3bdeba9ee54b1e9a3334e6fe4b 2003/02/12 06:21:04 darcs-hash:20040130065114-2ba56-b548161e0ee805fea5f5bea9640cc7413c9a85f9.gz --- diff --git a/src/org/bouncycastle/asn1/ASN1OctetString.java b/src/org/bouncycastle/asn1/ASN1OctetString.java new file mode 100644 index 0000000..7daf025 --- /dev/null +++ b/src/org/bouncycastle/asn1/ASN1OctetString.java @@ -0,0 +1,139 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.util.*; + +public abstract class ASN1OctetString + extends DERObject +{ + byte[] string; + + /** + * return an Octet String from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1OctetString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** + * return an Octet String from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1OctetString getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1OctetString) + { + return (ASN1OctetString)obj; + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + if (obj instanceof ASN1Sequence) + { + Vector v = new Vector(); + Enumeration e = ((ASN1Sequence)obj).getObjects(); + + while (e.hasMoreElements()) + { + v.addElement(e.nextElement()); + } + + return new BERConstructedOctetString(v); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * @param string the octets making up the octet string. + */ + public ASN1OctetString( + byte[] string) + { + this.string = string; + } + + public ASN1OctetString( + DEREncodable obj) + { + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + + dOut.writeObject(obj); + dOut.close(); + + this.string = bOut.toByteArray(); + } + catch (IOException e) + { + throw new IllegalArgumentException("Error processing object : " + e.toString()); + } + } + + public byte[] getOctets() + { + return string; + } + + public int hashCode() + { + byte[] b = this.getOctets(); + int value = 0; + + for (int i = 0; i != b.length; i++) + { + value ^= (b[i] & 0xff) << (i % 4); + } + + return value; + } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof DEROctetString)) + { + return false; + } + + DEROctetString other = (DEROctetString)o; + + byte[] b1 = other.getOctets(); + byte[] b2 = this.getOctets(); + + if (b1.length != b2.length) + { + return false; + } + + for (int i = 0; i != b1.length; i++) + { + if (b1[i] != b2[i]) + { + return false; + } + } + + return true; + } + + abstract void encode(DEROutputStream out) + throws IOException; +} diff --git a/src/org/bouncycastle/asn1/ASN1OutputStream.java b/src/org/bouncycastle/asn1/ASN1OutputStream.java new file mode 100644 index 0000000..d309e12 --- /dev/null +++ b/src/org/bouncycastle/asn1/ASN1OutputStream.java @@ -0,0 +1,35 @@ +package org.bouncycastle.asn1; + +import java.io.*; + +public class ASN1OutputStream + extends DEROutputStream +{ + public ASN1OutputStream( + OutputStream os) + { + super(os); + } + + public void writeObject( + Object obj) + throws IOException + { + if (obj == null) + { + writeNull(); + } + else if (obj instanceof DERObject) + { + ((DERObject)obj).encode(this); + } + else if (obj instanceof DEREncodable) + { + ((DEREncodable)obj).getDERObject().encode(this); + } + else + { + throw new IOException("object not ASN1Encodable"); + } + } +} diff --git a/src/org/bouncycastle/asn1/ASN1Sequence.java b/src/org/bouncycastle/asn1/ASN1Sequence.java new file mode 100644 index 0000000..5362f34 --- /dev/null +++ b/src/org/bouncycastle/asn1/ASN1Sequence.java @@ -0,0 +1,173 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.util.*; + +public abstract class ASN1Sequence + extends DERObject +{ + private Vector seq = new Vector(); + + /** + * return an ASN1Sequence from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Sequence getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Sequence) + { + return (ASN1Sequence)obj; + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + /** + * Return an ASN1 sequence from a tagged object. There is a special + * case here, if an object appears to have been explicitly tagged on + * reading but we were expecting it to be implictly tagged in the + * normal course of events it indicates that we lost the surrounding + * sequence - so we need to add it back (this will happen if the tagged + * object is a sequence that contains other sequences). If you are + * dealing with implicitly tagged sequences you really should + * be using this method. + * + * @param obj the tagged object. + * @param explicit true if the object is meant to be explicitly tagged, + * false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Sequence getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + if (explicit) + { + if (!obj.isExplicit()) + { + throw new IllegalArgumentException("object implicit - explicit expected."); + } + + return (ASN1Sequence)obj.getObject(); + } + else + { + // + // constructed object which appears to be explicitly tagged + // when it should be implicit means we have to add the + // surrounding sequence. + // + if (obj.isExplicit()) + { + ASN1Sequence seq; + + if (obj instanceof BERTaggedObject) + { + seq = new BERConstructedSequence(); + } + else + { + seq = new DERConstructedSequence(); + } + + seq.addObject(obj.getObject()); + + return seq; + } + else + { + ASN1Sequence seq; + + if (obj.getObject() instanceof ASN1Sequence) + { + return (ASN1Sequence)obj.getObject(); + } + } + } + + throw new IllegalArgumentException( + "unknown object in getInstanceFromTagged"); + } + + public Enumeration getObjects() + { + return seq.elements(); + } + + /** + * return the object at the sequence postion indicated by index. + * + * @param the sequence number (starting at zero) of the object + * @return the object at the sequence postion indicated by index. + */ + public DEREncodable getObjectAt( + int index) + { + return (DEREncodable)seq.elementAt(index); + } + + /** + * return the number of objects in this sequence. + * + * @return the number of objects in this sequence. + */ + public int size() + { + return seq.size(); + } + + public int hashCode() + { + Enumeration e = this.getObjects(); + int hashCode = 0; + + while (e.hasMoreElements()) + { + hashCode ^= e.nextElement().hashCode(); + } + + return hashCode; + } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof ASN1Sequence)) + { + return false; + } + + ASN1Sequence other = (ASN1Sequence)o; + + if (this.size() != other.size()) + { + return false; + } + + Enumeration s1 = this.getObjects(); + Enumeration s2 = other.getObjects(); + + while (s1.hasMoreElements()) + { + if (!s1.nextElement().equals(s2.nextElement())) + { + return false; + } + } + + return true; + } + + protected void addObject( + DEREncodable obj) + { + seq.addElement(obj); + } + + abstract void encode(DEROutputStream out) + throws IOException; +} diff --git a/src/org/bouncycastle/asn1/ASN1Set.java b/src/org/bouncycastle/asn1/ASN1Set.java new file mode 100644 index 0000000..adb1b10 --- /dev/null +++ b/src/org/bouncycastle/asn1/ASN1Set.java @@ -0,0 +1,178 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.util.*; + +abstract public class ASN1Set + extends DERObject +{ + protected Vector set = new Vector(); + + /** + * return an ASN1Set from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Set getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Set) + { + return (ASN1Set)obj; + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + /** + * Return an ASN1 set from a tagged object. There is a special + * case here, if an object appears to have been explicitly tagged on + * reading but we were expecting it to be implictly tagged in the + * normal course of events it indicates that we lost the surrounding + * set - so we need to add it back (this will happen if the tagged + * object is a sequence that contains other sequences). If you are + * dealing with implicitly tagged sets you really should + * be using this method. + * + * @param obj the tagged object. + * @param explicit true if the object is meant to be explicitly tagged + * false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Set getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + if (explicit) + { + if (!obj.isExplicit()) + { + throw new IllegalArgumentException("object implicit - explicit expected."); + } + + return (ASN1Set)obj.getObject(); + } + else + { + // + // constructed object which appears to be explicitly tagged + // and it's really implicit means we have to add the + // surrounding sequence. + // + if (obj.isExplicit()) + { + ASN1Set set = new DERSet(obj.getObject()); + + return set; + } + else + { + // + // in this case the parser returns a sequence, convert it + // into a set. + // + DEREncodableVector v = new DEREncodableVector(); + + if (obj.getObject() instanceof ASN1Sequence) + { + ASN1Sequence s = (ASN1Sequence)obj.getObject(); + Enumeration e = s.getObjects(); + + while (e.hasMoreElements()) + { + v.add((DEREncodable)e.nextElement()); + } + + return new DERSet(v); + } + } + } + + throw new IllegalArgumentException( + "unknown object in getInstanceFromTagged"); + } + + public ASN1Set() + { + } + + public Enumeration getObjects() + { + return set.elements(); + } + + /** + * return the object at the set postion indicated by index. + * + * @param the set number (starting at zero) of the object + * @return the object at the set postion indicated by index. + */ + public DEREncodable getObjectAt( + int index) + { + return (DEREncodable)set.elementAt(index); + } + + /** + * return the number of objects in this set. + * + * @return the number of objects in this set. + */ + public int size() + { + return set.size(); + } + + public int hashCode() + { + Enumeration e = this.getObjects(); + int hashCode = 0; + + while (e.hasMoreElements()) + { + hashCode ^= e.nextElement().hashCode(); + } + + return hashCode; + } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof ASN1Set)) + { + return false; + } + + ASN1Set other = (ASN1Set)o; + + if (this.size() != other.size()) + { + return false; + } + + Enumeration s1 = this.getObjects(); + Enumeration s2 = other.getObjects(); + + while (s1.hasMoreElements()) + { + if (!s1.nextElement().equals(s2.nextElement())) + { + return false; + } + } + + return true; + } + + protected void addObject( + DEREncodable obj) + { + set.addElement(obj); + } + + abstract void encode(DEROutputStream out) + throws IOException; +} diff --git a/src/org/bouncycastle/asn1/ASN1TaggedObject.java b/src/org/bouncycastle/asn1/ASN1TaggedObject.java new file mode 100644 index 0000000..deadcdb --- /dev/null +++ b/src/org/bouncycastle/asn1/ASN1TaggedObject.java @@ -0,0 +1,122 @@ +package org.bouncycastle.asn1; + +import java.io.*; + +/** + * ASN.1 TaggedObject - in ASN.1 nottation this is any object proceeded by + * a [n] where n is some number - these are assume to follow the construction + * rules (as with sequences). + */ +public abstract class ASN1TaggedObject + extends DERObject +{ + int tagNo; + boolean empty = false; + boolean explicit = true; + DEREncodable obj = null; + + /** + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public ASN1TaggedObject( + int tagNo, + DEREncodable obj) + { + this.explicit = true; + this.tagNo = tagNo; + this.obj = obj; + } + + /** + * @param explicit true if the object is explicitly tagged. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public ASN1TaggedObject( + boolean explicit, + int tagNo, + DEREncodable obj) + { + this.explicit = explicit; + this.tagNo = tagNo; + this.obj = obj; + } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof ASN1TaggedObject)) + { + return false; + } + + ASN1TaggedObject other = (ASN1TaggedObject)o; + + if(tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) + { + return false; + } + + if(obj == null) + { + if(other.obj != null) + { + return false; + } + } + else + { + if(!(obj.equals(other.obj))) + { + return false; + } + } + + return true; + } + + public int getTagNo() + { + return tagNo; + } + + /** + * return whether or not the object may be explicitly tagged. + *

+ * Note: if the object has been read from an input stream, the only + * time you can be sure if isExplicit is returning the true state of + * affairs is if it returns false. An implicitly tagged object may appear + * to be explicitly tagged, so you need to understand the context under + * which the reading was done as well, see getObject below. + */ + public boolean isExplicit() + { + return explicit; + } + + public boolean isEmpty() + { + return empty; + } + + /** + * return whatever was following the tag. + *

+ * Note: tagged objects are generally context dependent if you're + * trying to extract a tagged object you should be going via the + * appropriate getInstance method. + */ + public DERObject getObject() + { + if (obj != null) + { + return obj.getDERObject(); + } + + return null; + } + + abstract void encode(DEROutputStream out) + throws IOException; +} diff --git a/src/org/bouncycastle/asn1/BERConstructedOctetString.java b/src/org/bouncycastle/asn1/BERConstructedOctetString.java index 47b4245..20b7175 100644 --- a/src/org/bouncycastle/asn1/BERConstructedOctetString.java +++ b/src/org/bouncycastle/asn1/BERConstructedOctetString.java @@ -67,14 +67,17 @@ public class BERConstructedOctetString return string; } - public Vector getDEROctets() + /** + * return the DER octets that make up this string. + */ + public Enumeration getObjects() { if (octs == null) { octs = generateOcts(); } - return octs; + return octs.elements(); } private Vector generateOcts() @@ -83,27 +86,24 @@ public class BERConstructedOctetString int end = 0; Vector vec = new Vector(); - while (end < string.length) + while ((end + 1) < string.length) { - if ((end + 1) < string.length) + if (string[end] == 0 && string[end + 1] == 0) { - if (string[end] == 0 && string[end + 1] == 0) - { - byte[] nStr = new byte[end - start + 1]; + byte[] nStr = new byte[end - start + 1]; - for (int i = 0; i != nStr.length; i++) - { - nStr[i] = string[start + i]; - } - - vec.addElement(new DEROctetString(nStr)); - start = end + 1; + for (int i = 0; i != nStr.length; i++) + { + nStr[i] = string[start + i]; } + + vec.addElement(new DEROctetString(nStr)); + start = end + 1; } end++; } - byte[] nStr = new byte[end - start]; + byte[] nStr = new byte[string.length - start]; for (int i = 0; i != nStr.length; i++) { nStr[i] = string[start + i]; @@ -118,8 +118,8 @@ public class BERConstructedOctetString DEROutputStream out) throws IOException { - if (out instanceof BEROutputStream) - { + if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) + { out.write(CONSTRUCTED | OCTET_STRING); out.write(0x80); @@ -136,10 +136,10 @@ public class BERConstructedOctetString out.write(0x00); out.write(0x00); - } - else - { - super.encode(out); - } + } + else + { + super.encode(out); + } } } diff --git a/src/org/bouncycastle/asn1/BERConstructedSequence.java b/src/org/bouncycastle/asn1/BERConstructedSequence.java index b8a3c2d..b3c51e1 100644 --- a/src/org/bouncycastle/asn1/BERConstructedSequence.java +++ b/src/org/bouncycastle/asn1/BERConstructedSequence.java @@ -7,37 +7,22 @@ public class BERConstructedSequence extends DERConstructedSequence { /* - * A note on the implementation: - *

- * As DER requires the constructed, definite-length model to - * be used for structured types, this varies slightly from the - * ASN.1 descriptions given. Rather than just outputing SEQUENCE, - * we also have to specify CONSTRUCTED, and the objects length. */ void encode( DEROutputStream out) throws IOException { - if (out instanceof BEROutputStream) + if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - BEROutputStream dOut = new BEROutputStream(bOut); - Enumeration e = getObjects(); - + out.write(SEQUENCE | CONSTRUCTED); + out.write(0x80); + + Enumeration e = getObjects(); while (e.hasMoreElements()) { - Object obj = e.nextElement(); - - dOut.writeObject(obj); + out.writeObject(e.nextElement()); } - - dOut.close(); - - byte[] bytes = bOut.toByteArray(); - - out.write(SEQUENCE | CONSTRUCTED); - out.write(0x80); - out.write(bytes); + out.write(0x00); out.write(0x00); } diff --git a/src/org/bouncycastle/asn1/BERInputStream.java b/src/org/bouncycastle/asn1/BERInputStream.java index 824b439..fd960ec 100644 --- a/src/org/bouncycastle/asn1/BERInputStream.java +++ b/src/org/bouncycastle/asn1/BERInputStream.java @@ -47,19 +47,11 @@ public class BERInputStream return bOut.toByteArray(); } - private BERConstructedOctetString buildConstructedOctetString( - DEROctetString o1, - DEROctetString o2) + private BERConstructedOctetString buildConstructedOctetString() throws IOException { Vector octs = new Vector(); - if (o1 != null) - { - octs.addElement(o1); - octs.addElement(o2); - } - for (;;) { DERObject o = readObject(); @@ -88,8 +80,6 @@ public class BERInputStream if (length < 0) // indefinite length method { - byte[] bytes; - switch (tag) { case NULL: @@ -110,36 +100,82 @@ public class BERInputStream } return seq; case OCTET_STRING | CONSTRUCTED: - return buildConstructedOctetString(null, null); - default: - if ((tag & (TAGGED | CONSTRUCTED)) != 0) - { - // with tagged object tag number is bottom 4 bits - BERTaggedObject tagObj = new BERTaggedObject(tag & 0x0f, readObject()); - DERObject o = readObject(); + return buildConstructedOctetString(); + case SET | CONSTRUCTED: + DEREncodableVector v = new DEREncodableVector(); + + for (;;) + { + DERObject obj = readObject(); - if (o == END_OF_STREAM) - { - return tagObj; - } - else if (o instanceof DEROctetString - && tagObj.getObject() instanceof DEROctetString) + if (obj == END_OF_STREAM) { - // - // it's an implicit object - mark it as so... - // - tagObj = new BERTaggedObject(false, tag & 0x0f, - buildConstructedOctetString((DEROctetString)tagObj.getObject(), (DEROctetString)o)); - - return tagObj; + break; } - throw new IOException("truncated tagged object"); + v.add(obj); + } + return new BERSet(v); + default: + // + // with tagged object tag number is bottom 5 bits + // + if ((tag & TAGGED) != 0) + { + if ((tag & 0x1f) == 0x1f) + { + throw new IOException("unsupported high tag encountered"); + } + + // + // simple type - implicit... return an octet string + // + if ((tag & CONSTRUCTED) == 0) + { + byte[] bytes = readIndefiniteLengthFully(); + + return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes)); + } + + // + // either constructed or explicitly tagged + // + DERObject dObj = readObject(); + + if (dObj == END_OF_STREAM) // empty tag! + { + return new DERTaggedObject(tag & 0x1f); + } + + DERObject next = readObject(); + + // + // explicitly tagged (probably!) - if it isn't we'd have to + // tell from the context + // + if (next == END_OF_STREAM) + { + return new BERTaggedObject(tag & 0x1f, dObj); + } + + // + // another implicit object, we'll create a sequence... + // + seq = new BERConstructedSequence(); + + seq.addObject(dObj); + + do + { + seq.addObject(next); + next = readObject(); + } + while (next != END_OF_STREAM); + + return new BERTaggedObject(false, tag & 0x1f, seq); } - - bytes = readIndefiniteLengthFully(); - return buildObject(tag, bytes); + throw new IOException("unknown BER object encountered"); } } else diff --git a/src/org/bouncycastle/asn1/BERSet.java b/src/org/bouncycastle/asn1/BERSet.java new file mode 100644 index 0000000..5e99b4f --- /dev/null +++ b/src/org/bouncycastle/asn1/BERSet.java @@ -0,0 +1,59 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.util.*; + +public class BERSet + extends DERSet +{ + /** + * create an empty sequence + */ + public BERSet() + { + } + + /** + * create a set containing one object + */ + public BERSet( + DEREncodable obj) + { + super(obj); + } + + /** + * create a set containing a vector of objects. + */ + public BERSet( + DEREncodableVector v) + { + super(v); + } + + /* + */ + void encode( + DEROutputStream out) + throws IOException + { + if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) + { + out.write(SET | CONSTRUCTED); + out.write(0x80); + + Enumeration e = getObjects(); + while (e.hasMoreElements()) + { + out.writeObject(e.nextElement()); + } + + out.write(0x00); + out.write(0x00); + } + else + { + super.encode(out); + } + } +} diff --git a/src/org/bouncycastle/asn1/BERTaggedObject.java b/src/org/bouncycastle/asn1/BERTaggedObject.java index b24f037..10f83e2 100644 --- a/src/org/bouncycastle/asn1/BERTaggedObject.java +++ b/src/org/bouncycastle/asn1/BERTaggedObject.java @@ -12,86 +12,96 @@ public class BERTaggedObject extends DERTaggedObject { /** - * This creates an empty tagged object of tagNo (ie. zero length). - * * @param tagNo the tag number for this object. + * @param obj the tagged object. */ public BERTaggedObject( - int tagNo) + int tagNo, + DEREncodable obj) { - super(tagNo); + super(tagNo, obj); } /** + * @param explicit true if an explicitly tagged object. * @param tagNo the tag number for this object. * @param obj the tagged object. */ public BERTaggedObject( - int tagNo, - DERObject obj) + boolean explicit, + int tagNo, + DEREncodable obj) { - super(tagNo, obj); + super(explicit, tagNo, obj); } /** - * @param explicit true if an explicitly tagged object. - * @param tagNo the tag number for this object. - * @param obj the tagged object. + * create an implicitly tagged object that contains a zero + * length sequence. */ public BERTaggedObject( - boolean explicit, - int tagNo, - DERObject obj) + int tagNo) { - super(explicit, tagNo, obj); + super(false, tagNo, new BERConstructedSequence()); } void encode( DEROutputStream out) throws IOException { - if (out instanceof BEROutputStream) - { + if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) + { out.write(CONSTRUCTED | TAGGED | tagNo); out.write(0x80); - if (!empty) - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - BEROutputStream dOut = new BEROutputStream(bOut); - + if (!empty) + { if (!explicit) { if (obj instanceof BERConstructedOctetString) { - Vector octs = ((BERConstructedOctetString)obj).getDEROctets(); + Enumeration e = ((BERConstructedOctetString)obj).getObjects(); + + while (e.hasMoreElements()) + { + out.writeObject(e.nextElement()); + } + } + else if (obj instanceof ASN1Sequence) + { + Enumeration e = ((ASN1Sequence)obj).getObjects(); - for (int i = 0; i != octs.size(); i++) + while (e.hasMoreElements()) { - dOut.writeObject(octs.elementAt(i)); + out.writeObject(e.nextElement()); + } + } + else if (obj instanceof ASN1Set) + { + Enumeration e = ((ASN1Set)obj).getObjects(); + + while (e.hasMoreElements()) + { + out.writeObject(e.nextElement()); } } else { - dOut.writeObject(obj); // hmmm... + throw new RuntimeException("not implemented: " + obj.getClass().getName()); } } else { - dOut.writeObject(obj); + out.writeObject(obj); } - - dOut.close(); - - out.write(bOut.toByteArray()); - } + } out.write(0x00); out.write(0x00); - } - else - { - super.encode(out); - } + } + else + { + super.encode(out); + } } } diff --git a/src/org/bouncycastle/asn1/DERBMPString.java b/src/org/bouncycastle/asn1/DERBMPString.java index 8a58b4a..23f467b 100644 --- a/src/org/bouncycastle/asn1/DERBMPString.java +++ b/src/org/bouncycastle/asn1/DERBMPString.java @@ -12,19 +12,63 @@ public class DERBMPString String string; /** + * return a BMP String from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERBMPString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERBMPString) + { + return (DERBMPString)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERBMPString(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a BMP String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERBMPString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + + /** * basic constructor - byte encoded string. */ public DERBMPString( byte[] string) { - try - { - this.string = new String(string, "UnicodeBig"); - } - catch (UnsupportedEncodingException e) - { - throw new RuntimeException(e.toString()); - } + char[] cs = new char[string.length / 2]; + + for (int i = 0; i != cs.length; i++) + { + cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff)); + } + + this.string = new String(cs); } /** @@ -41,6 +85,24 @@ public class DERBMPString return string; } + public int hashCode() + { + return this.getString().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof DERBMPString)) + { + return false; + } + + DERPrintableString s = (DERPrintableString)o; + + return this.getString().equals(s.getString()); + } + void encode( DEROutputStream out) throws IOException @@ -50,7 +112,7 @@ public class DERBMPString for (int i = 0; i != c.length; i++) { - b[2 * i] = (byte)((c[i] & 0xff00) >> 8); + b[2 * i] = (byte)(c[i] >> 8); b[2 * i + 1] = (byte)c[i]; } diff --git a/src/org/bouncycastle/asn1/DERBitString.java b/src/org/bouncycastle/asn1/DERBitString.java index 0c888d5..56046a7 100644 --- a/src/org/bouncycastle/asn1/DERBitString.java +++ b/src/org/bouncycastle/asn1/DERBitString.java @@ -8,6 +8,113 @@ public class DERBitString protected byte[] data; protected int padBits; + /** + * return the correct number of pad bits for a bit string defined in + * a 16 bit constant + */ + static protected int getPadBits( + int bitString) + { + int val; + + if (bitString == 0) + { + return 7; + } + + if (bitString > 255) + { + val = ((bitString >> 8) & 0xFF); + } + else + { + val = (bitString & 0xFF); + } + + int bits = 1; + + while (((val <<= 1) & 0xFF) != 0) + { + bits++; + } + + return 8 - bits; + } + + /** + * return the correct number of bytes for a bit string defined in + * a 16 bit constant + */ + static protected byte[] getBytes( + int bitString) + { + if (bitString > 255) + { + byte[] bytes = new byte[2]; + + bytes[0] = (byte)(bitString & 0xFF); + bytes[1] = (byte)((bitString >> 8) & 0xFF); + + return bytes; + } + else + { + byte[] bytes = new byte[1]; + + bytes[0] = (byte)(bitString & 0xFF); + + return bytes; + } + } + + /** + * return a Bit String from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERBitString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERBitString) + { + return (DERBitString)obj; + } + + if (obj instanceof ASN1OctetString) + { + byte[] bytes = ((ASN1OctetString)obj).getOctets(); + int padBits = bytes[0]; + byte[] data = new byte[bytes.length - 1]; + + System.arraycopy(bytes, 1, data, 0, bytes.length - 1); + + return new DERBitString(data, padBits); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Bit String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERBitString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + protected DERBitString( byte data, int padBits) @@ -36,7 +143,7 @@ public class DERBitString } public DERBitString( - DERObject obj) + DEREncodable obj) { try { @@ -55,12 +162,6 @@ public class DERBitString } } - public DERBitString( - DEREncodable obj) - { - this(obj.getDERObject()); - } - public byte[] getBytes() { return data; @@ -82,4 +183,30 @@ public class DERBitString out.writeEncoded(BIT_STRING, bytes); } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof DERBitString)) + { + return false; + } + + DERBitString other = (DERBitString)o; + + if (data.length != other.data.length) + { + return false; + } + + for (int i = 0; i != data.length; i++) + { + if (data[i] != other.data[i]) + { + return false; + } + } + + return (padBits == other.padBits); + } } diff --git a/src/org/bouncycastle/asn1/DERBoolean.java b/src/org/bouncycastle/asn1/DERBoolean.java index 4fce317..8837dfd 100644 --- a/src/org/bouncycastle/asn1/DERBoolean.java +++ b/src/org/bouncycastle/asn1/DERBoolean.java @@ -7,6 +7,60 @@ public class DERBoolean { byte value; + public static final DERBoolean FALSE = new DERBoolean(false); + public static final DERBoolean TRUE = new DERBoolean(true); + + /** + * return a boolean from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERBoolean getInstance( + Object obj) + { + if (obj == null || obj instanceof DERBoolean) + { + return (DERBoolean)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERBoolean(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a DERBoolean from the passed in boolean. + */ + public static DERBoolean getInstance( + boolean value) + { + return (value ? TRUE : FALSE); + } + + /** + * return a Boolean from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERBoolean getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + public DERBoolean( byte[] value) { @@ -34,4 +88,16 @@ public class DERBoolean out.writeEncoded(BOOLEAN, bytes); } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERBoolean)) + { + return false; + } + + return (value == ((DERBoolean)o).value); + } + } diff --git a/src/org/bouncycastle/asn1/DERConstructedSequence.java b/src/org/bouncycastle/asn1/DERConstructedSequence.java index d600d95..f1dba33 100644 --- a/src/org/bouncycastle/asn1/DERConstructedSequence.java +++ b/src/org/bouncycastle/asn1/DERConstructedSequence.java @@ -4,45 +4,17 @@ import java.io.*; import java.util.*; public class DERConstructedSequence - extends DERObject + extends ASN1Sequence { - private Vector seq = new Vector(); - - public DERConstructedSequence() - { - } - public void addObject( DEREncodable obj) { - seq.addElement(obj); - } - - public Enumeration getObjects() - { - return seq.elements(); - } - - /** - * return the object at the sequence postion indicated by index. - * - * @param the sequence number (starting at zero) of the object - * @return the object at the sequence postion indicated by index. - */ - public Object getObjectAt( - int index) - { - return seq.elementAt(index); + super.addObject(obj); } - /** - * return the number of objects in this sequence. - * - * @return the number of objects in this sequence. - */ public int getSize() { - return seq.size(); + return size(); } /* @@ -59,7 +31,7 @@ public class DERConstructedSequence { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); - Enumeration e = getObjects(); + Enumeration e = this.getObjects(); while (e.hasMoreElements()) { diff --git a/src/org/bouncycastle/asn1/DERConstructedSet.java b/src/org/bouncycastle/asn1/DERConstructedSet.java index f675b42..27f060e 100644 --- a/src/org/bouncycastle/asn1/DERConstructedSet.java +++ b/src/org/bouncycastle/asn1/DERConstructedSet.java @@ -4,45 +4,42 @@ import java.io.*; import java.util.*; public class DERConstructedSet - extends DERObject + extends ASN1Set { - private Vector set = new Vector(); - public DERConstructedSet() { } - public void addObject( - DEREncodable obj) + /** + * @param obj - a single object that makes up the set. + */ + public DERConstructedSet( + DEREncodable obj) { - set.addElement(obj); + this.addObject(obj); } - public Enumeration getObjects() + /** + * @param v - a vector of objects making up the set. + */ + public DERConstructedSet( + DEREncodableVector v) { - return set.elements(); + for (int i = 0; i != v.size(); i++) + { + this.addObject(v.get(i)); + } } - /** - * return the object at the set postion indicated by index. - * - * @param the set number (starting at zero) of the object - * @return the object at the set postion indicated by index. - */ - public Object getObjectAt( - int index) + public void addObject( + DEREncodable obj) { - return set.elementAt(index); + super.addObject(obj); } - /** - * return the number of objects in this set. - * - * @return the number of objects in this set. - */ public int getSize() { - return set.size(); + return size(); } /* @@ -59,7 +56,7 @@ public class DERConstructedSet { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); - Enumeration e = getObjects(); + Enumeration e = this.getObjects(); while (e.hasMoreElements()) { diff --git a/src/org/bouncycastle/asn1/DEREncodableVector.java b/src/org/bouncycastle/asn1/DEREncodableVector.java new file mode 100644 index 0000000..6135d25 --- /dev/null +++ b/src/org/bouncycastle/asn1/DEREncodableVector.java @@ -0,0 +1,28 @@ +package org.bouncycastle.asn1; + +import java.util.Vector; + +/** + * a general class for building up a vector of DER encodable objects + */ +public class DEREncodableVector +{ + private Vector v = new Vector(); + + public void add( + DEREncodable obj) + { + v.addElement(obj); + } + + public DEREncodable get( + int i) + { + return (DEREncodable)v.elementAt(i); + } + + public int size() + { + return v.size(); + } +} diff --git a/src/org/bouncycastle/asn1/DEREnumerated.java b/src/org/bouncycastle/asn1/DEREnumerated.java new file mode 100644 index 0000000..1ab5dca --- /dev/null +++ b/src/org/bouncycastle/asn1/DEREnumerated.java @@ -0,0 +1,108 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.math.BigInteger; + +public class DEREnumerated + extends DERObject +{ + byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DEREnumerated getInstance( + Object obj) + { + if (obj == null || obj instanceof DEREnumerated) + { + return (DEREnumerated)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DEREnumerated(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Enumerated from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DEREnumerated getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + public DEREnumerated( + int value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + public DEREnumerated( + BigInteger value) + { + bytes = value.toByteArray(); + } + + public DEREnumerated( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger getValue() + { + return new BigInteger(bytes); + } + + void encode( + DEROutputStream out) + throws IOException + { + out.writeEncoded(ENUMERATED, bytes); + } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof DEREnumerated)) + { + return false; + } + + DEREnumerated other = (DEREnumerated)o; + + if (bytes.length != other.bytes.length) + { + return false; + } + + for (int i = 0; i != bytes.length; i++) + { + if (bytes[i] != other.bytes[i]) + { + return false; + } + } + + return true; + } +} diff --git a/src/org/bouncycastle/asn1/DERGeneralizedTime.java b/src/org/bouncycastle/asn1/DERGeneralizedTime.java new file mode 100644 index 0000000..5361a04 --- /dev/null +++ b/src/org/bouncycastle/asn1/DERGeneralizedTime.java @@ -0,0 +1,156 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.util.*; +import java.io.*; +import java.text.*; + +/** + * Generalized time object. + */ +public class DERGeneralizedTime + extends DERObject +{ + String time; + + /** + * return a generalized time from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERGeneralizedTime getInstance( + Object obj) + { + if (obj == null || obj instanceof DERGeneralizedTime) + { + return (DERGeneralizedTime)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERGeneralizedTime(((ASN1OctetString)obj).getOctets()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Generalized Time object from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERGeneralizedTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** + * The correct format for this is YYYYMMDDHHMMSSZ, or without the Z + * for local time, or Z+-HHMM on the end, for difference between local + * time and UTC time. + *

+ * + * @param time the time string. + */ + public DERGeneralizedTime( + String time) + { + this.time = time; + } + + /** + * base constructer from a java.util.date object + */ + public DERGeneralizedTime( + Date time) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = dateF.format(time); + } + + DERGeneralizedTime( + byte[] bytes) + { + // + // explicitly convert to characters + // + char[] dateC = new char[bytes.length]; + + for (int i = 0; i != dateC.length; i++) + { + dateC[i] = (char)(bytes[i] & 0xff); + } + + this.time = new String(dateC); + } + + /** + * return the time - always in the form of + * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm). + *

+ * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *

+     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+     * 
+ * To read in the time and get a date which is compatible with our local + * time zone. + */ + public String getTime() + { + // + // standardise the format. + // + if (time.length() == 15) + { + return time.substring(0, 14) + "GMT+00:00"; + } + else if (time.length() == 17) + { + return time.substring(0, 14) + "GMT" + time.substring(15, 17) + ":" + time.substring(17, 19); + } + + return time; + } + + private byte[] getOctets() + { + char[] cs = time.toCharArray(); + byte[] bs = new byte[cs.length]; + + for (int i = 0; i != cs.length; i++) + { + bs[i] = (byte)cs[i]; + } + + return bs; + } + + + void encode( + DEROutputStream out) + throws IOException + { + out.writeEncoded(GENERALIZED_TIME, this.getOctets()); + } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERGeneralizedTime)) + { + return false; + } + + return time.equals(((DERGeneralizedTime)o).time); + } +} diff --git a/src/org/bouncycastle/asn1/DERIA5String.java b/src/org/bouncycastle/asn1/DERIA5String.java index 5181bdd..da20589 100644 --- a/src/org/bouncycastle/asn1/DERIA5String.java +++ b/src/org/bouncycastle/asn1/DERIA5String.java @@ -12,19 +12,61 @@ public class DERIA5String String string; /** + * return a IA5 string from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERIA5String getInstance( + Object obj) + { + if (obj == null || obj instanceof DERIA5String) + { + return (DERIA5String)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERIA5String(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an IA5 String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERIA5String getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** * basic constructor - with bytes. */ public DERIA5String( byte[] string) { - try - { - this.string = new String(string, "US-ASCII"); - } - catch(UnsupportedEncodingException e) + char[] cs = new char[string.length]; + + for (int i = 0; i != cs.length; i++) { - throw new RuntimeException("PANIC: " + e); + cs[i] = (char)(string[i] & 0xff); } + + this.string = new String(cs); } /** @@ -43,14 +85,15 @@ public class DERIA5String public byte[] getOctets() { - try - { - return string.getBytes("US-ASCII"); - } - catch(UnsupportedEncodingException e) + char[] cs = string.toCharArray(); + byte[] bs = new byte[cs.length]; + + for (int i = 0; i != cs.length; i++) { - throw new RuntimeException("PANIC: " + e); + bs[i] = (byte)cs[i]; } + + return bs; } void encode( @@ -59,4 +102,22 @@ public class DERIA5String { out.writeEncoded(IA5_STRING, this.getOctets()); } + + public int hashCode() + { + return this.getString().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof DERIA5String)) + { + return false; + } + + DERIA5String s = (DERIA5String)o; + + return this.getString().equals(s.getString()); + } } diff --git a/src/org/bouncycastle/asn1/DERInputStream.java b/src/org/bouncycastle/asn1/DERInputStream.java index 61de735..9cf0ef1 100644 --- a/src/org/bouncycastle/asn1/DERInputStream.java +++ b/src/org/bouncycastle/asn1/DERInputStream.java @@ -1,7 +1,13 @@ package org.bouncycastle.asn1; import java.math.BigInteger; -import java.io.*; +import java.io.FilterInputStream; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.EOFException; + public class DERInputStream extends FilterInputStream implements DERTags @@ -69,7 +75,7 @@ public class DERInputStream * from. */ protected DERObject buildObject( - int tag, + int tag, byte[] bytes) throws IOException { @@ -99,7 +105,7 @@ public class DERInputStream bIn = new ByteArrayInputStream(bytes); dIn = new BERInputStream(bIn); - DERSet set = new DERSet(dIn.readObject()); + DEREncodableVector v = new DEREncodableVector(); try { @@ -107,41 +113,21 @@ public class DERInputStream { DERObject obj = dIn.readObject(); - set.addObject(obj); + v.add(obj); } } catch (EOFException ex) { - return set; + return new DERConstructedSet(v); } case BOOLEAN: return new DERBoolean(bytes); case INTEGER: return new DERInteger(bytes); + case ENUMERATED: + return new DEREnumerated(bytes); case OBJECT_IDENTIFIER: - int head = bytes[0] & 0xff; - StringBuffer objId = new StringBuffer(); - - objId.append(Integer.toString(head / 40)); - objId.append('.'); - objId.append(Integer.toString(head % 40)); - - int value = 0; - - for (int i = 1; i != bytes.length; i++) - { - int b = bytes[i] & 0xff; - - value = value * 128 + (b & 0x7f); - if ((b & 128) == 0) // end of number reached - { - objId.append('.'); - objId.append(Integer.toString(value)); - value = 0; - } - } - - return new DERObjectIdentifier(objId.toString()); + return new DERObjectIdentifier(bytes); case BIT_STRING: int padBits = bytes[0]; byte[] data = new byte[bytes.length - 1]; @@ -149,6 +135,8 @@ public class DERInputStream System.arraycopy(bytes, 1, data, 0, bytes.length - 1); return new DERBitString(data, padBits); + case UTF8_STRING: + return new DERUTF8String(bytes); case PRINTABLE_STRING: return new DERPrintableString(bytes); case IA5_STRING: @@ -157,21 +145,30 @@ public class DERInputStream return new DERT61String(bytes); case VISIBLE_STRING: return new DERVisibleString(bytes); + case UNIVERSAL_STRING: + return new DERUniversalString(bytes); case BMP_STRING: return new DERBMPString(bytes); case OCTET_STRING: return new DEROctetString(bytes); case UTC_TIME: - return new DERUTCTime(new String(bytes)); + return new DERUTCTime(bytes); + case GENERALIZED_TIME: + return new DERGeneralizedTime(bytes); default: // - // with tagged object tag number is bottom 4 bits + // with tagged object tag number is bottom 5 bits // - if ((tag & (TAGGED | CONSTRUCTED)) != 0) + if ((tag & TAGGED) != 0) { + if ((tag & 0x1f) == 0x1f) + { + throw new IOException("unsupported high tag encountered"); + } + if (bytes.length == 0) // empty tag! { - return new DERTaggedObject(tag & 0x0f); + return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence()); } // @@ -179,7 +176,7 @@ public class DERInputStream // if ((tag & CONSTRUCTED) == 0) { - return new DERTaggedObject(false, tag & 0x0f, new DEROctetString(bytes)); + return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes)); } bIn = new ByteArrayInputStream(bytes); @@ -193,7 +190,7 @@ public class DERInputStream // if (dIn.available() == 0) { - return new DERTaggedObject(tag & 0x0f, dObj); + return new DERTaggedObject(tag & 0x1f, dObj); } // @@ -217,7 +214,7 @@ public class DERInputStream // ignore -- } - return new DERTaggedObject(false, tag & 0x0f, seq); + return new DERTaggedObject(false, tag & 0x1f, seq); } return new DERUnknownTag(tag, bytes); diff --git a/src/org/bouncycastle/asn1/DERInteger.java b/src/org/bouncycastle/asn1/DERInteger.java index 0f86910..351de94 100644 --- a/src/org/bouncycastle/asn1/DERInteger.java +++ b/src/org/bouncycastle/asn1/DERInteger.java @@ -8,6 +8,48 @@ public class DERInteger { byte[] bytes; + /** + * return an integer from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERInteger getInstance( + Object obj) + { + if (obj == null || obj instanceof DERInteger) + { + return (DERInteger)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERInteger(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Integer from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERInteger getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + public DERInteger( int value) { @@ -46,4 +88,30 @@ public class DERInteger { out.writeEncoded(INTEGER, bytes); } + + public boolean equals( + Object o) + { + if (o == null || !(o instanceof DERInteger)) + { + return false; + } + + DERInteger other = (DERInteger)o; + + if (bytes.length != other.bytes.length) + { + return false; + } + + for (int i = 0; i != bytes.length; i++) + { + if (bytes[i] != other.bytes[i]) + { + return false; + } + } + + return true; + } } diff --git a/src/org/bouncycastle/asn1/DERObject.java b/src/org/bouncycastle/asn1/DERObject.java index fb75442..ac0dc03 100644 --- a/src/org/bouncycastle/asn1/DERObject.java +++ b/src/org/bouncycastle/asn1/DERObject.java @@ -5,11 +5,11 @@ import java.io.IOException; public abstract class DERObject implements DERTags, DEREncodable { - abstract void encode(DEROutputStream out) - throws IOException; - public DERObject getDERObject() { return this; } + + abstract void encode(DEROutputStream out) + throws IOException; } diff --git a/src/org/bouncycastle/asn1/DERObjectIdentifier.java b/src/org/bouncycastle/asn1/DERObjectIdentifier.java index 8f04454..fb16ac9 100644 --- a/src/org/bouncycastle/asn1/DERObjectIdentifier.java +++ b/src/org/bouncycastle/asn1/DERObjectIdentifier.java @@ -7,6 +7,91 @@ public class DERObjectIdentifier { String identifier; + /** + * return an OID from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERObjectIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof DERObjectIdentifier) + { + return (DERObjectIdentifier)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERObjectIdentifier(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Object Identifier from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERObjectIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + + DERObjectIdentifier( + byte[] bytes) + { + int head = bytes[0] & 0xff; + StringBuffer objId = new StringBuffer(); + int value = 0; + boolean first = true; + + for (int i = 0; i != bytes.length; i++) + { + int b = bytes[i] & 0xff; + + value = value * 128 + (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + switch (value / 40) + { + case 0: + objId.append('0'); + break; + case 1: + objId.append('1'); + value -= 40; + break; + default: + objId.append('2'); + value -= 80; + } + first = false; + } + + objId.append('.'); + objId.append(Integer.toString(value)); + value = 0; + } + } + + this.identifier = objId.toString(); + } + public DERObjectIdentifier( String identifier) { @@ -18,6 +103,30 @@ public class DERObjectIdentifier return identifier; } + private void writeField( + OutputStream out, + int fieldValue) + throws IOException + { + if (fieldValue >= (1 << 7)) + { + if (fieldValue >= (1 << 14)) + { + if (fieldValue >= (1 << 21)) + { + if (fieldValue >= (1 << 28)) + { + out.write((fieldValue >> 28) | 0x80); + } + out.write((fieldValue >> 21) | 0x80); + } + out.write((fieldValue >> 14) | 0x80); + } + out.write((fieldValue >> 7) | 0x80); + } + out.write(fieldValue & 0x7f); + } + void encode( DEROutputStream out) throws IOException @@ -26,31 +135,13 @@ public class DERObjectIdentifier ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); - // space for 5 7 bit numbers in an int - byte[] iBuf = new byte[5]; - - // FIXED by Adam Megacz -- GCJ doesn't handle evaluation order properly - String t1 = tok.nextToken(); - String t2 = tok.nextToken(); - dOut.write(Integer.parseInt(t1) * 40 + Integer.parseInt(t2)); + writeField(bOut, + Integer.parseInt(tok.nextToken()) * 40 + + Integer.parseInt(tok.nextToken())); while (tok.hasMoreTokens()) { - // - // translate into base 128 - // - int value = Integer.parseInt(tok.nextToken()); - int count = iBuf.length - 1; - - iBuf[count--] = (byte)(value % 128); - value /= 128; - - while (value != 0) - { - iBuf[count--] = (byte)((value % 128) | 0x80); - value /= 128; - } - dOut.write(iBuf, count + 1, iBuf.length - (count + 1)); + writeField(bOut, Integer.parseInt(tok.nextToken())); } dOut.close(); diff --git a/src/org/bouncycastle/asn1/DEROctetString.java b/src/org/bouncycastle/asn1/DEROctetString.java index fd9f516..9ce9350 100644 --- a/src/org/bouncycastle/asn1/DEROctetString.java +++ b/src/org/bouncycastle/asn1/DEROctetString.java @@ -3,47 +3,21 @@ package org.bouncycastle.asn1; import java.io.*; public class DEROctetString - extends DERObject + extends ASN1OctetString { - byte[] string; - /** * @param string the octets making up the octet string. */ public DEROctetString( byte[] string) { - this.string = string; - } - - public DEROctetString( - DERObject obj) - { - try - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DEROutputStream dOut = new DEROutputStream(bOut); - - dOut.writeObject(obj); - dOut.close(); - - this.string = bOut.toByteArray(); - } - catch (IOException e) - { - throw new IllegalArgumentException("Error processing object : " + e.toString()); - } + super(string); } public DEROctetString( DEREncodable obj) { - this(obj.getDERObject()); - } - - public byte[] getOctets() - { - return string; + super(obj); } void encode( @@ -52,46 +26,4 @@ public class DEROctetString { out.writeEncoded(OCTET_STRING, string); } - - public int hashCode() - { - byte[] b = this.getOctets(); - int value = 0; - - for (int i = 0; i != b.length; i++) - { - value ^= (b[i] & 0xff) << (i % 4); - } - - return value; - } - - public boolean equals( - Object o) - { - if (o == null || !(o instanceof DEROctetString)) - { - return false; - } - - DEROctetString other = (DEROctetString)o; - - if (other.getOctets().length != this.getOctets().length) - { - return false; - } - - byte[] b1 = other.getOctets(); - byte[] b2 = this.getOctets(); - - for (int i = 0; i != b1.length; i++) - { - if (b1[i] != b2[i]) - { - return false; - } - } - - return true; - } } diff --git a/src/org/bouncycastle/asn1/DEROutputStream.java b/src/org/bouncycastle/asn1/DEROutputStream.java index 03e77a2..f8b4c54 100644 --- a/src/org/bouncycastle/asn1/DEROutputStream.java +++ b/src/org/bouncycastle/asn1/DEROutputStream.java @@ -1,6 +1,10 @@ package org.bouncycastle.asn1; -import java.io.*; +import java.io.FilterOutputStream; + +import java.io.OutputStream; +import java.io.IOException; +import java.io.EOFException; public class DEROutputStream extends FilterOutputStream implements DERTags diff --git a/src/org/bouncycastle/asn1/DERPrintableString.java b/src/org/bouncycastle/asn1/DERPrintableString.java index 7834edf..fdb5b1d 100644 --- a/src/org/bouncycastle/asn1/DERPrintableString.java +++ b/src/org/bouncycastle/asn1/DERPrintableString.java @@ -12,19 +12,61 @@ public class DERPrintableString String string; /** + * return a printable string from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERPrintableString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERPrintableString) + { + return (DERPrintableString)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERPrintableString(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Printable String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERPrintableString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** * basic constructor - byte encoded string. */ public DERPrintableString( byte[] string) { - try - { - this.string = new String(string, "US-ASCII"); - } - catch(UnsupportedEncodingException e) + char[] cs = new char[string.length]; + + for (int i = 0; i != cs.length; i++) { - throw new RuntimeException("PANIC: " + e); + cs[i] = (char)(string[i] & 0xff); } + + this.string = new String(cs); } /** @@ -43,14 +85,15 @@ public class DERPrintableString public byte[] getOctets() { - try - { - return string.getBytes("US-ASCII"); - } - catch(UnsupportedEncodingException e) + char[] cs = string.toCharArray(); + byte[] bs = new byte[cs.length]; + + for (int i = 0; i != cs.length; i++) { - throw new RuntimeException("PANIC: " + e); + bs[i] = (byte)cs[i]; } + + return bs; } void encode( @@ -59,4 +102,22 @@ public class DERPrintableString { out.writeEncoded(PRINTABLE_STRING, this.getOctets()); } + + public int hashCode() + { + return this.getString().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof DERPrintableString)) + { + return false; + } + + DERPrintableString s = (DERPrintableString)o; + + return this.getString().equals(s.getString()); + } } diff --git a/src/org/bouncycastle/asn1/DERSequence.java b/src/org/bouncycastle/asn1/DERSequence.java new file mode 100644 index 0000000..b440858 --- /dev/null +++ b/src/org/bouncycastle/asn1/DERSequence.java @@ -0,0 +1,66 @@ +package org.bouncycastle.asn1; + +import java.io.*; +import java.util.*; + +public class DERSequence + extends ASN1Sequence +{ + /** + * create an empty sequence + */ + public DERSequence() + { + } + + /** + * create a sequence containing one object + */ + public DERSequence( + DEREncodable obj) + { + this.addObject(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + public DERSequence( + DEREncodableVector v) + { + for (int i = 0; i != v.size(); i++) + { + this.addObject(v.get(i)); + } + } + + /* + * A note on the implementation: + *

+ * As DER requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputing SEQUENCE, + * we also have to specify CONSTRUCTED, and the objects length. + */ + void encode( + DEROutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + Enumeration e = this.getObjects(); + + while (e.hasMoreElements()) + { + Object obj = e.nextElement(); + + dOut.writeObject(obj); + } + + dOut.close(); + + byte[] bytes = bOut.toByteArray(); + + out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes); + } +} diff --git a/src/org/bouncycastle/asn1/DERSet.java b/src/org/bouncycastle/asn1/DERSet.java index 2d2caf4..c08fa5a 100644 --- a/src/org/bouncycastle/asn1/DERSet.java +++ b/src/org/bouncycastle/asn1/DERSet.java @@ -1,24 +1,69 @@ package org.bouncycastle.asn1; import java.io.*; +import java.util.*; /** - * DER Set with a single object. + * A DER encoded set object */ public class DERSet - extends DERConstructedSet + extends ASN1Set { /** - * @param sequence the sequence making up the set + * create an empty set + */ + public DERSet() + { + } + + /** + * @param obj - a single object that makes up the set. */ public DERSet( - DEREncodable sequence) + DEREncodable obj) { - this.addObject(sequence); + this.addObject(obj); } - public DERObject getSequence() + /** + * @param v - a vector of objects making up the set. + */ + public DERSet( + DEREncodableVector v) { - return (DERObject)this.getObjectAt(0); + for (int i = 0; i != v.size(); i++) + { + this.addObject(v.get(i)); + } + } + + /* + * A note on the implementation: + *

+ * As DER requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputing SET, + * we also have to specify CONSTRUCTED, and the objects length. + */ + void encode( + DEROutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + Enumeration e = this.getObjects(); + + while (e.hasMoreElements()) + { + Object obj = e.nextElement(); + + dOut.writeObject(obj); + } + + dOut.close(); + + byte[] bytes = bOut.toByteArray(); + + out.writeEncoded(SET | CONSTRUCTED, bytes); } } diff --git a/src/org/bouncycastle/asn1/DERT61String.java b/src/org/bouncycastle/asn1/DERT61String.java index 4412efc..189a939 100644 --- a/src/org/bouncycastle/asn1/DERT61String.java +++ b/src/org/bouncycastle/asn1/DERT61String.java @@ -12,6 +12,48 @@ public class DERT61String String string; /** + * return a T61 string from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERT61String getInstance( + Object obj) + { + if (obj == null || obj instanceof DERT61String) + { + return (DERT61String)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERT61String(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an T61 String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERT61String getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** * basic constructor - with bytes. */ public DERT61String( @@ -40,4 +82,15 @@ public class DERT61String { out.writeEncoded(T61_STRING, string.getBytes()); } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERT61String)) + { + return false; + } + + return this.getString().equals(((DERT61String)o).getString()); + } } diff --git a/src/org/bouncycastle/asn1/DERTaggedObject.java b/src/org/bouncycastle/asn1/DERTaggedObject.java index 4ec0310..ba69412 100644 --- a/src/org/bouncycastle/asn1/DERTaggedObject.java +++ b/src/org/bouncycastle/asn1/DERTaggedObject.java @@ -8,26 +8,8 @@ import java.io.*; * rules (as with sequences). */ public class DERTaggedObject - extends DERObject + extends ASN1TaggedObject { - int tagNo; - boolean empty = false; - boolean explicit = true; - DEREncodable obj = null; - - /** - * This creates an empty tagged object of tagNo (ie. zero length). - * - * @param tagNo the tag number for this object. - */ - public DERTaggedObject( - int tagNo) - { - this.explicit = true; - this.tagNo = tagNo; - this.empty = true; - } - /** * @param tagNo the tag number for this object. * @param obj the tagged object. @@ -36,13 +18,11 @@ public class DERTaggedObject int tagNo, DEREncodable obj) { - this.explicit = true; - this.tagNo = tagNo; - this.obj = obj; + super(tagNo, obj); } /** - * @param explicit true if the object is explicitly tagged. + * @param explicit true if an explicitly tagged object. * @param tagNo the tag number for this object. * @param obj the tagged object. */ @@ -51,29 +31,17 @@ public class DERTaggedObject int tagNo, DEREncodable obj) { - this.explicit = explicit; - this.tagNo = tagNo; - this.obj = obj; - } - - public int getTagNo() - { - return tagNo; - } - - public boolean isExplicit() - { - return explicit; - } - - public boolean isEmpty() - { - return empty; + super(explicit, tagNo, obj); } - public DERObject getObject() + /** + * create an implicitly tagged object that contains a zero + * length sequence. + */ + public DERTaggedObject( + int tagNo) { - return obj.getDERObject(); + super(false, tagNo, new DERSequence()); } void encode( @@ -92,7 +60,7 @@ public class DERTaggedObject if (explicit) { - out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, bOut.toByteArray()); + out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, bytes); } else { diff --git a/src/org/bouncycastle/asn1/DERTags.java b/src/org/bouncycastle/asn1/DERTags.java index 085b787..0b4896e 100644 --- a/src/org/bouncycastle/asn1/DERTags.java +++ b/src/org/bouncycastle/asn1/DERTags.java @@ -9,6 +9,7 @@ public interface DERTags public static final int NULL = 0x05; public static final int OBJECT_IDENTIFIER = 0x06; public static final int EXTERNAL = 0x08; + public static final int ENUMERATED = 0x0a; public static final int SEQUENCE = 0x10; public static final int SEQUENCE_OF = 0x10; // for completeness public static final int SET = 0x11; @@ -26,5 +27,7 @@ public interface DERTags public static final int GRAPHIC_STRING = 0x19; public static final int VISIBLE_STRING = 0x1a; public static final int GENERAL_STRING = 0x1b; + public static final int UNIVERSAL_STRING = 0x1c; public static final int BMP_STRING = 0x1e; + public static final int UTF8_STRING = 0x0c; } diff --git a/src/org/bouncycastle/asn1/DERUTCTime.java b/src/org/bouncycastle/asn1/DERUTCTime.java index 061bf54..ae59c22 100644 --- a/src/org/bouncycastle/asn1/DERUTCTime.java +++ b/src/org/bouncycastle/asn1/DERUTCTime.java @@ -3,6 +3,7 @@ package org.bouncycastle.asn1; import java.io.*; import java.util.*; import java.io.*; +import java.text.*; /** * UTC time object. @@ -13,21 +14,49 @@ public class DERUTCTime String time; /** + * return an UTC Time from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERUTCTime getInstance( + Object obj) + { + if (obj == null || obj instanceof DERUTCTime) + { + return (DERUTCTime)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERUTCTime(((ASN1OctetString)obj).getOctets()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an UTC Time from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERUTCTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were * never encoded. When you're creating one of these objects from scratch, that's * what you want to use, otherwise we'll try to deal with whatever gets read from * the input stream... (this is why the input format is different from the getTime() * method output). *

- * You can generate a Java date string in the right format by using: - *

-     *      dateF = new SimpleDateFormat("yyMMddHHmmss");
-     *      tz = new SimpleTimeZone(0, "Z");
-     *     
-     *      dateF.setTimeZone(tz);
-     *
-     *      utcTime = new DERUTCTime(dateF.format(new Date()) + "Z");
-     * 
* * @param time the time string. */ @@ -38,6 +67,35 @@ public class DERUTCTime } /** + * base constructer from a java.util.date object + */ + public DERUTCTime( + Date time) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = dateF.format(time); + } + + DERUTCTime( + byte[] bytes) + { + // + // explicitly convert to characters + // + char[] dateC = new char[bytes.length]; + + for (int i = 0; i != dateC.length; i++) + { + dateC[i] = (char)(bytes[i] & 0xff); + } + + this.time = new String(dateC); + } + + /** * return the time - always in the form of * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). *

@@ -48,6 +106,10 @@ public class DERUTCTime * * To read in the time and get a date which is compatible with our local * time zone. + *

+ * Note: In some cases, due to the local date processing, this + * may lead to unexpected results. If you want to stick the normal + * convention of 1950 to 2049 use the getAdjustedTime() method. */ public String getTime() { @@ -70,10 +132,52 @@ public class DERUTCTime return time; } + /** + * return the time as an adjusted date with a 4 digit year. This goes + * in the range of 1950 - 2049. + */ + public String getAdjustedTime() + { + String d = this.getTime(); + + if (d.charAt(0) < '5') + { + return "20" + d; + } + else + { + return "19" + d; + } + } + + private byte[] getOctets() + { + char[] cs = time.toCharArray(); + byte[] bs = new byte[cs.length]; + + for (int i = 0; i != cs.length; i++) + { + bs[i] = (byte)cs[i]; + } + + return bs; + } + void encode( DEROutputStream out) throws IOException { - out.writeEncoded(UTC_TIME, time.getBytes()); + out.writeEncoded(UTC_TIME, this.getOctets()); + } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERUTCTime)) + { + return false; + } + + return time.equals(((DERUTCTime)o).time); } } diff --git a/src/org/bouncycastle/asn1/DERUTF8String.java b/src/org/bouncycastle/asn1/DERUTF8String.java new file mode 100644 index 0000000..6c3563f --- /dev/null +++ b/src/org/bouncycastle/asn1/DERUTF8String.java @@ -0,0 +1,176 @@ +package org.bouncycastle.asn1; + +import java.io.*; + +/** + * DER UTF8String object. + */ +public class DERUTF8String + extends DERObject + implements DERString +{ + String string; + + /** + * return an UTF8 string from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERUTF8String getInstance( + Object obj) + { + if (obj == null || obj instanceof DERUTF8String) + { + return (DERUTF8String)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERUTF8String(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an UTF8 String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERUTF8String getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** + * basic constructor - byte encoded string. + */ + DERUTF8String( + byte[] string) + { + int i = 0; + int length = 0; + + while (i < string.length) + { + length++; + if ((string[i] & 0xe0) == 0xe0) + { + i += 3; + } + else if ((string[i] & 0xc0) == 0xc0) + { + i += 2; + } + else + { + i += 1; + } + } + + char[] cs = new char[length]; + + i = 0; + length = 0; + + while (i < string.length) + { + char ch; + + if ((string[i] & 0xe0) == 0xe0) + { + ch = (char)(((string[i] & 0x1f) << 12) + | ((string[i + 1] & 0x3f) << 6) | (string[i + 2] & 0x3f)); + i += 3; + } + else if ((string[i] & 0xc0) == 0xc0) + { + ch = (char)(((string[i] & 0x3f) << 6) | (string[i + 1] & 0x3f)); + i += 2; + } + else + { + ch = (char)(string[i] & 0xff); + i += 1; + } + + cs[length++] = ch; + } + + this.string = new String(cs); + } + + /** + * basic constructor + */ + public DERUTF8String( + String string) + { + this.string = string; + } + + public String getString() + { + return string; + } + + public int hashCode() + { + return this.getString().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof DERUTF8String)) + { + return false; + } + + DERUTF8String s = (DERUTF8String)o; + + return this.getString().equals(s.getString()); + } + + void encode( + DEROutputStream out) + throws IOException + { + char[] c = string.toCharArray(); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + for (int i = 0; i != c.length; i++) + { + char ch = c[i]; + + if (ch < 0x0080) + { + bOut.write(ch); + } + else if (ch < 0x0800) + { + bOut.write(0xc0 | (ch >> 6)); + bOut.write(0x80 | (ch & 0x3f)); + } + else + { + bOut.write(0xe0 | (ch >> 12)); + bOut.write(0x80 | ((ch >> 6) & 0x3F)); + bOut.write(0x80 | (ch & 0x3F)); + } + } + + out.writeEncoded(UTF8_STRING, bOut.toByteArray()); + } +} diff --git a/src/org/bouncycastle/asn1/DERUniversalString.java b/src/org/bouncycastle/asn1/DERUniversalString.java new file mode 100644 index 0000000..ec12385 --- /dev/null +++ b/src/org/bouncycastle/asn1/DERUniversalString.java @@ -0,0 +1,100 @@ +package org.bouncycastle.asn1; + +import java.io.*; + +/** + * DER UniversalString object. + */ +public class DERUniversalString + extends DERObject + implements DERString +{ + byte[] string; + char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + /** + * return a Universal String from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERUniversalString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERUniversalString) + { + return (DERUniversalString)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERUniversalString(((ASN1OctetString)obj).getOctets()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Universal String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERUniversalString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** + * basic constructor - byte encoded string. + */ + public DERUniversalString( + byte[] string) + { + this.string = string; + } + + /** + * UniversalStrings have characters which are 4 bytes long - for the + * moment we just return them in Hex... + */ + public String getString() + { + StringBuffer buf = new StringBuffer(); + + for (int i = 0; i != string.length; i++) + { + buf.append(table[(string[i] >>> 4) % 0xf]); + buf.append(table[string[i] & 0xf]); + } + + return buf.toString(); + } + + public byte[] getOctets() + { + return string; + } + + void encode( + DEROutputStream out) + throws IOException + { + out.writeEncoded(UNIVERSAL_STRING, this.getOctets()); + } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERUniversalString)) + { + return false; + } + + return this.getString().equals(((DERUniversalString)o).getString()); + } +} diff --git a/src/org/bouncycastle/asn1/DERUnknownTag.java b/src/org/bouncycastle/asn1/DERUnknownTag.java index c5f46f9..010f911 100644 --- a/src/org/bouncycastle/asn1/DERUnknownTag.java +++ b/src/org/bouncycastle/asn1/DERUnknownTag.java @@ -39,4 +39,35 @@ public class DERUnknownTag { out.writeEncoded(tag, data); } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERUnknownTag)) + { + return false; + } + + DERUnknownTag other = (DERUnknownTag)o; + + if(tag != other.tag) + { + return false; + } + + if(data.length != other.data.length) + { + return false; + } + + for(int i = 0; i < data.length; i++) + { + if(data[i] != other.data[i]) + { + return false; + } + } + + return true; + } } diff --git a/src/org/bouncycastle/asn1/DERVisibleString.java b/src/org/bouncycastle/asn1/DERVisibleString.java index f2071d3..f603b93 100644 --- a/src/org/bouncycastle/asn1/DERVisibleString.java +++ b/src/org/bouncycastle/asn1/DERVisibleString.java @@ -12,19 +12,61 @@ public class DERVisibleString String string; /** + * return a Visible String from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERVisibleString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERVisibleString) + { + return (DERVisibleString)obj; + } + + if (obj instanceof ASN1OctetString) + { + return new DERVisibleString(((ASN1OctetString)obj).getOctets()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Visible String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static DERVisibleString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + /** * basic constructor - byte encoded string. */ public DERVisibleString( byte[] string) { - try - { - this.string = new String(string, "US-ASCII"); - } - catch(UnsupportedEncodingException e) + char[] cs = new char[string.length]; + + for (int i = 0; i != cs.length; i++) { - throw new RuntimeException("PANIC: " + e); + cs[i] = (char)(string[i] & 0xff); } + + this.string = new String(cs); } /** @@ -43,14 +85,15 @@ public class DERVisibleString public byte[] getOctets() { - try - { - return string.getBytes("US-ASCII"); - } - catch(UnsupportedEncodingException e) + char[] cs = string.toCharArray(); + byte[] bs = new byte[cs.length]; + + for (int i = 0; i != cs.length; i++) { - throw new RuntimeException("PANIC: " + e); + bs[i] = (byte)cs[i]; } + + return bs; } void encode( @@ -59,4 +102,15 @@ public class DERVisibleString { out.writeEncoded(VISIBLE_STRING, this.getOctets()); } + + public boolean equals( + Object o) + { + if ((o == null) || !(o instanceof DERVisibleString)) + { + return false; + } + + return this.getString().equals(((DERVisibleString)o).getString()); + } } diff --git a/src/org/bouncycastle/asn1/cms/Attribute.java b/src/org/bouncycastle/asn1/cms/Attribute.java new file mode 100644 index 0000000..0763ea2 --- /dev/null +++ b/src/org/bouncycastle/asn1/cms/Attribute.java @@ -0,0 +1,75 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.*; + +public class Attribute + implements DEREncodable +{ + private DERObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o == null || o instanceof Attribute) + { + return (Attribute)o; + } + + if (o instanceof ASN1Sequence) + { + return new Attribute((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + + public Attribute( + ASN1Sequence seq) + { + attrType = (DERObjectIdentifier)seq.getObjectAt(0); + attrValues = (ASN1Set)seq.getObjectAt(1); + } + + public Attribute( + DERObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public DERObjectIdentifier getAttrType() + { + return attrType; + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + /** + *

+     * Attribute ::= SEQUENCE {
+     * 	attrType OBJECT IDENTIFIER,
+     * 	attrValues SET OF AttributeValue
+     * }
+     * 
+ */ + public DERObject getDERObject() + { + DEREncodableVector v = new DEREncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/src/org/bouncycastle/asn1/cms/SignedAttributes.java b/src/org/bouncycastle/asn1/cms/SignedAttributes.java new file mode 100644 index 0000000..47b460e --- /dev/null +++ b/src/org/bouncycastle/asn1/cms/SignedAttributes.java @@ -0,0 +1,86 @@ +// Decompiled by Jad v1.5.7f. Copyright 2000 Pavel Kouznetsov. +// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html +// Decompiler options: packimports(3) +// Source File Name: SignedAttributes.java + +package org.bouncycastle.asn1.cms; + +import java.util.Vector; +import org.bouncycastle.asn1.*; + +// Referenced classes of package org.bouncycastle.asn1.cms: +// Attribute + +public class SignedAttributes + implements DEREncodable +{ + + public SignedAttributes(Vector vector) + { + setAttributes(vector); + } + + public SignedAttributes(DERConstructedSet derconstructedset) + { + attributes = derconstructedset; + } + + public SignedAttributes(SignedAttributes signedattributes) + { + attributes = signedattributes.attributes; + } + + public static SignedAttributes getInstance(Object obj) + { + if(obj == null) + return null; + if(obj instanceof SignedAttributes) + return (SignedAttributes)obj; + if(obj instanceof DERConstructedSet) + return new SignedAttributes((DERConstructedSet)obj); + if(obj instanceof DERTaggedObject) + return getInstance(((DERTaggedObject)obj).getObject()); + else + throw new IllegalArgumentException("Invalid SignedAttributes"); + } + + public static SignedAttributes newInstance(Object obj) + { + if(obj == null) + return null; + if(obj instanceof SignedAttributes) + return new SignedAttributes((SignedAttributes)obj); + if(obj instanceof DERConstructedSet) + return new SignedAttributes((DERConstructedSet)obj); + if(obj instanceof DERTaggedObject) + return getInstance(((DERTaggedObject)obj).getObject()); + else + throw new IllegalArgumentException("Invalid SignedAttributes"); + } + + public Vector getAttributes() + { + int i = attributes.getSize(); + Vector vector = new Vector(); + for(int j = 0; j < i; j++) + vector.addElement(Attribute.getInstance(attributes.getObjectAt(j))); + + return vector; + } + + private void setAttributes(Vector vector) + { + int i = vector.size(); + attributes = new DERConstructedSet(); + for(int j = 0; j < i; j++) + attributes.addObject(Attribute.getInstance(vector.elementAt(j))); + + } + + public DERObject getDERObject() + { + return attributes; + } + + private DERConstructedSet attributes; +} diff --git a/src/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/src/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java index f471332..3977e9f 100644 --- a/src/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java +++ b/src/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java @@ -15,6 +15,9 @@ public interface PKCSObjectIdentifiers static final DERObjectIdentifier md5WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".4"); static final DERObjectIdentifier sha1WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".5"); static final DERObjectIdentifier srsaOAEPEncryptionSET = new DERObjectIdentifier(pkcs_1 + ".6"); + static final DERObjectIdentifier sha256WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".11"); + static final DERObjectIdentifier sha384WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".12"); + static final DERObjectIdentifier sha512WithRSAEncryption = new DERObjectIdentifier(pkcs_1 + ".13"); // // pkcs-3 OBJECT IDENTIFIER ::= { @@ -77,11 +80,48 @@ public interface PKCSObjectIdentifiers static final String pkcs_9 = "1.2.840.113549.1.9"; static final DERObjectIdentifier pkcs_9_at_emailAddress = new DERObjectIdentifier(pkcs_9 + ".1"); + static final DERObjectIdentifier pkcs_9_at_unstructuredName = new DERObjectIdentifier(pkcs_9 + ".2"); + static final DERObjectIdentifier pkcs_9_at_contentType = new DERObjectIdentifier(pkcs_9 + ".3"); + static final DERObjectIdentifier pkcs_9_at_messageDigest = new DERObjectIdentifier(pkcs_9 + ".4"); + static final DERObjectIdentifier pkcs_9_at_signingTime = new DERObjectIdentifier(pkcs_9 + ".5"); + static final DERObjectIdentifier pkcs_9_at_counterSignature = new DERObjectIdentifier(pkcs_9 + ".6"); + static final DERObjectIdentifier pkcs_9_at_challengePassword = new DERObjectIdentifier(pkcs_9 + ".7"); + static final DERObjectIdentifier pkcs_9_at_unstructuredAddress = new DERObjectIdentifier(pkcs_9 + ".8"); + static final DERObjectIdentifier pkcs_9_at_extendedCertificateAttributes = new DERObjectIdentifier(pkcs_9 + ".9"); + + static final DERObjectIdentifier pkcs_9_at_signingDescription = new DERObjectIdentifier(pkcs_9 + ".13"); + static final DERObjectIdentifier pkcs_9_at_extensionRequest = new DERObjectIdentifier(pkcs_9 + ".14"); + static final DERObjectIdentifier pkcs_9_at_smimeCapabilities = new DERObjectIdentifier(pkcs_9 + ".15"); + static final DERObjectIdentifier pkcs_9_at_friendlyName = new DERObjectIdentifier(pkcs_9 + ".20"); static final DERObjectIdentifier pkcs_9_at_localKeyId = new DERObjectIdentifier(pkcs_9 + ".21"); + static final DERObjectIdentifier x509certType = new DERObjectIdentifier(pkcs_9 + ".22.1"); // + // SMIME capability sub oids. + // + static final DERObjectIdentifier preferSignedData = new DERObjectIdentifier(pkcs_9 + ".15.1"); + static final DERObjectIdentifier canNotDecryptAny = new DERObjectIdentifier(pkcs_9 + ".15.2"); + static final DERObjectIdentifier sMIMECapabilitiesVersions = new DERObjectIdentifier(pkcs_9 + ".15.3"); + + // + // other SMIME attributes + // + + // + // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} + // + static String id_aa = "1.2.840.113549.1.9.16.2"; + + /* + * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} + * + */ + static DERObjectIdentifier id_aa_encrypKeyPref = new DERObjectIdentifier(id_aa + ".11"); + + // // pkcs-12 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } // diff --git a/src/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/src/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java index cad4c82..945f948 100644 --- a/src/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java +++ b/src/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java @@ -9,8 +9,41 @@ public class AlgorithmIdentifier implements DEREncodable { private DERObjectIdentifier objectId; - private DERObject parameters; + private DEREncodable parameters; private boolean parametersDefined = false; + + public static AlgorithmIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AlgorithmIdentifier getInstance( + Object obj) + { + if (obj instanceof AlgorithmIdentifier) + { + return (AlgorithmIdentifier)obj; + } + + if (obj instanceof DERObjectIdentifier) + { + return new AlgorithmIdentifier((DERObjectIdentifier)obj); + } + + if (obj instanceof String) + { + return new AlgorithmIdentifier((String)obj); + } + + if (obj instanceof ASN1Sequence) + { + return new AlgorithmIdentifier((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } public AlgorithmIdentifier( DERObjectIdentifier objectId) @@ -19,24 +52,29 @@ public class AlgorithmIdentifier } public AlgorithmIdentifier( + String objectId) + { + this.objectId = new DERObjectIdentifier(objectId); + } + + public AlgorithmIdentifier( DERObjectIdentifier objectId, - DERObject parameters) + DEREncodable parameters) { parametersDefined = true; - this.objectId = objectId; this.parameters = parameters; } public AlgorithmIdentifier( - DERConstructedSequence obj) + ASN1Sequence seq) { - objectId = (DERObjectIdentifier)obj.getObjectAt(0); + objectId = (DERObjectIdentifier)seq.getObjectAt(0); - if (obj.getSize() == 2) + if (seq.size() == 2) { parametersDefined = true; - parameters = (DERObject)obj.getObjectAt(1); + parameters = seq.getObjectAt(1); } else { @@ -49,7 +87,7 @@ public class AlgorithmIdentifier return objectId; } - public DERObject getParameters() + public DEREncodable getParameters() { return parameters; } diff --git a/src/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/src/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java index 9285c96..d15309d 100644 --- a/src/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java +++ b/src/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java @@ -22,16 +22,38 @@ import org.bouncycastle.asn1.*; * */ public class AuthorityKeyIdentifier - implements DEREncodable + implements DEREncodable, DERTags { - DEROctetString keyidentifier=null; + ASN1OctetString keyidentifier=null; GeneralNames certissuer=null; DERInteger certserno=null; + public static AuthorityKeyIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AuthorityKeyIdentifier getInstance( + Object obj) + { + if (obj instanceof AuthorityKeyIdentifier) + { + return (AuthorityKeyIdentifier)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new AuthorityKeyIdentifier((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + public AuthorityKeyIdentifier( - DERConstructedSequence seq) + ASN1Sequence seq) { - Enumeration e = seq.getObjects(); + Enumeration e = seq.getObjects(); while (e.hasMoreElements()) { @@ -40,33 +62,13 @@ public class AuthorityKeyIdentifier switch (o.getTagNo()) { case 0: - this.keyidentifier= (DEROctetString)o.getObject(); + this.keyidentifier = ASN1OctetString.getInstance(o, false); break; - case 1: - if (o.getObject() instanceof DERConstructedSequence) - { - this.certissuer = new GeneralNames((DERConstructedSequence)o.getObject()); - } - else - { - // as it's implicitly tagged we can loose the"sequence" - // if there is only one object. - // - DERConstructedSequence s = new DERConstructedSequence(); - - s.addObject(o.getObject()); - - this.certissuer = new GeneralNames(s); - } + this.certissuer = GeneralNames.getInstance(o, false); break; case 2: - // - // implicit tagging again... - // - DEROctetString oct = (DEROctetString)o.getObject(); - - this.certserno = new DERInteger(new BigInteger(oct.getOctets())); + this.certserno = DERInteger.getInstance(o, false); break; default: throw new IllegalArgumentException("illegal tag"); @@ -93,11 +95,10 @@ public class AuthorityKeyIdentifier Digest digest = new SHA1Digest(); byte[] resBuf = new byte[digest.getDigestSize()]; - DERBitString derpk = new DERBitString(spki.getPublicKey()); - byte[] bytes = derpk.getBytes(); + byte[] bytes = spki.getPublicKeyData().getBytes(); digest.update(bytes, 0, bytes.length); digest.doFinal(resBuf, 0); - this.keyidentifier=new DEROctetString(resBuf); + this.keyidentifier = new DEROctetString(resBuf); } /** @@ -112,8 +113,7 @@ public class AuthorityKeyIdentifier Digest digest = new SHA1Digest(); byte[] resBuf = new byte[digest.getDigestSize()]; - DERBitString derpk = new DERBitString(spki.getPublicKey()); - byte[] bytes = derpk.getBytes(); + byte[] bytes = spki.getPublicKeyData().getBytes(); digest.update(bytes, 0, bytes.length); digest.doFinal(resBuf, 0); diff --git a/src/org/bouncycastle/asn1/x509/BasicConstraints.java b/src/org/bouncycastle/asn1/x509/BasicConstraints.java index ec84915..b798ea8 100644 --- a/src/org/bouncycastle/asn1/x509/BasicConstraints.java +++ b/src/org/bouncycastle/asn1/x509/BasicConstraints.java @@ -10,10 +10,32 @@ public class BasicConstraints DERBoolean cA = new DERBoolean(false); DERInteger pathLenConstraint = null; + public static BasicConstraints getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static BasicConstraints getInstance( + Object obj) + { + if (obj instanceof BasicConstraints) + { + return (BasicConstraints)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new BasicConstraints((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + public BasicConstraints( - DERConstructedSequence seq) + ASN1Sequence seq) { - if (seq.getSize() != 0) + if (seq.size() != 0) { this.cA = (DERBoolean)seq.getObjectAt(0); this.pathLenConstraint = (DERInteger)seq.getObjectAt(1); diff --git a/src/org/bouncycastle/asn1/x509/CRLDistPoint.java b/src/org/bouncycastle/asn1/x509/CRLDistPoint.java index 780ab16..11b347a 100644 --- a/src/org/bouncycastle/asn1/x509/CRLDistPoint.java +++ b/src/org/bouncycastle/asn1/x509/CRLDistPoint.java @@ -5,17 +5,47 @@ import org.bouncycastle.asn1.*; public class CRLDistPoint implements DEREncodable { - DERConstructedSequence seq = null; + ASN1Sequence seq = null; + public static CRLDistPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CRLDistPoint getInstance( + Object obj) + { + if (obj instanceof CRLDistPoint) + { + return (CRLDistPoint)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new CRLDistPoint((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + + public CRLDistPoint( + ASN1Sequence seq) + { + this.seq = seq; + } + public CRLDistPoint( DistributionPoint[] points) { - seq = new DERConstructedSequence(); + DEREncodableVector v = new DEREncodableVector(); for (int i = 0; i != points.length; i++) { - seq.addObject(points[i]); + v.add(points[i]); } + + seq = new DERSequence(v); } /** diff --git a/src/org/bouncycastle/asn1/x509/CRLReason.java b/src/org/bouncycastle/asn1/x509/CRLReason.java new file mode 100644 index 0000000..1edf885 --- /dev/null +++ b/src/org/bouncycastle/asn1/x509/CRLReason.java @@ -0,0 +1,40 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.*; + +public class CRLReason + extends DEREnumerated +{ + public static final int UNSPECIFIED = 0; + public static final int KEY_COMPROMISE = 1; + public static final int CA_COMPROMISE = 2; + public static final int AFFILIATION_CHANGED = 3; + public static final int SUPERSEDED = 4; + public static final int CESSATION_OF_OPERATION = 5; + public static final int CERTIFICATE_HOLD = 6; + public static final int REMOVE_FROM_CRL = 8; + public static final int PRIVILEGE_WITHDRAWN = 9; + public static final int AA_COMPROMISE = 10; + + /** + *
+     * CRLReason ::= ENUMERATED {
+     *  unspecified             (0),
+     *  keyCompromise           (1),
+     *  cACompromise            (2),
+     *  affiliationChanged      (3),
+     *  superseded              (4),
+     *  cessationOfOperation    (5),
+     *  certificateHold         (6),
+     *  removeFromCRL           (8),
+     *  privilegeWithdrawn      (9),
+     *  aACompromise           (10)
+     * }
+     * 
+ */ + public CRLReason( + int reason) + { + super(reason); + } +} diff --git a/src/org/bouncycastle/asn1/x509/CertificateList.java b/src/org/bouncycastle/asn1/x509/CertificateList.java index 48703d1..b325e9f 100644 --- a/src/org/bouncycastle/asn1/x509/CertificateList.java +++ b/src/org/bouncycastle/asn1/x509/CertificateList.java @@ -17,85 +17,89 @@ import org.bouncycastle.asn1.pkcs.*; * signatureValue BIT STRING } * */ - public class CertificateList - implements DEREncodable + implements DEREncodable { - DERConstructedSequence seq; + TBSCertList tbsCertList; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static CertificateList getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } - TBSCertList tbsCertList; - AlgorithmIdentifier sigAlgId; - DERBitString sig; + public static CertificateList getInstance( + Object obj) + { + if (obj instanceof CertificateList) + { + return (CertificateList)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new CertificateList((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } public CertificateList( - DERConstructedSequence seq) + ASN1Sequence seq) { - this.seq = seq; - - if ( seq.getObjectAt(0) instanceof TBSCertList ) - { - tbsCertList = (TBSCertList)seq.getObjectAt(0); - } - else - { - tbsCertList = new TBSCertList((DERConstructedSequence)seq.getObjectAt(0)); - } - - if ( seq.getObjectAt(1) instanceof AlgorithmIdentifier ) - { - sigAlgId = (AlgorithmIdentifier)seq.getObjectAt(1); - } - else - { - sigAlgId = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(1)); - } - - sig = (DERBitString)seq.getObjectAt(2); - } - - public TBSCertList getTBSCertList() - { - return tbsCertList; - } - - public TBSCertList.CRLEntry[] getRevokedCertificates() - { - return tbsCertList.getRevokedCertificates(); - } - - public AlgorithmIdentifier getSignatureAlgorithm() - { - return sigAlgId; - } - - public DERBitString getSignature() - { - return sig; - } - - public int getVersion() - { - return tbsCertList.getVersion(); - } - - public X509Name getIssuer() - { - return tbsCertList.getIssuer(); - } - - public DERUTCTime getThisUpdate() - { - return tbsCertList.getThisUpdate(); - } - - public DERUTCTime getNextUpdate() - { - return tbsCertList.getNextUpdate(); - } - - public DERObject getDERObject() - { - return seq; - } -} + tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + sig = (DERBitString)seq.getObjectAt(2); + } + + public TBSCertList getTBSCertList() + { + return tbsCertList; + } + + public TBSCertList.CRLEntry[] getRevokedCertificates() + { + return tbsCertList.getRevokedCertificates(); + } + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public int getVersion() + { + return tbsCertList.getVersion(); + } + + public X509Name getIssuer() + { + return tbsCertList.getIssuer(); + } + + public Time getThisUpdate() + { + return tbsCertList.getThisUpdate(); + } + + public Time getNextUpdate() + { + return tbsCertList.getNextUpdate(); + } + + public DERObject getDERObject() + { + DERConstructedSequence seq = new DERConstructedSequence(); + seq.addObject(tbsCertList); + seq.addObject(sigAlgId); + seq.addObject(sig); + return seq; + } +} diff --git a/src/org/bouncycastle/asn1/x509/DSAParameter.java b/src/org/bouncycastle/asn1/x509/DSAParameter.java index b6234bb..3cd24d9 100644 --- a/src/org/bouncycastle/asn1/x509/DSAParameter.java +++ b/src/org/bouncycastle/asn1/x509/DSAParameter.java @@ -1,6 +1,6 @@ package org.bouncycastle.asn1.x509; -import java.math.*; +import java.math.BigInteger; import java.util.*; import org.bouncycastle.asn1.*; @@ -10,6 +10,29 @@ public class DSAParameter { DERInteger p, q, g; + public static DSAParameter getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DSAParameter getInstance( + Object obj) + { + if(obj == null || obj instanceof DSAParameter) + { + return (DSAParameter)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new DSAParameter((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DSAParameter: " + obj.getClass().getName()); + } + public DSAParameter( BigInteger p, BigInteger q, @@ -21,7 +44,7 @@ public class DSAParameter } public DSAParameter( - DERConstructedSequence seq) + ASN1Sequence seq) { Enumeration e = seq.getObjects(); @@ -47,12 +70,12 @@ public class DSAParameter public DERObject getDERObject() { - DERConstructedSequence seq = new DERConstructedSequence(); + DEREncodableVector v = new DEREncodableVector(); - seq.addObject(p); - seq.addObject(q); - seq.addObject(g); + v.add(p); + v.add(q); + v.add(g); - return seq; + return new DERSequence(v); } } diff --git a/src/org/bouncycastle/asn1/x509/DigestInfo.java b/src/org/bouncycastle/asn1/x509/DigestInfo.java index b15d37e..a882fa8 100644 --- a/src/org/bouncycastle/asn1/x509/DigestInfo.java +++ b/src/org/bouncycastle/asn1/x509/DigestInfo.java @@ -13,11 +13,33 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; * */ public class DigestInfo - implements PKCSObjectIdentifiers, DEREncodable + implements DEREncodable { private byte[] digest; private AlgorithmIdentifier algId; + public static DigestInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DigestInfo getInstance( + Object obj) + { + if (obj instanceof DigestInfo) + { + return (DigestInfo)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new DigestInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + public DigestInfo( AlgorithmIdentifier algId, byte[] digest) @@ -27,12 +49,12 @@ public class DigestInfo } public DigestInfo( - DERConstructedSequence seq) + ASN1Sequence obj) { - Enumeration e = seq.getObjects(); + Enumeration e = obj.getObjects(); - algId = new AlgorithmIdentifier((DERConstructedSequence)e.nextElement()); - digest = ((DEROctetString)e.nextElement()).getOctets(); + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + digest = ((ASN1OctetString)e.nextElement()).getOctets(); } public AlgorithmIdentifier getAlgorithmId() @@ -47,11 +69,11 @@ public class DigestInfo public DERObject getDERObject() { - DERConstructedSequence seq = new DERConstructedSequence(); + DEREncodableVector v = new DEREncodableVector(); - seq.addObject(algId); - seq.addObject(new DEROctetString(digest)); + v.add(algId); + v.add(new DEROctetString(digest)); - return seq; + return new DERSequence(v); } } diff --git a/src/org/bouncycastle/asn1/x509/DistributionPoint.java b/src/org/bouncycastle/asn1/x509/DistributionPoint.java index cb64d68..1331546 100644 --- a/src/org/bouncycastle/asn1/x509/DistributionPoint.java +++ b/src/org/bouncycastle/asn1/x509/DistributionPoint.java @@ -5,29 +5,60 @@ import org.bouncycastle.asn1.*; public class DistributionPoint implements DEREncodable { - DERConstructedSequence seq = null; + ASN1Sequence seq = null; + + public static DistributionPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DistributionPoint getInstance( + Object obj) + { + if(obj == null || obj instanceof DistributionPoint) + { + return (DistributionPoint)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new DistributionPoint((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DistributionPoint: " + obj.getClass().getName()); + } public DistributionPoint( + ASN1Sequence seq) + { + this.seq = seq; + } + + public DistributionPoint( DistributionPointName distributionPoint, ReasonFlags reasons, GeneralNames cRLIssuer) { - seq = new DERConstructedSequence(); + DEREncodableVector v = new DEREncodableVector(); if (distributionPoint != null) { - seq.addObject(new DERTaggedObject(0, distributionPoint)); + v.add(new DERTaggedObject(0, distributionPoint)); } if (reasons != null) { - seq.addObject(new DERTaggedObject(1, reasons)); + v.add(new DERTaggedObject(1, reasons)); } if (cRLIssuer != null) { - seq.addObject(new DERTaggedObject(2, cRLIssuer)); + v.add(new DERTaggedObject(2, cRLIssuer)); } + + seq = new DERSequence(v); } /** diff --git a/src/org/bouncycastle/asn1/x509/GeneralName.java b/src/org/bouncycastle/asn1/x509/GeneralName.java index 41c2578..1246f15 100644 --- a/src/org/bouncycastle/asn1/x509/GeneralName.java +++ b/src/org/bouncycastle/asn1/x509/GeneralName.java @@ -27,8 +27,9 @@ import org.bouncycastle.asn1.*; public class GeneralName implements DEREncodable { - DEREncodable obj; - int tag; + DEREncodable obj; + int tag; + boolean isInsideImplicit = false; // if we are in an implicitly tagged object public GeneralName( X509Name directoryName) @@ -71,8 +72,26 @@ public class GeneralName this.tag = tag; } + /** + * mark whether or not we are contained inside an implicitly tagged + * object. + * @deprecated + */ + public void markInsideImplicit( + boolean isInsideImplicit) + { + this.isInsideImplicit = isInsideImplicit; + } + public DERObject getDERObject() { - return new DERTaggedObject(false, tag, obj); + if (obj.getDERObject() instanceof ASN1Sequence) + { + return new DERTaggedObject(true, tag, obj); + } + else + { + return new DERTaggedObject(false, tag, obj); + } } } diff --git a/src/org/bouncycastle/asn1/x509/GeneralNames.java b/src/org/bouncycastle/asn1/x509/GeneralNames.java index e13ffb0..44a5ae3 100644 --- a/src/org/bouncycastle/asn1/x509/GeneralNames.java +++ b/src/org/bouncycastle/asn1/x509/GeneralNames.java @@ -1,18 +1,55 @@ package org.bouncycastle.asn1.x509; +import java.util.Enumeration; + import org.bouncycastle.asn1.*; public class GeneralNames implements DEREncodable { - DERConstructedSequence seq; + ASN1Sequence seq; + boolean isInsideImplicit = false; + + public static GeneralNames getInstance( + Object obj) + { + if (obj == null || obj instanceof GeneralNames) + { + return (GeneralNames)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new GeneralNames((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + public static GeneralNames getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } public GeneralNames( - DERConstructedSequence seq) + ASN1Sequence seq) { this.seq = seq; } + /* + * this is a hack! But it will have to do until the ambiguity rules + * get sorted out for implicit/explicit tagging... + * @deprecated + */ + public void markInsideImplicit( + boolean isInsideImplicit) + { + this.isInsideImplicit = isInsideImplicit; + } + /** *
      * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
diff --git a/src/org/bouncycastle/asn1/x509/KeyUsage.java b/src/org/bouncycastle/asn1/x509/KeyUsage.java
index e4ed284..ff2c3e5 100644
--- a/src/org/bouncycastle/asn1/x509/KeyUsage.java
+++ b/src/org/bouncycastle/asn1/x509/KeyUsage.java
@@ -31,17 +31,6 @@ public class KeyUsage
     public static final int        encipherOnly     = (1 << 0);
     public static final int        decipherOnly     = (1 << 15);
 
-    static private byte[] getUsageBytes(
-        int usage)
-    {
-        byte[]  usageBytes = new byte[2];
-
-        usageBytes[0] = (byte)(usage & 0xFF);
-        usageBytes[1] = (byte)((usage >> 8) & 0xFF);
-
-        return usageBytes;
-    }
-
     /**
      * Basic constructor.
      * 
@@ -52,7 +41,7 @@ public class KeyUsage
     public KeyUsage(
         int usage)
     {
-        super(getUsageBytes(usage), 7);
+        super(getBytes(usage), getPadBits(usage));
     }
 
     public KeyUsage(
diff --git a/src/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/src/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
index b792fe1..b390245 100644
--- a/src/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
+++ b/src/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
@@ -11,6 +11,29 @@ public class RSAPublicKeyStructure
     private BigInteger  modulus;
     private BigInteger  publicExponent;
 
+    public static RSAPublicKeyStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPublicKeyStructure getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof RSAPublicKeyStructure) 
+        {
+            return (RSAPublicKeyStructure)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new RSAPublicKeyStructure((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName());
+    }
+    
     public RSAPublicKeyStructure(
         BigInteger  modulus,
         BigInteger  publicExponent)
@@ -20,7 +43,7 @@ public class RSAPublicKeyStructure
     }
 
     public RSAPublicKeyStructure(
-        DERConstructedSequence  seq)
+        ASN1Sequence  seq)
     {
         Enumeration e = seq.getObjects();
 
diff --git a/src/org/bouncycastle/asn1/x509/ReasonFlags.java b/src/org/bouncycastle/asn1/x509/ReasonFlags.java
index 568cf1f..0e8ac27 100644
--- a/src/org/bouncycastle/asn1/x509/ReasonFlags.java
+++ b/src/org/bouncycastle/asn1/x509/ReasonFlags.java
@@ -5,12 +5,15 @@ import org.bouncycastle.asn1.*;
 public class ReasonFlags
     extends DERBitString
 {
-    public static final int KEY_COMPROMISE          = 1;
-    public static final int CA_COMPROMISE           = (1 << 2);
-    public static final int AFFILIATION_CHANGED     = (1 << 3);
-    public static final int SUPERSEDED              = (1 << 4);
-    public static final int CESSATION_OF_OPERATION  = (1 << 5);
-    public static final int CERTIFICATE_HOLD        = (1 << 6);
+    public static final int UNUSED                  = (1 << 7);
+    public static final int KEY_COMPROMISE          = (1 << 6);
+    public static final int CA_COMPROMISE           = (1 << 5);
+    public static final int AFFILIATION_CHANGED     = (1 << 4);
+    public static final int SUPERSEDED              = (1 << 3);
+    public static final int CESSATION_OF_OPERATION  = (1 << 2);
+    public static final int CERTIFICATE_HOLD        = (1 << 1);
+    public static final int PRIVILEGE_WITHDRAWN     = (1 << 0);
+    public static final int AA_COMPROMISE           = (1 << 15);
 
     /**
      * 
@@ -24,10 +27,18 @@ public class ReasonFlags
      *    certficateHold(6)
      * }
      * 
+ * @param reasons - the bitwise OR of the Key Reason flags giving the + * allowed uses for the key. */ public ReasonFlags( int reasons) { - super((byte)reasons, 1); + super(getBytes(reasons), getPadBits(reasons)); + } + + public ReasonFlags( + DERBitString reasons) + { + super(reasons.getBytes(), reasons.getPadBits()); } } diff --git a/src/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/src/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java index 0dd2b27..5d6ffd8 100644 --- a/src/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java +++ b/src/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java @@ -14,6 +14,34 @@ public class SubjectKeyIdentifier { private byte[] keyidentifier; + public static SubjectKeyIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1OctetString.getInstance(obj, explicit)); + } + + public static SubjectKeyIdentifier getInstance( + Object obj) + { + if(obj == null || obj instanceof SubjectKeyIdentifier) + { + return (SubjectKeyIdentifier)obj; + } + + if(obj instanceof SubjectPublicKeyInfo) + { + return new SubjectKeyIdentifier((SubjectPublicKeyInfo)obj); + } + + if(obj instanceof ASN1OctetString) + { + return new SubjectKeyIdentifier((ASN1OctetString)obj); + } + + throw new IllegalArgumentException("Invalid SubjectKeyIdentifier: " + obj.getClass().getName()); + } + public SubjectKeyIdentifier( byte[] keyid) { @@ -21,7 +49,7 @@ public class SubjectKeyIdentifier } public SubjectKeyIdentifier( - DEROctetString keyid) + ASN1OctetString keyid) { this.keyidentifier=keyid.getOctets(); @@ -39,8 +67,7 @@ public class SubjectKeyIdentifier Digest digest = new SHA1Digest(); byte[] resBuf = new byte[digest.getDigestSize()]; - DERBitString derpk = new DERBitString(spki.getPublicKey()); - byte[] bytes = derpk.getBytes(); + byte[] bytes = spki.getPublicKeyData().getBytes(); digest.update(bytes, 0, bytes.length); digest.doFinal(resBuf, 0); this.keyidentifier=resBuf; @@ -58,7 +85,6 @@ public class SubjectKeyIdentifier */ public DERObject getDERObject() { - DEROctetString oct = new DEROctetString(keyidentifier); - return oct; + return new DEROctetString(keyidentifier); } } diff --git a/src/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/src/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java index 2e65881..53541b9 100644 --- a/src/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java +++ b/src/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java @@ -17,36 +17,53 @@ public class SubjectPublicKeyInfo implements DEREncodable { private AlgorithmIdentifier algId; - private DERObject pubKey; + private DERBitString keyData; + + public static SubjectPublicKeyInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static SubjectPublicKeyInfo getInstance( + Object obj) + { + if (obj instanceof SubjectPublicKeyInfo) + { + return (SubjectPublicKeyInfo)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new SubjectPublicKeyInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } public SubjectPublicKeyInfo( AlgorithmIdentifier algId, - DERObject publicKey) + DEREncodable publicKey) { - this.pubKey = publicKey; + this.keyData = new DERBitString(publicKey); this.algId = algId; } public SubjectPublicKeyInfo( - DERConstructedSequence seq) + AlgorithmIdentifier algId, + byte[] publicKey) { - Enumeration e = seq.getObjects(); - - algId = new AlgorithmIdentifier((DERConstructedSequence)e.nextElement()); - - byte[] keyData = ((DERBitString)e.nextElement()).getBytes(); + this.keyData = new DERBitString(publicKey); + this.algId = algId; + } - try - { - ByteArrayInputStream bIn = new ByteArrayInputStream(keyData); - DERInputStream dIn = new DERInputStream(bIn); + public SubjectPublicKeyInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); - pubKey = (DERObject)dIn.readObject(); - } - catch (IOException ex) - { - throw new IllegalArgumentException("error recovering public key"); - } + this.algId = AlgorithmIdentifier.getInstance(e.nextElement()); + this.keyData = (DERBitString)e.nextElement(); } public AlgorithmIdentifier getAlgorithmId() @@ -54,9 +71,28 @@ public class SubjectPublicKeyInfo return algId; } + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @exception IOException - if the bit string doesn't represent a DER + * encoded object. + */ public DERObject getPublicKey() + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(keyData.getBytes()); + DERInputStream dIn = new DERInputStream(bIn); + + return dIn.readObject(); + } + + /** + * for when the public key is raw bits... + */ + public DERBitString getPublicKeyData() { - return pubKey; + return keyData; } /** @@ -71,7 +107,7 @@ public class SubjectPublicKeyInfo DERConstructedSequence seq = new DERConstructedSequence(); seq.addObject(algId); - seq.addObject(new DERBitString(pubKey)); + seq.addObject(keyData); return seq; } diff --git a/src/org/bouncycastle/asn1/x509/TBSCertList.java b/src/org/bouncycastle/asn1/x509/TBSCertList.java index 11cb2ab..8a47019 100644 --- a/src/org/bouncycastle/asn1/x509/TBSCertList.java +++ b/src/org/bouncycastle/asn1/x509/TBSCertList.java @@ -28,69 +28,91 @@ import org.bouncycastle.asn1.pkcs.*; */ public class TBSCertList - implements DEREncodable + implements DEREncodable { - public class CRLEntry - implements DEREncodable - { - DERConstructedSequence seq; - - DERInteger userCertificate; - DERUTCTime revocationDate; - X509Extensions crlEntryExtensions; - - public CRLEntry( - DERConstructedSequence seq) - { - this.seq = seq; - - userCertificate = (DERInteger)seq.getObjectAt(0); - revocationDate = (DERUTCTime)seq.getObjectAt(1); - if ( seq.getSize() == 3 ) - { - crlEntryExtensions = new X509Extensions((DERConstructedSequence)seq.getObjectAt(2)); - } - } - - public DERInteger getUserCertificate() - { - return userCertificate; - } - - public DERUTCTime getRevocationDate() - { - return revocationDate; - } - - public X509Extensions getExtensions() - { - return crlEntryExtensions; - } - - public DERObject getDERObject() - { - return seq; - } - } - - DERConstructedSequence seq; + public class CRLEntry + implements DEREncodable + { + DERConstructedSequence seq; + + DERInteger userCertificate; + Time revocationDate; + X509Extensions crlEntryExtensions; + + public CRLEntry( + DERConstructedSequence seq) + { + this.seq = seq; + + userCertificate = (DERInteger)seq.getObjectAt(0); + revocationDate = Time.getInstance(seq.getObjectAt(1)); + if (seq.getSize() == 3) + { + crlEntryExtensions = X509Extensions.getInstance(seq.getObjectAt(2)); + } + } + + public DERInteger getUserCertificate() + { + return userCertificate; + } + + public Time getRevocationDate() + { + return revocationDate; + } + + public X509Extensions getExtensions() + { + return crlEntryExtensions; + } + + public DERObject getDERObject() + { + return seq; + } + } + + ASN1Sequence seq; DERInteger version; AlgorithmIdentifier signature; X509Name issuer; - DERUTCTime thisUpdate; - DERUTCTime nextUpdate; - CRLEntry[] revokedCertificates; + Time thisUpdate; + Time nextUpdate; + CRLEntry[] revokedCertificates; X509Extensions crlExtensions; + public static TBSCertList getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertList getInstance( + Object obj) + { + if (obj instanceof TBSCertList) + { + return (TBSCertList)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new TBSCertList((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + public TBSCertList( - DERConstructedSequence seq) + ASN1Sequence seq) { int seqPos = 0; this.seq = seq; - if ( seq.getObjectAt(seqPos) instanceof DERInteger ) + if (seq.getObjectAt(seqPos) instanceof DERInteger) { version = (DERInteger)seq.getObjectAt(seqPos++); } @@ -99,49 +121,35 @@ public class TBSCertList version = new DERInteger(0); } - if ( seq.getObjectAt(seqPos) instanceof AlgorithmIdentifier ) - { - signature = (AlgorithmIdentifier)seq.getObjectAt(seqPos++); - } - else - { - signature = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(seqPos++)); - } + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++)); + issuer = X509Name.getInstance(seq.getObjectAt(seqPos++)); + thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); - if ( seq.getObjectAt(seqPos) instanceof X509Name ) + if (seqPos < seq.size() + && (seq.getObjectAt(seqPos) instanceof DERUTCTime + || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime + || seq.getObjectAt(seqPos) instanceof Time)) { - issuer = (X509Name)seq.getObjectAt(seqPos++); + nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); } - else + + if (seqPos < seq.size() + && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject)) { - issuer = new X509Name((DERConstructedSequence)seq.getObjectAt(seqPos++)); - } + DERConstructedSequence certs = (DERConstructedSequence)seq.getObjectAt(seqPos++); + revokedCertificates = new CRLEntry[certs.getSize()]; - thisUpdate = (DERUTCTime)seq.getObjectAt(seqPos++); + for ( int i = 0; i < revokedCertificates.length; i++) + { + revokedCertificates[i] = new CRLEntry((DERConstructedSequence)certs.getObjectAt(i)); + } + } - if ( seqPos < seq.getSize() - && seq.getObjectAt(seqPos) instanceof DERUTCTime ) + if (seqPos < seq.size() + && seq.getObjectAt(seqPos) instanceof DERTaggedObject) { - nextUpdate = (DERUTCTime)seq.getObjectAt(seqPos++); + crlExtensions = X509Extensions.getInstance(seq.getObjectAt(seqPos++)); } - - if ( seqPos < seq.getSize() - && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject) ) - { - DERConstructedSequence certs = (DERConstructedSequence)seq.getObjectAt(seqPos++); - revokedCertificates = new CRLEntry[certs.getSize()]; - - for ( int i = 0; i < revokedCertificates.length; i++ ) - { - revokedCertificates[i] = new CRLEntry((DERConstructedSequence)certs.getObjectAt(i)); - } - } - - if ( seqPos < seq.getSize() - && seq.getObjectAt(seqPos) instanceof DERTaggedObject ) - { - crlExtensions = new X509Extensions((DERConstructedSequence)((DERTaggedObject)seq.getObjectAt(seqPos++)).getObject()); - } } public int getVersion() @@ -164,12 +172,12 @@ public class TBSCertList return issuer; } - public DERUTCTime getThisUpdate() + public Time getThisUpdate() { return thisUpdate; } - public DERUTCTime getNextUpdate() + public Time getNextUpdate() { return nextUpdate; } @@ -189,4 +197,3 @@ public class TBSCertList return seq; } } - diff --git a/src/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/src/org/bouncycastle/asn1/x509/TBSCertificateStructure.java index d5c7cf7..fa4b06d 100644 --- a/src/org/bouncycastle/asn1/x509/TBSCertificateStructure.java +++ b/src/org/bouncycastle/asn1/x509/TBSCertificateStructure.java @@ -25,21 +25,43 @@ import org.bouncycastle.asn1.pkcs.*; public class TBSCertificateStructure implements DEREncodable, X509ObjectIdentifiers, PKCSObjectIdentifiers { - DERConstructedSequence seq; + ASN1Sequence seq; DERInteger version; DERInteger serialNumber; AlgorithmIdentifier signature; X509Name issuer; - DERUTCTime startDate, endDate; + Time startDate, endDate; X509Name subject; SubjectPublicKeyInfo subjectPublicKeyInfo; DERBitString issuerUniqueId; DERBitString subjectUniqueId; X509Extensions extensions; + public static TBSCertificateStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertificateStructure getInstance( + Object obj) + { + if (obj instanceof TBSCertificateStructure) + { + return (TBSCertificateStructure)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new TBSCertificateStructure((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + public TBSCertificateStructure( - DERConstructedSequence seq) + ASN1Sequence seq) { int seqStart = 0; @@ -50,7 +72,7 @@ public class TBSCertificateStructure // if (seq.getObjectAt(0) instanceof DERTaggedObject) { - version = (DERInteger)((DERTaggedObject)seq.getObjectAt(0)).getObject(); + version = DERInteger.getInstance(seq.getObjectAt(0)); } else { @@ -58,68 +80,40 @@ public class TBSCertificateStructure version = new DERInteger(0); } - serialNumber = (DERInteger)seq.getObjectAt(seqStart + 1); + serialNumber = DERInteger.getInstance(seq.getObjectAt(seqStart + 1)); - if (seq.getObjectAt(seqStart + 2) instanceof AlgorithmIdentifier) - { - signature = (AlgorithmIdentifier)seq.getObjectAt(seqStart + 2); - } - else - { - signature = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(seqStart + 2)); - } - - if (seq.getObjectAt(seqStart + 3) instanceof X509Name) - { - issuer = (X509Name)seq.getObjectAt(seqStart + 3); - } - else - { - issuer = new X509Name((DERConstructedSequence)seq.getObjectAt(seqStart + 3)); - } + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2)); + issuer = X509Name.getInstance(seq.getObjectAt(seqStart + 3)); // // before and after dates // - DERConstructedSequence dates = (DERConstructedSequence)seq.getObjectAt(seqStart + 4); - startDate = (DERUTCTime)dates.getObjectAt(0); - endDate = (DERUTCTime)dates.getObjectAt(1); + ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4); - if (seq.getObjectAt(seqStart + 5) instanceof X509Name) - { - subject = (X509Name)seq.getObjectAt(seqStart + 5); - } - else - { - subject = new X509Name((DERConstructedSequence)seq.getObjectAt(seqStart + 5)); - } + startDate = Time.getInstance(dates.getObjectAt(0)); + endDate = Time.getInstance(dates.getObjectAt(1)); + + subject = X509Name.getInstance(seq.getObjectAt(seqStart + 5)); // // public key info. // - if (seq.getObjectAt(seqStart + 6) instanceof SubjectPublicKeyInfo) - { - subjectPublicKeyInfo = (SubjectPublicKeyInfo)seq.getObjectAt(seqStart + 6); - } - else - { - subjectPublicKeyInfo = new SubjectPublicKeyInfo((DERConstructedSequence)seq.getObjectAt(seqStart + 6)); - } + subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6)); - for (int extras = seq.getSize() - (seqStart + 6) - 1; extras > 0; extras--) + for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) { DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras); switch (extra.getTagNo()) { case 1: - issuerUniqueId = (DERBitString)extra.getObject(); + issuerUniqueId = DERBitString.getInstance(extra); break; case 2: - subjectUniqueId = (DERBitString)extra.getObject(); + subjectUniqueId = DERBitString.getInstance(extra); break; case 3: - extensions = new X509Extensions((DERConstructedSequence)extra.getObject()); + extensions = X509Extensions.getInstance(extra); } } } @@ -149,12 +143,12 @@ public class TBSCertificateStructure return issuer; } - public DERUTCTime getStartDate() + public Time getStartDate() { return startDate; } - public DERUTCTime getEndDate() + public Time getEndDate() { return endDate; } diff --git a/src/org/bouncycastle/asn1/x509/Time.java b/src/org/bouncycastle/asn1/x509/Time.java new file mode 100644 index 0000000..77c72bf --- /dev/null +++ b/src/org/bouncycastle/asn1/x509/Time.java @@ -0,0 +1,109 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Date; +import java.util.SimpleTimeZone; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; + +import org.bouncycastle.asn1.*; + +public class Time + implements DEREncodable +{ + DERObject time; + + public static Time getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + public Time( + DERObject time) + { + if (!(time instanceof DERUTCTime) + && !(time instanceof DERGeneralizedTime)) + { + throw new IllegalArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + Date date) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + + dateF.setTimeZone(tz); + + String d = dateF.format(date) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DERGeneralizedTime(d); + } + else + { + time = new DERUTCTime(d.substring(2)); + } + } + + public static Time getInstance( + Object obj) + { + if (obj instanceof Time) + { + return (Time)obj; + } + else if (obj instanceof DERUTCTime) + { + return new Time((DERUTCTime)obj); + } + else if (obj instanceof DERGeneralizedTime) + { + return new Time((DERGeneralizedTime)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + + public String getTime() + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedTime(); + } + else + { + return ((DERGeneralizedTime)time).getTime(); + } + } + + public Date getDate() + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + + return dateF.parse(this.getTime(), new ParsePosition(0)); + } + + /** + *
+     * Time ::= CHOICE {
+     *             utcTime        UTCTime,
+     *             generalTime    GeneralizedTime }
+     * 
+ */ + public DERObject getDERObject() + { + return time; + } +} diff --git a/src/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/src/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java index 9cb5745..d2b3bfd 100644 --- a/src/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java +++ b/src/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java @@ -25,7 +25,7 @@ public class V1TBSCertificateGenerator DERInteger serialNumber; AlgorithmIdentifier signature; X509Name issuer; - DERUTCTime startDate, endDate; + Time startDate, endDate; X509Name subject; SubjectPublicKeyInfo subjectPublicKeyInfo; @@ -52,17 +52,29 @@ public class V1TBSCertificateGenerator } public void setStartDate( - DERUTCTime startDate) + Time startDate) { this.startDate = startDate; } + public void setStartDate( + DERUTCTime startDate) + { + this.startDate = new Time(startDate); + } + public void setEndDate( - DERUTCTime endDate) + Time endDate) { this.endDate = endDate; } + public void setEndDate( + DERUTCTime endDate) + { + this.endDate = new Time(endDate); + } + public void setSubject( X509Name subject) { diff --git a/src/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java b/src/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java index 92b82a3..ab8f7b4 100644 --- a/src/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java +++ b/src/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java @@ -1,5 +1,6 @@ package org.bouncycastle.asn1.x509; +import java.io.*; import java.util.Vector; import java.util.Enumeration; @@ -34,7 +35,7 @@ public class V2TBSCertListGenerator AlgorithmIdentifier signature; X509Name issuer; - DERUTCTime thisUpdate, nextUpdate=null; + Time thisUpdate, nextUpdate=null; X509Extensions extensions=null; private Vector crlentries=null; @@ -58,15 +59,26 @@ public class V2TBSCertListGenerator public void setThisUpdate( DERUTCTime thisUpdate) { - this.thisUpdate = thisUpdate; + this.thisUpdate = new Time(thisUpdate); } public void setNextUpdate( DERUTCTime nextUpdate) { - this.nextUpdate = nextUpdate; + this.nextUpdate = new Time(nextUpdate); + } + + public void setThisUpdate( + Time thisUpdate) + { + this.thisUpdate = thisUpdate; } + public void setNextUpdate( + Time nextUpdate) + { + this.nextUpdate = nextUpdate; + } public void addCRLEntry( DERConstructedSequence crlEntry) @@ -78,15 +90,34 @@ public class V2TBSCertListGenerator public void addCRLEntry(DERInteger userCertificate, DERUTCTime revocationDate, int reason) { + addCRLEntry(userCertificate, new Time(revocationDate), reason); + } + + public void addCRLEntry(DERInteger userCertificate, Time revocationDate, int reason) + { DERConstructedSequence seq = new DERConstructedSequence(); seq.addObject(userCertificate); seq.addObject(revocationDate); + if (reason != 0) { - ReasonFlags rf = new ReasonFlags(reason); + CRLReason rf = new CRLReason(reason); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + DEROutputStream dOut = new DEROutputStream(bOut); + try + { + dOut.writeObject(rf); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding value: " + e); + } + byte[] value = bOut.toByteArray(); DERConstructedSequence eseq = new DERConstructedSequence(); - eseq.addObject(X509Extensions.ReasonCode); - eseq.addObject(rf); + DERConstructedSequence eseq1 = new DERConstructedSequence(); + eseq1.addObject(X509Extensions.ReasonCode); + eseq1.addObject(new DEROctetString(value)); + eseq.addObject(eseq1); X509Extensions ex = new X509Extensions(eseq); seq.addObject(ex); } @@ -130,7 +161,7 @@ public class V2TBSCertListGenerator if (extensions != null) { - seq.addObject(new DERTaggedObject(0, extensions.getDERObject())); + seq.addObject(new DERTaggedObject(0, extensions)); } return new TBSCertList(seq); diff --git a/src/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/src/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java index ae966ec..16c4e69 100644 --- a/src/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java +++ b/src/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java @@ -28,7 +28,7 @@ public class V3TBSCertificateGenerator DERInteger serialNumber; AlgorithmIdentifier signature; X509Name issuer; - DERUTCTime startDate, endDate; + Time startDate, endDate; X509Name subject; SubjectPublicKeyInfo subjectPublicKeyInfo; X509Extensions extensions; @@ -58,12 +58,24 @@ public class V3TBSCertificateGenerator public void setStartDate( DERUTCTime startDate) { + this.startDate = new Time(startDate); + } + + public void setStartDate( + Time startDate) + { this.startDate = startDate; } public void setEndDate( DERUTCTime endDate) { + this.endDate = new Time(endDate); + } + + public void setEndDate( + Time endDate) + { this.endDate = endDate; } @@ -117,7 +129,7 @@ public class V3TBSCertificateGenerator if (extensions != null) { - seq.addObject(new DERTaggedObject(3, extensions.getDERObject())); + seq.addObject(new DERTaggedObject(3, extensions)); } return new TBSCertificateStructure(seq); diff --git a/src/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/src/org/bouncycastle/asn1/x509/X509CertificateStructure.java index 68479c5..54fc803 100644 --- a/src/org/bouncycastle/asn1/x509/X509CertificateStructure.java +++ b/src/org/bouncycastle/asn1/x509/X509CertificateStructure.java @@ -16,38 +16,45 @@ import org.bouncycastle.asn1.pkcs.*; public class X509CertificateStructure implements DEREncodable, X509ObjectIdentifiers, PKCSObjectIdentifiers { - DERConstructedSequence seq; + ASN1Sequence seq; TBSCertificateStructure tbsCert; AlgorithmIdentifier sigAlgId; DERBitString sig; + public static X509CertificateStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509CertificateStructure getInstance( + Object obj) + { + if (obj instanceof X509CertificateStructure) + { + return (X509CertificateStructure)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new X509CertificateStructure((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } + public X509CertificateStructure( - DERConstructedSequence seq) + ASN1Sequence seq) { this.seq = seq; // // correct x509 certficate // - if (seq.getSize() == 3) + if (seq.size() == 3) { - if (seq.getObjectAt(0) instanceof TBSCertificateStructure) - { - tbsCert = (TBSCertificateStructure)seq.getObjectAt(0); - } - else - { - tbsCert = new TBSCertificateStructure((DERConstructedSequence)seq.getObjectAt(0)); - } - - if (seq.getObjectAt(1) instanceof AlgorithmIdentifier) - { - sigAlgId = (AlgorithmIdentifier)seq.getObjectAt(1); - } - else - { - sigAlgId = new AlgorithmIdentifier((DERConstructedSequence)seq.getObjectAt(1)); - } + tbsCert = TBSCertificateStructure.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); sig = (DERBitString)seq.getObjectAt(2); } @@ -73,12 +80,12 @@ public class X509CertificateStructure return tbsCert.getIssuer(); } - public DERUTCTime getStartDate() + public Time getStartDate() { return tbsCert.getStartDate(); } - public DERUTCTime getEndDate() + public Time getEndDate() { return tbsCert.getEndDate(); } diff --git a/src/org/bouncycastle/asn1/x509/X509Extensions.java b/src/org/bouncycastle/asn1/x509/X509Extensions.java index 7fb75f6..6528529 100644 --- a/src/org/bouncycastle/asn1/x509/X509Extensions.java +++ b/src/org/bouncycastle/asn1/x509/X509Extensions.java @@ -103,9 +103,41 @@ public class X509Extensions */ public static final DERObjectIdentifier PolicyConstraints = new DERObjectIdentifier("2.5.29.36"); + /** + * Extended Key Usage + */ + public static final DERObjectIdentifier ExtendedKeyUsage = new DERObjectIdentifier("2.5.29.37"); + private Hashtable extensions = new Hashtable(); private Vector ordering = new Vector(); - private DERConstructedSequence seq; + + public static X509Extensions getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509Extensions getInstance( + Object obj) + { + if (obj == null || obj instanceof X509Extensions) + { + return (X509Extensions)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new X509Extensions((ASN1Sequence)obj); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } /** * Constructor from DERConstructedSequence. @@ -113,18 +145,16 @@ public class X509Extensions * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) */ public X509Extensions( - DERConstructedSequence seq) + ASN1Sequence seq) { - this.seq = seq; - Enumeration e = seq.getObjects(); while (e.hasMoreElements()) { - DERConstructedSequence s = (DERConstructedSequence)e.nextElement(); + ASN1Sequence s = (ASN1Sequence)e.nextElement(); Enumeration e1 = s.getObjects(); - if (s.getSize() == 3) + if (s.size() == 3) { extensions.put(s.getObjectAt(0), new X509Extension((DERBoolean)s.getObjectAt(1), (DEROctetString)s.getObjectAt(2))); } @@ -157,38 +187,30 @@ public class X509Extensions Vector ordering, Hashtable extensions) { - this.seq = new DERConstructedSequence(); + Enumeration e; if (ordering == null) { - Enumeration e = extensions.keys(); - - ordering = this.ordering; + e = extensions.keys(); + } + else + { + e = ordering.elements(); + } - while (e.hasMoreElements()) - { - this.ordering.addElement(e.nextElement()); - } + while (e.hasMoreElements()) + { + this.ordering.addElement(e.nextElement()); } - Enumeration e = ordering.elements(); + e = this.ordering.elements(); while (e.hasMoreElements()) { DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement(); X509Extension ext = (X509Extension)extensions.get(oid); - DERConstructedSequence s = new DERConstructedSequence(); - - s.addObject(oid); - - if (ext.isCritical()) - { - s.addObject(new DERBoolean(true)); - } - - s.addObject(ext.getValue()); - seq.addObject(s); + this.extensions.put(oid, ext); } } @@ -214,7 +236,28 @@ public class X509Extensions public DERObject getDERObject() { - return seq; + DEREncodableVector vec = new DEREncodableVector(); + Enumeration e = ordering.elements(); + + while (e.hasMoreElements()) + { + DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement(); + X509Extension ext = (X509Extension)extensions.get(oid); + DEREncodableVector v = new DEREncodableVector(); + + v.add(oid); + + if (ext.isCritical()) + { + v.add(new DERBoolean(true)); + } + + v.add(ext.getValue()); + + vec.add(new DERSequence(v)); + } + + return new DERSequence(vec); } public int hashCode() diff --git a/src/org/bouncycastle/asn1/x509/X509Name.java b/src/org/bouncycastle/asn1/x509/X509Name.java index 2f2a60f..139bf09 100644 --- a/src/org/bouncycastle/asn1/x509/X509Name.java +++ b/src/org/bouncycastle/asn1/x509/X509Name.java @@ -24,6 +24,11 @@ public class X509Name public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11"); /** + * Title + */ + public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12"); + + /** * common name - StringType(SIZE(1..64)) */ public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3"); @@ -43,12 +48,28 @@ public class X509Name */ public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8"); + /** * email address (RSA PKCS#9 extension) - IA5String *

* note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. */ public static final DERObjectIdentifier EmailAddress = new DERObjectIdentifier("1.2.840.113549.1.9.1"); + + /** + * email address in Verisign certificates + */ + public static final DERObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1"); /** * look up table translating OID values into their common symbols. @@ -64,46 +85,75 @@ public class X509Name { OIDLookUp.put(C, "C"); OIDLookUp.put(O, "O"); + OIDLookUp.put(T, "T"); OIDLookUp.put(OU, "OU"); OIDLookUp.put(CN, "CN"); OIDLookUp.put(L, "L"); OIDLookUp.put(ST, "ST"); OIDLookUp.put(SN, "SN"); - OIDLookUp.put(EmailAddress, "EmailAddress"); - - SymbolLookUp.put("C", C); - SymbolLookUp.put("O", O); - SymbolLookUp.put("OU", OU); - SymbolLookUp.put("CN", CN); - SymbolLookUp.put("L", L); - SymbolLookUp.put("ST", ST); - SymbolLookUp.put("SN", SN); - SymbolLookUp.put("EmailAddress", EmailAddress); + OIDLookUp.put(EmailAddress, "E"); + OIDLookUp.put(DC, "DC"); + OIDLookUp.put(UID, "UID"); + + SymbolLookUp.put("c", C); + SymbolLookUp.put("o", O); + SymbolLookUp.put("t", T); + SymbolLookUp.put("ou", OU); + SymbolLookUp.put("cn", CN); + SymbolLookUp.put("l", L); + SymbolLookUp.put("st", ST); + SymbolLookUp.put("sn", SN); + SymbolLookUp.put("emailaddress", E); + SymbolLookUp.put("dc", DC); + SymbolLookUp.put("e", E); + SymbolLookUp.put("uid", UID); } private Vector ordering = new Vector(); - private Hashtable attributes = new Hashtable(); - private DERConstructedSequence seq = null; + private Vector values = new Vector(); + private ASN1Sequence seq; + + public static X509Name getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509Name getInstance( + Object obj) + { + if (obj == null || obj instanceof X509Name) + { + return (X509Name)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new X509Name((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory"); + } /** - * Constructor from DERConstructedSequence. + * Constructor from ASN1Sequence * * the principal will be a list of constructed sets, each containing an (OID, String) pair. */ public X509Name( - DERConstructedSequence seq) + ASN1Sequence seq) { - this.seq = seq; + this.seq = seq; Enumeration e = seq.getObjects(); while (e.hasMoreElements()) { - DERSet set = (DERSet)e.nextElement(); - DERConstructedSequence s = (DERConstructedSequence)set.getSequence(); + ASN1Set set = (ASN1Set)e.nextElement(); + ASN1Sequence s = (ASN1Sequence)set.getObjectAt(0); ordering.addElement(s.getObjectAt(0)); - attributes.put(s.getObjectAt(0), ((DERString)s.getObjectAt(1)).getString()); + values.addElement(((DERString)s.getObjectAt(1)).getString()); } } @@ -167,7 +217,26 @@ public class X509Name throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name"); } - this.attributes.put(oid, attributes.get(oid)); // copy the hash table + this.values.addElement(attributes.get(oid)); // copy the hash table + } + } + + /** + * takes two vectors one of the oids and the other of the values. + */ + public X509Name( + Vector ordering, + Vector values) + { + if (ordering.size() != values.size()) + { + throw new IllegalArgumentException("ordering vector must be same length as values."); + } + + for (int i = 0; i < ordering.size(); i++) + { + this.ordering.addElement(ordering.elementAt(i)); + this.values.addElement(values.elementAt(i)); } } @@ -190,123 +259,175 @@ public class X509Name throw new IllegalArgumentException("badly formated directory string"); } - String name = token.substring(0, index); - String value = token.substring(index + 1); + String name = token.substring(0, index); + String value = token.substring(index + 1); + DERObjectIdentifier oid = null; - DERObjectIdentifier oid = (DERObjectIdentifier)SymbolLookUp.get(name); - if (oid == null) + if (name.toUpperCase().startsWith("OID.")) { - throw new IllegalArgumentException("Unknown object id - " + oid.getId() + " - passed to distinguished name"); + oid = new DERObjectIdentifier(name.substring(4)); + } + else if (name.charAt(0) >= '0' && name.charAt(0) <= '9') + { + oid = new DERObjectIdentifier(name); + } + else + { + oid = (DERObjectIdentifier)SymbolLookUp.get(name.toLowerCase()); + if (oid == null) + { + throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } } this.ordering.addElement(oid); - this.attributes.put(oid, value); + this.values.addElement(value); } } + /** + * return false if we have characters out of the range of a printable + * string, true otherwise. + */ + private boolean canBePrintable( + String str) + { + for (int i = str.length() - 1; i >= 0; i--) + { + if (str.charAt(i) > 0x007f) + { + return false; + } + } + + return true; + } + public DERObject getDERObject() { if (seq == null) { - seq = new DERConstructedSequence(); + DEREncodableVector vec = new DEREncodableVector(); for (int i = 0; i != ordering.size(); i++) { - DERConstructedSequence s = new DERConstructedSequence(); + DEREncodableVector v = new DEREncodableVector(); DERObjectIdentifier oid = (DERObjectIdentifier)ordering.elementAt(i); - s.addObject(oid); + v.add(oid); + + String str = (String)values.elementAt(i); + if (oid.equals(EmailAddress)) { - s.addObject(new DERIA5String((String)attributes.get(oid))); + v.add(new DERIA5String(str)); } else { - s.addObject(new DERPrintableString((String)attributes.get(oid))); + if (canBePrintable(str)) + { + v.add(new DERPrintableString(str)); + } + else + { + v.add(new DERUTF8String(str)); + } } - seq.addObject(new DERSet(s)); + vec.add(new DERSet(new DERSequence(v))); } - } - return seq; - } - - public int hashCode() - { - Enumeration e = attributes.keys(); - int hashCode = 0; - - while (e.hasMoreElements()) - { - Object o = e.nextElement(); - - hashCode ^= o.hashCode(); - hashCode ^= attributes.get(o).hashCode(); + seq = new DERSequence(vec); } - for (int i = 0; i != ordering.size(); i++) - { - hashCode ^= ordering.elementAt(i).hashCode(); - } - - return hashCode; + return seq; } - public boolean equals( - Object o) + /** + * test for equality - note: case is ignored. + */ + public boolean equals(Object _obj) { - if (o == null || !(o instanceof X509Name)) + if (_obj == this) { - return false; + return true; } - X509Name other = (X509Name)o; - - if (ordering.size() != other.ordering.size()) + if (_obj == null || !(_obj instanceof X509Name)) { return false; } + + X509Name _oxn = (X509Name)_obj; + int _orderingSize = ordering.size(); - for (int i = 0; i != ordering.size(); i++) + if (_orderingSize != _oxn.ordering.size()) { - if (!ordering.elementAt(i).equals(other.ordering.elementAt(i))) - { - return false; - } - } - - Enumeration e1 = attributes.keys(); - Enumeration e2 = other.attributes.keys(); - - while (e1.hasMoreElements() && e2.hasMoreElements()) - { - Object o1 = e1.nextElement(); - Object o2 = e2.nextElement(); - - if (!o1.equals(o2)) - { - return false; - } - } + return false; + } + + boolean[] _indexes = new boolean[_orderingSize]; + + for(int i = 0; i < _orderingSize; i++) + { + boolean _found = false; + String _oid = ((DERObjectIdentifier)ordering.elementAt(i)).getId(); + String _val = (String)values.elementAt(i); + + for(int j = 0; j < _orderingSize; j++) + { + if(_indexes[j] == true) + { + continue; + } + + String _oOID = ((DERObjectIdentifier)_oxn.ordering.elementAt(j)).getId(); + String _oVal = (String)_oxn.values.elementAt(j); + + // was equalsIgnoreCase but MIDP doesn't like that. + if(_oid.equals(_oOID) && _val.toLowerCase().equals(_oVal.toLowerCase())) + { + _indexes[j] = true; + _found = true; + break; + } + + } + + if(!_found) + { + return false; + } + } + + return true; + } + + public int hashCode() + { + ASN1Sequence seq = (ASN1Sequence)this.getDERObject(); + Enumeration e = seq.getObjects(); + int hashCode = 0; - if (e1.hasMoreElements() || e2.hasMoreElements()) + while (e.hasMoreElements()) { - return false; + hashCode ^= e.nextElement().hashCode(); } - return true; + return hashCode; } public String toString() { - StringBuffer buf = new StringBuffer(); - boolean first = true; + StringBuffer buf = new StringBuffer(); + boolean first = true; + Enumeration e1 = ordering.elements(); + Enumeration e2 = values.elements(); - for (int i = 0; i != ordering.size(); i++) + while (e1.hasMoreElements()) { - Object oid = ordering.elementAt(i); - String sym = (String)OIDLookUp.get(oid); + Object oid = e1.nextElement(); + String sym = (String)OIDLookUp.get(oid); if (first) { @@ -314,20 +435,42 @@ public class X509Name } else { - buf.append(", "); + buf.append(","); } if (sym != null) { buf.append(sym); - buf.append("="); - buf.append((String)attributes.get(oid)); } else { buf.append(((DERObjectIdentifier)oid).getId()); - buf.append("="); - buf.append((String)attributes.get(oid)); + } + + buf.append("="); + + int index = buf.length(); + + buf.append((String)e2.nextElement()); + + int end = buf.length(); + + while (index != end) + { + if ((buf.charAt(index) == ',') + || (buf.charAt(index) == '"') + || (buf.charAt(index) == '\\') + || (buf.charAt(index) == '+') + || (buf.charAt(index) == '<') + || (buf.charAt(index) == '>') + || (buf.charAt(index) == ';')) + { + buf.insert(index, "\\"); + index++; + end++; + } + + index++; } } diff --git a/src/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/src/org/bouncycastle/asn1/x509/X509NameTokenizer.java index 2474027..f91c7be 100644 --- a/src/org/bouncycastle/asn1/x509/X509NameTokenizer.java +++ b/src/org/bouncycastle/asn1/x509/X509NameTokenizer.java @@ -1,48 +1,82 @@ package org.bouncycastle.asn1.x509; /** - * class for breaking up an X509 Name into it's component tokens, ala + * class for breaking up an X500 Name into it's component tokens, ala * java.util.StringTokenizer. We need this class as some of the * lightweight Java environment don't support classes like * StringTokenizer. */ public class X509NameTokenizer { - private String oid; - private int index; + private String oid; + private int index; + private StringBuffer buf = new StringBuffer(); public X509NameTokenizer( String oid) { this.oid = oid; - this.index = 0; + this.index = -1; } public boolean hasMoreTokens() { - return (index != -1); + return (index != oid.length()); } public String nextToken() { - if (index == -1) + if (index == oid.length()) { return null; } - String token; - int end = oid.indexOf(',', index); + int end = index + 1; + boolean quoted = false; + boolean escaped = false; - if (end == -1) + buf.setLength(0); + + while (end != oid.length()) { - token = oid.substring(index); - index = -1; - return token.trim(); - } + char c = oid.charAt(end); - token = oid.substring(index, end); + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + buf.append(c); + } + escaped = false; + } + else + { + if (escaped || quoted) + { + buf.append(c); + escaped = false; + } + else if (c == '\\') + { + escaped = true; + } + else if (c == ',') + { + break; + } + else + { + buf.append(c); + } + } + end++; + } - index = end + 1; - return token.trim(); + index = end; + return buf.toString().trim(); } } diff --git a/src/org/bouncycastle/crypto/digests/MD2Digest.java b/src/org/bouncycastle/crypto/digests/MD2Digest.java index 88aa6a4..64de3b0 100644 --- a/src/org/bouncycastle/crypto/digests/MD2Digest.java +++ b/src/org/bouncycastle/crypto/digests/MD2Digest.java @@ -4,8 +4,6 @@ import org.bouncycastle.crypto.Digest; /** * implementation of MD2 * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992 - * - * @author Michael Lee */ public class MD2Digest implements Digest diff --git a/src/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/src/org/bouncycastle/crypto/encodings/PKCS1Encoding.java index aa4ee61..380542a 100644 --- a/src/org/bouncycastle/crypto/encodings/PKCS1Encoding.java +++ b/src/org/bouncycastle/crypto/encodings/PKCS1Encoding.java @@ -1,7 +1,6 @@ package org.bouncycastle.crypto.encodings; import java.math.BigInteger; -import java.util.Random; import java.security.SecureRandom; import org.bouncycastle.crypto.CipherParameters; @@ -19,10 +18,7 @@ public class PKCS1Encoding { private static int HEADER_LENGTH = 10; - // HACK - //private SecureRandom random; - private Random random = new Random(); - + private SecureRandom random; private AsymmetricBlockCipher engine; private boolean forEncryption; private boolean forPrivateKey; @@ -43,18 +39,17 @@ public class PKCS1Encoding CipherParameters param) { AsymmetricKeyParameter kParam; + if (param instanceof ParametersWithRandom) { ParametersWithRandom rParam = (ParametersWithRandom)param; - // HACK - //this.random = rParam.getRandom(); + this.random = rParam.getRandom(); kParam = (AsymmetricKeyParameter)rParam.getParameters(); } else { - // HACK - //this.random = new SecureRandom(); + this.random = new SecureRandom(); kParam = (AsymmetricKeyParameter)param; } @@ -160,6 +155,7 @@ public class PKCS1Encoding throws InvalidCipherTextException { byte[] block = engine.processBlock(in, inOff, inLen); + if (block.length < getOutputBlockSize()) { throw new InvalidCipherTextException("block truncated"); diff --git a/src/org/bouncycastle/crypto/engines/RSAEngine.java b/src/org/bouncycastle/crypto/engines/RSAEngine.java index 2cbac54..c02e20a 100644 --- a/src/org/bouncycastle/crypto/engines/RSAEngine.java +++ b/src/org/bouncycastle/crypto/engines/RSAEngine.java @@ -21,7 +21,7 @@ public class RSAEngine /** * initialise the RSA engine. * - * @param forEncryption treu if we are encrypting, false otherwise. + * @param forEncryption true if we are encrypting, false otherwise. * @param param the necessary RSA key parameters. */ public void init( @@ -45,12 +45,7 @@ public class RSAEngine if (forEncryption) { - if ((bitSize % 8) == 0) - { - return bitSize / 8 - 1; - } - - return bitSize / 8; + return (bitSize + 7) / 8 - 1; } else { @@ -63,7 +58,7 @@ public class RSAEngine * For RSA this is always one byte less than the key size on * decryption, and the same length as the key size on encryption. * - * @return maximum size for an input block. + * @return maximum size for an output block. */ public int getOutputBlockSize() { @@ -71,11 +66,11 @@ public class RSAEngine if (forEncryption) { - return ((bitSize - 1) + 7) / 8; + return (bitSize + 7) / 8; } else { - return (bitSize - 7) / 8; + return (bitSize + 7) / 8 - 1; } }