OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/cert/internal/verify_signed_data.h" | |
6 | |
7 #include "base/base_paths.h" | |
8 #include "base/files/file_util.h" | |
9 #include "base/path_service.h" | |
10 #include "net/cert/internal/signature_algorithm.h" | |
11 #include "net/cert/pem_tokenizer.h" | |
12 #include "net/der/input.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace net { | |
16 | |
17 namespace { | |
18 | |
19 // Creates a der::Input from an std::string. The lifetimes are a bit subtle | |
20 // when using this function: | |
21 // | |
22 // The returned der::Input() is only valid so long as the input string is alive | |
23 // and is not mutated. | |
24 // | |
25 // Note that the input parameter has been made a pointer to prevent callers | |
26 // from accidentally passing an r-value. | |
27 der::Input InputFromString(const std::string* s) { | |
28 return der::Input(reinterpret_cast<const uint8_t*>(s->data()), s->size()); | |
29 } | |
30 | |
31 // Reads a signature verification test file. | |
32 // | |
33 // The test file is a series of PEM blocks (PEM is just base64 data) with | |
34 // headings of: | |
35 // | |
36 // "PUBLIC KEY" - DER encoding of the SubjectPublicKeyInfo | |
37 // "ALGORITHM" - DER encoding of the AlgorithmIdentifier for the signature | |
38 // algorithm (signatureAlgorithm in X.509) | |
39 // "DATA" - The data that was signed (tbsCertificate in X.509) | |
40 // "SIGNATURE" - The result of signing DATA. | |
41 ::testing::AssertionResult ParseTestDataFile(const std::string& file_data, | |
42 std::string* public_key, | |
43 std::string* algorithm, | |
44 std::string* signed_data, | |
45 std::string* signature_value) { | |
46 const char kPublicKeyBlock[] = "PUBLIC KEY"; | |
47 const char kAlgorithmBlock[] = "ALGORITHM"; | |
48 const char kSignedDataBlock[] = "DATA"; | |
49 const char kSignatureBlock[] = "SIGNATURE"; | |
50 | |
51 std::vector<std::string> pem_headers; | |
52 pem_headers.push_back(kPublicKeyBlock); | |
53 pem_headers.push_back(kAlgorithmBlock); | |
54 pem_headers.push_back(kSignedDataBlock); | |
55 pem_headers.push_back(kSignatureBlock); | |
56 | |
57 PEMTokenizer pem_tokenizer(file_data, pem_headers); | |
58 while (pem_tokenizer.GetNext()) { | |
59 if (pem_tokenizer.block_type() == kPublicKeyBlock) { | |
60 public_key->assign(pem_tokenizer.data()); | |
61 } else if (pem_tokenizer.block_type() == kAlgorithmBlock) { | |
62 algorithm->assign(pem_tokenizer.data()); | |
63 } else if (pem_tokenizer.block_type() == kSignedDataBlock) { | |
64 signed_data->assign(pem_tokenizer.data()); | |
65 } else if (pem_tokenizer.block_type() == kSignatureBlock) { | |
66 signature_value->assign(pem_tokenizer.data()); | |
67 } | |
68 } | |
69 | |
70 return ::testing::AssertionSuccess(); | |
davidben
2015/07/21 16:26:27
This function never fails. (Did you mean for it to
eroman
2015/07/21 19:24:28
Done -- I additionally made it fail if a block is
| |
71 } | |
72 | |
73 // Returns a path to the file |file_name| within the unittest data directory. | |
74 base::FilePath GetTestFilePath(const char* file_name) { | |
75 base::FilePath src_root; | |
76 PathService::Get(base::DIR_SOURCE_ROOT, &src_root); | |
77 return src_root.Append( | |
78 FILE_PATH_LITERAL("net/data/verify_signed_data_unittest")) | |
79 .AppendASCII(file_name); | |
80 } | |
81 | |
82 enum VerifyResult { | |
83 SUCCESS, | |
84 FAILURE, | |
85 }; | |
86 | |
87 // Reads test data from |file_name| and runs VerifySignedData() over its inputs. | |
88 // | |
89 // If expected_result was SUCCESS then the test will only succeed if | |
90 // VerifySignedData() returns true. | |
91 // | |
92 // If expected_result was FAILURE then the test will only succeed if | |
93 // VerifySignedData() returns false. | |
94 void RunTestCase(VerifyResult expected_result, const char* file_name) { | |
95 #if !defined(USE_OPENSSL) | |
96 LOG(INFO) << "Skipping test, only implemented for BoringSSL"; | |
97 return; | |
98 #endif | |
99 | |
100 base::FilePath test_file_path = GetTestFilePath(file_name); | |
101 | |
102 std::string file_data; | |
103 ASSERT_TRUE(base::ReadFileToString(test_file_path, &file_data)) | |
104 << "Couldn't read file: " << test_file_path.value(); | |
105 | |
106 std::string public_key; | |
107 std::string algorithm; | |
108 std::string signed_data; | |
109 std::string signature_value; | |
110 | |
111 ASSERT_TRUE(ParseTestDataFile(file_data, &public_key, &algorithm, | |
112 &signed_data, &signature_value)); | |
113 | |
114 scoped_ptr<SignatureAlgorithm> signature_algorithm = | |
115 SignatureAlgorithm::CreateFromDer(InputFromString(&algorithm)); | |
116 ASSERT_TRUE(signature_algorithm); | |
117 | |
118 bool expected_result_bool = expected_result == SUCCESS; | |
119 | |
120 ASSERT_EQ( | |
davidben
2015/07/21 16:26:27
Nit: I think this can just be EXPECT_EQ.
eroman
2015/07/21 19:24:29
Done.
| |
121 expected_result_bool, | |
122 VerifySignedData(*signature_algorithm, InputFromString(&signed_data), | |
123 InputFromString(&signature_value), | |
124 InputFromString(&public_key))); | |
125 } | |
126 | |
127 // Read the descriptions in the test files themselves for details on what is | |
128 // being tested. | |
129 | |
130 TEST(VerifySignedDataTest, RsaPkcs1_Sha1) { | |
131 RunTestCase(SUCCESS, "rsa-pkcs1-sha1.pem"); | |
132 } | |
133 | |
134 TEST(VerifySignedDataTest, RsaPkcs1_Sha256) { | |
135 RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); | |
136 } | |
137 | |
138 TEST(VerifySignedDataTest, Ecdsa_Secp384r1_Sha256) { | |
139 RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); | |
140 } | |
141 | |
142 TEST(VerifySignedDataTest, Ecdsa_prime256v1_Sha512) { | |
143 RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); | |
144 } | |
145 | |
146 TEST(VerifySignedDataTest, RsaPss_Sha1) { | |
147 RunTestCase(SUCCESS, "rsa-pss-sha1-salt20.pem"); | |
148 } | |
149 | |
150 TEST(VerifySignedDataTest, RsaPss_Sha256_Mgf1_Sha512_Salt33) { | |
151 RunTestCase(SUCCESS, "rsa-pss-sha256-mgf1-sha512-salt33.pem"); | |
152 } | |
153 | |
154 TEST(VerifySignedDataTest, RsaPss_Sha256) { | |
155 RunTestCase(SUCCESS, "rsa-pss-sha256-salt10.pem"); | |
156 } | |
157 | |
158 TEST(VerifySignedDataTest, RsaPss_Sha1_WrongSalt) { | |
159 RunTestCase(FAILURE, "rsa-pss-sha1-wrong-salt.pem"); | |
160 } | |
161 | |
162 TEST(VerifySignedDataTest, Ecdsa_Secp384r1_Sha256_CorruptedData) { | |
163 RunTestCase(FAILURE, "ecdsa-secp384r1-sha256-corrupted-data.pem"); | |
164 } | |
165 | |
166 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_WrongAlgorithm) { | |
167 RunTestCase(FAILURE, "rsa-pkcs1-sha1-wrong-algorithm.pem"); | |
168 } | |
169 | |
170 TEST(VerifySignedDataTest, Ecdsa_prime256v1_Sha512_WrongSignatureFormat) { | |
171 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-wrong-signature-format.pem"); | |
172 } | |
173 | |
174 TEST(VerifySignedDataTest, EcdsaUsingRsaKey) { | |
175 RunTestCase(FAILURE, "ecdsa-using-rsa-key.pem"); | |
176 } | |
177 | |
178 TEST(VerifySignedDataTest, RsaUsingEcKey) { | |
179 RunTestCase(FAILURE, "rsa-using-ec-key.pem"); | |
180 } | |
181 | |
182 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_BadKeyDerNull) { | |
183 RunTestCase(FAILURE, "rsa-pkcs1-sha1-bad-key-der-null.pem"); | |
184 } | |
185 | |
186 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_BadKeyDerLength) { | |
187 RunTestCase(FAILURE, "rsa-pkcs1-sha1-bad-key-der-length.pem"); | |
188 } | |
189 | |
190 TEST(VerifySignedDataTest, RsaPkcs1_Sha256_UsingEcdsaAlgorithm) { | |
191 RunTestCase(FAILURE, "rsa-pkcs1-sha256-using-ecdsa-algorithm.pem"); | |
192 } | |
193 | |
194 TEST(VerifySignedDataTest, Ecdsa_Prim256v1_Sha512_UsingRsaAlgorithm) { | |
195 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-rsa-algorithm.pem"); | |
196 } | |
197 | |
198 TEST(VerifySignedDataTest, Ecdsa_Prim256v1_Sha512_UsingEcdhKey) { | |
199 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-ecdh-key.pem"); | |
200 } | |
201 | |
202 TEST(VerifySignedDataTest, Ecdsa_Prim256v1_Sha512_UsingEcmqvKey) { | |
203 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-ecmqv-key.pem"); | |
204 } | |
205 | |
206 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_KeyParamsAbsent) { | |
207 RunTestCase(SUCCESS, "rsa-pkcs1-sha1-key-params-absent.pem"); | |
208 } | |
209 | |
210 // TODO(eroman): Support rsaPss for the key algorithm. | |
211 TEST(VerifySignedDataTest, DISABLED_RsaPss_Sha1_Salt20_UsingPssKeyNoParams) { | |
212 RunTestCase(SUCCESS, "rsa-pss-sha1-salt20-using-pss-key-no-params.pem"); | |
213 } | |
214 | |
215 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_UsingPssKeyNoParams) { | |
216 RunTestCase(FAILURE, "rsa-pkcs1-sha1-using-pss-key-no-params.pem"); | |
217 } | |
218 | |
219 // TODO(eroman): Support rsaPss for the key algorithm. | |
220 TEST(VerifySignedDataTest, | |
221 DISABLED_RsaPss_Sha256_Salt10_UsingPssKeyWithParams) { | |
davidben
2015/07/21 16:26:27
Optional: Do you want to add disabled tests for 2.
eroman
2015/07/21 19:24:28
Yes, good ideas.
I will post another patchset whe
davidben
2015/07/21 19:41:14
I was thinking length encodings. I *think* crypto/
| |
222 RunTestCase(SUCCESS, "rsa-pss-sha256-salt10-using-pss-key-with-params.pem"); | |
223 } | |
224 | |
225 TEST(VerifySignedDataTest, RsaPss_Sha256_Salt10_UsingPssKeyWithWrongParams) { | |
226 RunTestCase(FAILURE, | |
227 "rsa-pss-sha256-salt10-using-pss-key-with-wrong-params.pem"); | |
228 } | |
229 | |
230 TEST(VerifySignedDataTest, RsaPss_Sha256_Salt12_UsingPssKeyWithNullParams) { | |
231 RunTestCase(FAILURE, | |
232 "rsa-pss-sha1-salt20-using-pss-key-with-null-params.pem"); | |
233 } | |
234 | |
235 } // namespace | |
236 | |
237 } // namespace net | |
OLD | NEW |