Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: net/ssl/ssl_platform_key_android.cc

Issue 2291213002: Remove ENGINE indirection from Android SSLPrivateKey. (Closed)
Patch Set: re-delete undeleted files Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/ssl/ssl_platform_key_android.h ('k') | net/ssl/ssl_platform_key_android_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/ssl/ssl_platform_key.h" 5 #include "net/ssl/ssl_platform_key_android.h"
6 6
7 #include <openssl/digest.h> 7 #include <openssl/ecdsa.h>
8 #include <openssl/evp.h> 8 #include <openssl/rsa.h>
9 #include <strings.h>
9 10
11 #include <memory>
10 #include <utility> 12 #include <utility>
13 #include <vector>
11 14
15 #include "base/android/build_info.h"
16 #include "base/android/scoped_java_ref.h"
17 #include "base/lazy_instance.h"
12 #include "base/logging.h" 18 #include "base/logging.h"
13 #include "base/macros.h" 19 #include "base/macros.h"
14 #include "base/memory/ptr_util.h" 20 #include "base/memory/ptr_util.h"
15 #include "crypto/scoped_openssl_types.h" 21 #include "crypto/scoped_openssl_types.h"
22 #include "net/android/keystore.h"
23 #include "net/android/legacy_openssl.h"
16 #include "net/base/net_errors.h" 24 #include "net/base/net_errors.h"
17 #include "net/ssl/openssl_client_key_store.h" 25 #include "net/ssl/openssl_client_key_store.h"
26 #include "net/ssl/ssl_platform_key.h"
18 #include "net/ssl/ssl_platform_key_task_runner.h" 27 #include "net/ssl/ssl_platform_key_task_runner.h"
19 #include "net/ssl/ssl_private_key.h"
20 #include "net/ssl/threaded_ssl_private_key.h" 28 #include "net/ssl/threaded_ssl_private_key.h"
21 29
30 using base::android::JavaRef;
31 using base::android::ScopedJavaGlobalRef;
32 using base::android::ScopedJavaLocalRef;
33
22 namespace net { 34 namespace net {
23 35
24 namespace { 36 namespace {
25 37
38 // On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not
39 // added to the global engine list. If all references to it are dropped, OpenSSL
40 // will dlclose the module, leaving a dangling function pointer in the RSA
41 // CRYPTO_EX_DATA class. To work around this, leak an extra reference to the
42 // ENGINE we extract in GetRsaLegacyKey.
43 //
44 // In 4.2, this change avoids the problem:
45 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d ddbe73ca5cb3d61
46 //
47 // https://crbug.com/381465
48 class KeystoreEngineWorkaround {
49 public:
50 KeystoreEngineWorkaround() {}
51
52 void LeakEngine(const JavaRef<jobject>& key) {
53 if (!engine_.is_null())
54 return;
55 ScopedJavaLocalRef<jobject> engine =
56 android::GetOpenSSLEngineForPrivateKey(key);
57 if (engine.is_null()) {
58 NOTREACHED();
59 return;
60 }
61 engine_.Reset(engine);
62 }
63
64 private:
65 ScopedJavaGlobalRef<jobject> engine_;
66 };
67
68 void LeakEngine(const JavaRef<jobject>& private_key) {
69 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance =
70 LAZY_INSTANCE_INITIALIZER;
71 s_instance.Get().LeakEngine(private_key);
72 }
73
26 class SSLPlatformKeyAndroid : public ThreadedSSLPrivateKey::Delegate { 74 class SSLPlatformKeyAndroid : public ThreadedSSLPrivateKey::Delegate {
27 public: 75 public:
28 SSLPlatformKeyAndroid(crypto::ScopedEVP_PKEY key, SSLPrivateKey::Type type) 76 SSLPlatformKeyAndroid(SSLPrivateKey::Type type,
29 : key_(std::move(key)), type_(type) {} 77 const JavaRef<jobject>& key,
78 size_t max_length,
79 android::AndroidRSA* legacy_rsa)
80 : type_(type), max_length_(max_length), legacy_rsa_(legacy_rsa) {
81 key_.Reset(key);
82 }
30 83
31 ~SSLPlatformKeyAndroid() override {} 84 ~SSLPlatformKeyAndroid() override {}
32 85
33 SSLPrivateKey::Type GetType() override { return type_; } 86 SSLPrivateKey::Type GetType() override { return type_; }
34 87
35 std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override { 88 std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override {
36 static const SSLPrivateKey::Hash kHashes[] = { 89 static const SSLPrivateKey::Hash kHashes[] = {
37 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384, 90 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
38 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1}; 91 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1};
39 return std::vector<SSLPrivateKey::Hash>(kHashes, 92 return std::vector<SSLPrivateKey::Hash>(kHashes,
40 kHashes + arraysize(kHashes)); 93 kHashes + arraysize(kHashes));
41 } 94 }
42 95
43 size_t GetMaxSignatureLengthInBytes() override { 96 size_t GetMaxSignatureLengthInBytes() override { return max_length_; }
44 return EVP_PKEY_size(key_.get());
45 }
46 97
47 Error SignDigest(SSLPrivateKey::Hash hash, 98 Error SignDigest(SSLPrivateKey::Hash hash,
48 const base::StringPiece& input, 99 const base::StringPiece& input_in,
49 std::vector<uint8_t>* signature) override { 100 std::vector<uint8_t>* signature) override {
50 crypto::ScopedEVP_PKEY_CTX ctx = 101 base::StringPiece input = input_in;
51 crypto::ScopedEVP_PKEY_CTX(EVP_PKEY_CTX_new(key_.get(), NULL));
52 if (!ctx)
53 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
54 if (!EVP_PKEY_sign_init(ctx.get()))
55 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
56 102
103 // Prepend the DigestInfo for RSA.
104 crypto::ScopedOpenSSLBytes digest_info_storage;
57 if (type_ == SSLPrivateKey::Type::RSA) { 105 if (type_ == SSLPrivateKey::Type::RSA) {
58 const EVP_MD* digest = nullptr; 106 int hash_nid = NID_undef;
59 switch (hash) { 107 switch (hash) {
60 case SSLPrivateKey::Hash::MD5_SHA1: 108 case SSLPrivateKey::Hash::MD5_SHA1:
61 digest = EVP_md5_sha1(); 109 hash_nid = NID_md5_sha1;
62 break; 110 break;
63 case SSLPrivateKey::Hash::SHA1: 111 case SSLPrivateKey::Hash::SHA1:
64 digest = EVP_sha1(); 112 hash_nid = NID_sha1;
65 break; 113 break;
66 case SSLPrivateKey::Hash::SHA256: 114 case SSLPrivateKey::Hash::SHA256:
67 digest = EVP_sha256(); 115 hash_nid = NID_sha256;
68 break; 116 break;
69 case SSLPrivateKey::Hash::SHA384: 117 case SSLPrivateKey::Hash::SHA384:
70 digest = EVP_sha384(); 118 hash_nid = NID_sha384;
71 break; 119 break;
72 case SSLPrivateKey::Hash::SHA512: 120 case SSLPrivateKey::Hash::SHA512:
73 digest = EVP_sha512(); 121 hash_nid = NID_sha512;
74 break; 122 break;
75 default:
76 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
77 } 123 }
78 DCHECK(digest); 124 DCHECK_NE(NID_undef, hash_nid);
79 if (!EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING)) 125
126 uint8_t* digest_info;
127 size_t digest_info_len;
128 int is_alloced;
129 if (!RSA_add_pkcs1_prefix(
130 &digest_info, &digest_info_len, &is_alloced, hash_nid,
131 reinterpret_cast<const uint8_t*>(input.data()), input.size())) {
80 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; 132 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
81 if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), digest)) 133 }
82 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; 134
135 if (is_alloced)
136 digest_info_storage.reset(digest_info);
137 input = base::StringPiece(reinterpret_cast<const char*>(digest_info),
138 digest_info_len);
83 } 139 }
84 140
85 const uint8_t* input_ptr = reinterpret_cast<const uint8_t*>(input.data()); 141 // Pre-4.2 legacy codepath.
86 size_t input_len = input.size(); 142 if (legacy_rsa_) {
87 size_t sig_len = 0; 143 signature->resize(max_length_);
88 if (!EVP_PKEY_sign(ctx.get(), NULL, &sig_len, input_ptr, input_len)) 144 int ret = legacy_rsa_->meth->rsa_priv_enc(
89 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; 145 input.size(), reinterpret_cast<const uint8_t*>(input.data()),
90 signature->resize(sig_len); 146 signature->data(), legacy_rsa_, android::ANDROID_RSA_PKCS1_PADDING);
91 if (!EVP_PKEY_sign(ctx.get(), signature->data(), &sig_len, input_ptr, 147 if (ret < 0) {
92 input_len)) { 148 LOG(WARNING) << "Could not sign message with legacy RSA key!";
149 // System OpenSSL will use a separate error queue, so it is still
150 // necessary to push a new error.
151 //
152 // TODO(davidben): It would be good to also clear the system error queue
153 // if there were some way to convince Java to do it. (Without going
154 // through Java, it's difficult to get a handle on a system OpenSSL
155 // function; dlopen loads a second copy.)
156 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
157 }
158 signature->resize(ret);
159 return OK;
160 }
161
162 if (!android::RawSignDigestWithPrivateKey(key_, input, signature)) {
163 LOG(WARNING) << "Could not sign message with private key!";
93 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; 164 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
94 } 165 }
95
96 signature->resize(sig_len);
97
98 return OK; 166 return OK;
99 } 167 }
100 168
101 private: 169 private:
102 crypto::ScopedEVP_PKEY key_;
103 SSLPrivateKey::Type type_; 170 SSLPrivateKey::Type type_;
171 ScopedJavaGlobalRef<jobject> key_;
172 size_t max_length_;
173 android::AndroidRSA* legacy_rsa_;
104 174
105 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyAndroid); 175 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyAndroid);
106 }; 176 };
107 177
108 scoped_refptr<SSLPrivateKey> WrapOpenSSLPrivateKey(crypto::ScopedEVP_PKEY key) { 178 // VectorBignumSize returns the number of bytes needed to represent the bignum
109 if (!key) 179 // given in |v|, i.e. the length of |v| less any leading zero bytes.
180 size_t VectorBignumSize(const std::vector<uint8_t>& v) {
181 size_t size = v.size();
182 // Ignore any leading zero bytes.
183 for (size_t i = 0; i < v.size() && v[i] == 0; i++) {
184 size--;
185 }
186 return size;
187 }
188
189 std::unique_ptr<SSLPlatformKeyAndroid> CreateRsaKey(
190 const JavaRef<jobject>& key) {
191 android::AndroidRSA* sys_rsa = nullptr;
192 const int kAndroid42ApiLevel = 17;
193 if (base::android::BuildInfo::GetInstance()->sdk_int() < kAndroid42ApiLevel) {
194 // Route around platform limitations: if Android < 4.2, then
195 // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get
196 // the system OpenSSL's EVP_PKEY backing this PrivateKey object.
197 android::AndroidEVP_PKEY* sys_pkey =
198 android::GetOpenSSLSystemHandleForPrivateKey(key);
199 if (!sys_pkey)
200 return nullptr;
201
202 if (sys_pkey->type != android::ANDROID_EVP_PKEY_RSA) {
203 LOG(ERROR) << "Private key has wrong type!";
204 return nullptr;
205 }
206
207 sys_rsa = sys_pkey->pkey.rsa;
208 if (sys_rsa->engine) {
209 // |private_key| may not have an engine if the PrivateKey did not come
210 // from the key store, such as in unit tests.
211 if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
212 LeakEngine(key);
213 } else {
214 NOTREACHED();
215 }
216 }
217 }
218
219 std::vector<uint8_t> modulus;
220 if (!android::GetRSAKeyModulus(key, &modulus)) {
221 LOG(ERROR) << "Failed to get private key modulus";
110 return nullptr; 222 return nullptr;
223 }
111 224
112 SSLPrivateKey::Type type; 225 return base::MakeUnique<SSLPlatformKeyAndroid>(
113 switch (EVP_PKEY_id(key.get())) { 226 SSLPrivateKey::Type::RSA, key, VectorBignumSize(modulus), sys_rsa);
114 case EVP_PKEY_RSA: 227 }
115 type = SSLPrivateKey::Type::RSA; 228
116 break; 229 std::unique_ptr<SSLPlatformKeyAndroid> CreateEcdsaKey(
117 case EVP_PKEY_EC: 230 const JavaRef<jobject>& key) {
118 type = SSLPrivateKey::Type::ECDSA; 231 std::vector<uint8_t> order;
119 break; 232 if (!android::GetECKeyOrder(key, &order)) {
120 default: 233 LOG(ERROR) << "Can't extract order parameter from EC private key";
121 LOG(ERROR) << "Unknown key type: " << EVP_PKEY_id(key.get()); 234 return nullptr;
122 return nullptr;
123 } 235 }
124 return make_scoped_refptr(new ThreadedSSLPrivateKey( 236
125 base::WrapUnique(new SSLPlatformKeyAndroid(std::move(key), type)), 237 return base::MakeUnique<SSLPlatformKeyAndroid>(
126 GetSSLPlatformKeyTaskRunner())); 238 SSLPrivateKey::Type::ECDSA, key,
239 ECDSA_SIG_max_len(VectorBignumSize(order)), nullptr);
127 } 240 }
128 241
129 } // namespace 242 } // namespace
130 243
244 scoped_refptr<SSLPrivateKey> WrapJavaPrivateKey(const JavaRef<jobject>& key) {
245 std::unique_ptr<SSLPlatformKeyAndroid> delegate;
246 switch (android::GetPrivateKeyType(key)) {
247 case android::PRIVATE_KEY_TYPE_RSA:
248 delegate = CreateRsaKey(key);
249 break;
250 case android::PRIVATE_KEY_TYPE_ECDSA:
251 delegate = CreateEcdsaKey(key);
252 break;
253 default:
254 LOG(WARNING) << "GetPrivateKeyType() returned invalid type";
255 return nullptr;
256 }
257
258 return make_scoped_refptr(new ThreadedSSLPrivateKey(
259 std::move(delegate), GetSSLPlatformKeyTaskRunner()));
260 }
261
131 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey( 262 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
132 X509Certificate* certificate) { 263 X509Certificate* certificate) {
133 crypto::ScopedEVP_PKEY key = 264 return OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
134 OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey( 265 certificate);
135 certificate);
136 return WrapOpenSSLPrivateKey(std::move(key));
137 } 266 }
138 267
139 } // namespace net 268 } // namespace net
OLDNEW
« no previous file with comments | « net/ssl/ssl_platform_key_android.h ('k') | net/ssl/ssl_platform_key_android_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698