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