From 1a74096bea39f2ed39d3d921db1032add526b03a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
Date: Mon, 11 Jan 2021 13:43:16 +0100
Subject: [PATCH] crypto: fix WebCrypto import of RSA-PSS keys

This patch changes GetRsaKeyDetail to work in older supported versions
of OpenSSL.

Refs: https://github.com/openssl/openssl/pull/10217
---
 src/crypto/crypto_rsa.cc                      | 18 ++++++++-
 .../parallel/test-webcrypto-rsa-pss-params.js | 40 +++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)
 create mode 100644 test/parallel/test-webcrypto-rsa-pss-params.js

diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc
index d859551392a382..971b184b0c53f5 100644
--- a/src/crypto/crypto_rsa.cc
+++ b/src/crypto/crypto_rsa.cc
@@ -367,7 +367,14 @@ Maybe<bool> ExportJWKRsaKey(
   int type = EVP_PKEY_id(pkey.get());
   CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
 
-  RSA* rsa = EVP_PKEY_get0_RSA(pkey.get());
+  // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
+  // versions older than 1.1.1e via FIPS / dynamic linking.
+  RSA* rsa;
+  if (OpenSSL_version_num() >= 0x1010105fL) {
+    rsa = EVP_PKEY_get0_RSA(pkey.get());
+  } else {
+    rsa = static_cast<RSA*>(EVP_PKEY_get0(pkey.get()));
+  }
   CHECK_NOT_NULL(rsa);
 
   const BIGNUM* n;
@@ -508,7 +515,14 @@ Maybe<bool> GetRsaKeyDetail(
   int type = EVP_PKEY_id(pkey.get());
   CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
 
-  RSA* rsa = EVP_PKEY_get0_RSA(pkey.get());
+  // TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
+  // versions older than 1.1.1e via FIPS / dynamic linking.
+  RSA* rsa;
+  if (OpenSSL_version_num() >= 0x1010105fL) {
+    rsa = EVP_PKEY_get0_RSA(pkey.get());
+  } else {
+    rsa = static_cast<RSA*>(EVP_PKEY_get0(pkey.get()));
+  }
   CHECK_NOT_NULL(rsa);
 
   RSA_get0_key(rsa, &n, &e, nullptr);
diff --git a/test/parallel/test-webcrypto-rsa-pss-params.js b/test/parallel/test-webcrypto-rsa-pss-params.js
new file mode 100644
index 00000000000000..964eaf32e890fd
--- /dev/null
+++ b/test/parallel/test-webcrypto-rsa-pss-params.js
@@ -0,0 +1,40 @@
+'use strict';
+
+const common = require('../common');
+
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const {
+  createPrivateKey,
+  createPublicKey,
+  webcrypto: {
+    subtle
+  }
+} = require('crypto');
+
+const fixtures = require('../common/fixtures');
+
+{
+  const rsaPssKeyWithoutParams = fixtures.readKey('rsa_pss_private_2048.pem');
+
+  const pkcs8 = createPrivateKey(rsaPssKeyWithoutParams).export({
+    type: 'pkcs8',
+    format: 'der'
+  });
+  const spki = createPublicKey(rsaPssKeyWithoutParams).export({
+    type: 'spki',
+    format: 'der'
+  });
+
+  const hashes = ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'];
+
+  const tasks = [];
+  for (const hash of hashes) {
+    const algorithm = { name: 'RSA-PSS', hash };
+    tasks.push(subtle.importKey('pkcs8', pkcs8, algorithm, true, ['sign']));
+    tasks.push(subtle.importKey('spki', spki, algorithm, true, ['verify']));
+  }
+
+  Promise.all(tasks).then(common.mustCall());
+}