xref: /aosp_15_r20/external/cronet/net/ssl/ssl_platform_key_android.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 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_platform_key_android.h"
6 
7 #include <strings.h>
8 
9 #include <memory>
10 #include <optional>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/android/scoped_java_ref.h"
15 #include "base/containers/flat_set.h"
16 #include "base/logging.h"
17 #include "net/android/keystore.h"
18 #include "net/base/net_errors.h"
19 #include "net/ssl/ssl_platform_key_util.h"
20 #include "net/ssl/threaded_ssl_private_key.h"
21 #include "third_party/boringssl/src/include/openssl/ecdsa.h"
22 #include "third_party/boringssl/src/include/openssl/evp.h"
23 #include "third_party/boringssl/src/include/openssl/mem.h"
24 #include "third_party/boringssl/src/include/openssl/nid.h"
25 #include "third_party/boringssl/src/include/openssl/rsa.h"
26 #include "third_party/boringssl/src/include/openssl/ssl.h"
27 
28 using base::android::JavaRef;
29 using base::android::ScopedJavaGlobalRef;
30 
31 namespace net {
32 
33 namespace {
34 
GetJavaAlgorithm(uint16_t algorithm)35 const char* GetJavaAlgorithm(uint16_t algorithm) {
36   switch (algorithm) {
37     case SSL_SIGN_RSA_PKCS1_SHA1:
38       return "SHA1withRSA";
39     case SSL_SIGN_RSA_PKCS1_SHA256:
40       return "SHA256withRSA";
41     case SSL_SIGN_RSA_PKCS1_SHA384:
42       return "SHA384withRSA";
43     case SSL_SIGN_RSA_PKCS1_SHA512:
44       return "SHA512withRSA";
45     case SSL_SIGN_ECDSA_SHA1:
46       return "SHA1withECDSA";
47     case SSL_SIGN_ECDSA_SECP256R1_SHA256:
48       return "SHA256withECDSA";
49     case SSL_SIGN_ECDSA_SECP384R1_SHA384:
50       return "SHA384withECDSA";
51     case SSL_SIGN_ECDSA_SECP521R1_SHA512:
52       return "SHA512withECDSA";
53     case SSL_SIGN_RSA_PSS_SHA256:
54       return "SHA256withRSA/PSS";
55     case SSL_SIGN_RSA_PSS_SHA384:
56       return "SHA384withRSA/PSS";
57     case SSL_SIGN_RSA_PSS_SHA512:
58       return "SHA512withRSA/PSS";
59     default:
60       return nullptr;
61   }
62 }
63 
64 // Java's public-key encryption algorithms are mis-named. It incorrectly
65 // classifies RSA's "mode" as ECB.
66 const char kRSANoPadding[] = "RSA/ECB/NoPadding";
67 
68 class SSLPlatformKeyAndroid : public ThreadedSSLPrivateKey::Delegate {
69  public:
SSLPlatformKeyAndroid(bssl::UniquePtr<EVP_PKEY> pubkey,const JavaRef<jobject> & key)70   SSLPlatformKeyAndroid(bssl::UniquePtr<EVP_PKEY> pubkey,
71                         const JavaRef<jobject>& key)
72       : pubkey_(std::move(pubkey)),
73         provider_name_(android::GetPrivateKeyClassName(key)) {
74     key_.Reset(key);
75 
76     std::optional<bool> supports_rsa_no_padding;
77     for (uint16_t algorithm : SSLPrivateKey::DefaultAlgorithmPreferences(
78              EVP_PKEY_id(pubkey_.get()), true /* include PSS */)) {
79       const char* java_algorithm = GetJavaAlgorithm(algorithm);
80       if (java_algorithm &&
81           android::PrivateKeySupportsSignature(key_, java_algorithm)) {
82         preferences_.push_back(algorithm);
83       } else if (SSL_is_signature_algorithm_rsa_pss(algorithm)) {
84         // Check if we can use the fallback path instead.
85         if (!supports_rsa_no_padding) {
86           supports_rsa_no_padding =
87               android::PrivateKeySupportsCipher(key_, kRSANoPadding);
88         }
89         if (*supports_rsa_no_padding) {
90           preferences_.push_back(algorithm);
91           use_pss_fallback_.insert(algorithm);
92         }
93       }
94     }
95   }
96 
97   SSLPlatformKeyAndroid(const SSLPlatformKeyAndroid&) = delete;
98   SSLPlatformKeyAndroid& operator=(const SSLPlatformKeyAndroid&) = delete;
99 
100   ~SSLPlatformKeyAndroid() override = default;
101 
GetProviderName()102   std::string GetProviderName() override { return provider_name_; }
103 
GetAlgorithmPreferences()104   std::vector<uint16_t> GetAlgorithmPreferences() override {
105     return preferences_;
106   }
107 
Sign(uint16_t algorithm,base::span<const uint8_t> input,std::vector<uint8_t> * signature)108   Error Sign(uint16_t algorithm,
109              base::span<const uint8_t> input,
110              std::vector<uint8_t>* signature) override {
111     if (use_pss_fallback_.contains(algorithm)) {
112       return SignPSSFallback(algorithm, input, signature);
113     }
114 
115     const char* java_algorithm = GetJavaAlgorithm(algorithm);
116     if (!java_algorithm) {
117       LOG(ERROR) << "Unknown algorithm " << algorithm;
118       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
119     }
120     if (!android::SignWithPrivateKey(key_, java_algorithm, input, signature)) {
121       LOG(ERROR) << "Could not sign message with private key!";
122       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
123     }
124     return OK;
125   }
126 
127  private:
SignPSSFallback(uint16_t algorithm,base::span<const uint8_t> input,std::vector<uint8_t> * signature)128   Error SignPSSFallback(uint16_t algorithm,
129                         base::span<const uint8_t> input,
130                         std::vector<uint8_t>* signature) {
131     const EVP_MD* md = SSL_get_signature_algorithm_digest(algorithm);
132     uint8_t digest[EVP_MAX_MD_SIZE];
133     unsigned digest_len;
134     if (!EVP_Digest(input.data(), input.size(), digest, &digest_len, md,
135                     nullptr)) {
136       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
137     }
138 
139     std::optional<std::vector<uint8_t>> padded =
140         AddPSSPadding(pubkey_.get(), md, base::make_span(digest, digest_len));
141     if (!padded) {
142       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
143     }
144 
145     if (!android::EncryptWithPrivateKey(key_, kRSANoPadding, *padded,
146                                         signature)) {
147       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
148     }
149     return OK;
150   }
151 
152   bssl::UniquePtr<EVP_PKEY> pubkey_;
153   ScopedJavaGlobalRef<jobject> key_;
154   std::string provider_name_;
155   std::vector<uint16_t> preferences_;
156   base::flat_set<uint16_t> use_pss_fallback_;
157 };
158 
159 }  // namespace
160 
WrapJavaPrivateKey(const X509Certificate * certificate,const JavaRef<jobject> & key)161 scoped_refptr<SSLPrivateKey> WrapJavaPrivateKey(
162     const X509Certificate* certificate,
163     const JavaRef<jobject>& key) {
164   bssl::UniquePtr<EVP_PKEY> pubkey = GetClientCertPublicKey(certificate);
165   if (!pubkey)
166     return nullptr;
167 
168   return base::MakeRefCounted<ThreadedSSLPrivateKey>(
169       std::make_unique<SSLPlatformKeyAndroid>(std::move(pubkey), key),
170       GetSSLPlatformKeyTaskRunner());
171 }
172 
SignatureAlgorithmsToJavaKeyTypes(base::span<const uint16_t> algorithms)173 std::vector<std::string> SignatureAlgorithmsToJavaKeyTypes(
174     base::span<const uint16_t> algorithms) {
175   std::vector<std::string> key_types;
176   bool has_rsa = false, has_ec = false;
177   for (uint16_t alg : algorithms) {
178     switch (SSL_get_signature_algorithm_key_type(alg)) {
179       case EVP_PKEY_RSA:
180         if (!has_rsa) {
181           // https://developer.android.com/reference/android/security/keystore/KeyProperties#KEY_ALGORITHM_RSA
182           key_types.push_back("RSA");
183           has_rsa = true;
184         }
185         break;
186       case EVP_PKEY_EC:
187         if (!has_ec) {
188           // https://developer.android.com/reference/android/security/keystore/KeyProperties#KEY_ALGORITHM_EC
189           key_types.push_back("EC");
190           has_ec = true;
191         }
192         break;
193     }
194   }
195   return key_types;
196 }
197 
198 }  // namespace net
199