Make ASN1_OBJECT opaque.

This cleans up the story with
https://boringssl-review.googlesource.com/c/boringssl/+/46164. None of
our exported functions mutate ASN1_OBJECTS, with the exception of
ASN1_OBJECT_free, the object reuse mode of c2i_ASN1_OBJECT, and their
callers. Those functions check flags to correctly handle static
ASN1_OBJECTs.

For now, I've kept the struct definition in crypto/asn1 even though
ASN1_OBJECT is partially in crypto/obj. Since we prefer to cut
dependencies to crypto/asn1, we probably should rearrange this later.

I've also, for now, kept crypto/asn1/internal.h at C-style comments,
though our style story here is weird. (Maybe it's time to clang-format
crypto/asn1 and crypto/x509? Patches from upstream rarely directly apply
anyway, since we're a mix of 1.0.2 and 1.1.1 in crypto/x509.)

Update-Note: ASN1_OBJECT is now opaque. Callers should use accessors.

Change-Id: I655e6bd8afda98a2d1e676c3abeb873aa8de6691
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/48326
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c
index 665e0d6..de27e87 100644
--- a/crypto/asn1/a_object.c
+++ b/crypto/asn1/a_object.c
@@ -64,6 +64,7 @@
 #include <openssl/obj.h>
 
 #include "../internal.h"
+#include "internal.h"
 
 
 int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
diff --git a/crypto/asn1/internal.h b/crypto/asn1/internal.h
index a2dbf76..4e42c70 100644
--- a/crypto/asn1/internal.h
+++ b/crypto/asn1/internal.h
@@ -86,6 +86,26 @@
 
 /* Internal ASN1 structures and functions: not for application use */
 
+/* These are used internally in the ASN1_OBJECT to keep track of
+ * whether the names and data need to be free()ed */
+#define ASN1_OBJECT_FLAG_DYNAMIC 0x01         /* internal use */
+#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */
+#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08    /* internal use */
+
+/* An asn1_object_st (aka |ASN1_OBJECT|) represents an ASN.1 OBJECT IDENTIFIER.
+ * Note: Mutating an |ASN1_OBJECT| is only permitted when initializing it. The
+ * library maintains a table of static |ASN1_OBJECT|s, which may be referenced
+ * by non-const |ASN1_OBJECT| pointers. Code which receives an |ASN1_OBJECT|
+ * pointer externally must assume it is immutable, even if the pointer is not
+ * const. */
+struct asn1_object_st {
+  const char *sn, *ln;
+  int nid;
+  int length;
+  const unsigned char *data; /* data remains const after init */
+  int flags;                 /* Should we free this one */
+};
+
 int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
 int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
 
diff --git a/crypto/digest_extra/digest_extra.c b/crypto/digest_extra/digest_extra.c
index 311c5cb..a93601c 100644
--- a/crypto/digest_extra/digest_extra.c
+++ b/crypto/digest_extra/digest_extra.c
@@ -58,11 +58,12 @@
 
 #include <string.h>
 
-#include <openssl/asn1.h>
 #include <openssl/blake2.h>
 #include <openssl/bytestring.h>
+#include <openssl/obj.h>
 #include <openssl/nid.h>
 
+#include "../asn1/internal.h"
 #include "../internal.h"
 #include "../fipsmodule/digest/internal.h"
 
@@ -152,13 +153,14 @@
 }
 
 const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) {
-  // Handle objects with no corresponding OID.
+  // Handle objects with no corresponding OID. Note we don't use |OBJ_obj2nid|
+  // here to avoid pulling in the OID table.
   if (obj->nid != NID_undef) {
     return EVP_get_digestbynid(obj->nid);
   }
 
   CBS cbs;
-  CBS_init(&cbs, obj->data, obj->length);
+  CBS_init(&cbs, OBJ_get0_data(obj), OBJ_length(obj));
   return cbs_to_md(&cbs);
 }
 
diff --git a/crypto/obj/obj.c b/crypto/obj/obj.c
index 6310785..958625d 100644
--- a/crypto/obj/obj.c
+++ b/crypto/obj/obj.c
@@ -67,10 +67,13 @@
 #include <openssl/mem.h>
 #include <openssl/thread.h>
 
-#include "obj_dat.h"
+#include "../asn1/internal.h"
 #include "../internal.h"
 #include "../lhash/internal.h"
 
+// obj_data.h must be included after the definition of |ASN1_OBJECT|.
+#include "obj_dat.h"
+
 
 DEFINE_LHASH_OF(ASN1_OBJECT)
 
diff --git a/crypto/obj/obj_test.cc b/crypto/obj/obj_test.cc
index e623843..08796e2 100644
--- a/crypto/obj/obj_test.cc
+++ b/crypto/obj/obj_test.cc
@@ -75,14 +75,16 @@
 
 static bool ExpectObj2Txt(const uint8_t *der, size_t der_len,
                           bool always_return_oid, const char *expected) {
-  ASN1_OBJECT obj;
-  OPENSSL_memset(&obj, 0, sizeof(obj));
-  obj.data = der;
-  obj.length = static_cast<int>(der_len);
+  bssl::UniquePtr<ASN1_OBJECT> obj(
+      ASN1_OBJECT_create(NID_undef, der, static_cast<int>(der_len),
+                         /*sn=*/nullptr, /*ln=*/nullptr));
+  if (!obj) {
+    return false;
+  }
 
   int expected_len = static_cast<int>(strlen(expected));
 
-  int len = OBJ_obj2txt(nullptr, 0, &obj, always_return_oid);
+  int len = OBJ_obj2txt(nullptr, 0, obj.get(), always_return_oid);
   if (len != expected_len) {
     fprintf(stderr,
             "OBJ_obj2txt of %s with out_len = 0 returned %d, wanted %d.\n",
@@ -92,7 +94,7 @@
 
   char short_buf[1];
   OPENSSL_memset(short_buf, 0xff, sizeof(short_buf));
-  len = OBJ_obj2txt(short_buf, sizeof(short_buf), &obj, always_return_oid);
+  len = OBJ_obj2txt(short_buf, sizeof(short_buf), obj.get(), always_return_oid);
   if (len != expected_len) {
     fprintf(stderr,
             "OBJ_obj2txt of %s with out_len = 1 returned %d, wanted %d.\n",
@@ -109,7 +111,7 @@
   }
 
   char buf[256];
-  len = OBJ_obj2txt(buf, sizeof(buf), &obj, always_return_oid);
+  len = OBJ_obj2txt(buf, sizeof(buf), obj.get(), always_return_oid);
   if (len != expected_len) {
     fprintf(stderr,
             "OBJ_obj2txt of %s with out_len = 256 returned %d, wanted %d.\n",
@@ -166,17 +168,14 @@
   ASSERT_TRUE(ExpectObj2Txt(nullptr, 0, false /* return name */, ""));
   ASSERT_TRUE(ExpectObj2Txt(nullptr, 0, true /* don't return name */, ""));
 
-  ASN1_OBJECT obj;
-  OPENSSL_memset(&obj, 0, sizeof(obj));
-
   // kNonMinimalOID is kBasicConstraints with the final component non-minimally
   // encoded.
-  static const uint8_t kNonMinimalOID[] = {
-      0x55, 0x1d, 0x80, 0x13,
-  };
-  obj.data = kNonMinimalOID;
-  obj.length = sizeof(kNonMinimalOID);
-  ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, &obj, 0));
+  static const uint8_t kNonMinimalOID[] = {0x55, 0x1d, 0x80, 0x13};
+  bssl::UniquePtr<ASN1_OBJECT> obj(
+      ASN1_OBJECT_create(NID_undef, kNonMinimalOID, sizeof(kNonMinimalOID),
+                         /*sn=*/nullptr, /*ln=*/nullptr));
+  ASSERT_TRUE(obj);
+  ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, obj.get(), 0));
 
   // kOverflowOID is the DER representation of
   // 1.2.840.113554.4.1.72585.18446744073709551616. (The final value is 2^64.)
@@ -184,16 +183,16 @@
       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09,
       0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
   };
-  obj.data = kOverflowOID;
-  obj.length = sizeof(kOverflowOID);
-  ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, &obj, 0));
+  obj.reset(ASN1_OBJECT_create(NID_undef, kOverflowOID, sizeof(kOverflowOID),
+                               /*sn=*/nullptr, /*ln=*/nullptr));
+  ASSERT_TRUE(obj);
+  ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, obj.get(), 0));
 
   // kInvalidOID is a mis-encoded version of kBasicConstraints with the final
   // octet having the high bit set.
-  static const uint8_t kInvalidOID[] = {
-      0x55, 0x1d, 0x93,
-  };
-  obj.data = kInvalidOID;
-  obj.length = sizeof(kInvalidOID);
-  ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, &obj, 0));
+  static const uint8_t kInvalidOID[] = {0x55, 0x1d, 0x93};
+  obj.reset(ASN1_OBJECT_create(NID_undef, kInvalidOID, sizeof(kInvalidOID),
+                               /*sn=*/nullptr, /*ln=*/nullptr));
+  ASSERT_TRUE(obj);
+  ASSERT_EQ(-1, OBJ_obj2txt(NULL, 0, obj.get(), 0));
 }
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 06eeab0..db467fd 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -593,29 +593,6 @@
 #define MBSTRING_BMP (MBSTRING_FLAG | 2)
 #define MBSTRING_UNIV (MBSTRING_FLAG | 4)
 
-// These are used internally in the ASN1_OBJECT to keep track of
-// whether the names and data need to be free()ed
-#define ASN1_OBJECT_FLAG_DYNAMIC 0x01          // internal use
-#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04  // internal use
-#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08     // internal use
-
-// An asn1_object_st (aka |ASN1_OBJECT|) represents an ASN.1 OBJECT IDENTIFIER.
-//
-// Note: Although the struct is exposed, mutating an |ASN1_OBJECT| is only
-// permitted when initializing it. The library maintains a table of static
-// |ASN1_OBJECT|s, which may be referenced by non-const |ASN1_OBJECT| pointers.
-// Code which receives an |ASN1_OBJECT| pointer externally must assume it is
-// immutable, even if the pointer is not const.
-//
-// TODO(davidben): Document this more completely in its own section.
-struct asn1_object_st {
-  const char *sn, *ln;
-  int nid;
-  int length;
-  const unsigned char *data;  // data remains const after init
-  int flags;                  // Should we free this one
-};
-
 DEFINE_STACK_OF(ASN1_OBJECT)
 
 // ASN1_ENCODING structure: this is used to save the received
diff --git a/include/openssl/obj.h b/include/openssl/obj.h
index 187586d..ad7271e 100644
--- a/include/openssl/obj.h
+++ b/include/openssl/obj.h
@@ -84,7 +84,8 @@
 
 // Basic operations.
 
-// OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure.
+// OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure. The
+// caller must call |ASN1_OBJECT_free| on the result to release it.
 OPENSSL_EXPORT ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *obj);
 
 // OBJ_cmp returns a value less than, equal to or greater than zero if |a| is
@@ -133,9 +134,9 @@
 // OBJ_nid2obj returns the |ASN1_OBJECT| corresponding to |nid|, or NULL if
 // |nid| is unknown.
 //
-// This function returns a static, immutable |ASN1_OBJECT|. Although the output
-// is not const, callers may not mutate it. It is also not necessary to release
-// the object with |ASN1_OBJECT_free|.
+// Although the output is not const, this function returns a static, immutable
+// |ASN1_OBJECT|. It is not necessary to release the object with
+// |ASN1_OBJECT_free|.
 //
 // However, functions like |X509_ALGOR_set0| expect to take ownership of a
 // possibly dynamically-allocated |ASN1_OBJECT|. |ASN1_OBJECT_free| is a no-op