Add |BIO_read_asn1| to read a single ASN.1 object.

Android needs to be able to read a PKCS#7 blob from a Java InputStream.
This change adds |BIO_read_asn1| which reads a single ASN.1 object from
the start of a BIO without overreading.

(Taken from upstream's https://boringssl-review.googlesource.com/4800)

Change-Id: Id88f34bedfdff4963c72bcd5c84f2915785d1fcd
diff --git a/src/crypto/bio/bio.c b/src/crypto/bio/bio.c
index 48c1466..694a11c 100644
--- a/src/crypto/bio/bio.c
+++ b/src/crypto/bio/bio.c
@@ -56,6 +56,7 @@
 
 #include <openssl/bio.h>
 
+#include <assert.h>
 #include <errno.h>
 #include <limits.h>
 #include <string.h>
@@ -459,3 +460,142 @@
 void BIO_print_errors(BIO *bio) {
   ERR_print_errors_cb(print_bio, bio);
 }
+
+/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
+ * success, |*out| is set to an allocated buffer (which should be freed with
+ * |OPENSSL_free|), |*out_len| is set to its length and one is returned. The
+ * buffer will contain |prefix| followed by the contents of |bio|. On failure,
+ * zero is returned.
+ *
+ * The function will fail if the size of the output would equal or exceed
+ * |max_len|. */
+static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len,
+                        const uint8_t *prefix, size_t prefix_len,
+                        size_t max_len) {
+  static const size_t kChunkSize = 4096;
+
+  size_t len = prefix_len + kChunkSize;
+  if (len > max_len) {
+    len = max_len;
+  }
+  if (len < prefix_len) {
+    return 0;
+  }
+  *out = OPENSSL_malloc(len);
+  if (*out == NULL) {
+    return 0;
+  }
+  memcpy(*out, prefix, prefix_len);
+  size_t done = prefix_len;
+
+  for (;;) {
+    if (done == len) {
+      OPENSSL_free(*out);
+      return 0;
+    }
+    const size_t todo = len - done;
+    assert(todo < INT_MAX);
+    const int n = BIO_read(bio, *out + done, todo);
+    if (n == 0) {
+      *out_len = done;
+      return 1;
+    } else if (n == -1) {
+      OPENSSL_free(*out);
+      return 0;
+    }
+
+    done += n;
+    if (len < max_len && len - done < kChunkSize / 2) {
+      len += kChunkSize;
+      if (len > max_len) {
+        len = max_len;
+      }
+      uint8_t *new_buf = OPENSSL_realloc(*out, len);
+      if (new_buf == NULL) {
+        OPENSSL_free(*out);
+        return 0;
+      }
+      *out = new_buf;
+    }
+  }
+}
+
+int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
+  uint8_t header[6];
+
+  static const size_t kInitialHeaderLen = 2;
+  if (BIO_read(bio, header, kInitialHeaderLen) != kInitialHeaderLen) {
+    return 0;
+  }
+
+  const uint8_t tag = header[0];
+  const uint8_t length_byte = header[1];
+
+  if ((tag & 0x1f) == 0x1f) {
+    /* Long form tags are not supported. */
+    return 0;
+  }
+
+  size_t len, header_len;
+  if ((length_byte & 0x80) == 0) {
+    /* Short form length. */
+    len = length_byte;
+    header_len = kInitialHeaderLen;
+  } else {
+    const size_t num_bytes = length_byte & 0x7f;
+
+    if ((tag & 0x20 /* constructed */) != 0 && num_bytes == 0) {
+      /* indefinite length. */
+      return bio_read_all(bio, out, out_len, header, kInitialHeaderLen,
+                          max_len);
+    }
+
+    if (num_bytes == 0 || num_bytes > 4) {
+      return 0;
+    }
+
+    if (BIO_read(bio, header + kInitialHeaderLen, num_bytes) != num_bytes) {
+      return 0;
+    }
+    header_len = kInitialHeaderLen + num_bytes;
+
+    uint32_t len32 = 0;
+    unsigned i;
+    for (i = 0; i < num_bytes; i++) {
+      len32 <<= 8;
+      len32 |= header[kInitialHeaderLen + i];
+    }
+
+    if (len32 < 128) {
+      /* Length should have used short-form encoding. */
+      return 0;
+    }
+
+    if ((len32 >> ((num_bytes-1)*8)) == 0) {
+      /* Length should have been at least one byte shorter. */
+      return 0;
+    }
+
+    len = len32;
+  }
+
+  if (len + header_len < len ||
+      len + header_len > max_len) {
+    return 0;
+  }
+  len += header_len;
+  *out_len = len;
+
+  *out = OPENSSL_malloc(len);
+  if (*out == NULL) {
+    return 0;
+  }
+  memcpy(*out, header, header_len);
+  if (BIO_read(bio, (*out) + header_len, len - header_len) !=
+      len - header_len) {
+    OPENSSL_free(*out);
+    return 0;
+  }
+
+  return 1;
+}
diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc
index 4c88df5..e0193f8 100644
--- a/src/crypto/bio/bio_test.cc
+++ b/src/crypto/bio/bio_test.cc
@@ -329,6 +329,84 @@
   return true;
 }
 
+static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
+                     size_t expected_len, size_t max_len) {
+  ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(data), data_len));
+
+  uint8_t *out;
+  size_t out_len;
+  int ok = BIO_read_asn1(bio.get(), &out, &out_len, max_len);
+  if (!ok) {
+    out = nullptr;
+  }
+  ScopedOpenSSLBytes out_storage(out);
+
+  if (should_succeed != (ok == 1)) {
+    return false;
+  }
+
+  if (should_succeed &&
+      (out_len != expected_len || memcmp(data, out, expected_len) != 0)) {
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestASN1() {
+  static const uint8_t kData1[] = {0x30, 2, 1, 2, 0, 0};
+  static const uint8_t kData2[] = {0x30, 3, 1, 2};  /* truncated */
+  static const uint8_t kData3[] = {0x30, 0x81, 1, 1};  /* should be short len */
+  static const uint8_t kData4[] = {0x30, 0x82, 0, 1, 1};  /* zero padded. */
+
+  if (!ReadASN1(true, kData1, sizeof(kData1), 4, 100) ||
+      !ReadASN1(false, kData2, sizeof(kData2), 0, 100) ||
+      !ReadASN1(false, kData3, sizeof(kData3), 0, 100) ||
+      !ReadASN1(false, kData4, sizeof(kData4), 0, 100)) {
+    return false;
+  }
+
+  static const size_t kLargePayloadLen = 8000;
+  static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
+                                         kLargePayloadLen & 0xff};
+  ScopedOpenSSLBytes large(reinterpret_cast<uint8_t *>(
+      OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
+  memset(large.get() + sizeof(kLargePrefix), 0, kLargePayloadLen);
+  memcpy(large.get(), kLargePrefix, sizeof(kLargePrefix));
+
+  if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
+                sizeof(kLargePrefix) + kLargePayloadLen,
+                kLargePayloadLen * 2)) {
+    fprintf(stderr, "Large payload test failed.\n");
+    return false;
+  }
+
+  if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
+                sizeof(kLargePrefix) + kLargePayloadLen,
+                kLargePayloadLen - 1)) {
+    fprintf(stderr, "max_len test failed.\n");
+    return false;
+  }
+
+  static const uint8_t kIndefPrefix[] = {0x30, 0x80};
+  memcpy(large.get(), kIndefPrefix, sizeof(kIndefPrefix));
+  if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
+                sizeof(kLargePrefix) + kLargePayloadLen,
+                kLargePayloadLen*2)) {
+    fprintf(stderr, "indefinite length test failed.\n");
+    return false;
+  }
+
+  if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
+                sizeof(kLargePrefix) + kLargePayloadLen,
+                kLargePayloadLen-1)) {
+    fprintf(stderr, "indefinite length, max_len test failed.\n");
+    return false;
+  }
+
+  return true;
+}
+
 int main(void) {
   CRYPTO_library_init();
   ERR_load_crypto_strings();
@@ -350,7 +428,8 @@
 
   if (!TestSocketConnect() ||
       !TestPrintf() ||
-      !TestZeroCopyBioPairs()) {
+      !TestZeroCopyBioPairs() ||
+      !TestASN1()) {
     return 1;
   }
 
diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h
index b70b42f..a37077c 100644
--- a/src/include/openssl/bio.h
+++ b/src/include/openssl/bio.h
@@ -338,6 +338,21 @@
  * using human readable strings where possible. */
 OPENSSL_EXPORT void BIO_print_errors(BIO *bio);
 
+/* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets
+ * |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|),
+ * |*out_size| to the length, in bytes, of that buffer and returns one.
+ * Otherwise it returns zero.
+ *
+ * If the length of the object is greater than |max_len| or 2^32 then the
+ * function will fail. Long-form tags are not supported. If the length of the
+ * object is indefinite the full contents of |bio| are read, unless it would be
+ * greater than |max_len|, in which case the function fails.
+ *
+ * If the function fails then some unknown amount of data may have been read
+ * from |bio|. */
+OPENSSL_EXPORT int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len,
+                                 size_t max_len);
+
 
 /* Memory BIOs.
  *