blob: ce29c91a3a6ddb3c9840687056305132a5bbf044 [file] [log] [blame]
eroman@chromium.org38409aec2014-07-19 00:54:511// 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
erg56f12322015-04-17 00:51:485#include "components/webcrypto/algorithm_dispatch.h"
eroman@chromium.org38409aec2014-07-19 00:54:516
7#include "base/logging.h"
erg56f12322015-04-17 00:51:488#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"
eroman@chromium.org38409aec2014-07-19 00:54:5115#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
16
eroman@chromium.org38409aec2014-07-19 00:54:5117namespace webcrypto {
18
19namespace {
20
21Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
22 const blink::WebCryptoKey& key,
23 const CryptoData& data,
eroman@chromium.org53b6c9d22014-07-19 05:08:3824 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:5125 if (algorithm.id() != key.algorithm().id())
26 return Status::ErrorUnexpected();
27
28 const AlgorithmImplementation* impl = NULL;
29 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
30 if (status.IsError())
31 return status;
32
33 return impl->Decrypt(algorithm, key, data, buffer);
34}
35
36Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
37 const blink::WebCryptoKey& key,
38 const CryptoData& data,
eroman@chromium.org53b6c9d22014-07-19 05:08:3839 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:5140 if (algorithm.id() != key.algorithm().id())
41 return Status::ErrorUnexpected();
42
43 const AlgorithmImplementation* impl = NULL;
44 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
45 if (status.IsError())
46 return status;
47
48 return impl->Encrypt(algorithm, key, data, buffer);
49}
50
51Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
52 const blink::WebCryptoKey& key,
eroman@chromium.org53b6c9d22014-07-19 05:08:3853 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:5154 const AlgorithmImplementation* impl = NULL;
55 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
56 if (status.IsError())
57 return status;
58
eromana22536b22014-12-12 03:29:2859 return impl->ExportKey(format, key, buffer);
eroman@chromium.org38409aec2014-07-19 00:54:5160}
61
62} // namespace
63
64Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
65 const blink::WebCryptoKey& key,
66 const CryptoData& data,
eroman@chromium.org53b6c9d22014-07-19 05:08:3867 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:5168 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
69 return Status::ErrorUnexpected();
70 return EncryptDontCheckUsage(algorithm, key, data, buffer);
71}
72
73Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
74 const blink::WebCryptoKey& key,
75 const CryptoData& data,
eroman@chromium.org53b6c9d22014-07-19 05:08:3876 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:5177 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
78 return Status::ErrorUnexpected();
79 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
80}
81
82Status Digest(const blink::WebCryptoAlgorithm& algorithm,
83 const CryptoData& data,
eroman@chromium.org53b6c9d22014-07-19 05:08:3884 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:5185 const AlgorithmImplementation* impl = NULL;
86 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
87 if (status.IsError())
88 return status;
89
90 return impl->Digest(algorithm, data, buffer);
91}
92
eroman9b747eaf2014-10-18 22:03:2893Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
94 bool extractable,
eroman0e1d34e2014-10-21 19:13:3195 blink::WebCryptoKeyUsageMask usages,
eroman9b747eaf2014-10-18 22:03:2896 GenerateKeyResult* result) {
eroman@chromium.org38409aec2014-07-19 00:54:5197 const AlgorithmImplementation* impl = NULL;
98 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
99 if (status.IsError())
100 return status;
101
nharper3e2062b2014-12-06 01:05:58102 status = impl->GenerateKey(algorithm, extractable, usages, result);
103 if (status.IsError())
104 return status;
105
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();
113
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();
119 }
120 return status;
eroman@chromium.org38409aec2014-07-19 00:54:51121}
122
eroman@chromium.org38409aec2014-07-19 00:54:51123Status ImportKey(blink::WebCryptoKeyFormat format,
124 const CryptoData& key_data,
125 const blink::WebCryptoAlgorithm& algorithm,
126 bool extractable,
eroman0e1d34e2014-10-21 19:13:31127 blink::WebCryptoKeyUsageMask usages,
eroman@chromium.org38409aec2014-07-19 00:54:51128 blink::WebCryptoKey* key) {
129 const AlgorithmImplementation* impl = NULL;
130 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
131 if (status.IsError())
132 return status;
133
eroman0e1d34e2014-10-21 19:13:31134 status = impl->VerifyKeyUsagesBeforeImportKey(format, usages);
eroman@chromium.org38409aec2014-07-19 00:54:51135 if (status.IsError())
136 return status;
137
eromana22536b22014-12-12 03:29:28138 return impl->ImportKey(format, key_data, algorithm, extractable, usages, key);
eroman@chromium.org38409aec2014-07-19 00:54:51139}
140
141Status ExportKey(blink::WebCryptoKeyFormat format,
142 const blink::WebCryptoKey& key,
eroman@chromium.org53b6c9d22014-07-19 05:08:38143 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:51144 if (!key.extractable())
145 return Status::ErrorKeyNotExtractable();
146 return ExportKeyDontCheckExtractability(format, key, buffer);
147}
148
149Status Sign(const blink::WebCryptoAlgorithm& algorithm,
150 const blink::WebCryptoKey& key,
151 const CryptoData& data,
eroman@chromium.org53b6c9d22014-07-19 05:08:38152 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:51153 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
154 return Status::ErrorUnexpected();
155 if (algorithm.id() != key.algorithm().id())
156 return Status::ErrorUnexpected();
157
158 const AlgorithmImplementation* impl = NULL;
159 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
160 if (status.IsError())
161 return status;
162
163 return impl->Sign(algorithm, key, data, buffer);
164}
165
166Status 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();
175
eroman@chromium.org38409aec2014-07-19 00:54:51176 const AlgorithmImplementation* impl = NULL;
177 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
178 if (status.IsError())
179 return status;
180
181 return impl->Verify(algorithm, key, signature, data, signature_match);
182}
183
184Status WrapKey(blink::WebCryptoKeyFormat format,
185 const blink::WebCryptoKey& key_to_wrap,
186 const blink::WebCryptoKey& wrapping_key,
187 const blink::WebCryptoAlgorithm& wrapping_algorithm,
eroman@chromium.org53b6c9d22014-07-19 05:08:38188 std::vector<uint8_t>* buffer) {
eroman@chromium.org38409aec2014-07-19 00:54:51189 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
190 return Status::ErrorUnexpected();
191
eroman@chromium.org53b6c9d22014-07-19 05:08:38192 std::vector<uint8_t> exported_data;
eroman@chromium.org38409aec2014-07-19 00:54:51193 Status status = ExportKey(format, key_to_wrap, &exported_data);
194 if (status.IsError())
195 return status;
eroman38bb4bd2014-11-24 23:47:06196 return EncryptDontCheckUsage(wrapping_algorithm, wrapping_key,
197 CryptoData(exported_data), buffer);
eroman@chromium.org38409aec2014-07-19 00:54:51198}
199
200Status 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,
eroman0e1d34e2014-10-21 19:13:31206 blink::WebCryptoKeyUsageMask usages,
eroman@chromium.org38409aec2014-07-19 00:54:51207 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();
212
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;
218
eroman0e1d34e2014-10-21 19:13:31219 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usages);
eroman@chromium.org38409aec2014-07-19 00:54:51220 if (status.IsError())
221 return status;
222
eroman@chromium.org53b6c9d22014-07-19 05:08:38223 std::vector<uint8_t> buffer;
eroman38bb4bd2014-11-24 23:47:06224 status = DecryptDontCheckKeyUsage(wrapping_algorithm, wrapping_key,
225 wrapped_key_data, &buffer);
eroman@chromium.org38409aec2014-07-19 00:54:51226 if (status.IsError())
227 return status;
228
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
eroman38bb4bd2014-11-24 23:47:06234 return ImportKey(format, CryptoData(buffer), algorithm, extractable, usages,
235 key);
eroman@chromium.org38409aec2014-07-19 00:54:51236}
237
eroman1499b4942014-11-26 19:59:53238Status 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();
244
245 if (algorithm.id() != base_key.algorithm().id())
246 return Status::ErrorUnexpected();
247
248 const AlgorithmImplementation* impl = NULL;
249 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
250 if (status.IsError())
251 return status;
252
eroman20bf4c3c2014-12-12 17:22:37253 return impl->DeriveBits(algorithm, base_key, true, length_bits,
254 derived_bytes);
255}
256
257Status 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();
266
267 if (algorithm.id() != base_key.algorithm().id())
268 return Status::ErrorUnexpected();
269
270 if (import_algorithm.id() != key_length_algorithm.id())
271 return Status::ErrorUnexpected();
272
273 const AlgorithmImplementation* import_impl = NULL;
274 Status status =
275 GetAlgorithmImplementation(import_algorithm.id(), &import_impl);
276 if (status.IsError())
277 return status;
278
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;
284
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;
292
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;
298
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;
304
305 // Create the key using the derived bytes.
306 return ImportKey(blink::WebCryptoKeyFormatRaw, CryptoData(derived_bytes),
307 import_algorithm, extractable, usages, derived_key);
eroman1499b4942014-11-26 19:59:53308}
309
eroman@chromium.org38409aec2014-07-19 00:54:51310scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
311 blink::WebCryptoAlgorithmId algorithm) {
312 PlatformInit();
313 return CreatePlatformDigestor(algorithm);
314}
315
eromana895fed2014-11-08 03:10:25316bool 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;
322
323 status = impl->SerializeKeyForClone(key, key_data);
324 return status.IsSuccess();
325}
326
327bool 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;
337
338 status = impl->DeserializeKeyForClone(algorithm, type, extractable, usages,
339 key_data, key);
340 return status.IsSuccess();
341}
342
eroman@chromium.org38409aec2014-07-19 00:54:51343} // namespace webcrypto