iaik.asn1
Class DerInputStream

java.lang.Object
  |
  +--java.io.InputStream
        |
        +--iaik.asn1.DerInputStream

public class DerInputStream
extends InputStream

This class can be used to parse an InputStream containing DER encoded data. The advantage of this class is the possibility to process single ASN.1 types without reading the whole object. This class shall be used for dealing with large ASN.1 objects.

For any ASN.1 type implemented by IAIK-JCE, this class provides a specific method to be used for parsing the corresponding value from the stream. The, for instance, readInteger method decodes an ASN.1 INTEGER type from the stream and parses it for obtaining the inherent int value. Where possible, immediately the inherent Java value is returned when calling a specific readASN1Type method for the requested ASN.1 type (e.g. a Java BigInteger value for an ASN.1 INTEGER type, parsed by means of the readInteger method as stated above. Otherwise, when reading a constructed type from the stream, a new DerInputStream instance is returned to be parsed for any containing ASN.1 objects. In this way, the DerInputStream class works in a recursive manner. Consider, for instance a SEQUENCE structure that contains another SEQUENCE structure as one of its components:

 someASN1Type  ::=  SEQUENCE  {
   ...
   ...
   component_3           someFurtherASN1Type
   ...
 }
 someFurtherASN1Type ::= SEQUENCE {
   ...
 }
 

When calling the readSequence() method for the inherent component_3 a new DerInputInputStream is returned to be parsed for getting the several ASN.1 objects included in the corresponding subordinate SEQUENCE component. After parsing the last object from the sub-DerInputStream, any remaining EOC octets - in the case of indefinite length encoding - are read and the super DerInputStream automatically is notified that the end of the sub-stream has been reached. Now the parsing of the super-stream can be continued to get any further components following the component_3 sequence. It is essential entirely to parse (read) the sub-DerInputStream before continuing to parse the super-stream; otherwise an Exception will be thrown.

This class only contains one public constructor for creating a DerInputStream to be used for decoding and parsing ASN.1 object values from a DER encoded data supplying input stream. The following example instantiates the DerInputStream for parsing a SEQUENCE object consisting of three components: an INTEGER object with value 1, an OCTET_STRING component with byte value 01:34:AB, and a PrintableString containing the test message "test":

 //first create the SEQUENCE object and its components:
 INTEGER i = new INTEGER(1);
 byte[] b = { (byte)0x01, (byte)0x34, (byte)0xAB };
 OCTET_STRING o = new OCTET_STRING(b);
 PrintableString p = new PrintableString("test");
 SEQUENCE seq = new SEQUENCE();
 seq.addComponent(i);
 seq.addComponent(o);
 seq.addComponent(p);
 //now encode the SEQUENCE:
 byte[] encoding = DerCoder.encode(seq);
 //for testing the DerInputStream create a ByteArrayInputStream on the encoding:
 ByteArrayInputStream bais = new ByteArrayInputStream(encoding);
 //now initialize the DerInputStream for the DER encoded data supplying stream:
 DerInputStream der_is = new DerInputStream(bais);
 //read the SEQUENCE:
 DerInputStream seq_is = ((DerInputStream)der_is).readSequence();
 //parse the INTEGER value:
 int i_ = seq_is.readInteger().intValue();
 System.out.println("INTEGER value: " + i_);
 //read and parse the OCTET_STRING component:
 ByteArrayInputStream is = (ByteArrayInputStream)seq_is.readOctetString();
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 int r = -1;
 while ((r = is.read()) != -1) {
   baos.write(r);
 }
 System.out.println("OCTET_STRING value: " + Util.toString(baos.toByteArray()));
 //finally read the PrintableString component
 String s = seq_is.readString();
 System.out.println("PrintableString value: " + s);
 
When using the DerInputStream for decoding DER encoded data, the internal structure of the ASN1Object to be parsed from the stream has to be known in advance. As an alternative, a proper decode method of the DerCoder class may be utilized. These methods will return a general ASN1Object instance from the DER encoding, that may be further parsed for recovering its internal structure. The DerCoder class, however, only shall be used for ASN.1 structures of reasonable size, because whole the data is processed within the memory.

Version:
File Revision 34

Field Summary
static int APPLICATION
          Tag class: application
static int BIT_STRING
          Global ASN.1 type BIT_STRING
static int BMPString
          Global ASN.1 type BMPString
static int BOOLEAN
          Global ASN.1 type BOOLEAN
static int CONSTRUCTED
          Constant for constructed tags.
static int CONTEXT_SPECIFIC
          Tag class: context-specific
static int ENUMERATED
          Global ASN.1 type ENUMERATED
static int EXTERNAL
          Global ASN.1 type EXTERNAL
static int GeneralizedTime
          Global ASN.1 type GeneralizedTime (any time precision according to the ISO 2014 norm)
static int GeneralString
          Global ASN.1 type GeneralString
static int IA5String
          Global ASN.1 type IA5String (String of ASCII characters)
static int INTEGER
          Global ASN.1 type INTEGER
static int NULL
          Global ASN.1 type NULL
static int NumericString
          Global ASN.1 type NumericString
static int OBJECT_DESCRIPTOR
          Global ASN.1 type OBJECT_DESCRIPTOR
static int OBJECT_ID
          Global ASN.1 type ObjectID
static int OCTET_STRING
          Global ASN.1 type OCTET_STRING
static int PrintableString
          Global ASN.1 type PrintableString
static int PRIVATE
          Tag class: private
static int SEQUENCE
          Global ASN.1 type SEQUENCE
static int SET
          Global ASN.1 type SET
static int T61String
          Global ASN.1 type T61String (TeletexString; eight-bit extension to the ASCII character set )
static int UNIString
          Global ASN.1 type UniversalString
static int UNIVERSAL
          Tag class: universal
static int UTCTime
          Global ASN.1 type UTCTime (coordinated universal time) (maximum precision down to seconds)
static int UTF8String
          Global ASN.1 type UTF8String
static int VisibleString
          Global ASN.1 type VisibleString (ISO 646 String)
 
Constructor Summary
DerInputStream(InputStream is)
          Creates a new DerInputStream to read data from the specified input stream.
 
Method Summary
 int available()
          Returns the number of bytes available for this stream.
 void close()
          Closes this input stream.
 int getTag()
          Returns the tag of the ASN1 type this DerInputStream currently is parsing.
 boolean nextIsApplication()
          Returns true if the next tag is APPLICATION.
 boolean nextIsConstructed()
          Returns true if the next tag is CONSTRUCTED.
 boolean nextIsContextSpecific()
          Returns true if the next tag is CONTEXT SPECIFIC.
 boolean nextIsPrivate()
          Returns true if the next tag is PRIVATE.
 boolean nextIsUniversal()
          Returns true if the next tag is UNIVERSAL.
 int nextTag()
          Returns the next tag number without reading it from the stream.
 int read()
          Reads one byte from this InputStream.
 int read(boolean unread)
          Reads one byte from this InputStream.
 int read(byte[] b, int off, int len)
          Reads bytes into a portion of an array.
 BIT_STRING readBitString()
          Reads a BIT STRING from the input stream.
 boolean readBoolean()
          Reads a BOOLEAN from the input stream.
 DerInputStream readConstructed()
          Reads any CONSTRUCTED ASN.1 type from the input stream.
 DerInputStream readContextSpecific()
          Reads an explicitly tagged CONTEXT SPECIFIC ASN.1 type from the input stream.
 int readContextSpecific(int tag)
          Reads an implicitly tagged CONTEXT SPECIFIC ASN.1 type.
 void readEOC()
          Reads final EOC octets from an indefinite length encoded constructed stream.
 GeneralizedTime readGeneralizedTime()
          Reads a GeneralizedTime from the input stream.
 BigInteger readInteger()
          Reads an INTEGER from the input stream.
 void readNull()
          Reads an ASN.1 NULL object from the input stream.
 ObjectID readObjectID()
          Reads an ObjectID from the input stream.
 InputStream readOctetString()
          Reads an OCTET STRING and returns it as a new InputStream.
 byte[] readOctetStringByteArray()
          Reads a primitive encoded OCTET STRING from the input stream and returns the content as a byte array.
 DerInputStream readSequence()
          Reads a SEQUENCE from the input stream.
 DerInputStream readSet()
          Reads a SET from the input stream.
 String readString()
          Reads an ASN.1 string type from the input stream.
 UTCTime readUTCTime()
          Reads an UTCTime from the input stream.
 long skip(long n)
          Skips n bytes.
 int skipObjects(int n)
          Skips a number of ASN.1 objects.
 
Methods inherited from class java.io.InputStream
mark, markSupported, read, reset
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

UNIVERSAL

public static final int UNIVERSAL
Tag class: universal

APPLICATION

public static final int APPLICATION
Tag class: application

CONTEXT_SPECIFIC

public static final int CONTEXT_SPECIFIC
Tag class: context-specific

PRIVATE

public static final int PRIVATE
Tag class: private

CONSTRUCTED

public static final int CONSTRUCTED
Constant for constructed tags.

BOOLEAN

public static final int BOOLEAN
Global ASN.1 type BOOLEAN

INTEGER

public static final int INTEGER
Global ASN.1 type INTEGER

BIT_STRING

public static final int BIT_STRING
Global ASN.1 type BIT_STRING

OCTET_STRING

public static final int OCTET_STRING
Global ASN.1 type OCTET_STRING

NULL

public static final int NULL
Global ASN.1 type NULL

OBJECT_ID

public static final int OBJECT_ID
Global ASN.1 type ObjectID

OBJECT_DESCRIPTOR

public static final int OBJECT_DESCRIPTOR
Global ASN.1 type OBJECT_DESCRIPTOR

EXTERNAL

public static final int EXTERNAL
Global ASN.1 type EXTERNAL

ENUMERATED

public static final int ENUMERATED
Global ASN.1 type ENUMERATED

UTF8String

public static final int UTF8String
Global ASN.1 type UTF8String

SEQUENCE

public static final int SEQUENCE
Global ASN.1 type SEQUENCE

SET

public static final int SET
Global ASN.1 type SET

NumericString

public static final int NumericString
Global ASN.1 type NumericString

PrintableString

public static final int PrintableString
Global ASN.1 type PrintableString

T61String

public static final int T61String
Global ASN.1 type T61String (TeletexString; eight-bit extension to the ASCII character set )

IA5String

public static final int IA5String
Global ASN.1 type IA5String (String of ASCII characters)

UTCTime

public static final int UTCTime
Global ASN.1 type UTCTime (coordinated universal time) (maximum precision down to seconds)

GeneralizedTime

public static final int GeneralizedTime
Global ASN.1 type GeneralizedTime (any time precision according to the ISO 2014 norm)

VisibleString

public static final int VisibleString
Global ASN.1 type VisibleString (ISO 646 String)

GeneralString

public static final int GeneralString
Global ASN.1 type GeneralString

UNIString

public static final int UNIString
Global ASN.1 type UniversalString

BMPString

public static final int BMPString
Global ASN.1 type BMPString
Constructor Detail

DerInputStream

public DerInputStream(InputStream is)
Creates a new DerInputStream to read data from the specified input stream. The given input stream supplies DER encoded data. This constrcutor creates a new DerInputStream for parsing any ASN.1 objects represented by the DER encoding and getting the inherent Java type vaues.
Parameters:
is - the InputStream supplying DER encoded data
Method Detail

skipObjects

public int skipObjects(int n)
                throws IOException
Skips a number of ASN.1 objects. When parsing a structured ASN.1 object from the stream, this method may be used for skipping a specific number of components. Consider, for instance, a SEQEUNCE object containing an INTEGER, an OCTET_STRING, and a PrintableString component. The following code example will parse the first component (INTEGER), skip the second component (OCTET_STRING), and finally get the value of the last PrintableString component:
 //the stream supplying the DER encoded sequence:
 InputStream is = ...;
 //create a DerInputStream for parsing the DER encoded data:
 DerInputStream der_is = new DerInputStream(is);
 //read the sequence:
 DerInputStream seq_is = ((DerInputStream)der_is).readSequence();
 //parse the first component (INTEGER) from the sequence
 int i_ = seq_is.readInteger().intValue();
 System.out.println("Int value: " + i_);
 //now skip the second component:
 seq_is.skipObjects(1);
 //finally parse the last component (PrintableString):
 String s = seq_is.readString();
 System.out.println("Printable String: " + s);
 
Parameters:
n - the number of ASN.1 objects to skip or -1 for skipping all objects till the end of this stream
Returns:
the number of ASN.1 objects actually skipped
Throws:
IOException - if an I/O or a DER decoding error occurs

available

public int available()
Returns the number of bytes available for this stream. This method actually returns the value of the length octet(s), i.e. the number of content octets used by this DerInputStream for representing the value of particular ASN.1 object it suppies. If the indefinite length encoding is used, -1 is returned. And if this is the super (top) stream, -2 is returned.
Overrides:
available in class InputStream
Returns:
the number of bytes available for this stream

close

public void close()
           throws IOException
Closes this input stream.
Overrides:
close in class InputStream

readEOC

public void readEOC()
             throws IOException
Reads final EOC octets from an indefinite length encoded constructed stream. This method may be called to properly finsih a indefinte length constructed decoding.
Throws:
IOException - if the indefinite length encoding is not properly closed by two EOC octets of all zeros

nextTag

public int nextTag()
            throws IOException
Returns the next tag number without reading it from the stream. When parsing the encoding of a structured ASN.1 object this method may be used for asking for the ASN.1 type of the next component without actually reading the tag. Supposing an input stream supplies the DER encoding of a SEQUENCE object, this method may be used as follows:
 //the stream supplying the DER encoded sequence:
 InputStream is = ...;
 //create a DerInputStream for parsing the DER encoded data:
 DerInputStream der_is = new DerInputStream(is);
 //read the sequence:
 DerInputStream seq_is = ((DerInputStream)der_is).readSequence();
 ...
 //parse components
 ...
 //look if the next component is an OCTET_STRING:
 if (seq_is.nectTag() == DerInputStream.OCTET_STRING) {
   InputStream is = seq_is.readOctetString();
 }
 ...
 
If no further tag can be read from the stream this method returns -1. This behaviour may be useful for querying if the end of the stream already has been, or if there are any further optional components:
 if (seq_is.nextTag() != -1) {
  ...
 //continue parsing
 }
 
Returns:
the tag number of the next ASN1Object or -1 if the end of the stream has been reached
Throws:
IOException - if an I/O or a DER decoding error occurs

readBoolean

public boolean readBoolean()
                    throws IOException
Reads a BOOLEAN from the input stream. When using this method to read an ASN.1 BOOLEAN type from the DerInputStream immediately the inherent boolean Java value (true/false) is returned, e.g.:
 DerInputStream der_is = new DerInputStream(encodedStream);
 boolean bool_value = der_is.readBoolean();
 System.out.println(bool_value ? "true" : "false");
 
Returns:
the inherent boolean value (true/false) when reading an ASN.1 BOOLEAN type from the stream
Throws:
IOException - if an I/O or a DER decoding error occurs

readInteger

public BigInteger readInteger()
                       throws IOException
Reads an INTEGER from the input stream. When using this method to read an ASN.1 INTEGER type from the DerInputStream immediately the inherent Java value of type BigInteger is returned, e.g.:
 DerInputStream der_is = new DerInputStream(encodedStream);
 BigInteger int_value = der_is.readInteger();
 System.out.println(int_value.intValue());
 
Returns:
the inherent BigInteger when reading an ASN.1 type INTEGER from the DerInputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readBitString

public BIT_STRING readBitString()
                         throws IOException
Reads a BIT STRING from the input stream. After reading an BIT_STRING object from the DerInputStream, use the getValue or getBinaryString method for obtaining the inherent value:
 DerInputStream der_is = new DerInputStream(encodedStream);
 BIT_STRING bit_string = der_is.readBitString();
 System.out.println(bit_string.getBinaryString());
 
Returns:
the next BIT STRING
Throws:
IOException - if an I/O or a DER decoding error occurs

readOctetStringByteArray

public byte[] readOctetStringByteArray()
                                throws IOException
Reads a primitive encoded OCTET STRING from the input stream and returns the content as a byte array. This method only can properly handle primitive definite encoded OCTET_STRING objects (identifer tag 0x04), e.g:
 byte[] value = { (byte)0x03, (byte)0x07, (byte)0x05 };
 OCTET_STRING oct = new OCTET_STRING(value);
 byte[] encoding = DerCoder.encode(oct);
 //now use DerInputStream for decoding:
 DerInputStream der_is = new DerInputStream(new ByteArrayInputStream(encoding));
 byte[] oct_value = der_is.readOctetStringByteArray();
 
For decoding constructed OCTET_STRING objects, use the readOctetString() method.
Returns:
the inherent (byte array) value when reading an primitive encoded OCTET STRING type from the DerInputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readOctetString

public InputStream readOctetString()
                            throws IOException
Reads an OCTET STRING and returns it as a new InputStream. This method handles primitive and constructed encoded OCTET STRINGs.

Large amounts of data are usualy encoded as a constructed OCTET STRING. The DER encoding looks like:

 24                   constructed OCTET STRING
   80                 indefinite length encoding
     04 03 01:02:03   3 bytes of data
     04 xx ...        the next OCTET STRING
     ...              a lot of OCTET STRINGs with definite length encoding
 00:00                end of indefinite length encoding
 
This method first reads the identifier tag from the stream and checks whether it actually initiates an octet string. If the tag is not equal to hexadecimal 0x04 (a primitive octet string) or hexadecimal 0x24 (a constructed octet string), an IOException is thrown.

If the tag number is 0x04 a primitive octet string is expected, and an ordinary ByteArrayInputStream is returned holding the raw data.

If the tag number is 0x24, the encoding represents an constructed octet string to be parsed for the inherent components. If all components are primitive definite encoded, this method returns an instance of an OctetInputStream which is an inner class of thie DerInputStream class. The several read methods of the OctetInputStream class can be used for reading the raw data from all included definite primitive encoded octet string components. The components are parsed one after the other and only the inherent data bytes are returned, making it possible to actually handle rather small blocks within the memory, depending on the length of each primitive octet string encoding.

It is important to know that the OctetInputStream class only can be used to parse pure definite primitive encoded octet strings, or constructed octet strings consisting only of a certain number of definite primitive encoded octet strings, e.g.:

 24                   constructed OCTET STRING
   80                 indefinite length encoding
     04 03 01:02:03   3 bytes of data
     04 xx ...        the next OCTET STRING
     ...              a lot of OCTET STRINGs with definite length encoding
 00:00
 
TheOctetInputStream class is not able to resolve an encoding that represents an arbitrary nested octet string structure.

Furthermore it is important to know that this readOctetString method expects a series of primitive definite encoded octet strings, whenever it parses a primitive octet string as first octet string component of a constructed octet string (i.e. when an 0x04 comes after an 0x24). So, if a series of definite primitive encoded octet strings is discontinued by an octet string that is constructed encoded, the decoding process will fail! However, when a constructed encoded octet string component comes before a primitive encoded component, readOctetString will return a new DerInputStream instance rather than an OctetInputStream. This new DerInputStream again may be searched for any containing octet string components by calling the readOctetString method.

For that reason, it is recommended only to use this readOctetString method for parsing octet string encodings that represent constructed octet strings having only primitive definite encoded octet string components!

If, for instance, a constructed octet string has the following structure:

 24
    80
       04 02 05 07
       04 02 01 AB
       04 01 34
 00 00
 
the following code fragment will parse whole the value (05:07:01:AB:34) from the DerInputStream:
 //first build the octet string:
 byte[] value = { (byte)0x05, (byte)0x07, (byte)0x01, (byte)0xAB, (byte)0x34 };
 OCTET_STRING oct = new OCTET_STRING(new ByteArrayInputStream(value),2);
 //use DerCoder.encodeTo for recognizing the internal structure:
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 DerCoder.encodeTo(oct, baos);
 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 //now do the decoding:
 DerInputStream der_is = new DerInputStream(bais);
 InputStream is = der_is.readOctetString();
 //read the inherent value:
 baos.reset();
 StreamCopier sp = new StreamCopier(is, baos);
 sp.copyStream();
 System.out.println(Util.toString(baos_.toByteArray()));
 
Returns:
an InputStream for reading the content of the OCTET STRING
Throws:
IOException - if an I/O or a DER decoding error occurs

readNull

public void readNull()
              throws IOException
Reads an ASN.1 NULL object from the input stream.
Throws:
IOException - if an I/O or a DER decoding error occurs

readObjectID

public ObjectID readObjectID()
                      throws IOException
Reads an ObjectID from the input stream.
Returns:
the next ObjectID
Throws:
IOException - if an I/O or a DER decoding error occurs

readString

public String readString()
                  throws IOException
Reads an ASN.1 string type from the input stream. The following types can be read: Regardless of the specific ASN.1 String type parsed from the stream, this method will return the inherent Java String value, e.g.:
 DerInputStream der_is = new DerInputStream(encodedStream);
 String s = der_is.readString();
 System.out.println(s);
 
Returns:
the inherent Java String value when reading a ASN.1 STRING type from the DerinputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readUTCTime

public UTCTime readUTCTime()
                    throws IOException
Reads an UTCTime from the input stream.
Returns:
the next UTCTime
Throws:
IOException - if an I/O or a DER decoding error occurs

readGeneralizedTime

public GeneralizedTime readGeneralizedTime()
                                    throws IOException
Reads a GeneralizedTime from the input stream.
Returns:
the next GeneralizedTime
Throws:
IOException - if an I/O or a DER decoding error occurs

readSequence

public DerInputStream readSequence()
                            throws IOException
Reads a SEQUENCE from the input stream. This method returns a new DerInputStream instance for parsing an ASN.1 SEQUENCE type from the main DerInputStream. Remember, that the DerInputStream class works in a recursive manner. Consider, for instance a SEQUENCE structure that contains another SEQUENCE structure as one of its components:
 someASN1Type  ::=  SEQUENCE  {
   ...
   ...
   component_3           someFurtherASN1Type
   ...
 }
 someFurtherASN1Type ::= SEQUENCE {
   ...
 }
 

When calling the readSequence() method for the inherent component_3 a new DerInputInputStream is returned to be parsed for getting the several ASN.1 objects included in the corresponding subordinate SEQUENCE component. After parsing the last object from the sub-DerInputStream, any remaining EOC octets - in the case of indefinite length encoding - are read and the super DerInputStream automatically is notified that the end of the sub-stream has been reached. Now the parsing of the super-stream can be continued to get any further components following the component_3 sequence. It is essential entirely to parse (read) the sub-DerInputStream before continuing to parse the super-stream; otherwise an Exception will be thrown.

The following example uses the readOctetString method for parsing a SEQUENCE object consisting of three components: an INTEGER object with value 1, an OCTET_STRING component with byte value 01:34:AB, and a PrintableString containing the test message "test":

 //first create the SEQUENCE object and its components:
 INTEGER i = new INTEGER(1);
 byte[] b = { (byte)0x01, (byte)0x34, (byte)0xAB };
 OCTET_STRING o = new OCTET_STRING(b);
 PrintableString p = new PrintableString("test");
 SEQUENCE seq = new SEQUENCE();
 seq.addComponent(i);
 seq.addComponent(o);
 seq.addComponent(p);
 //now encode the SEQUENCE:
 byte[] encoding = DerCoder.encode(seq);
 //for testing the DerInputStream create a ByteArrayInputStream on the encoding:
 ByteArrayInputStream bais = new ByteArrayInputStream(encoding);
 //now initialize the DerInputStream for the DER encoded data supplying stream:
 DerInputStream der_is = new DerInputStream(bais);
 //reading the SEQUENCE will give a new subordinate DerInputStream:
 DerInputStream seq_is = ((DerInputStream)der_is).readSequence();
 //parse the INTEGER value:
 int i_ = seq_is.readInteger().intValue();
 System.out.println("INTEGER value: " + i_);
 //read and parse the OCTET_STRING component:
 ByteArrayInputStream is = (ByteArrayInputStream)seq_is.readOctetString();
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 int r = -1;
 while ((r = is.read()) != -1) {
   baos.write(r);
 }
 System.out.println("OCTET_STRING value: " + Util.toString(baos.toByteArray()));
 //finally read the PrintableString component
 String s = seq_is.readString();
 System.out.println("PrintableString value: " + s);
 
Returns:
the content of the next SEQUENCE as a new DerInputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readSet

public DerInputStream readSet()
                       throws IOException
Reads a SET from the input stream. This method returns a new DerInputStream instance for parsing an ASN.1 SET type from the main DerInputStream. The new DerInputStream has to be parsed for obtaining the components of the ASN.1 SET object it represents. After completely having parsed the SET-DerInputStream, the parsing of the main DerInputStream may be continued. In this way, the usage of this method corresponds to that of the readSequence() method.
Returns:
the content of the next SET as a new DerInputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readConstructed

public DerInputStream readConstructed()
                               throws IOException
Reads any CONSTRUCTED ASN.1 type from the input stream. This method returns a new DerInputStream instance for parsing an constructed ASN.1 type from the main DerInputStream. After completely having parsed the new DerInputStream, the parsing of the main DerInputStream may be continued.

In this way, this method provides, for example, a more general usage of the readSequence() method for reading an ASN.1 SEQUENCE object; and so the following two code fragments will give the same result for parsing a SEQUENCE object consisting of one INTEGER and one BOOLEAN component:

 //first build the test sequence:
 SEQUENCE sequence = new SEQUENCE();
 sequence.addComponent(new INTEGER(3));
 sequence.addComponent(new BOOLEAN(true));
 byte[] encoding = DerCoder.encode(sequence);
 
Now use readSequence() for performing decoding:
 DerInputStream der_is = new DerInputStream(new ByteArrayInputStream(encoding));
 DerInputStream seq_is = der_is.readSequence();
 System.out.println(seq_is.readInteger().intValue());
 System.out.println(seq_is.readBoolean());
 
Now use readConstructed():
 DerInputStream der_is = new DerInputStream(new ByteArrayInputStream(encoding));
 DerInputStream constr_is = der_is.readConstructed();
 System.out.println(constr_is.readInteger().intValue());
 System.out.println(constr_is.readBoolean());
 
Returns:
the content of the next constructed ASN.1 type as a new DerInputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readContextSpecific

public DerInputStream readContextSpecific()
                                   throws IOException
Reads an explicitly tagged CONTEXT SPECIFIC ASN.1 type from the input stream. Explicitly tagging includes the tag of the underlying ASN.1 object in the encoding, and so the tag immediately can be parsed again when decoding the CONTEXT SPECIFIC from the stream. Since implicitly tagging does not include the tag of the underlying type, the receiving application has to take care for a correct decoding by setting the tag of the underlying base type by means of the readContextSpecific(int tag) method.

The following example creates a SEQUENCE object that includes an OCTET_STRING component that has to be context specific explicitly tagged. The decoding procedure uses a DerInputStream and utilizes this readContextSpecific method for parsing the explicitly tagged octet string:

 //create the SEQUENCE and add components:
 SEQUENCE seq = new SEQUENCE();
 INTEGER i = new INTEGER(1);
 byte[] b = { (byte)0x01, (byte)0x34, (byte)0xAB };
 iaik.asn1.OCTET_STRING o = new iaik.asn1.OCTET_STRING(b);
 PrintableString p = new PrintableString("test");
 seq.addComponent(i);
 //add the octet string as CON_SPEC with tag number 0, that has to be explicitly tagged:
 CON_SPEC con_spec = new CON_SPEC(0, o, false);
 seq.addComponent(con_spec);
 seq.addComponent(p);
 //DER encode the SEQUENCE:
 byte[] enc = DerCoder.encode(seq);
 //initialize a DerInputStream with the encoding:
 DerInputStream der_is = new DerInputStream(new ByteArrayInputStream(enc));
 //read the SEQUENCE:
 DerInputStream seq_is = ((DerInputStream)der_is).readSequence();
 //get the value of the first component (INTEGER) from the SEQUENCE:
 int i = seq_is.readInteger().intValue();
 System.out.println("Int value: " + i);
 //now parse the explicitly tagged context specific component:
 DerInputStream con_is = seq_is.readContextSpecific();
 //get the base octet string:
 InputStream is = con_is.readOctetString();
 //get the value from the octet string and print it to System.out:
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 int r = -1;
 while ((r = is.read()) != -1) {
     baos.write(r);
 }
 System.out.println("OCTET_STRING value: " + Util.toString(baos.toByteArray()));
 //now go back to seq_is for parsing the last component (PrintableSrting):
 System.out.println("Printable String: " + seq_is.readString());
 
Returns:
the content of the next context specific ASN.1 type as a new DerInputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

readContextSpecific

public int readContextSpecific(int tag)
                        throws IOException
Reads an implicitly tagged CONTEXT SPECIFIC ASN.1 type. This method replaces the the context specific tag with the provided tag and returns the context specific tag number.

Explicitly tagging includes the tag of the underlying ASN.1 object in the encoding, and so the tag immediately can be parsed again when decoding the CONTEXT SPECIFIC from the stream by using the readContextSpecific() method. Since implicitly tagging does not include the tag of the underlying type, the receiving application has to take care for a correct decoding by setting the tag of the underlying base type by means of this method.

The following example creates a SEQUENCE object that includes an OCTET_STRING component that has to be context specific implicitly tagged. The decoding procedure uses a DerInputStream and utilizes this readContextSpecific method for parsing the implicitly tagged octet string:

 //create the SEQUENCE and add components:
 SEQUENCE seq = new SEQUENCE();
 INTEGER i = new INTEGER(1);
 byte[] b = { (byte)0x01, (byte)0x34, (byte)0xAB };
 iaik.asn1.OCTET_STRING o = new iaik.asn1.OCTET_STRING(b);
 PrintableString p = new PrintableString("test");
 seq.addComponent(i);
 //add the octet string as CON_SPEC with tag number 0, that has to be implicitly tagged:
 CON_SPEC con_spec = new CON_SPEC(0, o, true);
 seq.addComponent(con_spec);
 seq.addComponent(p);
 //DER encode the SEQUENCE:
 byte[] enc = DerCoder.encode(seq);
 //initialize a DerInputStream with the encoding:
 DerInputStream der_is = new DerInputStream(new ByteArrayInputStream(enc));
 //read the SEQUENCE:
 DerInputStream seq_is = ((DerInputStream)der_is).readSequence();
 //get the value of the first component (INTEGER) from the SEQUENCE:
 int i = seq_is.readInteger().intValue();
 System.out.println("Int value: " + i);
 //now parse the implicitly tagged context specific component by specifying the
 //OCTET_STRING type:
 int con_tag = seq_is.readContextSpecific(DerInputStream.OCTET_STRING);
 InputStream is = seq_is.readOctetString();
 //get the value from the octet string and print it to System.out:
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 int r = -1;
 while ((r = is.read()) != -1) {
     baos.write(r);
 }
 System.out.println("OCTET_STRING value: " + Util.toString(baos.toByteArray()));
 //now go back to seq_is for parsing the last component (PrintableSrting):
 System.out.println("Printable String: " + seq_is.readString());
 
Parameters:
tag - the tag of the underlying base type (lost through DER encoding)
Returns:
the context specific tag [0,1,2,...]
Throws:
IOException - if an I/O or a DER decoding error occurs

getTag

public int getTag()
Returns the tag of the ASN1 type this DerInputStream currently is parsing. Mainly to be used for getting the underlying tag when parsing a context specific object.
Returns:
the tag

nextIsUniversal

public boolean nextIsUniversal()
                        throws IOException
Returns true if the next tag is UNIVERSAL. This method only checks the next tag without actually reading it from the stream.
Returns:
true if the next tag is UNIVERSAL, false if not
Throws:
IOException - if an I/O or a DER decoding error occurs

nextIsApplication

public boolean nextIsApplication()
                          throws IOException
Returns true if the next tag is APPLICATION. This method only checks the next tag without actually reading it from the stream.
Returns:
true if the next tag is APPLICATION, false if not
Throws:
IOException - if an I/O or a DER decoding error occurs

nextIsContextSpecific

public boolean nextIsContextSpecific()
                              throws IOException
Returns true if the next tag is CONTEXT SPECIFIC. This method only checks the next tag without actually reading it from the stream.
Returns:
true if the next tag is CONTEXT SPECIFIC false if not
Throws:
IOException - if an I/O or a DER decoding error occurs

nextIsPrivate

public boolean nextIsPrivate()
                      throws IOException
Returns true if the next tag is PRIVATE. This method only checks the next tag without actually reading it from the stream.
Returns:
true if the next tag is PRIVATE false if not
Throws:
IOException - if an I/O or a DER decoding error occurs

nextIsConstructed

public boolean nextIsConstructed()
                          throws IOException
Returns true if the next tag is CONSTRUCTED. This method only checks the next tag without actually reading it from the stream.
Returns:
true if the next tag is CONSTRUCTED false if not
Throws:
IOException - if an I/O or a DER decoding error occurs

read

public int read()
         throws IOException
Reads one byte from this InputStream. If the length encoding of this InputStream is indefinite no length checking is performed.
Overrides:
read in class InputStream
Returns:
the next byte from this InputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

read

public int read(boolean unread)
         throws IOException
Reads one byte from this InputStream. If the length encoding of this InputStream is indefinite no length checking is performed. If unread is set to true, the byte is pushed back again.
Parameters:
unread - true if the byte shall be unread
Returns:
the next byte from this InputStream
Throws:
IOException - if an I/O or a DER decoding error occurs

read

public int read(byte[] b,
                int off,
                int len)
         throws IOException
Reads bytes into a portion of an array. If the length encoding of this InputStream is indefinite no length checking is performed.
Overrides:
read in class InputStream
Parameters:
b - the byte array to which the data shall be read
off - the start offset of the data
len - the maximum number of bytes to be read
Returns:
the number of bytes actually read, or -1 if no more bytes can be read because the end of the stream already has been reached
Throws:
IOException - if an I/O or a DER decoding error occurs

skip

public long skip(long n)
          throws IOException
Skips n bytes.
Overrides:
skip in class InputStream
Parameters:
n - the number of bytes to be skipped
Throws:
IOException - if an I/O or a DER decoding error occurs

This Javadoc may contain text parts from Internet Standard specifications (RFC 2459, 3280, 3039, 2560, 1521, 821, 822, 2253, 1319, 1321, ,2630, 2631, 2268, 3058, 2984, 2104, 2144, 2040, 2311, 2279, see copyright note) and RSA Data Security Public-Key Cryptography Standards (PKCS#1,3,5,7,8,9,10,12, see copyright note).

IAIK-JCE 3.1 with IAIK-JCE CC Core 3.1, (c) 1997-2004 IAIK