Rewrite ASN1_item_pack and ASN1_item_unpack.

ASN1_item_unpack was missing checks for trailing data. ASN1_item_pack's
error handling was all wrong. (Leaking the temporary on error, checking
the the wrong return value for i2d, would-be redundant check for NULL,
were the other check not wrong.)

Update-Note: ASN1_item_unpack now checks for trailing data.

Change-Id: Ibaa19ba2b264fca36dd21109e66f9558d373c58b
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/49927
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index dee685a..cd47d2b 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -1418,6 +1418,66 @@
   EXPECT_EQ(nullptr, null_type->value.ptr);
 }
 
+TEST(ASN1Test, Pack) {
+  bssl::UniquePtr<BASIC_CONSTRAINTS> val(BASIC_CONSTRAINTS_new());
+  ASSERT_TRUE(val);
+  val->ca = 0;
+
+  // Test all three calling conventions.
+  static const uint8_t kExpected[] = {0x30, 0x00};
+  bssl::UniquePtr<ASN1_STRING> str(
+      ASN1_item_pack(val.get(), ASN1_ITEM_rptr(BASIC_CONSTRAINTS), nullptr));
+  ASSERT_TRUE(str);
+  EXPECT_EQ(
+      Bytes(ASN1_STRING_get0_data(str.get()), ASN1_STRING_length(str.get())),
+      Bytes(kExpected));
+
+  ASN1_STRING *raw = nullptr;
+  str.reset(ASN1_item_pack(val.get(), ASN1_ITEM_rptr(BASIC_CONSTRAINTS), &raw));
+  ASSERT_TRUE(str);
+  EXPECT_EQ(raw, str.get());
+  EXPECT_EQ(
+      Bytes(ASN1_STRING_get0_data(str.get()), ASN1_STRING_length(str.get())),
+      Bytes(kExpected));
+
+  str.reset(ASN1_STRING_new());
+  ASSERT_TRUE(str);
+  raw = str.get();
+  EXPECT_TRUE(
+      ASN1_item_pack(val.get(), ASN1_ITEM_rptr(BASIC_CONSTRAINTS), &raw));
+  EXPECT_EQ(raw, str.get());
+  EXPECT_EQ(
+      Bytes(ASN1_STRING_get0_data(str.get()), ASN1_STRING_length(str.get())),
+      Bytes(kExpected));
+}
+
+TEST(ASN1Test, Unpack) {
+  bssl::UniquePtr<ASN1_STRING> str(ASN1_STRING_new());
+  ASSERT_TRUE(str);
+
+  static const uint8_t kValid[] = {0x30, 0x00};
+  ASSERT_TRUE(
+      ASN1_STRING_set(str.get(), kValid, sizeof(kValid)));
+  bssl::UniquePtr<BASIC_CONSTRAINTS> val(static_cast<BASIC_CONSTRAINTS *>(
+      ASN1_item_unpack(str.get(), ASN1_ITEM_rptr(BASIC_CONSTRAINTS))));
+  ASSERT_TRUE(val);
+  EXPECT_EQ(val->ca, 0);
+  EXPECT_EQ(val->pathlen, nullptr);
+
+  static const uint8_t kInvalid[] = {0x31, 0x00};
+  ASSERT_TRUE(ASN1_STRING_set(str.get(), kInvalid, sizeof(kInvalid)));
+  val.reset(static_cast<BASIC_CONSTRAINTS *>(
+      ASN1_item_unpack(str.get(), ASN1_ITEM_rptr(BASIC_CONSTRAINTS))));
+  EXPECT_FALSE(val);
+
+  static const uint8_t kTraiilingData[] = {0x30, 0x00, 0x00};
+  ASSERT_TRUE(
+      ASN1_STRING_set(str.get(), kTraiilingData, sizeof(kTraiilingData)));
+  val.reset(static_cast<BASIC_CONSTRAINTS *>(
+      ASN1_item_unpack(str.get(), ASN1_ITEM_rptr(BASIC_CONSTRAINTS))));
+  EXPECT_FALSE(val);
+}
+
 // The ASN.1 macros do not work on Windows shared library builds, where usage of
 // |OPENSSL_EXPORT| is a bit stricter.
 #if !defined(OPENSSL_WINDOWS) || !defined(BORINGSSL_SHARED_LIBRARY)
diff --git a/crypto/asn1/asn_pack.c b/crypto/asn1/asn_pack.c
index fd7ab4b..9124f23 100644
--- a/crypto/asn1/asn_pack.c
+++ b/crypto/asn1/asn_pack.c
@@ -59,48 +59,43 @@
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
-/* ASN1_ITEM versions of the above */
 
-ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct)
+ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **out)
 {
-    ASN1_STRING *octmp;
-
-    if (!oct || !*oct) {
-        if (!(octmp = ASN1_STRING_new())) {
-            OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-            return NULL;
-        }
-        if (oct)
-            *oct = octmp;
-    } else
-        octmp = *oct;
-
-    if (octmp->data) {
-        OPENSSL_free(octmp->data);
-        octmp->data = NULL;
-    }
-
-    if (!(octmp->length = ASN1_item_i2d(obj, &octmp->data, it))) {
+    uint8_t *new_data = NULL;
+    int len = ASN1_item_i2d(obj, &new_data, it);
+    if (len <= 0) {
         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ENCODE_ERROR);
         return NULL;
     }
-    if (!octmp->data) {
-        OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-        return NULL;
-    }
-    return octmp;
-}
 
-/* Extract an ASN1 object from an ASN1_STRING */
+    ASN1_STRING *ret = NULL;
+    if (out == NULL || *out == NULL) {
+        ret = ASN1_STRING_new();
+        if (ret == NULL) {
+            OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
+            OPENSSL_free(new_data);
+            return NULL;
+        }
+    } else {
+        ret = *out;
+    }
+
+    ASN1_STRING_set0(ret, new_data, len);
+    if (out != NULL) {
+        *out = ret;
+    }
+    return ret;
+}
 
 void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it)
 {
-    const unsigned char *p;
-    void *ret;
-
-    p = oct->data;
-    if (!(ret = ASN1_item_d2i(NULL, &p, oct->length, it)))
+    const unsigned char *p = oct->data;
+    void *ret = ASN1_item_d2i(NULL, &p, oct->length, it);
+    if (ret == NULL || p != oct->data + oct->length) {
         OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
-    /* TODO(davidben): Check for trailing data. */
+        ASN1_item_free(ret, it);
+        return NULL;
+    }
     return ret;
 }