forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssl_private_key_test_util.cc
179 lines (151 loc) · 5.65 KB
/
ssl_private_key_test_util.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/ssl/ssl_private_key_test_util.h"
#include <stdint.h>
#include <vector>
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "crypto/openssl_util.h"
#include "net/base/net_errors.h"
#include "net/ssl/ssl_private_key.h"
#include "net/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/ec.h"
#include "third_party/boringssl/src/include/openssl/ec_key.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
using net::test::IsOk;
namespace net {
namespace {
const char* HashToString(SSLPrivateKey::Hash hash) {
switch (hash) {
case SSLPrivateKey::Hash::MD5_SHA1:
return "MD5_SHA1";
case SSLPrivateKey::Hash::SHA1:
return "SHA1";
case SSLPrivateKey::Hash::SHA256:
return "SHA256";
case SSLPrivateKey::Hash::SHA384:
return "SHA384";
case SSLPrivateKey::Hash::SHA512:
return "SHA512";
}
NOTREACHED();
return "";
}
const EVP_MD* HashToMD(SSLPrivateKey::Hash hash) {
switch (hash) {
case SSLPrivateKey::Hash::MD5_SHA1:
return EVP_md5_sha1();
case SSLPrivateKey::Hash::SHA1:
return EVP_sha1();
case SSLPrivateKey::Hash::SHA256:
return EVP_sha256();
case SSLPrivateKey::Hash::SHA384:
return EVP_sha384();
case SSLPrivateKey::Hash::SHA512:
return EVP_sha512();
}
NOTREACHED();
return nullptr;
}
// Resize a string to |size| bytes of data, then return its data buffer address
// cast as an 'uint8_t*', as expected by OpenSSL functions.
// |str| the target string.
// |size| the number of bytes to write into the string.
// Return the string's new buffer in memory, as an 'uint8_t*' pointer.
uint8_t* OpenSSLWriteInto(std::string* str, size_t size) {
return reinterpret_cast<uint8_t*>(base::WriteInto(str, size + 1));
}
bool VerifyWithOpenSSL(const EVP_MD* md,
const base::StringPiece& digest,
EVP_PKEY* key,
const base::StringPiece& signature) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
if (!ctx || !EVP_PKEY_verify_init(ctx.get()) ||
!EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
!EVP_PKEY_verify(
ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), reinterpret_cast<const uint8_t*>(digest.data()),
digest.size())) {
return false;
}
return true;
}
bool SignWithOpenSSL(const EVP_MD* md,
const base::StringPiece& digest,
EVP_PKEY* key,
std::string* result) {
size_t sig_len = EVP_PKEY_size(key);
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
if (!ctx || !EVP_PKEY_sign_init(ctx.get()) ||
!EVP_PKEY_CTX_set_signature_md(ctx.get(), md) ||
!EVP_PKEY_sign(ctx.get(), OpenSSLWriteInto(result, sig_len), &sig_len,
reinterpret_cast<const uint8_t*>(digest.data()),
digest.size())) {
return false;
}
result->resize(sig_len);
return true;
}
void OnSignComplete(base::RunLoop* loop,
Error* out_error,
std::string* out_signature,
Error error,
const std::vector<uint8_t>& signature) {
*out_error = error;
out_signature->assign(signature.begin(), signature.end());
loop->Quit();
}
Error DoKeySigningWithWrapper(SSLPrivateKey* key,
SSLPrivateKey::Hash hash,
const base::StringPiece& message,
std::string* result) {
Error error;
base::RunLoop loop;
key->SignDigest(
hash, message,
base::Bind(OnSignComplete, base::Unretained(&loop),
base::Unretained(&error), base::Unretained(result)));
loop.Run();
return error;
}
} // namespace
void TestSSLPrivateKeyMatches(SSLPrivateKey* key, const std::string& pkcs8) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
// Create the equivalent OpenSSL key.
CBS cbs;
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()), pkcs8.size());
bssl::UniquePtr<EVP_PKEY> openssl_key(EVP_parse_private_key(&cbs));
ASSERT_TRUE(openssl_key);
EXPECT_EQ(0u, CBS_len(&cbs));
// Test all supported hash algorithms.
std::vector<SSLPrivateKey::Hash> hashes = key->GetDigestPreferences();
// To support TLS 1.1 and earlier, RSA keys must implicitly support MD5-SHA1,
// despite not being advertised.
if (EVP_PKEY_id(openssl_key.get()) == EVP_PKEY_RSA)
hashes.push_back(SSLPrivateKey::Hash::MD5_SHA1);
for (SSLPrivateKey::Hash hash : hashes) {
SCOPED_TRACE(HashToString(hash));
const EVP_MD* md = HashToMD(hash);
std::string digest(EVP_MD_size(md), 'a');
// Test the key generates valid signatures.
std::string signature;
Error error = DoKeySigningWithWrapper(key, hash, digest, &signature);
EXPECT_THAT(error, IsOk());
EXPECT_TRUE(VerifyWithOpenSSL(md, digest, openssl_key.get(), signature));
// RSA signing is deterministic, so further check the signature matches.
if (EVP_PKEY_id(openssl_key.get()) == EVP_PKEY_RSA) {
std::string openssl_signature;
ASSERT_TRUE(
SignWithOpenSSL(md, digest, openssl_key.get(), &openssl_signature));
EXPECT_EQ(openssl_signature, signature);
}
}
}
} // namespace net