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"
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
);
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
);
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
);
61 return impl
->ExportKey(format
, key
, buffer
);
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
);
92 return impl
->Digest(algorithm
, data
, buffer
);
95 Status
GenerateKey(const blink::WebCryptoAlgorithm
& algorithm
,
97 blink::WebCryptoKeyUsageMask usages
,
98 GenerateKeyResult
* result
) {
99 const AlgorithmImplementation
* impl
= NULL
;
100 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
101 if (status
.IsError())
104 status
= impl
->GenerateKey(algorithm
, extractable
, usages
, result
);
105 if (status
.IsError())
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();
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();
125 Status
ImportKey(blink::WebCryptoKeyFormat format
,
126 const CryptoData
& key_data
,
127 const blink::WebCryptoAlgorithm
& algorithm
,
129 blink::WebCryptoKeyUsageMask usages
,
130 blink::WebCryptoKey
* key
) {
131 const AlgorithmImplementation
* impl
= NULL
;
132 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
133 if (status
.IsError())
136 status
= impl
->VerifyKeyUsagesBeforeImportKey(format
, usages
);
137 if (status
.IsError())
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())
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())
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())
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
,
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())
221 status
= import_impl
->VerifyKeyUsagesBeforeImportKey(format
, usages
);
222 if (status
.IsError())
225 std::vector
<uint8_t> buffer
;
226 status
= DecryptDontCheckKeyUsage(wrapping_algorithm
, wrapping_key
,
227 wrapped_key_data
, &buffer
);
228 if (status
.IsError())
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
,
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())
255 return impl
->DeriveBits(algorithm
, base_key
, true, length_bits
,
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
,
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
;
277 GetAlgorithmImplementation(import_algorithm
.id(), &import_impl
);
278 if (status
.IsError())
281 // Fail fast if the requested key usages are incorect.
282 status
= import_impl
->VerifyKeyUsagesBeforeImportKey(
283 blink::WebCryptoKeyFormatRaw
, usages
);
284 if (status
.IsError())
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
,
292 if (status
.IsError())
295 // Derive the key bytes.
296 const AlgorithmImplementation
* derive_impl
= NULL
;
297 status
= GetAlgorithmImplementation(algorithm
.id(), &derive_impl
);
298 if (status
.IsError())
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())
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
) {
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())
325 status
= impl
->SerializeKeyForClone(key
, key_data
);
326 return status
.IsSuccess();
329 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
330 blink::WebCryptoKeyType type
,
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())
340 status
= impl
->DeserializeKeyForClone(algorithm
, type
, extractable
, usages
,
342 return status
.IsSuccess();
345 } // namespace webcrypto
347 } // namespace content