Make X509_ATTRIBUTE opaque.

x509_req.c changes imported from upstream's
9b0a453190efc9b14cc04e74ce2e8e35af45fb39.

Update-Note: Direct accesses of X509_ATTRIBUTE should be replaced with
one of the accessors. I couldn't find any direct accesses, so hopefully
this is fine.

Change-Id: I7eab6375d5dcf366ef72e5ce059f3558c947f35b
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/46946
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h
index 32af84d..6b7d0c6 100644
--- a/crypto/x509/internal.h
+++ b/crypto/x509/internal.h
@@ -37,6 +37,16 @@
   EVP_PKEY *pkey;
 } /* X509_PUBKEY */;
 
+struct x509_attributes_st {
+  ASN1_OBJECT *object;
+  int single;  // 0 for a set, 1 for a single item (which is wrong)
+  union {
+    char *ptr;
+    /* 0 */ STACK_OF(ASN1_TYPE) *set;
+    /* 1 */ ASN1_TYPE *single;
+  } value;
+} /* X509_ATTRIBUTE */;
+
 
 /* RSA-PSS functions. */
 
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
index 8e13de8..07edde9 100644
--- a/crypto/x509/x509_att.c
+++ b/crypto/x509/x509_att.c
@@ -63,6 +63,7 @@
 #include <openssl/x509.h>
 
 #include "../asn1/asn1_locl.h"
+#include "internal.h"
 
 
 int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c
index 22279d3..d15c05f 100644
--- a/crypto/x509/x509_req.c
+++ b/crypto/x509/x509_req.c
@@ -177,13 +177,7 @@
     }
 
     X509_ATTRIBUTE *attr = X509_REQ_get_attr(req, idx);
-    ASN1_TYPE *ext = NULL;
-    if (attr->single) {
-        ext = attr->value.single;
-    } else if (sk_ASN1_TYPE_num(attr->value.set)) {
-        ext = sk_ASN1_TYPE_value(attr->value.set, 0);
-    }
-
+    ASN1_TYPE *ext = X509_ATTRIBUTE_get0_type(attr, 0);
     if (!ext || ext->type != V_ASN1_SEQUENCE) {
         return NULL;
     }
@@ -201,37 +195,17 @@
 int X509_REQ_add_extensions_nid(X509_REQ *req,
                                 const STACK_OF(X509_EXTENSION) *exts, int nid)
 {
-    ASN1_TYPE *at = NULL;
-    X509_ATTRIBUTE *attr = NULL;
-    if (!(at = ASN1_TYPE_new()) || !(at->value.sequence = ASN1_STRING_new()))
-        goto err;
-
-    at->type = V_ASN1_SEQUENCE;
     /* Generate encoding of extensions */
-    at->value.sequence->length =
-        ASN1_item_i2d((ASN1_VALUE *)exts,
-                      &at->value.sequence->data,
-                      ASN1_ITEM_rptr(X509_EXTENSIONS));
-    if (!(attr = X509_ATTRIBUTE_new()))
-        goto err;
-    if (!(attr->value.set = sk_ASN1_TYPE_new_null()))
-        goto err;
-    if (!sk_ASN1_TYPE_push(attr->value.set, at))
-        goto err;
-    at = NULL;
-    attr->single = 0;
-    attr->object = OBJ_nid2obj(nid);
-    if (!req->req_info->attributes) {
-        if (!(req->req_info->attributes = sk_X509_ATTRIBUTE_new_null()))
-            goto err;
+    unsigned char *ext = NULL;
+    int ext_len = ASN1_item_i2d((ASN1_VALUE *)exts, &ext,
+                                ASN1_ITEM_rptr(X509_EXTENSIONS));
+    if (ext_len <= 0) {
+        return 0;
     }
-    if (!sk_X509_ATTRIBUTE_push(req->req_info->attributes, attr))
-        goto err;
-    return 1;
- err:
-    X509_ATTRIBUTE_free(attr);
-    ASN1_TYPE_free(at);
-    return 0;
+    int ret = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext,
+                                        ext_len);
+    OPENSSL_free(ext);
+    return ret;
 }
 
 /* This is the normal usage: use the "official" OID */
diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c
index 194f9e1..d906df8 100644
--- a/crypto/x509/x_attrib.c
+++ b/crypto/x509/x_attrib.c
@@ -59,6 +59,9 @@
 #include <openssl/x509.h>
 #include <openssl/obj.h>
 
+#include "internal.h"
+
+
 /*
  * X509_ATTRIBUTE: this has the following form: typedef struct
  * x509_attributes_st { ASN1_OBJECT *object; int single; union { char *ptr;
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index b6dcc7f..168cac4 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -153,17 +153,6 @@
 DEFINE_STACK_OF(X509_EXTENSION)
 DECLARE_ASN1_SET_OF(X509_EXTENSION)
 
-// a sequence of these are used
-struct x509_attributes_st {
-  ASN1_OBJECT *object;
-  int single;  // 0 for a set, 1 for a single item (which is wrong)
-  union {
-    char *ptr;
-    /* 0 */ STACK_OF(ASN1_TYPE) *set;
-    /* 1 */ ASN1_TYPE *single;
-  } value;
-} /* X509_ATTRIBUTE */;
-
 DEFINE_STACK_OF(X509_ATTRIBUTE)
 DECLARE_ASN1_SET_OF(X509_ATTRIBUTE)