xref: /aosp_15_r20/external/cronet/net/ssl/ssl_private_key_test_util.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/ssl/ssl_private_key_test_util.h"
6 
7 #include <stdint.h>
8 
9 #include <vector>
10 
11 #include "base/containers/span.h"
12 #include "base/functional/bind.h"
13 #include "base/location.h"
14 #include "base/run_loop.h"
15 #include "crypto/openssl_util.h"
16 #include "net/base/net_errors.h"
17 #include "net/ssl/ssl_private_key.h"
18 #include "net/test/gtest_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/boringssl/src/include/openssl/bytestring.h"
21 #include "third_party/boringssl/src/include/openssl/digest.h"
22 #include "third_party/boringssl/src/include/openssl/evp.h"
23 #include "third_party/boringssl/src/include/openssl/rsa.h"
24 #include "third_party/boringssl/src/include/openssl/ssl.h"
25 
26 using net::test::IsOk;
27 
28 namespace net {
29 
30 namespace {
31 
VerifyWithOpenSSL(uint16_t algorithm,base::span<const uint8_t> input,EVP_PKEY * key,base::span<const uint8_t> signature)32 bool VerifyWithOpenSSL(uint16_t algorithm,
33                        base::span<const uint8_t> input,
34                        EVP_PKEY* key,
35                        base::span<const uint8_t> signature) {
36   bssl::ScopedEVP_MD_CTX ctx;
37   EVP_PKEY_CTX* pctx;
38   if (!EVP_DigestVerifyInit(ctx.get(), &pctx,
39                             SSL_get_signature_algorithm_digest(algorithm),
40                             nullptr, key)) {
41     return false;
42   }
43   if (SSL_is_signature_algorithm_rsa_pss(algorithm)) {
44     if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
45         !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* hash length */)) {
46       return false;
47     }
48   }
49   return EVP_DigestVerify(ctx.get(), signature.data(), signature.size(),
50                           input.data(), input.size());
51 }
52 
OnSignComplete(base::RunLoop * loop,Error * out_error,std::vector<uint8_t> * out_signature,Error error,const std::vector<uint8_t> & signature)53 void OnSignComplete(base::RunLoop* loop,
54                     Error* out_error,
55                     std::vector<uint8_t>* out_signature,
56                     Error error,
57                     const std::vector<uint8_t>& signature) {
58   *out_error = error;
59   *out_signature = signature;
60   loop->Quit();
61 }
62 
DoKeySigningWithWrapper(SSLPrivateKey * key,uint16_t algorithm,base::span<const uint8_t> input,std::vector<uint8_t> * result)63 Error DoKeySigningWithWrapper(SSLPrivateKey* key,
64                               uint16_t algorithm,
65                               base::span<const uint8_t> input,
66                               std::vector<uint8_t>* result) {
67   Error error;
68   base::RunLoop loop;
69   key->Sign(algorithm, input,
70             base::BindOnce(OnSignComplete, base::Unretained(&loop),
71                            base::Unretained(&error), base::Unretained(result)));
72   loop.Run();
73   return error;
74 }
75 
76 }  // namespace
77 
TestSSLPrivateKeyMatches(SSLPrivateKey * key,const std::string & pkcs8)78 void TestSSLPrivateKeyMatches(SSLPrivateKey* key, const std::string& pkcs8) {
79   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
80 
81   // Create the equivalent OpenSSL key.
82   CBS cbs;
83   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()), pkcs8.size());
84   bssl::UniquePtr<EVP_PKEY> openssl_key(EVP_parse_private_key(&cbs));
85   ASSERT_TRUE(openssl_key);
86   EXPECT_EQ(0u, CBS_len(&cbs));
87 
88   // Test all supported algorithms.
89   std::vector<uint16_t> preferences = key->GetAlgorithmPreferences();
90 
91   for (uint16_t algorithm : preferences) {
92     SCOPED_TRACE(
93         SSL_get_signature_algorithm_name(algorithm, 0 /* exclude curve */));
94     // BoringSSL will skip signatures algorithms that don't match the key type.
95     if (EVP_PKEY_id(openssl_key.get()) !=
96         SSL_get_signature_algorithm_key_type(algorithm)) {
97       continue;
98     }
99     // If the RSA key is too small for the hash, skip the algorithm. BoringSSL
100     // will filter this algorithm out and decline using it. In particular,
101     // 1024-bit RSA keys cannot sign RSA-PSS with SHA-512 and test keys are
102     // often 1024 bits.
103     if (SSL_is_signature_algorithm_rsa_pss(algorithm) &&
104         static_cast<size_t>(EVP_PKEY_size(openssl_key.get())) <
105             2 * EVP_MD_size(SSL_get_signature_algorithm_digest(algorithm)) +
106                 2) {
107       continue;
108     }
109 
110     // Test the key generates valid signatures.
111     std::vector<uint8_t> input(100, 'a');
112     std::vector<uint8_t> signature;
113     Error error = DoKeySigningWithWrapper(key, algorithm, input, &signature);
114     EXPECT_THAT(error, IsOk());
115     EXPECT_TRUE(
116         VerifyWithOpenSSL(algorithm, input, openssl_key.get(), signature));
117   }
118 }
119 
120 }  // namespace net
121