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