Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / content / child / webcrypto / algorithm_dispatch.cc
blob4badeea98674c47c297ee6c46c890f503cb795df
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.
5 #include "content/child/webcrypto/algorithm_dispatch.h"
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"
17 namespace content {
19 namespace webcrypto {
21 namespace {
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();
30 const AlgorithmImplementation* impl = NULL;
31 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
32 if (status.IsError())
33 return status;
35 return impl->Decrypt(algorithm, key, data, buffer);
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();
45 const AlgorithmImplementation* impl = NULL;
46 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
47 if (status.IsError())
48 return status;
50 return impl->Encrypt(algorithm, key, data, buffer);
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;
61 return impl->ExportKey(format, key, buffer);
64 } // namespace
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);
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);
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;
92 return impl->Digest(algorithm, data, buffer);
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;
104 status = impl->GenerateKey(algorithm, extractable, usages, result);
105 if (status.IsError())
106 return status;
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();
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();
122 return status;
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;
136 status = impl->VerifyKeyUsagesBeforeImportKey(format, usages);
137 if (status.IsError())
138 return status;
140 return impl->ImportKey(format, key_data, algorithm, extractable, usages, key);
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);
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();
160 const AlgorithmImplementation* impl = NULL;
161 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
162 if (status.IsError())
163 return status;
165 return impl->Sign(algorithm, key, data, buffer);
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();
178 const AlgorithmImplementation* impl = NULL;
179 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
180 if (status.IsError())
181 return status;
183 return impl->Verify(algorithm, key, signature, data, signature_match);
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();
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);
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();
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;
221 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usages);
222 if (status.IsError())
223 return status;
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;
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);
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();
247 if (algorithm.id() != base_key.algorithm().id())
248 return Status::ErrorUnexpected();
250 const AlgorithmImplementation* impl = NULL;
251 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
252 if (status.IsError())
253 return status;
255 return impl->DeriveBits(algorithm, base_key, true, length_bits,
256 derived_bytes);
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();
269 if (algorithm.id() != base_key.algorithm().id())
270 return Status::ErrorUnexpected();
272 if (import_algorithm.id() != key_length_algorithm.id())
273 return Status::ErrorUnexpected();
275 const AlgorithmImplementation* import_impl = NULL;
276 Status status =
277 GetAlgorithmImplementation(import_algorithm.id(), &import_impl);
278 if (status.IsError())
279 return status;
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;
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;
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;
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;
307 // Create the key using the derived bytes.
308 return ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(derived_bytes),
309 import_algorithm, extractable, usages, derived_key);
312 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
313 blink::WebCryptoAlgorithmId algorithm) {
314 PlatformInit();
315 return CreatePlatformDigestor(algorithm);
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;
325 status = impl->SerializeKeyForClone(key, key_data);
326 return status.IsSuccess();
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;
340 status = impl->DeserializeKeyForClone(algorithm, type, extractable, usages,
341 key_data, key);
342 return status.IsSuccess();
345 } // namespace webcrypto
347 } // namespace content