Fix X509_ALGOR_set_md()

This API allocates internally and can leave a corrupted |alg| behind.
Change it to return an int so that callers can check for an error.
Also fix its only caller in rsa_md_to_algor().

This is an ABI change but will not break any callers.

Also add a small regress test for this API.

Change-Id: I7a5d1729dcd4c7726c3d4ead3740d478231f3611
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67187
Commit-Queue: Theo Buehler <theorbuehler@gmail.com>
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/x509/rsa_pss.c b/crypto/x509/rsa_pss.c
index 5974bfa..8e19b8c 100644
--- a/crypto/x509/rsa_pss.c
+++ b/crypto/x509/rsa_pss.c
@@ -125,7 +125,11 @@
   if (*palg == NULL) {
     return 0;
   }
-  X509_ALGOR_set_md(*palg, md);
+  if (!X509_ALGOR_set_md(*palg, md)) {
+    X509_ALGOR_free(*palg);
+    *palg = NULL;
+    return 0;
+  }
   return 1;
 }
 
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index d7f4313..4559b22 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -2814,6 +2814,25 @@
   }
 }
 
+TEST(X509Test, X509AlgorSetMd) {
+  bssl::UniquePtr<X509_ALGOR> alg(X509_ALGOR_new());
+  ASSERT_TRUE(alg);
+  EXPECT_TRUE(X509_ALGOR_set_md(alg.get(), EVP_sha256()));
+  const ASN1_OBJECT *obj;
+  const void *pval;
+  int ptype = 0;
+  X509_ALGOR_get0(&obj, &ptype, &pval, alg.get());
+  EXPECT_TRUE(obj);
+  EXPECT_EQ(OBJ_obj2nid(obj), NID_sha256);
+  EXPECT_EQ(ptype, V_ASN1_NULL); // OpenSSL has V_ASN1_UNDEF
+  EXPECT_EQ(pval, nullptr);
+  EXPECT_TRUE(X509_ALGOR_set_md(alg.get(), EVP_md5()));
+  X509_ALGOR_get0(&obj, &ptype, &pval, alg.get());
+  EXPECT_EQ(OBJ_obj2nid(obj), NID_md5);
+  EXPECT_EQ(ptype, V_ASN1_NULL);
+  EXPECT_EQ(pval, nullptr);
+}
+
 TEST(X509Test, X509NameSet) {
   bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
   ASSERT_TRUE(name);
diff --git a/crypto/x509/x_algor.c b/crypto/x509/x_algor.c
index 819aee5..bdc77ae 100644
--- a/crypto/x509/x_algor.c
+++ b/crypto/x509/x_algor.c
@@ -123,7 +123,7 @@
 
 // Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD
 
-void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md) {
+int X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md) {
   int param_type;
 
   if (EVP_MD_flags(md) & EVP_MD_FLAG_DIGALGID_ABSENT) {
@@ -132,7 +132,7 @@
     param_type = V_ASN1_NULL;
   }
 
-  X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
+  return X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
 }
 
 // X509_ALGOR_cmp returns 0 if |a| and |b| are equal and non-zero otherwise.
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 414451f..a072d6f 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -2696,7 +2696,7 @@
 
 // X509_ALGOR_set_md sets |alg| to the hash function |md|. Note this
 // AlgorithmIdentifier represents the hash function itself, not a signature
-// algorithm that uses |md|.
+// algorithm that uses |md|. It returns one on success and zero on error.
 //
 // Due to historical specification mistakes (see Section 2.1 of RFC 4055), the
 // parameters field is sometimes omitted and sometimes a NULL value. When used
@@ -2707,7 +2707,7 @@
 //
 // TODO(davidben): Rename this function, or perhaps just add a bespoke API for
 // constructing PSS and move on.
-OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md);
+OPENSSL_EXPORT int X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md);
 
 // X509_ALGOR_cmp returns zero if |a| and |b| are equal, and some non-zero value
 // otherwise. Note this function can only be used for equality checks, not an