Rewrite ASN1_OBJECT and ASN1_BOOLEAN d2i/i2d functions.

These functions already don't go through tasn_*.c. Rewrite them to use
CBS and CBB. This removes some dependencies on ASN1_get_object and
ASN1_put_object.

Update-Note: d2i_ASN1_OBJECT and d2i_ASN1_BOOLEAN will no longer accept
non-minimal length prefixes (forbidden in DER). d2i_ASN1_BOOLEAN will
also no longer accept non-canonical representations of TRUE (also
forbidden in DER). This does not affect certificate parsing, as that
still goes through the old template system, though we will make a
similar change to those functions later.

Bug: 354, 548
Change-Id: I0b7aa96f47aca5c31ec4f702e27108b4106311f2
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58145
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/a_bool.c b/crypto/asn1/a_bool.c
index 67d6813..e227b7f 100644
--- a/crypto/asn1/a_bool.c
+++ b/crypto/asn1/a_bool.c
@@ -56,64 +56,40 @@
 
 #include <openssl/asn1.h>
 
+#include <openssl/bytestring.h>
 #include <openssl/err.h>
-#include <openssl/mem.h>
 
-int i2d_ASN1_BOOLEAN(ASN1_BOOLEAN a, unsigned char **pp) {
-  int r;
-  unsigned char *p, *allocated = NULL;
+#include "../bytestring/internal.h"
 
-  r = ASN1_object_size(0, 1, V_ASN1_BOOLEAN);
-  if (pp == NULL) {
-    return r;
+
+int i2d_ASN1_BOOLEAN(ASN1_BOOLEAN a, unsigned char **outp) {
+  CBB cbb;
+  if (!CBB_init(&cbb, 3) ||  //
+      !CBB_add_asn1_bool(&cbb, a != ASN1_BOOLEAN_FALSE)) {
+    CBB_cleanup(&cbb);
+    return -1;
   }
-
-  if (*pp == NULL) {
-    if ((p = allocated = OPENSSL_malloc(r)) == NULL) {
-      return -1;
-    }
-  } else {
-    p = *pp;
-  }
-
-  ASN1_put_object(&p, 0, 1, V_ASN1_BOOLEAN, V_ASN1_UNIVERSAL);
-  *p = a ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE;
-
-  // If a new buffer was allocated, just return it back.
-  // If not, return the incremented buffer pointer.
-  *pp = allocated != NULL ? allocated : p + 1;
-  return r;
+  return CBB_finish_i2d(&cbb, outp);
 }
 
-ASN1_BOOLEAN d2i_ASN1_BOOLEAN(ASN1_BOOLEAN *a, const unsigned char **pp,
-                              long length) {
-  const unsigned char *p = *pp;
-  long len;
-  int inf, tag, xclass;
-  inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
-  if (inf & 0x80) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_OBJECT_HEADER);
+ASN1_BOOLEAN d2i_ASN1_BOOLEAN(ASN1_BOOLEAN *out, const unsigned char **inp,
+                              long len) {
+  if (len < 0) {
     return ASN1_BOOLEAN_NONE;
   }
 
-  if (inf & V_ASN1_CONSTRUCTED) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_PRIMITIVE);
+  CBS cbs;
+  CBS_init(&cbs, *inp, (size_t)len);
+  int val;
+  if (!CBS_get_asn1_bool(&cbs, &val)) {
+    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
     return ASN1_BOOLEAN_NONE;
   }
 
-  if (tag != V_ASN1_BOOLEAN || xclass != V_ASN1_UNIVERSAL) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_BOOLEAN);
-    return ASN1_BOOLEAN_NONE;
+  ASN1_BOOLEAN ret = val ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE;
+  if (out != NULL) {
+    *out = ret;
   }
-
-  if (len != 1) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
-    return ASN1_BOOLEAN_NONE;
-  }
-  ASN1_BOOLEAN ret = (ASN1_BOOLEAN) * (p++);
-  if (a != NULL) {
-    (*a) = ret;
-  }
-  *pp = p;
+  *inp = CBS_data(&cbs);
   return ret;
 }
diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c
index 56219e1..77bd175 100644
--- a/crypto/asn1/a_object.c
+++ b/crypto/asn1/a_object.c
@@ -59,46 +59,36 @@
 #include <limits.h>
 #include <string.h>
 
+#include <openssl/bytestring.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 #include <openssl/obj.h>
 
+#include "../bytestring/internal.h"
 #include "../internal.h"
 #include "internal.h"
 
 
-int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp) {
-  if (a == NULL) {
+int i2d_ASN1_OBJECT(const ASN1_OBJECT *in, unsigned char **outp) {
+  if (in == NULL) {
     OPENSSL_PUT_ERROR(ASN1, ERR_R_PASSED_NULL_PARAMETER);
     return -1;
   }
 
-  if (a->length == 0) {
+  if (in->length <= 0) {
     OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT);
     return -1;
   }
 
-  int objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
-  if (pp == NULL || objsize == -1) {
-    return objsize;
+  CBB cbb, child;
+  if (!CBB_init(&cbb, (size_t)in->length + 2) ||
+      !CBB_add_asn1(&cbb, &child, CBS_ASN1_OBJECT) ||
+      !CBB_add_bytes(&child, in->data, in->length)) {
+    CBB_cleanup(&cbb);
+    return -1;
   }
 
-  unsigned char *p, *allocated = NULL;
-  if (*pp == NULL) {
-    if ((p = allocated = OPENSSL_malloc(objsize)) == NULL) {
-      return -1;
-    }
-  } else {
-    p = *pp;
-  }
-
-  ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
-  OPENSSL_memcpy(p, a->data, a->length);
-
-  // If a new buffer was allocated, just return it back.
-  // If not, return the incremented buffer pointer.
-  *pp = allocated != NULL ? allocated : p + a->length;
-  return objsize;
+  return CBB_finish_i2d(&cbb, outp);
 }
 
 int i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a) {
@@ -140,29 +130,25 @@
   return ret;
 }
 
-ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
-                             long length) {
-  long len;
-  int tag, xclass;
-  const unsigned char *p = *pp;
-  int inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
-  if (inf & 0x80) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_OBJECT_HEADER);
+ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **out, const unsigned char **inp,
+                             long len) {
+  if (len < 0) {
     return NULL;
   }
 
-  if (inf & V_ASN1_CONSTRUCTED) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_PRIMITIVE);
+  CBS cbs, child;
+  CBS_init(&cbs, *inp, (size_t)len);
+  if (!CBS_get_asn1(&cbs, &child, CBS_ASN1_OBJECT)) {
+    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
     return NULL;
   }
 
-  if (tag != V_ASN1_OBJECT || xclass != V_ASN1_UNIVERSAL) {
-    OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_AN_OBJECT);
-    return NULL;
-  }
-  ASN1_OBJECT *ret = c2i_ASN1_OBJECT(a, &p, len);
-  if (ret) {
-    *pp = p;
+  const uint8_t *contents = CBS_data(&child);
+  ASN1_OBJECT *ret = c2i_ASN1_OBJECT(out, &contents, CBS_len(&child));
+  if (ret != NULL) {
+    // |c2i_ASN1_OBJECT| should have consumed the entire input.
+    assert(CBS_data(&cbs) == contents);
+    *inp = CBS_data(&cbs);
   }
   return ret;
 }
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index 36ad676..640b726 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -552,8 +552,10 @@
       {0x81, 0x01, 0x00},
       // Element is constructed.
       {0x21, 0x01, 0x00},
-      // TODO(https://crbug.com/boringssl/354): Reject non-DER encodings of TRUE
-      // and test this.
+      // Not a DER encoding of TRUE.
+      {0x01, 0x01, 0x01},
+      // Non-minimal tag length.
+      {0x01, 0x81, 0x01, 0xff},
   };
   for (const auto &invalid : kInvalidBooleans) {
     SCOPED_TRACE(Bytes(invalid));
@@ -690,6 +692,8 @@
       {0x86, 0x03, 0x2b, 0x65, 0x70},
       // Element is constructed.
       {0x26, 0x03, 0x2b, 0x65, 0x70},
+      // Non-minimal tag length.
+      {0x06, 0x81, 0x03, 0x2b, 0x65, 0x70},
   };
   for (const auto &invalid : kInvalidObjects) {
     SCOPED_TRACE(Bytes(invalid));
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 26634a8..ff77955 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -443,9 +443,6 @@
 //
 // WARNING: This function's is slightly different from other |d2i_*| functions
 // because |ASN1_BOOLEAN| is not a pointer type.
-//
-// TODO(https://crbug.com/boringssl/354): This function currently also accepts
-// BER, but this will be removed in the future.
 OPENSSL_EXPORT ASN1_BOOLEAN d2i_ASN1_BOOLEAN(ASN1_BOOLEAN *out,
                                              const unsigned char **inp,
                                              long len);
@@ -1444,15 +1441,12 @@
 
 // d2i_ASN1_OBJECT parses a DER-encoded ASN.1 OBJECT IDENTIFIER from up to |len|
 // bytes at |*inp|, as described in |d2i_SAMPLE|.
-//
-// TODO(https://crbug.com/boringssl/354): This function currently also accepts
-// BER, but this will be removed in the future.
 OPENSSL_EXPORT ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **out,
                                             const uint8_t **inp, long len);
 
 // i2d_ASN1_OBJECT marshals |in| as a DER-encoded ASN.1 OBJECT IDENTIFIER, as
 // described in |i2d_SAMPLE|.
-OPENSSL_EXPORT int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, uint8_t **outp);
+OPENSSL_EXPORT int i2d_ASN1_OBJECT(const ASN1_OBJECT *in, uint8_t **outp);
 
 // c2i_ASN1_OBJECT decodes |len| bytes from |*inp| as the contents of a
 // DER-encoded OBJECT IDENTIFIER, excluding the tag and length. It behaves like