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/platform_crypto.h" | |
12 #include "content/child/webcrypto/status.h" | |
13 #include "content/child/webcrypto/webcrypto_util.h" | |
14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
15 | |
16 namespace content { | |
17 | |
18 namespace webcrypto { | |
19 | |
20 namespace { | |
21 | |
22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, | |
23 const blink::WebCryptoKey& key, | |
24 const CryptoData& data, | |
25 std::vector<uint8>* buffer) { | |
26 if (algorithm.id() != key.algorithm().id()) | |
27 return Status::ErrorUnexpected(); | |
28 | |
29 const AlgorithmImplementation* impl = NULL; | |
30 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
31 if (status.IsError()) | |
32 return status; | |
33 | |
34 return impl->Decrypt(algorithm, key, data, buffer); | |
35 } | |
36 | |
37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, | |
38 const blink::WebCryptoKey& key, | |
39 const CryptoData& data, | |
40 std::vector<uint8>* buffer) { | |
41 if (algorithm.id() != key.algorithm().id()) | |
42 return Status::ErrorUnexpected(); | |
43 | |
44 const AlgorithmImplementation* impl = NULL; | |
45 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
46 if (status.IsError()) | |
47 return status; | |
48 | |
49 return impl->Encrypt(algorithm, key, data, buffer); | |
50 } | |
51 | |
52 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, | |
53 const blink::WebCryptoKey& key, | |
54 std::vector<uint8>* buffer) { | |
55 const AlgorithmImplementation* impl = NULL; | |
56 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl); | |
57 if (status.IsError()) | |
58 return status; | |
59 | |
60 switch (format) { | |
61 case blink::WebCryptoKeyFormatRaw: | |
62 return impl->ExportKeyRaw(key, buffer); | |
63 case blink::WebCryptoKeyFormatSpki: | |
64 return impl->ExportKeySpki(key, buffer); | |
65 case blink::WebCryptoKeyFormatPkcs8: | |
66 return impl->ExportKeyPkcs8(key, buffer); | |
67 case blink::WebCryptoKeyFormatJwk: | |
68 return impl->ExportKeyJwk(key, buffer); | |
69 default: | |
70 return Status::ErrorUnsupported(); | |
71 } | |
72 } | |
73 | |
74 } // namespace | |
75 | |
76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, | |
77 const blink::WebCryptoKey& key, | |
78 const CryptoData& data, | |
79 std::vector<uint8>* buffer) { | |
80 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) | |
81 return Status::ErrorUnexpected(); | |
82 return EncryptDontCheckUsage(algorithm, key, data, buffer); | |
83 } | |
84 | |
85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, | |
86 const blink::WebCryptoKey& key, | |
87 const CryptoData& data, | |
88 std::vector<uint8>* buffer) { | |
89 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) | |
90 return Status::ErrorUnexpected(); | |
91 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); | |
92 } | |
93 | |
94 Status Digest(const blink::WebCryptoAlgorithm& algorithm, | |
95 const CryptoData& data, | |
96 std::vector<uint8>* buffer) { | |
97 const AlgorithmImplementation* impl = NULL; | |
98 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
99 if (status.IsError()) | |
100 return status; | |
101 | |
102 return impl->Digest(algorithm, data, buffer); | |
103 } | |
104 | |
105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, | |
106 bool extractable, | |
107 blink::WebCryptoKeyUsageMask usage_mask, | |
108 blink::WebCryptoKey* key) { | |
109 const AlgorithmImplementation* impl = NULL; | |
110 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
111 if (status.IsError()) | |
112 return status; | |
113 | |
114 status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask); | |
115 if (status.IsError()) | |
116 return status; | |
117 | |
118 return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key); | |
119 } | |
120 | |
121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, | |
122 bool extractable, | |
123 blink::WebCryptoKeyUsageMask combined_usage_mask, | |
124 blink::WebCryptoKey* public_key, | |
125 blink::WebCryptoKey* private_key) { | |
126 const AlgorithmImplementation* impl = NULL; | |
127 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
128 if (status.IsError()) | |
129 return status; | |
130 | |
131 blink::WebCryptoKeyUsageMask public_usage_mask; | |
132 blink::WebCryptoKeyUsageMask private_usage_mask; | |
133 status = impl->VerifyKeyUsagesBeforeGenerateKeyPair( | |
134 combined_usage_mask, &public_usage_mask, &private_usage_mask); | |
135 if (status.IsError()) | |
136 return status; | |
137 | |
138 return impl->GenerateKeyPair(algorithm, | |
139 extractable, | |
140 public_usage_mask, | |
141 private_usage_mask, | |
142 public_key, | |
143 private_key); | |
144 } | |
145 | |
146 // Note that this function may be called from the target Blink thread. | |
147 Status ImportKey(blink::WebCryptoKeyFormat format, | |
148 const CryptoData& key_data, | |
149 const blink::WebCryptoAlgorithm& algorithm, | |
150 bool extractable, | |
151 blink::WebCryptoKeyUsageMask usage_mask, | |
152 blink::WebCryptoKey* key) { | |
153 const AlgorithmImplementation* impl = NULL; | |
154 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
155 if (status.IsError()) | |
156 return status; | |
157 | |
158 status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); | |
159 if (status.IsError()) | |
160 return status; | |
161 | |
162 switch (format) { | |
163 case blink::WebCryptoKeyFormatRaw: | |
164 return impl->ImportKeyRaw( | |
165 key_data, algorithm, extractable, usage_mask, key); | |
166 case blink::WebCryptoKeyFormatSpki: | |
167 return impl->ImportKeySpki( | |
168 key_data, algorithm, extractable, usage_mask, key); | |
169 case blink::WebCryptoKeyFormatPkcs8: | |
170 return impl->ImportKeyPkcs8( | |
171 key_data, algorithm, extractable, usage_mask, key); | |
172 case blink::WebCryptoKeyFormatJwk: | |
173 return impl->ImportKeyJwk( | |
174 key_data, algorithm, extractable, usage_mask, key); | |
175 default: | |
176 return Status::ErrorUnsupported(); | |
177 } | |
178 } | |
179 | |
180 Status ExportKey(blink::WebCryptoKeyFormat format, | |
181 const blink::WebCryptoKey& key, | |
182 std::vector<uint8>* buffer) { | |
183 if (!key.extractable()) | |
184 return Status::ErrorKeyNotExtractable(); | |
185 return ExportKeyDontCheckExtractability(format, key, buffer); | |
186 } | |
187 | |
188 Status Sign(const blink::WebCryptoAlgorithm& algorithm, | |
189 const blink::WebCryptoKey& key, | |
190 const CryptoData& data, | |
191 std::vector<uint8>* buffer) { | |
192 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) | |
193 return Status::ErrorUnexpected(); | |
194 if (algorithm.id() != key.algorithm().id()) | |
195 return Status::ErrorUnexpected(); | |
196 | |
197 const AlgorithmImplementation* impl = NULL; | |
198 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
199 if (status.IsError()) | |
200 return status; | |
201 | |
202 return impl->Sign(algorithm, key, data, buffer); | |
203 } | |
204 | |
205 Status Verify(const blink::WebCryptoAlgorithm& algorithm, | |
206 const blink::WebCryptoKey& key, | |
207 const CryptoData& signature, | |
208 const CryptoData& data, | |
209 bool* signature_match) { | |
210 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) | |
211 return Status::ErrorUnexpected(); | |
212 if (algorithm.id() != key.algorithm().id()) | |
213 return Status::ErrorUnexpected(); | |
214 | |
215 // TODO(eroman): Move this into implementation which need it instead. | |
216 if (!signature.byte_length()) { | |
217 // None of the algorithms generate valid zero-length signatures so this | |
218 // will necessarily fail verification. Early return to protect | |
219 // implementations from dealing with a NULL signature pointer. | |
220 *signature_match = false; | |
221 return Status::Success(); | |
222 } | |
223 | |
224 const AlgorithmImplementation* impl = NULL; | |
225 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
226 if (status.IsError()) | |
227 return status; | |
228 | |
229 return impl->Verify(algorithm, key, signature, data, signature_match); | |
230 } | |
231 | |
232 Status WrapKey(blink::WebCryptoKeyFormat format, | |
233 const blink::WebCryptoKey& key_to_wrap, | |
234 const blink::WebCryptoKey& wrapping_key, | |
235 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
236 std::vector<uint8>* buffer) { | |
237 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) | |
238 return Status::ErrorUnexpected(); | |
239 | |
240 std::vector<uint8> exported_data; | |
241 Status status = ExportKey(format, key_to_wrap, &exported_data); | |
242 if (status.IsError()) | |
243 return status; | |
244 return EncryptDontCheckUsage( | |
245 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); | |
246 } | |
247 | |
248 Status UnwrapKey(blink::WebCryptoKeyFormat format, | |
249 const CryptoData& wrapped_key_data, | |
250 const blink::WebCryptoKey& wrapping_key, | |
251 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
252 const blink::WebCryptoAlgorithm& algorithm, | |
253 bool extractable, | |
254 blink::WebCryptoKeyUsageMask usage_mask, | |
255 blink::WebCryptoKey* key) { | |
256 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) | |
257 return Status::ErrorUnexpected(); | |
258 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | |
259 return Status::ErrorUnexpected(); | |
260 | |
261 // Fail fast if the import is doomed to fail. | |
262 const AlgorithmImplementation* import_impl = NULL; | |
263 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); | |
264 if (status.IsError()) | |
265 return status; | |
266 | |
267 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); | |
268 if (status.IsError()) | |
269 return status; | |
270 | |
271 std::vector<uint8> buffer; | |
272 status = DecryptDontCheckKeyUsage( | |
273 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); | |
274 if (status.IsError()) | |
275 return status; | |
276 | |
277 // NOTE that returning the details of ImportKey() failures may leak | |
278 // information about the plaintext of the encrypted key (for instance the JWK | |
279 // key_ops). As long as the ImportKey error messages don't describe actual | |
280 // key bytes however this should be OK. For more discussion see | |
281 // http://crubg.com/372040 | |
282 return ImportKey( | |
283 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); | |
284 } | |
285 | |
286 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( | |
287 blink::WebCryptoAlgorithmId algorithm) { | |
288 return CreatePlatformDigestor(algorithm); | |
289 } | |
290 | |
291 } // namespace webcrypto | |
292 | |
293 } // namespace content | |
OLD | NEW |