Add maskHash to RSA_PSS_PARAMS for compat

This CL adds a maskHash member to the rsa_pss_params_st struct for
increased compatibility with OpenSSL: https://source.chromium.org/chromium/chromium/src/+/main:third_party/perl/c/include/openssl/rsa.h;l=282-289

Node.js recently began to make use of this member in https://github.com/nodejs/node/pull/39851
and without this member Electron sees compilation errors.

Change-Id: Ibd18a31605b0a715edb279a3bca4b4f05e679767
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/49365
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/rsa/rsa.c b/crypto/fipsmodule/rsa/rsa.c
index fd84cba..8f58a10 100644
--- a/crypto/fipsmodule/rsa/rsa.c
+++ b/crypto/fipsmodule/rsa/rsa.c
@@ -206,6 +206,12 @@
   }
 }
 
+const RSA_PSS_PARAMS *RSA_get0_pss_params(const RSA *rsa) {
+  // We do not support the id-RSASSA-PSS key encoding. If we add support later,
+  // the |maskHash| field should be filled in for OpenSSL compatibility.
+  return NULL;
+}
+
 void RSA_get0_crt_params(const RSA *rsa, const BIGNUM **out_dmp1,
                          const BIGNUM **out_dmq1, const BIGNUM **out_iqmp) {
   if (out_dmp1 != NULL) {
diff --git a/crypto/x509/rsa_pss.c b/crypto/x509/rsa_pss.c
index 1520c08..21a6bea 100644
--- a/crypto/x509/rsa_pss.c
+++ b/crypto/x509/rsa_pss.c
@@ -67,12 +67,21 @@
 #include "internal.h"
 
 
-ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
+static int rsa_pss_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+                      void *exarg) {
+  if (operation == ASN1_OP_FREE_PRE) {
+    RSA_PSS_PARAMS *pss = (RSA_PSS_PARAMS *)*pval;
+    X509_ALGOR_free(pss->maskHash);
+  }
+  return 1;
+}
+
+ASN1_SEQUENCE_cb(RSA_PSS_PARAMS, rsa_pss_cb) = {
   ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
   ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1),
   ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2),
   ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3),
-} ASN1_SEQUENCE_END(RSA_PSS_PARAMS)
+} ASN1_SEQUENCE_END_cb(RSA_PSS_PARAMS, RSA_PSS_PARAMS)
 
 IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
 
diff --git a/include/openssl/base.h b/include/openssl/base.h
index 223c0c5..8be10d1 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -422,6 +422,7 @@
 typedef struct rand_meth_st RAND_METHOD;
 typedef struct rc4_key_st RC4_KEY;
 typedef struct rsa_meth_st RSA_METHOD;
+typedef struct rsa_pss_params_st RSA_PSS_PARAMS;
 typedef struct rsa_st RSA;
 typedef struct sha256_state_st SHA256_CTX;
 typedef struct sha512_state_st SHA512_CTX;
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
index 27bc7bf..95a478a 100644
--- a/include/openssl/rsa.h
+++ b/include/openssl/rsa.h
@@ -684,6 +684,11 @@
 // on success or zero otherwise.
 OPENSSL_EXPORT int RSA_print(BIO *bio, const RSA *rsa, int indent);
 
+// RSA_get0_pss_params returns NULL. In OpenSSL, this function retries RSA-PSS
+// parameters associated with |RSA| objects, but BoringSSL does not support
+// the id-RSASSA-PSS key encoding.
+OPENSSL_EXPORT const RSA_PSS_PARAMS *RSA_get0_pss_params(const RSA *rsa);
+
 
 struct rsa_meth_st {
   struct openssl_method_common_st common;
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index f4444c9..30ad4d2 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -1887,12 +1887,16 @@
 OPENSSL_EXPORT int X509_TRUST_get_trust(const X509_TRUST *xp);
 
 
-typedef struct rsa_pss_params_st {
+struct rsa_pss_params_st {
   X509_ALGOR *hashAlgorithm;
   X509_ALGOR *maskGenAlgorithm;
   ASN1_INTEGER *saltLength;
   ASN1_INTEGER *trailerField;
-} RSA_PSS_PARAMS;
+  // OpenSSL caches the MGF hash on |RSA_PSS_PARAMS| in some cases. None of the
+  // cases apply to BoringSSL, so this is always NULL, but Node expects the
+  // field to be present.
+  X509_ALGOR *maskHash;
+} /* RSA_PSS_PARAMS */;
 
 DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS)