Give BIO an ex_data

It has one in upstream OpenSSL. The most recent OpenSSL release is
hitting a compatibility issue with postgres, which seems like it'll get
fixed by postgres using BIO_get_app_data. Add it on our end too.

https://www.postgresql.org/message-id/CAN55FZ1eDDYsYaL7mv%2BoSLUij2h_u6hvD4Qmv-7PK7jkji0uyQ%40mail.gmail.com
https://github.com/Homebrew/homebrew-core/issues/155651

Change-Id: I5bf226cc3506a114cd62f885a8c15006512dfc65
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/64227
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/bio/bio.c b/crypto/bio/bio.c
index ed24560..abe753c 100644
--- a/crypto/bio/bio.c
+++ b/crypto/bio/bio.c
@@ -69,6 +69,9 @@
 #include "../internal.h"
 
 
+static CRYPTO_EX_DATA_CLASS g_ex_data_class =
+    CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
+
 BIO *BIO_new(const BIO_METHOD *method) {
   BIO *ret = OPENSSL_zalloc(sizeof(BIO));
   if (ret == NULL) {
@@ -78,6 +81,7 @@
   ret->method = method;
   ret->shutdown = 1;
   ret->references = 1;
+  CRYPTO_new_ex_data(&ret->ex_data);
 
   if (method->create != NULL && !method->create(ret)) {
     OPENSSL_free(ret);
@@ -101,6 +105,7 @@
       bio->method->destroy(bio);
     }
 
+    CRYPTO_free_ex_data(&g_ex_data_class, bio, &bio->ex_data);
     OPENSSL_free(bio);
   }
   return 1;
@@ -704,3 +709,23 @@
   // Ignore the parameter. We implement |BIO_puts| using |BIO_write|.
   return 1;
 }
+
+int BIO_get_ex_new_index(long argl, void *argp,
+                                    CRYPTO_EX_unused *unused,
+                                    CRYPTO_EX_dup *dup_unused,
+                                    CRYPTO_EX_free *free_func) {
+  int index;
+  if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp,
+                               free_func)) {
+    return -1;
+  }
+  return index;
+}
+
+int BIO_set_ex_data(BIO *bio, int idx, void *data) {
+  return CRYPTO_set_ex_data(&bio->ex_data, idx, data);
+}
+
+void *BIO_get_ex_data(const BIO *bio, int idx) {
+  return CRYPTO_get_ex_data(&bio->ex_data, idx);
+}
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 17d47fc..b28439a 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -703,9 +703,17 @@
 
 // BIO_set_data sets custom data on |bio|. It may be retried with
 // |BIO_get_data|.
+//
+// This function should only be called by the implementation of a custom |BIO|.
+// In particular, the data pointer of a built-in |BIO| is private to the
+// library. For other uses, see |BIO_set_ex_data| and |BIO_set_app_data|.
 OPENSSL_EXPORT void BIO_set_data(BIO *bio, void *ptr);
 
 // BIO_get_data returns custom data on |bio| set by |BIO_get_data|.
+//
+// This function should only be called by the implementation of a custom |BIO|.
+// In particular, the data pointer of a built-in |BIO| is private to the
+// library. For other uses, see |BIO_get_ex_data| and |BIO_get_app_data|.
 OPENSSL_EXPORT void *BIO_get_data(BIO *bio);
 
 // BIO_set_init sets whether |bio| has been fully initialized. Until fully
@@ -761,6 +769,21 @@
 #define BIO_CTRL_SET_FILENAME 30
 
 
+// ex_data functions.
+//
+// See |ex_data.h| for details.
+
+OPENSSL_EXPORT int BIO_get_ex_new_index(long argl, void *argp,
+                                        CRYPTO_EX_unused *unused,
+                                        CRYPTO_EX_dup *dup_unused,
+                                        CRYPTO_EX_free *free_func);
+OPENSSL_EXPORT int BIO_set_ex_data(BIO *bio, int idx, void *arg);
+OPENSSL_EXPORT void *BIO_get_ex_data(const BIO *bio, int idx);
+
+#define BIO_set_app_data(bio, arg) (BIO_set_ex_data(bio, 0, (char *)(arg)))
+#define BIO_get_app_data(bio) (BIO_get_ex_data(bio, 0))
+
+
 // Deprecated functions.
 
 // BIO_f_base64 returns a filter |BIO| that base64-encodes data written into
@@ -852,6 +875,7 @@
 
 struct bio_st {
   const BIO_METHOD *method;
+  CRYPTO_EX_DATA ex_data;
 
   // init is non-zero if this |BIO| has been initialised.
   int init;