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