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 non-const reference | |
26 // so it cannot be called incorrectly with an rvalue. | |
27 der::Input InputFromString(std::string& s) { | |
Ryan Sleevi
2015/07/16 04:05:24
I understand why, but this isn't allowed by the st
eroman
2015/07/20 20:03:40
Done.
| |
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(); | |
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(expected_result_bool, | |
121 VerifySignedData(*signature_algorithm, InputFromString(signed_data), | |
122 InputFromString(signature_value), | |
123 InputFromString(public_key))); | |
124 } | |
125 | |
126 // Read the descriptions in the test files themselves for details on what is | |
127 // being tested. | |
128 | |
129 TEST(VerifySignedDataTest, RsaPkcs1_Sha1) { | |
130 RunTestCase(SUCCESS, "rsa-pkcs1-sha1.pem"); | |
131 } | |
132 | |
133 TEST(VerifySignedDataTest, RsaPkcs1_Sha256) { | |
134 RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); | |
135 } | |
136 | |
137 TEST(VerifySignedDataTest, Ecdsa_Secp384r1_Sha256) { | |
138 RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); | |
139 } | |
140 | |
141 TEST(VerifySignedDataTest, Ecdsa_prime256v1_Sha512) { | |
142 RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); | |
143 } | |
144 | |
145 TEST(VerifySignedDataTest, RsaPss_Sha1) { | |
146 RunTestCase(SUCCESS, "rsa-pss-sha1-salt20.pem"); | |
147 } | |
148 | |
149 TEST(VerifySignedDataTest, RsaPss_Sha256_Mgf1_Sha512_Salt33) { | |
150 RunTestCase(SUCCESS, "rsa-pss-sha256-mgf1-sha512-salt33.pem"); | |
151 } | |
152 | |
153 TEST(VerifySignedDataTest, RsaPss_Sha256) { | |
154 RunTestCase(SUCCESS, "rsa-pss-sha256-salt10.pem"); | |
155 } | |
156 | |
157 TEST(VerifySignedDataTest, RsaPss_Sha1_WrongSalt) { | |
158 RunTestCase(FAILURE, "rsa-pss-sha1-wrong-salt.pem"); | |
159 } | |
160 | |
161 TEST(VerifySignedDataTest, Ecdsa_Secp384r1_Sha256_CorruptedData) { | |
162 RunTestCase(FAILURE, "ecdsa-secp384r1-sha256-corrupted-data.pem"); | |
163 } | |
164 | |
165 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_WrongAlgorithm) { | |
166 RunTestCase(FAILURE, "rsa-pkcs1-sha1-wrong-algorithm.pem"); | |
167 } | |
168 | |
169 TEST(VerifySignedDataTest, Ecdsa_prime256v1_Sha512_WrongSignatureFormat) { | |
170 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-wrong-signature-format.pem"); | |
171 } | |
172 | |
173 TEST(VerifySignedDataTest, EcdsaUsingRsaKey) { | |
174 RunTestCase(FAILURE, "ecdsa-using-rsa-key.pem"); | |
175 } | |
176 | |
177 TEST(VerifySignedDataTest, RsaUsingEcKey) { | |
178 RunTestCase(FAILURE, "rsa-using-ec-key.pem"); | |
179 } | |
180 | |
181 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_BadKeyDerNull) { | |
182 RunTestCase(FAILURE, "rsa-pkcs1-sha1-bad-key-der-null.pem"); | |
183 } | |
184 | |
185 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_BadKeyDerLength) { | |
186 RunTestCase(FAILURE, "rsa-pkcs1-sha1-bad-key-der-length.pem"); | |
187 } | |
188 | |
189 TEST(VerifySignedDataTest, RsaPkcs1_Sha256_UsingEcdsaAlgorithm) { | |
190 RunTestCase(FAILURE, "rsa-pkcs1-sha256-using-ecdsa-algorithm.pem"); | |
191 } | |
192 | |
193 TEST(VerifySignedDataTest, Ecdsa_Prim256v1_Sha512_UsingRsaAlgorithm) { | |
194 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-rsa-algorithm.pem"); | |
195 } | |
196 | |
197 TEST(VerifySignedDataTest, Ecdsa_Prim256v1_Sha512_UsingEcdhKey) { | |
198 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-ecdh-key.pem"); | |
199 } | |
200 | |
201 TEST(VerifySignedDataTest, Ecdsa_Prim256v1_Sha512_UsingEcmqvKey) { | |
202 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-ecmqv-key.pem"); | |
203 } | |
204 | |
205 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_KeyParamsAbsent) { | |
206 RunTestCase(SUCCESS, "rsa-pkcs1-sha1-key-params-absent.pem"); | |
207 } | |
208 | |
209 // TODO(eroman): Support rsaPss for the key algorithm. | |
210 TEST(VerifySignedDataTest, DISABLED_RsaPss_Sha1_Salt20_UsingPssKeyNoParams) { | |
211 RunTestCase(SUCCESS, "rsa-pss-sha1-salt20-using-pss-key-no-params.pem"); | |
212 } | |
213 | |
214 TEST(VerifySignedDataTest, RsaPkcs1_Sha1_UsingPssKeyNoParams) { | |
215 RunTestCase(FAILURE, "rsa-pkcs1-sha1-using-pss-key-no-params.pem"); | |
216 } | |
217 | |
218 // TODO(eroman): Support rsaPss for the key algorithm. | |
219 TEST(VerifySignedDataTest, | |
220 DISABLED_RsaPss_Sha256_Salt10_UsingPssKeyWithParams) { | |
221 RunTestCase(SUCCESS, "rsa-pss-sha256-salt10-using-pss-key-with-params.pem"); | |
222 } | |
223 | |
224 TEST(VerifySignedDataTest, RsaPss_Sha256_Salt10_UsingPssKeyWithWrongParams) { | |
225 RunTestCase(FAILURE, | |
226 "rsa-pss-sha256-salt10-using-pss-key-with-wrong-params.pem"); | |
227 } | |
228 | |
229 TEST(VerifySignedDataTest, RsaPss_Sha256_Salt12_UsingPssKeyWithNullParams) { | |
230 RunTestCase(FAILURE, | |
231 "rsa-pss-sha1-salt20-using-pss-key-with-null-params.pem"); | |
232 } | |
233 | |
234 } // namespace | |
235 | |
236 } // namespace net | |
OLD | NEW |