Add ERR_set_error_data for compatibility.

rust-openssl, rather than using Rust's existing error types, exposes the
OpenSSL error queue as the error type in its public callback types.
Supporting a simplified version of ERR_set_error_data is simple enough,
so it's easiest just to add this function.

Unlike OpenSSL's, we don't attempt to support non-string error data. We
also don't try to retain borrowed pointers. If the caller did not pass
ownership, make a copy internally.

Change-Id: I909eebc2867ab1f3b9975546a106ee1f762bf516
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/50625
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/err.c b/crypto/err/err.c
index 4aab75b..9b6d238 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -745,6 +745,22 @@
   err_set_error_data(buf);
 }
 
+void ERR_set_error_data(char *data, int flags) {
+  if (!(flags & ERR_FLAG_STRING)) {
+    // We do not support non-string error data.
+    assert(0);
+    return;
+  }
+  if (flags & ERR_FLAG_MALLOCED) {
+    err_set_error_data(data);
+  } else {
+    char *copy = OPENSSL_strdup(data);
+    if (copy != NULL) {
+      err_set_error_data(copy);
+    }
+  }
+}
+
 int ERR_set_mark(void) {
   ERR_STATE *const state = err_get_state();
 
diff --git a/crypto/err/err_test.cc b/crypto/err/err_test.cc
index b41f8dd..5dbe776 100644
--- a/crypto/err/err_test.cc
+++ b/crypto/err/err_test.cc
@@ -75,6 +75,17 @@
   EXPECT_EQ(1, ERR_GET_LIB(packed_error));
   EXPECT_EQ(2, ERR_GET_REASON(packed_error));
   EXPECT_STREQ("testing", data);
+
+  ERR_put_error(1, 0 /* unused */, 2, "test", 4);
+  ERR_set_error_data(const_cast<char *>("testing"), ERR_FLAG_STRING);
+  packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
+  EXPECT_STREQ("testing", data);
+
+  ERR_put_error(1, 0 /* unused */, 2, "test", 4);
+  bssl::UniquePtr<char> str(OPENSSL_strdup("testing"));
+  ERR_set_error_data(str.release(), ERR_FLAG_STRING | ERR_FLAG_MALLOCED);
+  packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
+  EXPECT_STREQ("testing", data);
 }
 
 TEST(ErrTest, ClearError) {
diff --git a/include/openssl/err.h b/include/openssl/err.h
index 572340c..28ba250 100644
--- a/include/openssl/err.h
+++ b/include/openssl/err.h
@@ -183,6 +183,11 @@
 // can be printed. This is always set if |data| is non-NULL.
 #define ERR_FLAG_STRING 1
 
+// ERR_FLAG_MALLOCED is passed into |ERR_set_error_data| to indicate that |data|
+// was allocated with |OPENSSL_malloc|. It is never returned from
+// |ERR_get_error_line_data|.
+#define ERR_FLAG_MALLOCED 2
+
 // ERR_get_error_line_data acts like |ERR_get_error_line|, but also returns the
 // error-specific data pointer and flags. The flags are a bitwise-OR of
 // |ERR_FLAG_*| values. The error-specific data is owned by the error queue
@@ -408,9 +413,10 @@
 // ERR_GET_FUNC returns zero. BoringSSL errors do not report a function code.
 #define ERR_GET_FUNC(packed_error) 0
 
-// ERR_TXT_STRING is provided for compatibility with code that assumes that
-// it's using OpenSSL.
+// ERR_TXT_* are provided for compatibility with code that assumes that it's
+// using OpenSSL.
 #define ERR_TXT_STRING ERR_FLAG_STRING
+#define ERR_TXT_MALLOCED ERR_FLAG_MALLOCED
 
 
 // Private functions.
@@ -444,6 +450,17 @@
 OPENSSL_EXPORT void ERR_add_error_dataf(const char *format, ...)
     OPENSSL_PRINTF_FORMAT_FUNC(1, 2);
 
+// ERR_set_error_data sets the data on the most recent error to |data|, which
+// must be a NUL-terminated string. |flags| must contain |ERR_FLAG_STRING|. If
+// |flags| contains |ERR_FLAG_MALLOCED|, this function takes ownership of
+// |data|, which must have been allocated with |OPENSSL_malloc|. Otherwise, it
+// saves a copy of |data|.
+//
+// Note this differs from OpenSSL which, when |ERR_FLAG_MALLOCED| is unset,
+// saves the pointer as-is and requires it remain valid for the lifetime of the
+// address space.
+OPENSSL_EXPORT void ERR_set_error_data(char *data, int flags);
+
 // ERR_NUM_ERRORS is one more than the limit of the number of errors in the
 // queue.
 #define ERR_NUM_ERRORS 16