OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "content/child/webcrypto/algorithm_dispatch.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "content/child/webcrypto/algorithm_implementation.h" | |
9 #include "content/child/webcrypto/algorithm_registry.h" | |
10 #include "content/child/webcrypto/crypto_data.h" | |
11 #include "content/child/webcrypto/generate_key_result.h" | |
12 #include "content/child/webcrypto/platform_crypto.h" | |
13 #include "content/child/webcrypto/status.h" | |
14 #include "content/child/webcrypto/webcrypto_util.h" | |
15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
16 | |
17 namespace content { | |
18 | |
19 namespace webcrypto { | |
20 | |
21 namespace { | |
22 | |
23 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, | |
24 const blink::WebCryptoKey& key, | |
25 const CryptoData& data, | |
26 std::vector<uint8_t>* buffer) { | |
27 if (algorithm.id() != key.algorithm().id()) | |
28 return Status::ErrorUnexpected(); | |
29 | |
30 const AlgorithmImplementation* impl = NULL; | |
31 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
32 if (status.IsError()) | |
33 return status; | |
34 | |
35 return impl->Decrypt(algorithm, key, data, buffer); | |
36 } | |
37 | |
38 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, | |
39 const blink::WebCryptoKey& key, | |
40 const CryptoData& data, | |
41 std::vector<uint8_t>* buffer) { | |
42 if (algorithm.id() != key.algorithm().id()) | |
43 return Status::ErrorUnexpected(); | |
44 | |
45 const AlgorithmImplementation* impl = NULL; | |
46 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
47 if (status.IsError()) | |
48 return status; | |
49 | |
50 return impl->Encrypt(algorithm, key, data, buffer); | |
51 } | |
52 | |
53 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, | |
54 const blink::WebCryptoKey& key, | |
55 std::vector<uint8_t>* buffer) { | |
56 const AlgorithmImplementation* impl = NULL; | |
57 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl); | |
58 if (status.IsError()) | |
59 return status; | |
60 | |
61 return impl->ExportKey(format, key, buffer); | |
62 } | |
63 | |
64 } // namespace | |
65 | |
66 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, | |
67 const blink::WebCryptoKey& key, | |
68 const CryptoData& data, | |
69 std::vector<uint8_t>* buffer) { | |
70 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) | |
71 return Status::ErrorUnexpected(); | |
72 return EncryptDontCheckUsage(algorithm, key, data, buffer); | |
73 } | |
74 | |
75 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, | |
76 const blink::WebCryptoKey& key, | |
77 const CryptoData& data, | |
78 std::vector<uint8_t>* buffer) { | |
79 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) | |
80 return Status::ErrorUnexpected(); | |
81 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); | |
82 } | |
83 | |
84 Status Digest(const blink::WebCryptoAlgorithm& algorithm, | |
85 const CryptoData& data, | |
86 std::vector<uint8_t>* buffer) { | |
87 const AlgorithmImplementation* impl = NULL; | |
88 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
89 if (status.IsError()) | |
90 return status; | |
91 | |
92 return impl->Digest(algorithm, data, buffer); | |
93 } | |
94 | |
95 Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm, | |
96 bool extractable, | |
97 blink::WebCryptoKeyUsageMask usages, | |
98 GenerateKeyResult* result) { | |
99 const AlgorithmImplementation* impl = NULL; | |
100 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
101 if (status.IsError()) | |
102 return status; | |
103 | |
104 status = impl->GenerateKey(algorithm, extractable, usages, result); | |
105 if (status.IsError()) | |
106 return status; | |
107 | |
108 const blink::WebCryptoKey* key = NULL; | |
109 if (result->type() == GenerateKeyResult::TYPE_SECRET_KEY) | |
110 key = &result->secret_key(); | |
111 if (result->type() == GenerateKeyResult::TYPE_PUBLIC_PRIVATE_KEY_PAIR) | |
112 key = &result->private_key(); | |
113 if (key == NULL) | |
114 return Status::ErrorUnexpected(); | |
115 | |
116 // This should only fail if an algorithm is implemented incorrectly and | |
117 // does not do its own check of the usages. | |
118 if (key->usages() == 0) { | |
119 DCHECK(false) << "Key usages for generateKey() must not be empty"; | |
120 return Status::ErrorCreateKeyEmptyUsages(); | |
121 } | |
122 return status; | |
123 } | |
124 | |
125 Status ImportKey(blink::WebCryptoKeyFormat format, | |
126 const CryptoData& key_data, | |
127 const blink::WebCryptoAlgorithm& algorithm, | |
128 bool extractable, | |
129 blink::WebCryptoKeyUsageMask usages, | |
130 blink::WebCryptoKey* key) { | |
131 const AlgorithmImplementation* impl = NULL; | |
132 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
133 if (status.IsError()) | |
134 return status; | |
135 | |
136 status = impl->VerifyKeyUsagesBeforeImportKey(format, usages); | |
137 if (status.IsError()) | |
138 return status; | |
139 | |
140 return impl->ImportKey(format, key_data, algorithm, extractable, usages, key); | |
141 } | |
142 | |
143 Status ExportKey(blink::WebCryptoKeyFormat format, | |
144 const blink::WebCryptoKey& key, | |
145 std::vector<uint8_t>* buffer) { | |
146 if (!key.extractable()) | |
147 return Status::ErrorKeyNotExtractable(); | |
148 return ExportKeyDontCheckExtractability(format, key, buffer); | |
149 } | |
150 | |
151 Status Sign(const blink::WebCryptoAlgorithm& algorithm, | |
152 const blink::WebCryptoKey& key, | |
153 const CryptoData& data, | |
154 std::vector<uint8_t>* buffer) { | |
155 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) | |
156 return Status::ErrorUnexpected(); | |
157 if (algorithm.id() != key.algorithm().id()) | |
158 return Status::ErrorUnexpected(); | |
159 | |
160 const AlgorithmImplementation* impl = NULL; | |
161 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
162 if (status.IsError()) | |
163 return status; | |
164 | |
165 return impl->Sign(algorithm, key, data, buffer); | |
166 } | |
167 | |
168 Status Verify(const blink::WebCryptoAlgorithm& algorithm, | |
169 const blink::WebCryptoKey& key, | |
170 const CryptoData& signature, | |
171 const CryptoData& data, | |
172 bool* signature_match) { | |
173 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) | |
174 return Status::ErrorUnexpected(); | |
175 if (algorithm.id() != key.algorithm().id()) | |
176 return Status::ErrorUnexpected(); | |
177 | |
178 const AlgorithmImplementation* impl = NULL; | |
179 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
180 if (status.IsError()) | |
181 return status; | |
182 | |
183 return impl->Verify(algorithm, key, signature, data, signature_match); | |
184 } | |
185 | |
186 Status WrapKey(blink::WebCryptoKeyFormat format, | |
187 const blink::WebCryptoKey& key_to_wrap, | |
188 const blink::WebCryptoKey& wrapping_key, | |
189 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
190 std::vector<uint8_t>* buffer) { | |
191 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) | |
192 return Status::ErrorUnexpected(); | |
193 | |
194 std::vector<uint8_t> exported_data; | |
195 Status status = ExportKey(format, key_to_wrap, &exported_data); | |
196 if (status.IsError()) | |
197 return status; | |
198 return EncryptDontCheckUsage(wrapping_algorithm, wrapping_key, | |
199 CryptoData(exported_data), buffer); | |
200 } | |
201 | |
202 Status UnwrapKey(blink::WebCryptoKeyFormat format, | |
203 const CryptoData& wrapped_key_data, | |
204 const blink::WebCryptoKey& wrapping_key, | |
205 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
206 const blink::WebCryptoAlgorithm& algorithm, | |
207 bool extractable, | |
208 blink::WebCryptoKeyUsageMask usages, | |
209 blink::WebCryptoKey* key) { | |
210 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) | |
211 return Status::ErrorUnexpected(); | |
212 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | |
213 return Status::ErrorUnexpected(); | |
214 | |
215 // Fail fast if the import is doomed to fail. | |
216 const AlgorithmImplementation* import_impl = NULL; | |
217 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); | |
218 if (status.IsError()) | |
219 return status; | |
220 | |
221 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usages); | |
222 if (status.IsError()) | |
223 return status; | |
224 | |
225 std::vector<uint8_t> buffer; | |
226 status = DecryptDontCheckKeyUsage(wrapping_algorithm, wrapping_key, | |
227 wrapped_key_data, &buffer); | |
228 if (status.IsError()) | |
229 return status; | |
230 | |
231 // NOTE that returning the details of ImportKey() failures may leak | |
232 // information about the plaintext of the encrypted key (for instance the JWK | |
233 // key_ops). As long as the ImportKey error messages don't describe actual | |
234 // key bytes however this should be OK. For more discussion see | |
235 // http://crubg.com/372040 | |
236 return ImportKey(format, CryptoData(buffer), algorithm, extractable, usages, | |
237 key); | |
238 } | |
239 | |
240 Status DeriveBits(const blink::WebCryptoAlgorithm& algorithm, | |
241 const blink::WebCryptoKey& base_key, | |
242 unsigned int length_bits, | |
243 std::vector<uint8_t>* derived_bytes) { | |
244 if (!KeyUsageAllows(base_key, blink::WebCryptoKeyUsageDeriveBits)) | |
245 return Status::ErrorUnexpected(); | |
246 | |
247 if (algorithm.id() != base_key.algorithm().id()) | |
248 return Status::ErrorUnexpected(); | |
249 | |
250 const AlgorithmImplementation* impl = NULL; | |
251 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
252 if (status.IsError()) | |
253 return status; | |
254 | |
255 return impl->DeriveBits(algorithm, base_key, true, length_bits, | |
256 derived_bytes); | |
257 } | |
258 | |
259 Status DeriveKey(const blink::WebCryptoAlgorithm& algorithm, | |
260 const blink::WebCryptoKey& base_key, | |
261 const blink::WebCryptoAlgorithm& import_algorithm, | |
262 const blink::WebCryptoAlgorithm& key_length_algorithm, | |
263 bool extractable, | |
264 blink::WebCryptoKeyUsageMask usages, | |
265 blink::WebCryptoKey* derived_key) { | |
266 if (!KeyUsageAllows(base_key, blink::WebCryptoKeyUsageDeriveKey)) | |
267 return Status::ErrorUnexpected(); | |
268 | |
269 if (algorithm.id() != base_key.algorithm().id()) | |
270 return Status::ErrorUnexpected(); | |
271 | |
272 if (import_algorithm.id() != key_length_algorithm.id()) | |
273 return Status::ErrorUnexpected(); | |
274 | |
275 const AlgorithmImplementation* import_impl = NULL; | |
276 Status status = | |
277 GetAlgorithmImplementation(import_algorithm.id(), &import_impl); | |
278 if (status.IsError()) | |
279 return status; | |
280 | |
281 // Fail fast if the requested key usages are incorect. | |
282 status = import_impl->VerifyKeyUsagesBeforeImportKey( | |
283 blink::WebCryptoKeyFormatRaw, usages); | |
284 if (status.IsError()) | |
285 return status; | |
286 | |
287 // Determine how many bits long the derived key should be. | |
288 unsigned int length_bits = 0; | |
289 bool has_length_bits = false; | |
290 status = import_impl->GetKeyLength(key_length_algorithm, &has_length_bits, | |
291 &length_bits); | |
292 if (status.IsError()) | |
293 return status; | |
294 | |
295 // Derive the key bytes. | |
296 const AlgorithmImplementation* derive_impl = NULL; | |
297 status = GetAlgorithmImplementation(algorithm.id(), &derive_impl); | |
298 if (status.IsError()) | |
299 return status; | |
300 | |
301 std::vector<uint8_t> derived_bytes; | |
302 status = derive_impl->DeriveBits(algorithm, base_key, has_length_bits, | |
303 length_bits, &derived_bytes); | |
304 if (status.IsError()) | |
305 return status; | |
306 | |
307 // Create the key using the derived bytes. | |
308 return ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(derived_bytes), | |
309 import_algorithm, extractable, usages, derived_key); | |
310 } | |
311 | |
312 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( | |
313 blink::WebCryptoAlgorithmId algorithm) { | |
314 PlatformInit(); | |
315 return CreatePlatformDigestor(algorithm); | |
316 } | |
317 | |
318 bool SerializeKeyForClone(const blink::WebCryptoKey& key, | |
319 blink::WebVector<uint8_t>* key_data) { | |
320 const AlgorithmImplementation* impl = NULL; | |
321 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl); | |
322 if (status.IsError()) | |
323 return false; | |
324 | |
325 status = impl->SerializeKeyForClone(key, key_data); | |
326 return status.IsSuccess(); | |
327 } | |
328 | |
329 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, | |
330 blink::WebCryptoKeyType type, | |
331 bool extractable, | |
332 blink::WebCryptoKeyUsageMask usages, | |
333 const CryptoData& key_data, | |
334 blink::WebCryptoKey* key) { | |
335 const AlgorithmImplementation* impl = NULL; | |
336 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
337 if (status.IsError()) | |
338 return false; | |
339 | |
340 status = impl->DeserializeKeyForClone(algorithm, type, extractable, usages, | |
341 key_data, key); | |
342 return status.IsSuccess(); | |
343 } | |
344 | |
345 } // namespace webcrypto | |
346 | |
347 } // namespace content | |
OLD | NEW |