summaryrefslogtreecommitdiff
path: root/android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java
diff options
context:
space:
mode:
authorNeil Fuller <nfuller@google.com>2018-07-12 15:58:48 +0100
committerPaul Duffin <paulduffin@google.com>2018-09-18 18:32:55 +0100
commit6a4a86b302cfc63e6917aef1f6937dae90646571 (patch)
tree2a196f81315b1fdd1d2bd5535a4a8846e5d36e9a /android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java
parent8ac7044ca44505764fdc9fa4e96fe79c11a2736a (diff)
downloadbouncycastle-6a4a86b302cfc63e6917aef1f6937dae90646571.tar.gz
Use generated source not jarjar
This commit switches to generating source code for com.android.org.bouncycastle used on Android devices rather than relying on jajar to repackage the bytecode. Source code can (and must) be regenerated using scripts in external/bouncycastle/srcgen when changes are made to bouncycastle source code. Having source code for the Android internal bouncycastle is being done to enable the code to be included in stubs for system and other internal API surfaces: the stubs generation relies on having source (which can be annotated, or just have associated API metadata). Test: build Test: CtsLibcoreTestCases Bug: 111055375 Bug: 111734251 Change-Id: I6d21774088e73c936e99059a9a0f071080174015
Diffstat (limited to 'android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java')
-rw-r--r--android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java477
1 files changed, 477 insertions, 0 deletions
diff --git a/android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java b/android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java
new file mode 100644
index 00000000..9d792ec2
--- /dev/null
+++ b/android_bcprov/src/main/java/com/android/org/bouncycastle/asn1/ASN1InputStream.java
@@ -0,0 +1,477 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+package com.android.org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.android.org.bouncycastle.util.io.Streams;
+
+/**
+ * a general purpose ASN.1 decoder - note: this class differs from the
+ * others in that it returns null after it has read the last object in
+ * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
+ * returned.
+ */
+public class ASN1InputStream
+ extends FilterInputStream
+ implements BERTags
+{
+ private final int limit;
+ private final boolean lazyEvaluate;
+
+ private final byte[][] tmpBuffers;
+
+ public ASN1InputStream(
+ InputStream is)
+ {
+ this(is, StreamUtil.findLimit(is));
+ }
+
+ /**
+ * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+ * the stream is automatically limited to the length of the input array.
+ *
+ * @param input array containing ASN.1 encoded data.
+ */
+ public ASN1InputStream(
+ byte[] input)
+ {
+ this(new ByteArrayInputStream(input), input.length);
+ }
+
+ /**
+ * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+ * the stream is automatically limited to the length of the input array.
+ *
+ * @param input array containing ASN.1 encoded data.
+ * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+ */
+ public ASN1InputStream(
+ byte[] input,
+ boolean lazyEvaluate)
+ {
+ this(new ByteArrayInputStream(input), input.length, lazyEvaluate);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param limit maximum size of a DER encoded object.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ int limit)
+ {
+ this(input, limit, false);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+ * objects such as sequences will be parsed lazily.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ boolean lazyEvaluate)
+ {
+ this(input, StreamUtil.findLimit(input), lazyEvaluate);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+ * objects such as sequences will be parsed lazily.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param limit maximum size of a DER encoded object.
+ * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ int limit,
+ boolean lazyEvaluate)
+ {
+ super(input);
+ this.limit = limit;
+ this.lazyEvaluate = lazyEvaluate;
+ this.tmpBuffers = new byte[11][];
+ }
+
+ int getLimit()
+ {
+ return limit;
+ }
+
+ protected int readLength()
+ throws IOException
+ {
+ return readLength(this, limit);
+ }
+
+ protected void readFully(
+ byte[] bytes)
+ throws IOException
+ {
+ if (Streams.readFully(this, bytes) != bytes.length)
+ {
+ throw new EOFException("EOF encountered in middle of object");
+ }
+ }
+
+ /**
+ * build an object given its tag and the number of bytes to construct it from.
+ *
+ * @param tag the full tag details.
+ * @param tagNo the tagNo defined.
+ * @param length the length of the object.
+ * @return the resulting primitive.
+ * @throws java.io.IOException on processing exception.
+ */
+ protected ASN1Primitive buildObject(
+ int tag,
+ int tagNo,
+ int length)
+ throws IOException
+ {
+ boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+ DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);
+
+ if ((tag & APPLICATION) != 0)
+ {
+ return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
+ }
+
+ if ((tag & TAGGED) != 0)
+ {
+ return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);
+ }
+
+ if (isConstructed)
+ {
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagNo)
+ {
+ case OCTET_STRING:
+ //
+ // yes, people actually do this...
+ //
+ ASN1EncodableVector v = buildDEREncodableVector(defIn);
+ ASN1OctetString[] strings = new ASN1OctetString[v.size()];
+
+ for (int i = 0; i != strings.length; i++)
+ {
+ strings[i] = (ASN1OctetString)v.get(i);
+ }
+
+ return new BEROctetString(strings);
+ case SEQUENCE:
+ if (lazyEvaluate)
+ {
+ return new LazyEncodedSequence(defIn.toByteArray());
+ }
+ else
+ {
+ return DERFactory.createSequence(buildDEREncodableVector(defIn));
+ }
+ case SET:
+ return DERFactory.createSet(buildDEREncodableVector(defIn));
+ case EXTERNAL:
+ return new DERExternal(buildDEREncodableVector(defIn));
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+
+ return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
+ }
+
+ ASN1EncodableVector buildEncodableVector()
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ ASN1Primitive o;
+
+ while ((o = readObject()) != null)
+ {
+ v.add(o);
+ }
+
+ return v;
+ }
+
+ ASN1EncodableVector buildDEREncodableVector(
+ DefiniteLengthInputStream dIn) throws IOException
+ {
+ return new ASN1InputStream(dIn).buildEncodableVector();
+ }
+
+ public ASN1Primitive readObject()
+ throws IOException
+ {
+ int tag = read();
+ if (tag <= 0)
+ {
+ if (tag == 0)
+ {
+ throw new IOException("unexpected end-of-contents marker");
+ }
+
+ return null;
+ }
+
+ //
+ // calculate tag number
+ //
+ int tagNo = readTagNumber(this, tag);
+
+ boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+ //
+ // calculate length
+ //
+ int length = readLength();
+
+ if (length < 0) // indefinite-length method
+ {
+ if (!isConstructed)
+ {
+ throw new IOException("indefinite-length primitive encoding encountered");
+ }
+
+ IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
+ ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
+
+ if ((tag & APPLICATION) != 0)
+ {
+ return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();
+ }
+
+ if ((tag & TAGGED) != 0)
+ {
+ return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();
+ }
+
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagNo)
+ {
+ case OCTET_STRING:
+ return new BEROctetStringParser(sp).getLoadedObject();
+ case SEQUENCE:
+ return new BERSequenceParser(sp).getLoadedObject();
+ case SET:
+ return new BERSetParser(sp).getLoadedObject();
+ case EXTERNAL:
+ return new DERExternalParser(sp).getLoadedObject();
+ default:
+ throw new IOException("unknown BER object encountered");
+ }
+ }
+ else
+ {
+ try
+ {
+ return buildObject(tag, tagNo, length);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ASN1Exception("corrupted stream detected", e);
+ }
+ }
+ }
+
+ static int readTagNumber(InputStream s, int tag)
+ throws IOException
+ {
+ int tagNo = tag & 0x1f;
+
+ //
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+ //
+ if (tagNo == 0x1f)
+ {
+ tagNo = 0;
+
+ int b = s.read();
+
+ // X.690-0207 8.1.2.4.2
+ // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+ if ((b & 0x7f) == 0) // Note: -1 will pass
+ {
+ throw new IOException("corrupted stream - invalid high tag number found");
+ }
+
+ while ((b >= 0) && ((b & 0x80) != 0))
+ {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = s.read();
+ }
+
+ if (b < 0)
+ {
+ throw new EOFException("EOF found inside tag value.");
+ }
+
+ tagNo |= (b & 0x7f);
+ }
+
+ return tagNo;
+ }
+
+ static int readLength(InputStream s, int limit)
+ throws IOException
+ {
+ int length = s.read();
+ if (length < 0)
+ {
+ throw new EOFException("EOF found when length expected");
+ }
+
+ if (length == 0x80)
+ {
+ return -1; // indefinite-length encoding
+ }
+
+ if (length > 127)
+ {
+ int size = length & 0x7f;
+
+ // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+ if (size > 4)
+ {
+ throw new IOException("DER length more than 4 bytes: " + size);
+ }
+
+ length = 0;
+ for (int i = 0; i < size; i++)
+ {
+ int next = s.read();
+
+ if (next < 0)
+ {
+ throw new EOFException("EOF found reading length");
+ }
+
+ length = (length << 8) + next;
+ }
+
+ if (length < 0)
+ {
+ throw new IOException("corrupted stream - negative length found");
+ }
+
+ if (length >= limit) // after all we must have read at least 1 byte
+ {
+ throw new IOException("corrupted stream - out of bounds length found");
+ }
+ }
+
+ return length;
+ }
+
+ private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
+ throws IOException
+ {
+ int len = defIn.getRemaining();
+ if (defIn.getRemaining() < tmpBuffers.length)
+ {
+ byte[] buf = tmpBuffers[len];
+
+ if (buf == null)
+ {
+ buf = tmpBuffers[len] = new byte[len];
+ }
+
+ Streams.readFully(defIn, buf);
+
+ return buf;
+ }
+ else
+ {
+ return defIn.toByteArray();
+ }
+ }
+
+ private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)
+ throws IOException
+ {
+ int len = defIn.getRemaining() / 2;
+ char[] buf = new char[len];
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int ch1 = defIn.read();
+ if (ch1 < 0)
+ {
+ break;
+ }
+ int ch2 = defIn.read();
+ if (ch2 < 0)
+ {
+ break;
+ }
+ buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));
+ }
+
+ return buf;
+ }
+
+ static ASN1Primitive createPrimitiveDERObject(
+ int tagNo,
+ DefiniteLengthInputStream defIn,
+ byte[][] tmpBuffers)
+ throws IOException
+ {
+ switch (tagNo)
+ {
+ case BIT_STRING:
+ return ASN1BitString.fromInputStream(defIn.getRemaining(), defIn);
+ case BMP_STRING:
+ return new DERBMPString(getBMPCharBuffer(defIn));
+ case BOOLEAN:
+ return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));
+ case ENUMERATED:
+ return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));
+ case GENERALIZED_TIME:
+ return new ASN1GeneralizedTime(defIn.toByteArray());
+ case GENERAL_STRING:
+ return new DERGeneralString(defIn.toByteArray());
+ case IA5_STRING:
+ return new DERIA5String(defIn.toByteArray());
+ case INTEGER:
+ return new ASN1Integer(defIn.toByteArray(), false);
+ case NULL:
+ return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?)
+ case NUMERIC_STRING:
+ return new DERNumericString(defIn.toByteArray());
+ case OBJECT_IDENTIFIER:
+ return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));
+ case OCTET_STRING:
+ return new DEROctetString(defIn.toByteArray());
+ case PRINTABLE_STRING:
+ return new DERPrintableString(defIn.toByteArray());
+ case T61_STRING:
+ return new DERT61String(defIn.toByteArray());
+ case UNIVERSAL_STRING:
+ return new DERUniversalString(defIn.toByteArray());
+ case UTC_TIME:
+ return new ASN1UTCTime(defIn.toByteArray());
+ case UTF8_STRING:
+ return new DERUTF8String(defIn.toByteArray());
+ case VISIBLE_STRING:
+ return new DERVisibleString(defIn.toByteArray());
+ case GRAPHIC_STRING:
+ return new DERGraphicString(defIn.toByteArray());
+ case VIDEOTEX_STRING:
+ return new DERVideotexString(defIn.toByteArray());
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+}