Manually verify the certificate with RSA-PSS & SHA1/SHA224 digests.
`x509_verify` not working with RSA-PSS & SHA1/SHA224 digests. BoringSSL
after https://boringssl-review.googlesource.com/c/boringssl/+/53865
does not support RSA-PSS with SHA1/SHA224 digests.
Bug: 270297780
Test: atest keystore2_crypto_test
Change-Id: Ibd570edce4294eeda7dea864686fe8fd022432d0
diff --git a/keystore2/src/crypto/tests/certificate_utils_test.cpp b/keystore2/src/crypto/tests/certificate_utils_test.cpp
index a851798..e2f7cdb 100644
--- a/keystore2/src/crypto/tests/certificate_utils_test.cpp
+++ b/keystore2/src/crypto/tests/certificate_utils_test.cpp
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include "certificate_utils.h"
+#include <gtest/gtest.h>
#include <openssl/err.h>
#include <openssl/evp.h>
@@ -231,6 +230,72 @@
return s.str();
}
+static std::optional<std::vector<uint8_t>> EncodeX509Algor(const X509_ALGOR* alg) {
+ uint8_t* der = nullptr;
+ int der_len = i2d_X509_ALGOR(alg, &der);
+ if (der_len < 0) {
+ return std::nullopt;
+ }
+ std::vector<uint8_t> ret(der, der + der_len);
+ OPENSSL_free(der);
+ return ret;
+}
+
+// `x509_verify` not working with RSA-PSS & SHA1/SHA224 digests. so, manually
+// verify the certificate with RSA-PSS & SHA1/SHA224 digests.
+// BoringSSL after https://boringssl-review.googlesource.com/c/boringssl/+/53865
+// does not support RSA-PSS with SHA1/SHA224 digests.
+static void verifyCertFieldsExplicitly(X509* cert, Digest digest) {
+ // RSA-PSS-SHA1 AlgorithmIdentifier DER encoded value
+ const std::vector<uint8_t> expected_rsa_pss_sha1 = {
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30, 0x00,
+ };
+ // RSA-PSS-SHA224 AlgorithmIdentifier DER encoded value
+ const std::vector<uint8_t> expected_rsa_pss_sha224 = {
+ 0x30, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
+ 0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+ 0x02, 0x04, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
+ 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0xa2, 0x03, 0x02, 0x01, 0x1c,
+ };
+ const X509_ALGOR* alg;
+ const ASN1_BIT_STRING* sig;
+ const EVP_MD* evp_digest;
+ X509_get0_signature(&sig, &alg, cert);
+ auto encoded = EncodeX509Algor(alg);
+ ASSERT_TRUE(encoded);
+
+ // Check the AlgorithmIdentifiers.
+ if (digest == Digest::SHA1) {
+ evp_digest = EVP_sha1();
+ EXPECT_EQ(encoded.value(), expected_rsa_pss_sha1);
+ } else if (digest == Digest::SHA224) {
+ evp_digest = EVP_sha224();
+ EXPECT_EQ(encoded.value(), expected_rsa_pss_sha224);
+ } else {
+ GTEST_FAIL()
+ << "Error: This is expected to be used only for RSA-PSS with SHA1/SHA224 as digests";
+ }
+
+ // Check the signature.
+ EVP_PKEY_Ptr pubkey(X509_get_pubkey(cert));
+ ASSERT_TRUE(pubkey);
+
+ uint8_t* tbs = nullptr;
+ int tbs_len = i2d_X509_tbs(cert, &tbs);
+ ASSERT_GT(tbs_len, 0);
+
+ size_t sig_len;
+ ASSERT_TRUE(ASN1_BIT_STRING_num_bytes(sig, &sig_len));
+ EVP_PKEY_CTX* pctx;
+ bssl::ScopedEVP_MD_CTX ctx;
+ ASSERT_TRUE(EVP_DigestVerifyInit(ctx.get(), &pctx, evp_digest, nullptr, pubkey.get()));
+ ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING));
+ // The salt length should match the digest length.
+ ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1));
+ EXPECT_TRUE(EVP_DigestVerify(ctx.get(), ASN1_STRING_get0_data(sig), sig_len, tbs, tbs_len));
+}
+
INSTANTIATE_TEST_SUITE_P(CertSigningWithCallbackRsa, CertificateUtilsWithRsa,
testing::Combine(testing::ValuesIn(rsa_key_sizes),
testing::ValuesIn(rsa_paddings),
@@ -315,10 +380,10 @@
EVP_PKEY_Ptr decoded_pkey(X509_get_pubkey(decoded_cert.get()));
if ((padding == Padding::PSS) && (digest == Digest::SHA1 || digest == Digest::SHA224)) {
// BoringSSL after https://boringssl-review.googlesource.com/c/boringssl/+/53865
- // does not support these PSS combinations, so skip certificate verification for them
- // and just check _something_ was returned.
+ // does not support these PSS combinations, so verify these certificates manually.
EXPECT_NE(decoded_cert.get(), nullptr);
EXPECT_NE(decoded_pkey.get(), nullptr);
+ verifyCertFieldsExplicitly(decoded_cert.get(), digest);
} else {
ASSERT_TRUE(X509_verify(decoded_cert.get(), decoded_pkey.get()));
}