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

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

Issue 2567523003: Fix P-521 client cert mapping and test all curves. (Closed)
Patch Set: reupload with hack to depot_tools 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/net.gypi ('k') | net/ssl/ssl_platform_key_util.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 "base/android/jni_android.h" 5 #include "base/android/jni_android.h"
6 #include "base/android/jni_array.h" 6 #include "base/android/jni_array.h"
7 #include "base/android/scoped_java_ref.h" 7 #include "base/android/scoped_java_ref.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
(...skipping 17 matching lines...) Expand all
28 #include "third_party/boringssl/src/include/openssl/pem.h" 28 #include "third_party/boringssl/src/include/openssl/pem.h"
29 #include "third_party/boringssl/src/include/openssl/rsa.h" 29 #include "third_party/boringssl/src/include/openssl/rsa.h"
30 #include "third_party/boringssl/src/include/openssl/x509.h" 30 #include "third_party/boringssl/src/include/openssl/x509.h"
31 31
32 namespace net { 32 namespace net {
33 33
34 namespace { 34 namespace {
35 35
36 typedef base::android::ScopedJavaLocalRef<jobject> ScopedJava; 36 typedef base::android::ScopedJavaLocalRef<jobject> ScopedJava;
37 37
38 // Resize a string to |size| bytes of data, then return its data buffer 38 // Resize a string to |size| bytes of data, then return its data buffer address
39 // address cast as an 'unsigned char*', as expected by OpenSSL functions. 39 // cast as an 'uint8_t*', as expected by OpenSSL functions.
40 // |str| the target string. 40 // |str| the target string.
41 // |size| the number of bytes to write into the string. 41 // |size| the number of bytes to write into the string.
42 // Return the string's new buffer in memory, as an 'unsigned char*' 42 // Return the string's new buffer in memory, as an 'uint8_t*' pointer.
43 // pointer. 43 uint8_t* OpenSSLWriteInto(std::string* str, size_t size) {
44 unsigned char* OpenSSLWriteInto(std::string* str, size_t size) { 44 return reinterpret_cast<uint8_t*>(base::WriteInto(str, size + 1));
45 return reinterpret_cast<unsigned char*>(base::WriteInto(str, size + 1));
46 } 45 }
47 46
48 bool ReadTestFile(const char* filename, std::string* pkcs8) { 47 bool ReadTestFile(const char* filename, std::string* pkcs8) {
49 base::FilePath certs_dir = GetTestCertsDirectory(); 48 base::FilePath certs_dir = GetTestCertsDirectory();
50 base::FilePath file_path = certs_dir.AppendASCII(filename); 49 base::FilePath file_path = certs_dir.AppendASCII(filename);
51 return base::ReadFileToString(file_path, pkcs8); 50 return base::ReadFileToString(file_path, pkcs8);
52 } 51 }
53 52
54 // Load a given private key file into an EVP_PKEY. 53 // Parses a PKCS#8 key into an OpenSSL private key object.
55 // |filename| is the key file path. 54 bssl::UniquePtr<EVP_PKEY> ImportPrivateKeyOpenSSL(const std::string& pkcs8) {
56 // Returns a new EVP_PKEY on success, NULL on failure.
57 bssl::UniquePtr<EVP_PKEY> ImportPrivateKeyFile(const char* filename) {
58 std::string pkcs8;
59 if (!ReadTestFile(filename, &pkcs8))
60 return nullptr;
61
62 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 55 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
63 CBS cbs; 56 CBS cbs;
64 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()), pkcs8.size()); 57 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()), pkcs8.size());
65 bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs)); 58 return bssl::UniquePtr<EVP_PKEY>(EVP_parse_private_key(&cbs));
66 if (!pkey) {
67 LOG(ERROR) << "Could not load private key file: " << filename;
68 return nullptr;
69 }
70
71 return pkey;
72 }
73
74 // Imports the public key from the specified test certificate.
75 bssl::UniquePtr<EVP_PKEY> ImportPublicKeyFromCertificateFile(
76 const char* filename) {
77 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
78
79 scoped_refptr<X509Certificate> cert =
80 ImportCertFromFile(GetTestCertsDirectory(), filename);
81 if (!cert) {
82 LOG(ERROR) << "Could not open certificate file: " << filename;
83 return nullptr;
84 }
85
86 bssl::UniquePtr<EVP_PKEY> pkey(X509_get_pubkey(cert->os_cert_handle()));
87 if (!pkey) {
88 LOG(ERROR) << "Could not load public key from certificate: " << filename;
89 return nullptr;
90 }
91
92 return pkey;
93 } 59 }
94 60
95 // Retrieve a JNI local ref from encoded PKCS#8 data. 61 // Retrieve a JNI local ref from encoded PKCS#8 data.
96 ScopedJava GetPKCS8PrivateKeyJava(android::PrivateKeyType key_type, 62 ScopedJava GetPKCS8PrivateKeyJava(android::PrivateKeyType key_type,
97 const std::string& pkcs8_key) { 63 const std::string& pkcs8_key) {
98 JNIEnv* env = base::android::AttachCurrentThread(); 64 JNIEnv* env = base::android::AttachCurrentThread();
99 base::android::ScopedJavaLocalRef<jbyteArray> bytes( 65 base::android::ScopedJavaLocalRef<jbyteArray> bytes(
100 base::android::ToJavaByteArray( 66 base::android::ToJavaByteArray(
101 env, reinterpret_cast<const uint8_t*>(pkcs8_key.data()), 67 env, reinterpret_cast<const uint8_t*>(pkcs8_key.data()),
102 pkcs8_key.size())); 68 pkcs8_key.size()));
103 69
104 ScopedJava key(Java_AndroidKeyStoreTestUtil_createPrivateKeyFromPKCS8( 70 ScopedJava key(Java_AndroidKeyStoreTestUtil_createPrivateKeyFromPKCS8(
105 env, key_type, bytes)); 71 env, key_type, bytes));
106 72
107 return key; 73 return key;
108 } 74 }
109 75
110 const char kTestRsaKeyFile[] = "client_1.pk8"; 76 bool VerifyWithOpenSSL(const EVP_MD* md,
111 const char kTestRsaCertificateFile[] = "client_1.pem"; 77 const base::StringPiece& digest,
112 78 EVP_PKEY* key,
113 // Retrieve a JNI local ref for our test RSA key. 79 const base::StringPiece& signature) {
114 ScopedJava GetRSATestKeyJava() {
115 std::string key;
116 if (!ReadTestFile(kTestRsaKeyFile, &key))
117 return ScopedJava();
118 return GetPKCS8PrivateKeyJava(android::PRIVATE_KEY_TYPE_RSA, key);
119 }
120
121 const char kTestEcdsaKeyFile[] = "client_4.pk8";
122 const char kTestEcdsaCertificateFile[] = "client_4.pem";
123
124 // Retrieve a JNI local ref for our test ECDSA key.
125 ScopedJava GetECDSATestKeyJava() {
126 std::string key;
127 if (!ReadTestFile(kTestEcdsaKeyFile, &key))
128 return ScopedJava();
129 return GetPKCS8PrivateKeyJava(android::PRIVATE_KEY_TYPE_ECDSA, key);
130 }
131
132 // Call this function to verify that one message signed with our
133 // test ECDSA private key is correct. Since ECDSA signing introduces
134 // random elements in the signature, it is not possible to compare
135 // signature bits directly. However, one can use the public key
136 // to do the check.
137 bool VerifyTestECDSASignature(const base::StringPiece& message,
138 const base::StringPiece& signature) {
139 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 80 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
140 81
141 bssl::UniquePtr<EVP_PKEY> pkey = 82 bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
142 ImportPublicKeyFromCertificateFile(kTestEcdsaCertificateFile); 83 if (!ctx || !EVP_PKEY_verify_init(ctx.get()) ||
143 if (!pkey) 84 !EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
144 return false; 85 !EVP_PKEY_verify(
145 86 ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()),
146 EC_KEY* pub_key = EVP_PKEY_get0_EC_KEY(pkey.get()); 87 signature.size(), reinterpret_cast<const uint8_t*>(digest.data()),
147 if (!pub_key) { 88 digest.size())) {
148 LOG(ERROR) << "Could not get ECDSA public key";
149 return false; 89 return false;
150 } 90 }
151 91
152 const unsigned char* digest =
153 reinterpret_cast<const unsigned char*>(message.data());
154 int digest_len = static_cast<int>(message.size());
155 const unsigned char* sigbuf =
156 reinterpret_cast<const unsigned char*>(signature.data());
157 int siglen = static_cast<int>(signature.size());
158
159 if (!ECDSA_verify(0, digest, digest_len, sigbuf, siglen, pub_key)) {
160 LOG(ERROR) << "ECDSA_verify() failed";
161 return false;
162 }
163 return true; 92 return true;
164 } 93 }
165 94
166 // Sign a message with OpenSSL, return the result as a string. 95 bool SignWithOpenSSL(const EVP_MD* md,
167 // |message| is the message to be signed. 96 const base::StringPiece& digest,
168 // |openssl_key| is an OpenSSL EVP_PKEY to use. 97 EVP_PKEY* key,
169 // |result| receives the result.
170 // Returns true on success, false otherwise.
171 bool SignWithOpenSSL(int hash_nid,
172 const base::StringPiece& message,
173 EVP_PKEY* openssl_key,
174 std::string* result) { 98 std::string* result) {
175 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 99 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
176 100
177 RSA* rsa = EVP_PKEY_get0_RSA(openssl_key); 101 size_t sig_len;
178 if (!rsa) { 102 bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
179 LOG(ERROR) << "Could not get RSA from EVP_PKEY"; 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())) {
180 return false; 108 return false;
181 } 109 }
182 110
183 const unsigned char* digest = 111 result->resize(sig_len);
184 reinterpret_cast<const unsigned char*>(message.data());
185 unsigned int digest_len = static_cast<unsigned int>(message.size());
186
187 // With RSA, the signature will always be RSA_size() bytes.
188 size_t max_signature_size = static_cast<size_t>(RSA_size(rsa));
189 std::string signature;
190 unsigned char* p = OpenSSLWriteInto(&signature, max_signature_size);
191 unsigned int p_len = 0;
192 if (!RSA_sign(hash_nid, digest, digest_len, p, &p_len, rsa)) {
193 LOG(ERROR) << "RSA_sign() failed";
194 return false;
195 }
196
197 size_t signature_size = static_cast<size_t>(p_len);
198 if (signature_size == 0) {
199 LOG(ERROR) << "Signature is empty!";
200 return false;
201 }
202 if (signature_size > max_signature_size) {
203 LOG(ERROR) << "Signature size mismatch, actual " << signature_size
204 << ", expected <= " << max_signature_size;
205 return false;
206 }
207 signature.resize(signature_size);
208 result->swap(signature);
209 return true; 112 return true;
210 } 113 }
211 114
212 // Check that a generated signature for a given message matches
213 // OpenSSL output byte-by-byte.
214 // |message| is the input message.
215 // |signature| is the generated signature for the message.
216 // |openssl_key| is a raw EVP_PKEY for the same private key than the
217 // one which was used to generate the signature.
218 // Returns true on success, false otherwise.
219 bool CompareSignatureWithOpenSSL(int hash_nid,
220 const base::StringPiece& message,
221 const base::StringPiece& signature,
222 EVP_PKEY* openssl_key) {
223 std::string openssl_signature;
224 if (!SignWithOpenSSL(hash_nid, message, openssl_key, &openssl_signature))
225 return false;
226
227 if (signature.size() != openssl_signature.size()) {
228 LOG(ERROR) << "Signature size mismatch, actual " << signature.size()
229 << ", expected " << openssl_signature.size();
230 return false;
231 }
232 for (size_t n = 0; n < signature.size(); ++n) {
233 if (openssl_signature[n] != signature[n]) {
234 LOG(ERROR) << "Signature byte mismatch at index " << n << "actual "
235 << signature[n] << ", expected " << openssl_signature[n];
236 LOG(ERROR) << "Actual signature : "
237 << base::HexEncode(signature.data(), signature.size());
238 LOG(ERROR) << "Expected signature: "
239 << base::HexEncode(openssl_signature.data(),
240 openssl_signature.size());
241 return false;
242 }
243 }
244 return true;
245 }
246
247 void OnSignComplete(base::RunLoop* loop, 115 void OnSignComplete(base::RunLoop* loop,
248 Error* out_error, 116 Error* out_error,
249 std::string* out_signature, 117 std::string* out_signature,
250 Error error, 118 Error error,
251 const std::vector<uint8_t>& signature) { 119 const std::vector<uint8_t>& signature) {
252 *out_error = error; 120 *out_error = error;
253 out_signature->assign(signature.begin(), signature.end()); 121 out_signature->assign(signature.begin(), signature.end());
254 loop->Quit(); 122 loop->Quit();
255 } 123 }
256 124
(...skipping 18 matching lines...) Expand all
275 int nid; 143 int nid;
276 SSLPrivateKey::Hash hash; 144 SSLPrivateKey::Hash hash;
277 } kHashes[] = { 145 } kHashes[] = {
278 {"MD5-SHA1", NID_md5_sha1, SSLPrivateKey::Hash::MD5_SHA1}, 146 {"MD5-SHA1", NID_md5_sha1, SSLPrivateKey::Hash::MD5_SHA1},
279 {"SHA-1", NID_sha1, SSLPrivateKey::Hash::SHA1}, 147 {"SHA-1", NID_sha1, SSLPrivateKey::Hash::SHA1},
280 {"SHA-256", NID_sha256, SSLPrivateKey::Hash::SHA256}, 148 {"SHA-256", NID_sha256, SSLPrivateKey::Hash::SHA256},
281 {"SHA-384", NID_sha384, SSLPrivateKey::Hash::SHA384}, 149 {"SHA-384", NID_sha384, SSLPrivateKey::Hash::SHA384},
282 {"SHA-512", NID_sha512, SSLPrivateKey::Hash::SHA512}, 150 {"SHA-512", NID_sha512, SSLPrivateKey::Hash::SHA512},
283 }; 151 };
284 152
153 struct TestKey {
154 const char* cert_file;
155 const char* key_file;
156 android::PrivateKeyType android_key_type;
157 SSLPrivateKey::Type key_type;
158 };
159
160 static const TestKey kTestKeys[] = {
161 {"client_1.pem", "client_1.pk8", android::PRIVATE_KEY_TYPE_RSA,
162 SSLPrivateKey::Type::RSA},
163 {"client_4.pem", "client_4.pk8", android::PRIVATE_KEY_TYPE_ECDSA,
164 SSLPrivateKey::Type::ECDSA_P256},
165 {"client_5.pem", "client_5.pk8", android::PRIVATE_KEY_TYPE_ECDSA,
166 SSLPrivateKey::Type::ECDSA_P384},
167 {"client_6.pem", "client_6.pk8", android::PRIVATE_KEY_TYPE_ECDSA,
168 SSLPrivateKey::Type::ECDSA_P521},
169 };
170
285 } // namespace 171 } // namespace
286 172
287 TEST(SSLPlatformKeyAndroid, RSA) { 173 class SSLPlatformKeyAndroidTest : public testing::TestWithParam<TestKey> {};
174
175 TEST_P(SSLPlatformKeyAndroidTest, SignHashes) {
288 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 176 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
177 const TestKey& test_key = GetParam();
289 178
290 scoped_refptr<X509Certificate> cert = 179 scoped_refptr<X509Certificate> cert =
291 ImportCertFromFile(GetTestCertsDirectory(), kTestRsaCertificateFile); 180 ImportCertFromFile(GetTestCertsDirectory(), test_key.cert_file);
292 ASSERT_TRUE(cert); 181 ASSERT_TRUE(cert);
293 ScopedJava rsa_key = GetRSATestKeyJava(); 182
294 ASSERT_FALSE(rsa_key.is_null()); 183 std::string key_bytes;
184 ASSERT_TRUE(ReadTestFile(test_key.key_file, &key_bytes));
185 ScopedJava java_key =
186 GetPKCS8PrivateKeyJava(test_key.android_key_type, key_bytes);
187 ASSERT_FALSE(java_key.is_null());
295 188
296 scoped_refptr<SSLPrivateKey> wrapper_key = 189 scoped_refptr<SSLPrivateKey> wrapper_key =
297 WrapJavaPrivateKey(cert.get(), rsa_key); 190 WrapJavaPrivateKey(cert.get(), java_key);
298 ASSERT_TRUE(wrapper_key); 191 ASSERT_TRUE(wrapper_key);
299 192
300 bssl::UniquePtr<EVP_PKEY> openssl_key = ImportPrivateKeyFile(kTestRsaKeyFile); 193 bssl::UniquePtr<EVP_PKEY> openssl_key = ImportPrivateKeyOpenSSL(key_bytes);
301 ASSERT_TRUE(openssl_key); 194 ASSERT_TRUE(openssl_key);
302 195
303 // Check that the wrapper key returns the correct length and type. 196 // Check that the wrapper key returns the correct length and type.
304 EXPECT_EQ(SSLPrivateKey::Type::RSA, wrapper_key->GetType()); 197 EXPECT_EQ(test_key.key_type, wrapper_key->GetType());
305 EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(openssl_key.get())), 198 EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(openssl_key.get())),
306 wrapper_key->GetMaxSignatureLengthInBytes()); 199 wrapper_key->GetMaxSignatureLengthInBytes());
307 200
308 // Test signing against each hash. 201 // Test signing against each hash.
309 for (const auto& hash : kHashes) { 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
310 SCOPED_TRACE(hash.name); 209 SCOPED_TRACE(hash.name);
311 210
312 const EVP_MD* md = EVP_get_digestbynid(hash.nid); 211 const EVP_MD* md = EVP_get_digestbynid(hash.nid);
313 ASSERT_TRUE(md); 212 ASSERT_TRUE(md);
314 std::string digest(EVP_MD_size(md), 'a'); 213 std::string digest(EVP_MD_size(md), 'a');
315 214
316 std::string signature; 215 std::string signature;
317 DoKeySigningWithWrapper(wrapper_key.get(), hash.hash, digest, &signature); 216 DoKeySigningWithWrapper(wrapper_key.get(), hash.hash, digest, &signature);
318 ASSERT_TRUE(CompareSignatureWithOpenSSL(hash.nid, digest, signature, 217 EXPECT_TRUE(VerifyWithOpenSSL(md, digest, openssl_key.get(), signature));
319 openssl_key.get())); 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 }
320 } 226 }
321 } 227 }
322 228
323 TEST(SSLPlatformKeyAndroid, ECDSA) { 229 INSTANTIATE_TEST_CASE_P(,
324 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 230 SSLPlatformKeyAndroidTest,
325 231 testing::ValuesIn(kTestKeys));
326 scoped_refptr<X509Certificate> cert =
327 ImportCertFromFile(GetTestCertsDirectory(), kTestEcdsaCertificateFile);
328 ASSERT_TRUE(cert);
329 ScopedJava ecdsa_key = GetECDSATestKeyJava();
330 ASSERT_FALSE(ecdsa_key.is_null());
331
332 scoped_refptr<SSLPrivateKey> wrapper_key =
333 WrapJavaPrivateKey(cert.get(), ecdsa_key);
334 ASSERT_TRUE(wrapper_key);
335
336 bssl::UniquePtr<EVP_PKEY> openssl_key =
337 ImportPrivateKeyFile(kTestEcdsaKeyFile);
338 ASSERT_TRUE(openssl_key);
339
340 // Check that the wrapper key returns the correct length and type.
341 EXPECT_EQ(SSLPrivateKey::Type::ECDSA_P256, wrapper_key->GetType());
342 EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(openssl_key.get())),
343 wrapper_key->GetMaxSignatureLengthInBytes());
344
345 // Test signing against each hash.
346 for (const auto& hash : kHashes) {
347 // ECDSA does not sign MD5-SHA1.
348 if (hash.nid == NID_md5_sha1)
349 continue;
350
351 SCOPED_TRACE(hash.name);
352 const EVP_MD* md = EVP_get_digestbynid(hash.nid);
353 ASSERT_TRUE(md);
354 std::string digest(EVP_MD_size(md), 'a');
355
356 std::string signature;
357 DoKeySigningWithWrapper(wrapper_key.get(), hash.hash, digest, &signature);
358 ASSERT_TRUE(VerifyTestECDSASignature(digest, signature));
359 }
360 }
361 232
362 } // namespace net 233 } // namespace net
OLDNEW
« no previous file with comments | « net/net.gypi ('k') | net/ssl/ssl_platform_key_util.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698