DER External type

View: New views
1 Messages — Rating Filter:   Alert me  

DER External type

by Lothar Kimmeringer-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello,

I came along an ASN1-structure containing an element of type
external (the user information element in an AARE-element).

To be able to read that structure in using BC I added the
corresponding class, parser and support in ASN1StreamParser
and ASN1InputStream.

Attached you can find the patch-file containing these changes
(including ASN1Dump). I'm not sure if I found all places where
a ASN1-class is instantiated, so maybe other classes need to
be changed as well.


Best regards, Lothar

Index: ASN1InputStream.java
===================================================================
RCS file: /home/users/bouncy/cvsroot/java/crypto/src/org/bouncycastle/asn1/ASN1InputStream.java,v
retrieving revision 1.28
diff -u -r1.28 ASN1InputStream.java
--- ASN1InputStream.java 25 Jun 2009 09:36:28 -0000 1.28
+++ ASN1InputStream.java 12 Oct 2009 12:58:54 -0000
@@ -229,6 +229,8 @@
                     return new BERSequenceParser(sp).getDERObject();
                 case SET:
                     return new BERSetParser(sp).getDERObject();
+                case EXTERNAL:
+                    return new DERExternalParser(sp).getDERObject();
                 default:
                     throw new IOException("unknown BER object encountered");
             }
@@ -298,7 +300,7 @@
 
             if (size > 4)
             {
-                throw new IOException("DER length more than 4 bytes");
+                throw new IOException("DER length more than 4 bytes: " + size);
             }
 
             length = 0;
Index: ASN1StreamParser.java
===================================================================
RCS file: /home/users/bouncy/cvsroot/java/crypto/src/org/bouncycastle/asn1/ASN1StreamParser.java,v
retrieving revision 1.17
diff -u -r1.17 ASN1StreamParser.java
--- ASN1StreamParser.java 6 Mar 2009 01:46:58 -0000 1.17
+++ ASN1StreamParser.java 12 Oct 2009 12:58:54 -0000
@@ -87,8 +87,11 @@
                     return new BERSequenceParser(sp);
                 case DERTags.SET:
                     return new BERSetParser(sp);
+                case DERTags.EXTERNAL:{
+                    return new DERExternalParser(sp);
+                }
                 default:
-                    throw new IOException("unknown BER object encountered");
+                    throw new IOException("unknown BER object encountered: 0x" + Integer.toHexString(tagNo));
             }
         }
         else
Index: BERTaggedObjectParser.java
===================================================================
RCS file: /home/users/bouncy/cvsroot/java/crypto/src/org/bouncycastle/asn1/BERTaggedObjectParser.java,v
retrieving revision 1.9
diff -u -r1.9 BERTaggedObjectParser.java
--- BERTaggedObjectParser.java 26 Feb 2008 22:02:16 -0000 1.9
+++ BERTaggedObjectParser.java 12 Oct 2009 12:58:55 -0000
@@ -86,7 +86,7 @@
         }
         catch (IOException e)
         {
-            throw new IllegalStateException(e.getMessage());
+            throw new IllegalStateException(e.getMessage(), e);
         }
     }
 
Index: util/ASN1Dump.java
===================================================================
RCS file: /home/users/bouncy/cvsroot/java/crypto/src/org/bouncycastle/asn1/util/ASN1Dump.java,v
retrieving revision 1.5
diff -u -r1.5 ASN1Dump.java
--- util/ASN1Dump.java 9 Mar 2009 00:18:25 -0000 1.5
+++ util/ASN1Dump.java 12 Oct 2009 12:58:55 -0000
@@ -14,6 +14,7 @@
 import org.bouncycastle.asn1.DERConstructedSequence;
 import org.bouncycastle.asn1.DERConstructedSet;
 import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERExternal;
 import org.bouncycastle.asn1.DERGeneralizedTime;
 import org.bouncycastle.asn1.DERIA5String;
 import org.bouncycastle.asn1.DERInteger;
@@ -37,6 +38,8 @@
 
 import java.util.Enumeration;
 import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 
 public class ASN1Dump
 {
@@ -48,15 +51,15 @@
      *
      * @param obj the DERObject to be dumped out.
      */
-    static String _dumpAsString(
+    static void _dumpAsString(
         String      indent,
         boolean     verbose,
-        DERObject   obj)
+        DERObject   obj,
+        StringBuffer    buf)
     {
         String nl = System.getProperty("line.separator");
         if (obj instanceof ASN1Sequence)
         {
-            StringBuffer    buf = new StringBuffer();
             Enumeration     e = ((ASN1Sequence)obj).getObjects();
             String          tab = indent + TAB;
 
@@ -96,18 +99,16 @@
                 }
                 else if (o instanceof DERObject)
                 {
-                    buf.append(_dumpAsString(tab, verbose, (DERObject)o));
+                    _dumpAsString(tab, verbose, (DERObject)o, buf);
                 }
                 else
                 {
-                    buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
+                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
                 }
             }
-            return buf.toString();
         }
         else if (obj instanceof DERTaggedObject)
         {
-            StringBuffer    buf = new StringBuffer();
             String          tab = indent + TAB;
 
             buf.append(indent);
@@ -140,14 +141,11 @@
             }
             else
             {
-                buf.append(_dumpAsString(tab, verbose, o.getObject()));
+                _dumpAsString(tab, verbose, o.getObject(), buf);
             }
-
-            return buf.toString();
         }
         else if (obj instanceof DERConstructedSet)
         {
-            StringBuffer    buf = new StringBuffer();
             Enumeration     e = ((ASN1Set)obj).getObjects();
             String          tab = indent + TAB;
 
@@ -167,18 +165,16 @@
                 }
                 else if (o instanceof DERObject)
                 {
-                    buf.append(_dumpAsString(tab, verbose, (DERObject)o));
+                    _dumpAsString(tab, verbose, (DERObject)o, buf);
                 }
                 else
                 {
-                    buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
+                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
                 }
             }
-            return buf.toString();
         }
         else if (obj instanceof BERSet)
         {
-            StringBuffer    buf = new StringBuffer();
             Enumeration     e = ((ASN1Set)obj).getObjects();
             String          tab = indent + TAB;
 
@@ -198,18 +194,16 @@
                 }
                 else if (o instanceof DERObject)
                 {
-                    buf.append(_dumpAsString(tab, verbose, (DERObject)o));
+                    _dumpAsString(tab, verbose, (DERObject)o, buf);
                 }
                 else
                 {
-                    buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
+                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
                 }
             }
-            return buf.toString();
         }
         else if (obj instanceof DERSet)
         {
-            StringBuffer    buf = new StringBuffer();
             Enumeration     e = ((ASN1Set)obj).getObjects();
             String          tab = indent + TAB;
 
@@ -229,104 +223,128 @@
                 }
                 else if (o instanceof DERObject)
                 {
-                    buf.append(_dumpAsString(tab, verbose, (DERObject)o));
+                    _dumpAsString(tab, verbose, (DERObject)o, buf);
                 }
                 else
                 {
-                    buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
+                    _dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject(), buf);
                 }
             }
-            return buf.toString();
         }
         else if (obj instanceof DERObjectIdentifier)
         {
-            return indent + "ObjectIdentifier(" + ((DERObjectIdentifier)obj).getId() + ")" + nl;
+            buf.append(indent + "ObjectIdentifier(" + ((DERObjectIdentifier)obj).getId() + ")" + nl);
         }
         else if (obj instanceof DERBoolean)
         {
-            return indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl;
+            buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl);
         }
         else if (obj instanceof DERInteger)
         {
-            return indent + "Integer(" + ((DERInteger)obj).getValue() + ")" + nl;
+            buf.append(indent + "Integer(" + ((DERInteger)obj).getValue() + ")" + nl);
         }
         else if (obj instanceof BERConstructedOctetString)
         {
             ASN1OctetString oct = (ASN1OctetString)obj;
+            buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] ");
             if (verbose)
             {
-                return indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] " + dumpBinaryDataAsString(indent, oct.getOctets()) + nl;
+                buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
+            }
+            else{
+                buf.append(nl);
             }
-            return indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] " + nl;
         }
         else if (obj instanceof DEROctetString)
         {
             ASN1OctetString oct = (ASN1OctetString)obj;
+            buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] ");
             if (verbose)
             {
-                return indent + "DER Octet String" + "[" + oct.getOctets().length + "] " + dumpBinaryDataAsString(indent, oct.getOctets()) + nl;
+                buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
+            }
+            else{
+                buf.append(nl);
             }
-            return indent + "DER Octet String" + "[" + oct.getOctets().length + "] " + nl;
         }
         else if (obj instanceof DERBitString)
         {
             DERBitString bt = (DERBitString)obj;
+            buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] ");
             if (verbose)
             {
-                return indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] "  + dumpBinaryDataAsString(indent, bt.getBytes()) + nl;
+                buf.append(dumpBinaryDataAsString(indent, bt.getBytes()));
+            }
+            else{
+                buf.append(nl);
             }
-            return indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] " + nl;
         }
         else if (obj instanceof DERIA5String)
         {
-            return indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl;
+            buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl);
         }
         else if (obj instanceof DERUTF8String)
         {
-            return indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl;
+            buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl);
         }
         else if (obj instanceof DERPrintableString)
         {
-            return indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl;
+            buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl);
         }
         else if (obj instanceof DERVisibleString)
         {
-            return indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl;
+            buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl);
         }
         else if (obj instanceof DERBMPString)
         {
-            return indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl;
+            buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl);
         }
         else if (obj instanceof DERT61String)
         {
-            return indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl;
+            buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl);
         }
         else if (obj instanceof DERUTCTime)
         {
-            return indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl;
+            buf.append(indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl);
         }
         else if (obj instanceof DERGeneralizedTime)
         {
-            return indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl;
+            buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl);
         }
         else if (obj instanceof DERUnknownTag)
         {
-            return indent + "Unknown " + Integer.toString(((DERUnknownTag)obj).getTag(), 16) + " " + new String(Hex.encode(((DERUnknownTag)obj).getData())) + nl;
+            buf.append(indent + "Unknown " + Integer.toString(((DERUnknownTag)obj).getTag(), 16) + " " + new String(Hex.encode(((DERUnknownTag)obj).getData())) + nl);
         }
         else if (obj instanceof BERApplicationSpecific)
         {
-            return outputApplicationSpecific("BER", indent, verbose, obj, nl);
+            buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl));
         }
         else if (obj instanceof DERApplicationSpecific)
         {
-            return outputApplicationSpecific("DER", indent, verbose, obj, nl);
+            buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl));
+        }
+        else if (obj instanceof DERExternal){
+            DERExternal ext = (DERExternal) obj;
+            buf.append(indent + "External " + nl);
+            String          tab = indent + TAB;
+            if (ext.getDirectReferemce() != null){
+                buf.append(tab + "Direct Reference: " + ext.getDirectReferemce().getId() + nl);
+            }
+            if (ext.getIndirectReference() != null){
+                buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl);
+            }
+            if (ext.getDataValueDescriptor() != null){
+                _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf);
+            }
+            buf.append(tab + "Encoding: " + ext.getEncoding() + nl);
+            _dumpAsString(tab, verbose, ext.getExternalContent(), buf);
         }
         else
         {
-            return indent + obj.toString() + nl;
+            buf.append(indent + obj.toString() + nl);
         }
     }
-
+    
     private static String outputApplicationSpecific(String type, String indent, boolean verbose, DERObject obj, String nl)
     {
         DERApplicationSpecific app = (DERApplicationSpecific)obj;
@@ -340,7 +358,7 @@
                 buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
                 for (Enumeration e = s.getObjects(); e.hasMoreElements();)
                 {
-                    buf.append(_dumpAsString(indent + TAB, verbose, (DERObject)e.nextElement()));
+                    _dumpAsString(indent + TAB, verbose, (DERObject)e.nextElement(), buf);
                 }
             }
             catch (IOException e)
@@ -376,16 +394,29 @@
         Object   obj,
         boolean  verbose)
     {
-        if (obj instanceof DERObject)
-        {
-            return _dumpAsString("", verbose, (DERObject)obj);
+        StringBuffer buf = new StringBuffer();
+        try{
+            if (obj instanceof DERObject)
+            {
+                _dumpAsString("", verbose, (DERObject)obj, buf);
+            }
+            else if (obj instanceof DEREncodable)
+            {
+                _dumpAsString("", verbose, ((DEREncodable)obj).getDERObject(), buf);
+            }
+            else{
+                return "unknown object type " + obj.toString();
+            }
         }
-        else if (obj instanceof DEREncodable)
-        {
-            return _dumpAsString("", verbose, ((DEREncodable)obj).getDERObject());
+        catch(Exception e){
+            buf.append("\nError while trying to dump DER-data: ");
+            buf.append(e.getMessage());
+            buf.append("\n");
+            StringWriter sw = new StringWriter();
+            e.printStackTrace(new PrintWriter(sw, true));
+            buf.append(sw.toString());
         }
-
-        return "unknown object type " + obj.toString();
+        return buf.toString();
     }
 
     private static String dumpBinaryDataAsString(String indent, byte[] bytes)
Index: util/DERDump.java
===================================================================
RCS file: /home/users/bouncy/cvsroot/java/crypto/src/org/bouncycastle/asn1/util/DERDump.java,v
retrieving revision 1.2
diff -u -r1.2 DERDump.java
--- util/DERDump.java 9 Mar 2009 00:26:09 -0000 1.2
+++ util/DERDump.java 12 Oct 2009 12:58:56 -0000
@@ -7,7 +7,6 @@
  * @deprecated use ASN1Dump.
  */
 public class DERDump
-    extends ASN1Dump
 {
     /**
      * dump out a DER object as a formatted string
@@ -17,7 +16,7 @@
     public static String dumpAsString(
         DERObject   obj)
     {
-        return _dumpAsString("", false, obj);
+        return ASN1Dump.dumpAsString(obj, false);
     }
 
     /**
@@ -28,6 +27,6 @@
     public static String dumpAsString(
         DEREncodable   obj)
     {
-        return _dumpAsString("", false, obj.getDERObject());
+        return ASN1Dump.dumpAsString(obj.getDERObject(), false);
     }
 }
Index: DERExternal.java
===================================================================
RCS file: DERExternal.java
diff -N DERExternal.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ DERExternal.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,206 @@
+/*
+ * Created on 09.10.2009
+ *
+ */
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Class representing the DER-type External
+ * @author Lothar Kimmeringer <lothar@...>
+ *
+ */
+public class DERExternal extends ASN1Object {
+    private DERObjectIdentifier directReferemce;
+    private DERInteger indirectReference;
+    private ASN1Object dataValueDescriptor;
+    private int encoding;
+    private DERObject externalContent;
+    
+    public DERExternal(DEREncodableVector vector){
+        int offset = 0;
+        DERObject enc = vector.get(offset).getDERObject();
+        if (enc instanceof DERObjectIdentifier){
+            directReferemce = (DERObjectIdentifier) enc;
+            offset++;
+            enc = vector.get(offset).getDERObject();
+        }
+        if (enc instanceof DERInteger){
+            indirectReference = (DERInteger) enc;
+            offset++;
+            enc = vector.get(offset).getDERObject();
+        }
+        if (!(enc instanceof DERTaggedObject)){
+            dataValueDescriptor = (ASN1Object) enc;
+            offset++;
+            enc = vector.get(offset).getDERObject();
+        }
+        if (!(enc instanceof DERTaggedObject)){
+            throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
+        }
+        DERTaggedObject obj = (DERTaggedObject) enc;
+        encoding = obj.getTagNo();
+        externalContent = obj.getDERObject();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        int ret = 0;
+        if (directReferemce != null){
+            ret = directReferemce.hashCode();
+        }
+        if (indirectReference != null){
+            ret ^= indirectReference.hashCode();
+        }
+        if (dataValueDescriptor != null){
+            ret ^= dataValueDescriptor.hashCode();
+        }
+        ret ^= externalContent.hashCode();
+        return ret;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.DERObject#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(DEROutputStream out) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if (directReferemce != null){
+            baos.write(directReferemce.getDEREncoded());
+        }
+        if (indirectReference != null){
+            baos.write(indirectReference.getDEREncoded());
+        }
+        if (dataValueDescriptor != null){
+            baos.write(dataValueDescriptor.getDEREncoded());
+        }
+        DERTaggedObject obj = new DERTaggedObject(DERTags.EXTERNAL, externalContent);
+        baos.write(obj.getDEREncoded());
+        out.writeEncoded(DERTags.CONSTRUCTED, DERTags.EXTERNAL, baos.toByteArray());
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.ASN1Object#asn1Equals(org.bouncycastle.asn1.DERObject)
+     */
+    boolean asn1Equals(DERObject o) {
+        if (!(o instanceof DERExternal)){
+            return false;
+        }
+        if (this == o){
+            return true;
+        }
+        DERExternal other = (DERExternal) o;
+        if (directReferemce != null){
+            if (other.directReferemce == null || !other.directReferemce.equals(directReferemce)){
+                return false;
+            }
+        }
+        if (indirectReference != null){
+            if (other.indirectReference == null || !other.indirectReference.equals(indirectReference)){
+                return false;
+            }
+        }
+        if (dataValueDescriptor != null){
+            if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor)){
+                return false;
+            }
+        }
+        return externalContent.equals(other.externalContent);
+    }
+
+    /**
+     * Returns the data value descriptor
+     * @return The descriptor
+     */
+    public ASN1Object getDataValueDescriptor() {
+        return dataValueDescriptor;
+    }
+
+    /**
+     * Sets the data value descriptor
+     * @param dataValueDescriptor The descriptor
+     */
+    public void setDataValueDescriptor(ASN1Object dataValueDescriptor) {
+        this.dataValueDescriptor = dataValueDescriptor;
+    }
+
+    /**
+     * Returns the direct reference of the external element
+     * @return The reference
+     */
+    public DERObjectIdentifier getDirectReferemce() {
+        return directReferemce;
+    }
+
+    /**
+     * Sets the direct reference of the external element
+     * @param directReferemce The reference
+     */
+    public void setDirectReferemce(DERObjectIdentifier directReferemce) {
+        this.directReferemce = directReferemce;
+    }
+    
+    /**
+     * Returns the encoding of the content. Valid values are
+     * <ul>
+     * <li><code>0</code> single-ASN1-type</li>
+     * <li><code>1</code> OCTET STRING</li>
+     * <li><code>2</code> BIT STRING</li>
+     * </ul>
+     * @return The encoding
+     */
+    public int getEncoding() {
+        return encoding;
+    }
+    
+    /**
+     * Sets the encoding of the content. Valid values are
+     * <ul>
+     * <li><code>0</code> single-ASN1-type</li>
+     * <li><code>1</code> OCTET STRING</li>
+     * <li><code>2</code> BIT STRING</li>
+     * </ul>
+     * @param encoding The encoding
+     */
+    public void setEncoding(int encoding) {
+        if (encoding < 0 || encoding > 2){
+            throw new IllegalArgumentException("invalid encoding value");
+        }
+        this.encoding = encoding;
+    }
+    
+    /**
+     * Returns the content of this element
+     * @return The content
+     */
+    public DERObject getExternalContent() {
+        return externalContent;
+    }
+    
+    /**
+     * Sets the content of this element
+     * @param externalContent The content
+     */
+    public void setExternalContent(DERObject externalContent) {
+        this.externalContent = externalContent;
+    }
+    
+    /**
+     * Returns the indirect reference of this element
+     * @return The reference
+     */
+    public DERInteger getIndirectReference() {
+        return indirectReference;
+    }
+    
+    /**
+     * Sets the indirect reference of this element
+     * @param indirectReference The reference
+     */
+    public void setIndirectReference(DERInteger indirectReference) {
+        this.indirectReference = indirectReference;
+    }
+}
Index: DERExternalParser.java
===================================================================
RCS file: DERExternalParser.java
diff -N DERExternalParser.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ DERExternalParser.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,40 @@
+/*
+ * Created on 09.10.2009
+ *
+ */
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * @author Lothar Kimmeringer <lothar@...>
+ *
+ */
+public class DERExternalParser implements DEREncodable{
+    private ASN1StreamParser _parser;
+
+    /**
+     *
+     */
+    public DERExternalParser(ASN1StreamParser parser) {
+        this._parser = parser;
+    }
+
+    public DEREncodable readObject() throws IOException{
+        try{
+            return new DERExternal(_parser.readVector());
+        }
+        catch(IllegalArgumentException iae){
+            throw (IOException) new IOException("unable to read in external data").initCause(iae);
+        }
+    }
+    
+    public DERObject getDERObject() {
+        try{
+            return new DERExternal(_parser.readVector());
+        }
+        catch(IOException ioe){
+            throw new IllegalArgumentException("unable to get DER object", ioe);
+        }
+    }
+}