2003/02/12 06:21:04
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:51:14 +0000 (06:51 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:51:14 +0000 (06:51 +0000)
darcs-hash:20040130065114-2ba56-b548161e0ee805fea5f5bea9640cc7413c9a85f9.gz

68 files changed:
src/org/bouncycastle/asn1/ASN1OctetString.java [new file with mode: 0644]
src/org/bouncycastle/asn1/ASN1OutputStream.java [new file with mode: 0644]
src/org/bouncycastle/asn1/ASN1Sequence.java [new file with mode: 0644]
src/org/bouncycastle/asn1/ASN1Set.java [new file with mode: 0644]
src/org/bouncycastle/asn1/ASN1TaggedObject.java [new file with mode: 0644]
src/org/bouncycastle/asn1/BERConstructedOctetString.java
src/org/bouncycastle/asn1/BERConstructedSequence.java
src/org/bouncycastle/asn1/BERInputStream.java
src/org/bouncycastle/asn1/BERSet.java [new file with mode: 0644]
src/org/bouncycastle/asn1/BERTaggedObject.java
src/org/bouncycastle/asn1/DERBMPString.java
src/org/bouncycastle/asn1/DERBitString.java
src/org/bouncycastle/asn1/DERBoolean.java
src/org/bouncycastle/asn1/DERConstructedSequence.java
src/org/bouncycastle/asn1/DERConstructedSet.java
src/org/bouncycastle/asn1/DEREncodableVector.java [new file with mode: 0644]
src/org/bouncycastle/asn1/DEREnumerated.java [new file with mode: 0644]
src/org/bouncycastle/asn1/DERGeneralizedTime.java [new file with mode: 0644]
src/org/bouncycastle/asn1/DERIA5String.java
src/org/bouncycastle/asn1/DERInputStream.java
src/org/bouncycastle/asn1/DERInteger.java
src/org/bouncycastle/asn1/DERObject.java
src/org/bouncycastle/asn1/DERObjectIdentifier.java
src/org/bouncycastle/asn1/DEROctetString.java
src/org/bouncycastle/asn1/DEROutputStream.java
src/org/bouncycastle/asn1/DERPrintableString.java
src/org/bouncycastle/asn1/DERSequence.java [new file with mode: 0644]
src/org/bouncycastle/asn1/DERSet.java
src/org/bouncycastle/asn1/DERT61String.java
src/org/bouncycastle/asn1/DERTaggedObject.java
src/org/bouncycastle/asn1/DERTags.java
src/org/bouncycastle/asn1/DERUTCTime.java
src/org/bouncycastle/asn1/DERUTF8String.java [new file with mode: 0644]
src/org/bouncycastle/asn1/DERUniversalString.java [new file with mode: 0644]
src/org/bouncycastle/asn1/DERUnknownTag.java
src/org/bouncycastle/asn1/DERVisibleString.java
src/org/bouncycastle/asn1/cms/Attribute.java [new file with mode: 0644]
src/org/bouncycastle/asn1/cms/SignedAttributes.java [new file with mode: 0644]
src/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
src/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
src/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
src/org/bouncycastle/asn1/x509/BasicConstraints.java
src/org/bouncycastle/asn1/x509/CRLDistPoint.java
src/org/bouncycastle/asn1/x509/CRLReason.java [new file with mode: 0644]
src/org/bouncycastle/asn1/x509/CertificateList.java
src/org/bouncycastle/asn1/x509/DSAParameter.java
src/org/bouncycastle/asn1/x509/DigestInfo.java
src/org/bouncycastle/asn1/x509/DistributionPoint.java
src/org/bouncycastle/asn1/x509/GeneralName.java
src/org/bouncycastle/asn1/x509/GeneralNames.java
src/org/bouncycastle/asn1/x509/KeyUsage.java
src/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
src/org/bouncycastle/asn1/x509/ReasonFlags.java
src/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
src/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
src/org/bouncycastle/asn1/x509/TBSCertList.java
src/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
src/org/bouncycastle/asn1/x509/Time.java [new file with mode: 0644]
src/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
src/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java
src/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
src/org/bouncycastle/asn1/x509/X509CertificateStructure.java
src/org/bouncycastle/asn1/x509/X509Extensions.java
src/org/bouncycastle/asn1/x509/X509Name.java
src/org/bouncycastle/asn1/x509/X509NameTokenizer.java
src/org/bouncycastle/crypto/digests/MD2Digest.java
src/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
src/org/bouncycastle/crypto/engines/RSAEngine.java

diff --git a/src/org/bouncycastle/asn1/ASN1OctetString.java b/src/org/bouncycastle/asn1/ASN1OctetString.java
new file mode 100644 (file)
index 0000000..7daf025
--- /dev/null
@@ -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 (file)
index 0000000..d309e12
--- /dev/null
@@ -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 (file)
index 0000000..5362f34
--- /dev/null
@@ -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 <b>should</b>
+     * 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 (file)
index 0000000..adb1b10
--- /dev/null
@@ -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 <b>should</b>
+     * 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 (file)
index 0000000..deadcdb
--- /dev/null
@@ -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. 
+     * <p>
+     * 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.
+     * <p>
+     * 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;
+}
index 47b4245..20b7175 100644 (file)
@@ -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);
+        }
     }
 }
index b8a3c2d..b3c51e1 100644 (file)
@@ -7,37 +7,22 @@ public class BERConstructedSequence
     extends DERConstructedSequence
 {
     /*
-     * A note on the implementation:
-     * <p>
-     * 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);
         }
index 824b439..fd960ec 100644 (file)
@@ -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 (file)
index 0000000..5e99b4f
--- /dev/null
@@ -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);
+        }
+    }
+}
index b24f037..10f83e2 100644 (file)
@@ -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);
+        }
     }
 }
index 8a58b4a..23f467b 100644 (file)
@@ -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];
         }
 
index 0c888d5..56046a7 100644 (file)
@@ -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);
+    }
 }
index 4fce317..8837dfd 100644 (file)
@@ -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);
+    }
+
 }
index d600d95..f1dba33 100644 (file)
@@ -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())
         {
index f675b42..27f060e 100644 (file)
@@ -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 (file)
index 0000000..6135d25
--- /dev/null
@@ -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 (file)
index 0000000..1ab5dca
--- /dev/null
@@ -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 (file)
index 0000000..5361a04
--- /dev/null
@@ -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.
+     * <p>
+     *
+     * @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).
+     * <p>
+     * Normally in a certificate we would expect "Z" rather than "GMT",
+     * however adding the "GMT" means we can just use:
+     * <pre>
+     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+     * </pre>
+     * 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);
+    }
+}
index 5181bdd..da20589 100644 (file)
@@ -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());
+    }
 }
index 61de735..9cf0ef1 100644 (file)
@@ -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);
index 0f86910..351de94 100644 (file)
@@ -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;
+    }
 }
index fb75442..ac0dc03 100644 (file)
@@ -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;
 }
index 8f04454..fb16ac9 100644 (file)
@@ -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();
index fd9f516..9ce9350 100644 (file)
@@ -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;
-    }
 }
index 03e77a2..f8b4c54 100644 (file)
@@ -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
index 7834edf..fdb5b1d 100644 (file)
@@ -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 (file)
index 0000000..b440858
--- /dev/null
@@ -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:
+     * <p>
+     * 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);
+    }
+}
index 2d2caf4..c08fa5a 100644 (file)
@@ -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:
+     * <p>
+     * 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);
     }
 }
index 4412efc..189a939 100644 (file)
@@ -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());
+    }
 }
index 4ec0310..ba69412 100644 (file)
@@ -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
             {
index 085b787..0b4896e 100644 (file)
@@ -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;
 }
index 061bf54..ae59c22 100644 (file)
@@ -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).
      * <p>
-     * You can generate a Java date string in the right format by using:
-     * <pre>
-     *      dateF = new SimpleDateFormat("yyMMddHHmmss");
-     *      tz = new SimpleTimeZone(0, "Z");
-     *     
-     *      dateF.setTimeZone(tz);
-     *
-     *      utcTime = new DERUTCTime(dateF.format(new Date()) + "Z");
-     * </pre>
      *
      * @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).
      * <p>
@@ -48,6 +106,10 @@ public class DERUTCTime
      * </pre>
      * To read in the time and get a date which is compatible with our local
      * time zone.
+     * <p>
+     * <b>Note:</b> 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 (file)
index 0000000..6c3563f
--- /dev/null
@@ -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 (file)
index 0000000..ec12385
--- /dev/null
@@ -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());
+    }
+}
index c5f46f9..010f911 100644 (file)
@@ -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;
+       }
 }
index f2071d3..f603b93 100644 (file)
@@ -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 (file)
index 0000000..0763ea2
--- /dev/null
@@ -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;
+       }
+
+    /** 
+     * <pre>
+     * Attribute ::= SEQUENCE {
+     *         attrType OBJECT IDENTIFIER,
+     *         attrValues SET OF AttributeValue
+     * }
+     * </pre>
+     */
+       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 (file)
index 0000000..47b460e
--- /dev/null
@@ -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;
+}
index f471332..3977e9f 100644 (file)
@@ -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 }
     //
index cad4c82..945f948 100644 (file)
@@ -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;
     }
index 9285c96..d15309d 100644 (file)
@@ -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);
 
index ec84915..b798ea8 100644 (file)
@@ -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);
index 780ab16..11b347a 100644 (file)
@@ -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 (file)
index 0000000..1edf885
--- /dev/null
@@ -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;
+
+    /**
+     * <pre>
+     * CRLReason ::= ENUMERATED {
+     *  unspecified             (0),
+     *  keyCompromise           (1),
+     *  cACompromise            (2),
+     *  affiliationChanged      (3),
+     *  superseded              (4),
+     *  cessationOfOperation    (5),
+     *  certificateHold         (6),
+     *  removeFromCRL           (8),
+     *  privilegeWithdrawn      (9),
+     *  aACompromise           (10)
+     * }
+     * </pre>
+     */
+    public CRLReason(
+        int reason)
+    {
+        super(reason);
+    }
+}
index 48703d1..b325e9f 100644 (file)
@@ -17,85 +17,89 @@ import org.bouncycastle.asn1.pkcs.*;
  *      signatureValue       BIT STRING  }
  * </pre>
  */
-
 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;
+    }
+}
index b6234bb..3cd24d9 100644 (file)
@@ -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);
     }
 }
index b15d37e..a882fa8 100644 (file)
@@ -13,11 +13,33 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
  * </pre>
  */
 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);
     }
 }
index cb64d68..1331546 100644 (file)
@@ -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);
     }
 
     /**
index 41c2578..1246f15 100644 (file)
@@ -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);
+        }
     }
 }
index e13ffb0..44a5ae3 100644 (file)
@@ -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;
+    }
+
     /**
      * <pre>
      * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
index e4ed284..ff2c3e5 100644 (file)
@@ -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(
index b792fe1..b390245 100644 (file)
@@ -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();
 
index 568cf1f..0e8ac27 100644 (file)
@@ -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);
 
     /**
      * <pre>
@@ -24,10 +27,18 @@ public class ReasonFlags
      *    certficateHold(6)
      * }
      * </pre>
+     * @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());
     }
 }
index 0dd2b27..5d6ffd8 100644 (file)
@@ -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);
     }
 }
index 2e65881..53541b9 100644 (file)
@@ -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;
     }
index 11cb2ab..8a47019 100644 (file)
@@ -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;
     }
 }
-
index d5c7cf7..fa4b06d 100644 (file)
@@ -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 (file)
index 0000000..77c72bf
--- /dev/null
@@ -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));
+    }
+
+    /**
+     * <pre>
+     * Time ::= CHOICE {
+     *             utcTime        UTCTime,
+     *             generalTime    GeneralizedTime }
+     * </pre>
+     */
+    public DERObject getDERObject()
+    {
+        return time;
+    }
+}
index 9cb5745..d2b3bfd 100644 (file)
@@ -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)
     {
index 92b82a3..ab8f7b4 100644 (file)
@@ -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);
index ae966ec..16c4e69 100644 (file)
@@ -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);
index 68479c5..54fc803 100644 (file)
@@ -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();
     }
index 7fb75f6..6528529 100644 (file)
@@ -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()
index 2f2a60f..139bf09 100644 (file)
@@ -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
      * <p>
      * 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++;
             }
         }
 
index 2474027..f91c7be 100644 (file)
@@ -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();
     }
 }
index 88aa6a4..64de3b0 100644 (file)
@@ -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\r
     implements Digest\r
index aa4ee61..380542a 100644 (file)
@@ -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");
index 2cbac54..c02e20a 100644 (file)
@@ -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;
         }
     }