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

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

Issue 2566273008: Use SecKeyCreateSignature on macOS 10.12 and later. (Closed)
Patch Set: rsleevi comments Created 4 years 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.cc ('k') | net/ssl/ssl_platform_key_chromecast.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 (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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_android.h"
6
7 #include <string>
8
5 #include "base/android/jni_android.h" 9 #include "base/android/jni_android.h"
6 #include "base/android/jni_array.h" 10 #include "base/android/jni_array.h"
7 #include "base/android/scoped_java_ref.h" 11 #include "base/android/scoped_java_ref.h"
8 #include "base/bind.h"
9 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
10 #include "base/files/file_util.h" 13 #include "base/files/file_util.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "crypto/openssl_util.h"
15 #include "net/android/keystore.h" 14 #include "net/android/keystore.h"
16 #include "net/cert/x509_certificate.h" 15 #include "net/cert/x509_certificate.h"
17 #include "net/ssl/ssl_platform_key_android.h"
18 #include "net/ssl/ssl_private_key.h" 16 #include "net/ssl/ssl_private_key.h"
17 #include "net/ssl/ssl_private_key_test_util.h"
19 #include "net/test/cert_test_util.h" 18 #include "net/test/cert_test_util.h"
20 #include "net/test/jni/AndroidKeyStoreTestUtil_jni.h" 19 #include "net/test/jni/AndroidKeyStoreTestUtil_jni.h"
21 #include "net/test/test_data_directory.h" 20 #include "net/test/test_data_directory.h"
22 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/boringssl/src/include/openssl/bytestring.h"
24 #include "third_party/boringssl/src/include/openssl/digest.h"
25 #include "third_party/boringssl/src/include/openssl/ecdsa.h"
26 #include "third_party/boringssl/src/include/openssl/err.h"
27 #include "third_party/boringssl/src/include/openssl/evp.h"
28 #include "third_party/boringssl/src/include/openssl/pem.h"
29 #include "third_party/boringssl/src/include/openssl/rsa.h"
30 #include "third_party/boringssl/src/include/openssl/x509.h"
31 22
32 namespace net { 23 namespace net {
33 24
34 namespace { 25 namespace {
35 26
36 typedef base::android::ScopedJavaLocalRef<jobject> ScopedJava; 27 typedef base::android::ScopedJavaLocalRef<jobject> ScopedJava;
37 28
38 // Resize a string to |size| bytes of data, then return its data buffer address
39 // cast as an 'uint8_t*', as expected by OpenSSL functions.
40 // |str| the target string.
41 // |size| the number of bytes to write into the string.
42 // Return the string's new buffer in memory, as an 'uint8_t*' pointer.
43 uint8_t* OpenSSLWriteInto(std::string* str, size_t size) {
44 return reinterpret_cast<uint8_t*>(base::WriteInto(str, size + 1));
45 }
46
47 bool ReadTestFile(const char* filename, std::string* pkcs8) { 29 bool ReadTestFile(const char* filename, std::string* pkcs8) {
48 base::FilePath certs_dir = GetTestCertsDirectory(); 30 base::FilePath certs_dir = GetTestCertsDirectory();
49 base::FilePath file_path = certs_dir.AppendASCII(filename); 31 base::FilePath file_path = certs_dir.AppendASCII(filename);
50 return base::ReadFileToString(file_path, pkcs8); 32 return base::ReadFileToString(file_path, pkcs8);
51 } 33 }
52 34
53 // Parses a PKCS#8 key into an OpenSSL private key object.
54 bssl::UniquePtr<EVP_PKEY> ImportPrivateKeyOpenSSL(const std::string& pkcs8) {
55 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
56 CBS cbs;
57 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()), pkcs8.size());
58 return bssl::UniquePtr<EVP_PKEY>(EVP_parse_private_key(&cbs));
59 }
60
61 // Retrieve a JNI local ref from encoded PKCS#8 data. 35 // Retrieve a JNI local ref from encoded PKCS#8 data.
62 ScopedJava GetPKCS8PrivateKeyJava(android::PrivateKeyType key_type, 36 ScopedJava GetPKCS8PrivateKeyJava(android::PrivateKeyType key_type,
63 const std::string& pkcs8_key) { 37 const std::string& pkcs8_key) {
64 JNIEnv* env = base::android::AttachCurrentThread(); 38 JNIEnv* env = base::android::AttachCurrentThread();
65 base::android::ScopedJavaLocalRef<jbyteArray> bytes( 39 base::android::ScopedJavaLocalRef<jbyteArray> bytes(
66 base::android::ToJavaByteArray( 40 base::android::ToJavaByteArray(
67 env, reinterpret_cast<const uint8_t*>(pkcs8_key.data()), 41 env, reinterpret_cast<const uint8_t*>(pkcs8_key.data()),
68 pkcs8_key.size())); 42 pkcs8_key.size()));
69 43
70 ScopedJava key(Java_AndroidKeyStoreTestUtil_createPrivateKeyFromPKCS8( 44 ScopedJava key(Java_AndroidKeyStoreTestUtil_createPrivateKeyFromPKCS8(
71 env, key_type, bytes)); 45 env, key_type, bytes));
72 46
73 return key; 47 return key;
74 } 48 }
75 49
76 bool VerifyWithOpenSSL(const EVP_MD* md,
77 const base::StringPiece& digest,
78 EVP_PKEY* key,
79 const base::StringPiece& signature) {
80 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
81
82 bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
83 if (!ctx || !EVP_PKEY_verify_init(ctx.get()) ||
84 !EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
85 !EVP_PKEY_verify(
86 ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()),
87 signature.size(), reinterpret_cast<const uint8_t*>(digest.data()),
88 digest.size())) {
89 return false;
90 }
91
92 return true;
93 }
94
95 bool SignWithOpenSSL(const EVP_MD* md,
96 const base::StringPiece& digest,
97 EVP_PKEY* key,
98 std::string* result) {
99 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
100
101 size_t sig_len;
102 bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
103 if (!ctx || !EVP_PKEY_sign_init(ctx.get()) ||
104 !EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
105 !EVP_PKEY_sign(ctx.get(), OpenSSLWriteInto(result, EVP_PKEY_size(key)),
106 &sig_len, reinterpret_cast<const uint8_t*>(digest.data()),
107 digest.size())) {
108 return false;
109 }
110
111 result->resize(sig_len);
112 return true;
113 }
114
115 void OnSignComplete(base::RunLoop* loop,
116 Error* out_error,
117 std::string* out_signature,
118 Error error,
119 const std::vector<uint8_t>& signature) {
120 *out_error = error;
121 out_signature->assign(signature.begin(), signature.end());
122 loop->Quit();
123 }
124
125 void DoKeySigningWithWrapper(SSLPrivateKey* key,
126 SSLPrivateKey::Hash hash,
127 const base::StringPiece& message,
128 std::string* result) {
129 Error error;
130 base::RunLoop loop;
131
132 key->SignDigest(
133 hash, message,
134 base::Bind(OnSignComplete, base::Unretained(&loop),
135 base::Unretained(&error), base::Unretained(result)));
136 loop.Run();
137
138 ASSERT_EQ(OK, error);
139 }
140
141 static const struct {
142 const char* name;
143 int nid;
144 SSLPrivateKey::Hash hash;
145 } kHashes[] = {
146 {"MD5-SHA1", NID_md5_sha1, SSLPrivateKey::Hash::MD5_SHA1},
147 {"SHA-1", NID_sha1, SSLPrivateKey::Hash::SHA1},
148 {"SHA-256", NID_sha256, SSLPrivateKey::Hash::SHA256},
149 {"SHA-384", NID_sha384, SSLPrivateKey::Hash::SHA384},
150 {"SHA-512", NID_sha512, SSLPrivateKey::Hash::SHA512},
151 };
152
153 struct TestKey { 50 struct TestKey {
154 const char* cert_file; 51 const char* cert_file;
155 const char* key_file; 52 const char* key_file;
156 android::PrivateKeyType android_key_type; 53 android::PrivateKeyType android_key_type;
157 SSLPrivateKey::Type key_type; 54 SSLPrivateKey::Type key_type;
158 }; 55 };
159 56
160 static const TestKey kTestKeys[] = { 57 const TestKey kTestKeys[] = {
161 {"client_1.pem", "client_1.pk8", android::PRIVATE_KEY_TYPE_RSA, 58 {"client_1.pem", "client_1.pk8", android::PRIVATE_KEY_TYPE_RSA,
162 SSLPrivateKey::Type::RSA}, 59 SSLPrivateKey::Type::RSA},
163 {"client_4.pem", "client_4.pk8", android::PRIVATE_KEY_TYPE_ECDSA, 60 {"client_4.pem", "client_4.pk8", android::PRIVATE_KEY_TYPE_ECDSA,
164 SSLPrivateKey::Type::ECDSA_P256}, 61 SSLPrivateKey::Type::ECDSA_P256},
165 {"client_5.pem", "client_5.pk8", android::PRIVATE_KEY_TYPE_ECDSA, 62 {"client_5.pem", "client_5.pk8", android::PRIVATE_KEY_TYPE_ECDSA,
166 SSLPrivateKey::Type::ECDSA_P384}, 63 SSLPrivateKey::Type::ECDSA_P384},
167 {"client_6.pem", "client_6.pk8", android::PRIVATE_KEY_TYPE_ECDSA, 64 {"client_6.pem", "client_6.pk8", android::PRIVATE_KEY_TYPE_ECDSA,
168 SSLPrivateKey::Type::ECDSA_P521}, 65 SSLPrivateKey::Type::ECDSA_P521},
169 }; 66 };
170 67
68 std::string TestKeyToString(const testing::TestParamInfo<TestKey>& params) {
69 return SSLPrivateKeyTypeToString(params.param.key_type);
70 }
71
171 } // namespace 72 } // namespace
172 73
173 class SSLPlatformKeyAndroidTest : public testing::TestWithParam<TestKey> {}; 74 class SSLPlatformKeyAndroidTest : public testing::TestWithParam<TestKey> {};
174 75
175 TEST_P(SSLPlatformKeyAndroidTest, SignHashes) { 76 TEST_P(SSLPlatformKeyAndroidTest, Matches) {
176 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
177 const TestKey& test_key = GetParam(); 77 const TestKey& test_key = GetParam();
178 78
179 scoped_refptr<X509Certificate> cert = 79 scoped_refptr<X509Certificate> cert =
180 ImportCertFromFile(GetTestCertsDirectory(), test_key.cert_file); 80 ImportCertFromFile(GetTestCertsDirectory(), test_key.cert_file);
181 ASSERT_TRUE(cert); 81 ASSERT_TRUE(cert);
182 82
183 std::string key_bytes; 83 std::string key_bytes;
184 ASSERT_TRUE(ReadTestFile(test_key.key_file, &key_bytes)); 84 ASSERT_TRUE(ReadTestFile(test_key.key_file, &key_bytes));
185 ScopedJava java_key = 85 ScopedJava java_key =
186 GetPKCS8PrivateKeyJava(test_key.android_key_type, key_bytes); 86 GetPKCS8PrivateKeyJava(test_key.android_key_type, key_bytes);
187 ASSERT_FALSE(java_key.is_null()); 87 ASSERT_FALSE(java_key.is_null());
188 88
189 scoped_refptr<SSLPrivateKey> wrapper_key = 89 scoped_refptr<SSLPrivateKey> key = WrapJavaPrivateKey(cert.get(), java_key);
190 WrapJavaPrivateKey(cert.get(), java_key); 90 ASSERT_TRUE(key);
191 ASSERT_TRUE(wrapper_key);
192 91
193 bssl::UniquePtr<EVP_PKEY> openssl_key = ImportPrivateKeyOpenSSL(key_bytes); 92 // All Android keys are expected to have the same hash preferences.
194 ASSERT_TRUE(openssl_key); 93 std::vector<SSLPrivateKey::Hash> expected_hashes = {
94 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
95 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1,
96 };
97 EXPECT_EQ(expected_hashes, key->GetDigestPreferences());
195 98
196 // Check that the wrapper key returns the correct length and type. 99 TestSSLPrivateKeyMatches(key.get(), key_bytes);
197 EXPECT_EQ(test_key.key_type, wrapper_key->GetType());
198 EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(openssl_key.get())),
199 wrapper_key->GetMaxSignatureLengthInBytes());
200
201 // Test signing against each hash.
202 for (const auto& hash : kHashes) {
203 // Only RSA signs MD5-SHA1.
204 if (test_key.key_type != SSLPrivateKey::Type::RSA &&
205 hash.nid == NID_md5_sha1) {
206 continue;
207 }
208
209 SCOPED_TRACE(hash.name);
210
211 const EVP_MD* md = EVP_get_digestbynid(hash.nid);
212 ASSERT_TRUE(md);
213 std::string digest(EVP_MD_size(md), 'a');
214
215 std::string signature;
216 DoKeySigningWithWrapper(wrapper_key.get(), hash.hash, digest, &signature);
217 EXPECT_TRUE(VerifyWithOpenSSL(md, digest, openssl_key.get(), signature));
218
219 // RSA signing is deterministic, so further check the signature matches.
220 if (test_key.key_type == SSLPrivateKey::Type::RSA) {
221 std::string openssl_signature;
222 ASSERT_TRUE(
223 SignWithOpenSSL(md, digest, openssl_key.get(), &openssl_signature));
224 EXPECT_EQ(openssl_signature, signature);
225 }
226 }
227 } 100 }
228 101
229 INSTANTIATE_TEST_CASE_P(, 102 INSTANTIATE_TEST_CASE_P(,
230 SSLPlatformKeyAndroidTest, 103 SSLPlatformKeyAndroidTest,
231 testing::ValuesIn(kTestKeys)); 104 testing::ValuesIn(kTestKeys),
105 TestKeyToString);
232 106
233 } // namespace net 107 } // namespace net
OLDNEW
« no previous file with comments | « net/ssl/ssl_platform_key_android.cc ('k') | net/ssl/ssl_platform_key_chromecast.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698