public class DerInputStream
extends java.io.InputStream
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 the whole data is processed
within the memory.Modifier and Type | Field and Description |
---|---|
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 and Description |
---|
DerInputStream(java.io.InputStream is)
Creates a new DerInputStream to read data from the specified input stream.
|
Modifier and Type | Method and Description |
---|---|
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.
|
java.math.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.
|
java.io.InputStream |
readOctetString()
Reads an OCTET STRING and returns it as a new InputStream.
|
java.io.InputStream |
readOctetString(boolean skipOuter)
Reads an OCTET STRING and returns an input stream from which the content
can be read.
|
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.
|
java.lang.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.
|
public static final int UNIVERSAL
public static final int APPLICATION
public static final int CONTEXT_SPECIFIC
public static final int PRIVATE
public static final int CONSTRUCTED
public static final int BOOLEAN
BOOLEAN
public static final int INTEGER
INTEGER
public static final int BIT_STRING
BIT_STRING
public static final int OCTET_STRING
OCTET_STRING
public static final int NULL
NULL
public static final int OBJECT_ID
ObjectID
public static final int OBJECT_DESCRIPTOR
OBJECT_DESCRIPTOR
public static final int EXTERNAL
EXTERNAL
public static final int ENUMERATED
ENUMERATED
public static final int UTF8String
UTF8String
public static final int SEQUENCE
SEQUENCE
public static final int SET
SET
public static final int NumericString
NumericString
public static final int PrintableString
PrintableString
public static final int T61String
T61String
(TeletexString; eight-bit
extension to the ASCII character set )public static final int IA5String
IA5String
(String of ASCII characters)public static final int UTCTime
UTCTime
(coordinated universal time)
(maximum precision down to seconds)public static final int GeneralizedTime
GeneralizedTime
(any time precision
according to the ISO 2014 norm)public static final int VisibleString
VisibleString
(ISO 646 String)public static final int GeneralString
GeneralString
public static final int UNIString
UniversalString
public static final int BMPString
BMPString
public DerInputStream(java.io.InputStream is)
is
- the InputStream supplying DER/BER encoded datapublic int skipObjects(int n) throws java.io.IOException
//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);
n
- the number of ASN.1 objects to skip or -1 for skipping all objects
till the end of this streamjava.io.IOException
- if an I/O or a DER decoding error occurspublic int available()
available
in class java.io.InputStream
public void close() throws java.io.IOException
close
in interface java.io.Closeable
close
in interface java.lang.AutoCloseable
close
in class java.io.InputStream
java.io.IOException
public void readEOC() throws java.io.IOException
java.io.EOFException
- if an unexpected EOF occursjava.io.IOException
- (DerInputException) if the indefinite length encoding is not
properly closed by two EOC octets of all zerospublic int nextTag() throws java.io.IOException
//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 behavior 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 }
java.io.IOException
- if an I/O or a DER decoding error occurspublic boolean readBoolean() throws java.io.IOException
DerInputStream der_is = new DerInputStream(encodedStream); boolean bool_value = der_is.readBoolean(); System.out.println(bool_value ? "true" : "false");
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic java.math.BigInteger readInteger() throws java.io.IOException
DerInputStream der_is = new DerInputStream(encodedStream); BigInteger int_value = der_is.readInteger(); System.out.println(int_value.intValue());
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic BIT_STRING readBitString() throws java.io.IOException
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());
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic byte[] readOctetStringByteArray() throws java.io.IOException
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.null
when the
stream is already readjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic java.io.InputStream readOctetString(boolean skipOuter) throws java.io.IOException
This method does the same as method readOctetString
except that any outer constructed octet string is parsed
"away" if skipOuter
is set to true
and
the octet string starts with some (nested) constructed octet strings, e.g.:
24 // constructed OCTET STRING 80 // indefinite length encoding 24 // first component is constructed, too 80 // indefinite length encoding 04 03 01:02:03 // primtive OCTET STRING components with 3 bytes of data 04 xx ... // the next primitive OCTET STRING component ... // any further primitive OCTET STRING components with definite length encoding 00 00 // end of indefinite length encoding of first constructed component 00 00 // end of indefinite length encoding of outermost constructed OCTET STRINGIn this case this method reads away the first constructed OCTET STRING tag and length haeders and returns a special
OctetInputStream
from
which the raw data contained in all definite primitive encoded octet string
components can be used, e.g.:
// the stream from which to read the encoded octet string InputStream is = ...; // create a DerInputStream for parsing the OCTET STRING DerInputStream derIs = new DerInputStream(is); // get the OctetInputStream InputStream octetIs = derIs.readOctetString(); //read the inherent content: OutputStream os = ...; Util.copyStream(is, os);If the OCTET STRING to be parsed represents a simple primitive definite encoded octet string (e.g.
04 03 02 05 01
), a
OctetInputStream
is returned by this method to be read for the
inherent content, e.g.:
... InputStream octetIs = derIs.readOctetString(); //read the inherent content: OutputStream os = ...; Util.copyStream(is, os);
skipOuter
- whether to parse "away" any constructed octet strings at
the outermost level and return a stream from which to read the
content of the the innermost (definite primitive or constructed
with definite primitive components) octet stringOctetInputStream
if the octet string
is primitive definite encoded or if the octet string is constructed
encoded with primitive componentsjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic java.io.InputStream readOctetString() throws java.io.IOException
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 encodingThis 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 DerInputException is thrown.
If the tag number is 0x04 a primitive octet string is expected, and an
OctetInputStream
is returned from which the raw data can be
read.
If the tag number is 0x24, the encoding represents an constructed octet
string to be parsed for the inherent components. In this case this method
first checks if the first component of the constructed octet string is
primitive definite encoded. If not, a new DerInputStream
is
returned which can be parsed for its octet string components. If yes, this
method returns an instance of a special OctetInputStream which is an
inner class of this DerInputStream
class. The
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 only handle
block by block within the memory, depending on the length of each primitive
octet string encoding.
Note that the OctetInputStream class only can be used to parse pure definite primitive encoded octet strings, or constructed octet strings consisting 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:00The OctetInputStream class is not able to resolve an encoding that represents an arbitrary nested octet string structure. For this purpose you can use class
OCTET_STRING
which is able to handle
arbitrary nested octet strings (but holds all data in memory). However, in
general it should be appropriate to use this
DerInputStream.readOctetString
method since deeper nested
octet strings are hardly used in practice.
In practice (e.g. PKCS#7 or CMS objects) most commonly pure definite primitive encoded octet strings are used, or constructed octet strings consisting of definite primitive encoded octet string components only. 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 00the following code fragment will parse the whole 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()));
OctetInputStream
if the octet string
is primitive definite encoded or if it is constructed encoded with
primitive components; or a DerInputStream
if a
constructed octet string has to be parsed for further constructed
componentsjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic void readNull() throws java.io.IOException
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic ObjectID readObjectID() throws java.io.IOException
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic java.lang.String readString() throws java.io.IOException
DerInputStream der_is = new DerInputStream(encodedStream); String s = der_is.readString(); System.out.println(s);
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic UTCTime readUTCTime() throws java.io.IOException
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic GeneralizedTime readGeneralizedTime() throws java.io.IOException
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic DerInputStream readSequence() throws java.io.IOException
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);
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic DerInputStream readSet() throws java.io.IOException
readSequence()
method.java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic DerInputStream readConstructed() throws java.io.IOException
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());
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic DerInputStream readContextSpecific() throws java.io.IOException
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 (Printablestring): System.out.println("Printable String: " + seq_is.readString());
java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic int readContextSpecific(int tag) throws java.io.IOException
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 (Printablestring): System.out.println("Printable String: " + seq_is.readString());
tag
- the tag of the underlying base type (lost through DER encoding)java.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic int getTag()
public boolean nextIsUniversal() throws java.io.IOException
true
if the next tag is UNIVERSAL, false
if notjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic boolean nextIsApplication() throws java.io.IOException
true
if the next tag is APPLICATION,
false
if notjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic boolean nextIsContextSpecific() throws java.io.IOException
true
if the next tag is CONTEXT SPECIFIC
false
if notjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic boolean nextIsPrivate() throws java.io.IOException
true
if the next tag is PRIVATE false
if
notjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic boolean nextIsConstructed() throws java.io.IOException
true
if the next tag is CONSTRUCTED false
if notjava.io.IOException
- if an I/O error occursjava.io.EOFException
- if an unexpected EOF occursDerInputException
- if a DER decoding error occurspublic int read() throws java.io.IOException
read
in class java.io.InputStream
java.io.IOException
- if an I/O or a DER decoding error occurspublic int read(boolean unread) throws java.io.IOException
unread
is set to true
, the byte is pushed back
again.unread
- true if the byte shall be unreadjava.io.IOException
- if an I/O or a DER decoding error occurspublic int read(byte[] b, int off, int len) throws java.io.IOException
read
in class java.io.InputStream
b
- the byte array to which the data shall be readoff
- the start offset of the datalen
- the maximum number of bytes to be readjava.io.IOException
- if an I/O error occurspublic long skip(long n) throws java.io.IOException
skip
in class java.io.InputStream
n
- the number of bytes to be skippedjava.io.IOException
- if an I/O or a DER decoding error occurs