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"
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
);
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
);
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
);
60 return impl
->ExportKey(format
, key
, buffer
);
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
);
91 return impl
->Digest(algorithm
, data
, buffer
);
94 Status
GenerateKey(const blink::WebCryptoAlgorithm
& algorithm
,
96 blink::WebCryptoKeyUsageMask usages
,
97 GenerateKeyResult
* result
) {
98 const AlgorithmImplementation
* impl
= NULL
;
99 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
100 if (status
.IsError())
103 status
= impl
->GenerateKey(algorithm
, extractable
, usages
, result
);
104 if (status
.IsError())
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();
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();
124 Status
ImportKey(blink::WebCryptoKeyFormat format
,
125 const CryptoData
& key_data
,
126 const blink::WebCryptoAlgorithm
& algorithm
,
128 blink::WebCryptoKeyUsageMask usages
,
129 blink::WebCryptoKey
* key
) {
130 const AlgorithmImplementation
* impl
= NULL
;
131 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
132 if (status
.IsError())
135 status
= impl
->VerifyKeyUsagesBeforeImportKey(format
, usages
);
136 if (status
.IsError())
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())
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())
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())
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
,
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())
220 status
= import_impl
->VerifyKeyUsagesBeforeImportKey(format
, usages
);
221 if (status
.IsError())
224 std::vector
<uint8_t> buffer
;
225 status
= DecryptDontCheckKeyUsage(wrapping_algorithm
, wrapping_key
,
226 wrapped_key_data
, &buffer
);
227 if (status
.IsError())
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
,
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())
254 return impl
->DeriveBits(algorithm
, base_key
, true, length_bits
,
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
,
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
;
276 GetAlgorithmImplementation(import_algorithm
.id(), &import_impl
);
277 if (status
.IsError())
280 // Fail fast if the requested key usages are incorect.
281 status
= import_impl
->VerifyKeyUsagesBeforeImportKey(
282 blink::WebCryptoKeyFormatRaw
, usages
);
283 if (status
.IsError())
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
,
291 if (status
.IsError())
294 // Derive the key bytes.
295 const AlgorithmImplementation
* derive_impl
= NULL
;
296 status
= GetAlgorithmImplementation(algorithm
.id(), &derive_impl
);
297 if (status
.IsError())
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())
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())
324 status
= impl
->SerializeKeyForClone(key
, key_data
);
325 return status
.IsSuccess();
328 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
329 blink::WebCryptoKeyType type
,
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())
339 status
= impl
->DeserializeKeyForClone(algorithm
, type
, extractable
, usages
,
341 return status
.IsSuccess();
344 } // namespace webcrypto