OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/webcrypto/shared_crypto.h" | 5 #include "content/child/webcrypto/algorithm_dispatch.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "content/child/webcrypto/algorithm.h" |
| 9 #include "content/child/webcrypto/algorithm_registry.h" |
8 #include "content/child/webcrypto/crypto_data.h" | 10 #include "content/child/webcrypto/crypto_data.h" |
9 #include "content/child/webcrypto/jwk.h" | |
10 #include "content/child/webcrypto/platform_crypto.h" | 11 #include "content/child/webcrypto/platform_crypto.h" |
11 #include "content/child/webcrypto/status.h" | 12 #include "content/child/webcrypto/status.h" |
12 #include "content/child/webcrypto/webcrypto_util.h" | 13 #include "content/child/webcrypto/webcrypto_util.h" |
13 #include "crypto/secure_util.h" | |
14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
16 #include "third_party/WebKit/public/platform/WebCryptoKey.h" | |
17 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
18 | 15 |
19 namespace content { | 16 namespace content { |
20 | 17 |
21 namespace webcrypto { | 18 namespace webcrypto { |
22 | 19 |
23 // ------------ | |
24 // Threading: | |
25 // ------------ | |
26 // | |
27 // All functions in this file are called from the webcrypto worker pool except | |
28 // for: | |
29 // | |
30 // * SerializeKeyForClone() | |
31 // * DeserializeKeyForClone() | |
32 // * ImportKey() // TODO(eroman): Change this. | |
33 | |
34 namespace { | 20 namespace { |
35 | 21 |
36 // TODO(eroman): Move this helper to WebCryptoKey. | |
37 bool KeyUsageAllows(const blink::WebCryptoKey& key, | |
38 const blink::WebCryptoKeyUsage usage) { | |
39 return ((key.usages() & usage) != 0); | |
40 } | |
41 | |
42 bool IsValidAesKeyLengthBits(unsigned int length_bits) { | |
43 // 192-bit AES is disallowed. | |
44 return length_bits == 128 || length_bits == 256; | |
45 } | |
46 | |
47 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) { | |
48 // 192-bit AES is disallowed. | |
49 return length_bytes == 16 || length_bytes == 32; | |
50 } | |
51 | |
52 const size_t kAesBlockSizeBytes = 16; | |
53 | |
54 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, | |
55 const blink::WebCryptoAlgorithm& algorithm, | |
56 const blink::WebCryptoKey& key, | |
57 const CryptoData& data, | |
58 std::vector<uint8>* buffer) { | |
59 platform::SymKey* sym_key; | |
60 Status status = ToPlatformSymKey(key, &sym_key); | |
61 if (status.IsError()) | |
62 return status; | |
63 | |
64 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); | |
65 if (!params) | |
66 return Status::ErrorUnexpected(); | |
67 | |
68 CryptoData iv(params->iv().data(), params->iv().size()); | |
69 if (iv.byte_length() != kAesBlockSizeBytes) | |
70 return Status::ErrorIncorrectSizeAesCbcIv(); | |
71 | |
72 return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer); | |
73 } | |
74 | |
75 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, | |
76 const blink::WebCryptoAlgorithm& algorithm, | |
77 const blink::WebCryptoKey& key, | |
78 const CryptoData& data, | |
79 std::vector<uint8>* buffer) { | |
80 platform::SymKey* sym_key; | |
81 Status status = ToPlatformSymKey(key, &sym_key); | |
82 if (status.IsError()) | |
83 return status; | |
84 | |
85 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams(); | |
86 if (!params) | |
87 return Status::ErrorUnexpected(); | |
88 | |
89 unsigned int tag_length_bits = 128; | |
90 if (params->hasTagLengthBits()) | |
91 tag_length_bits = params->optionalTagLengthBits(); | |
92 | |
93 if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 && | |
94 tag_length_bits != 104 && tag_length_bits != 112 && | |
95 tag_length_bits != 120 && tag_length_bits != 128) | |
96 return Status::ErrorInvalidAesGcmTagLength(); | |
97 | |
98 return platform::EncryptDecryptAesGcm( | |
99 mode, | |
100 sym_key, | |
101 data, | |
102 CryptoData(params->iv()), | |
103 CryptoData(params->optionalAdditionalData()), | |
104 tag_length_bits, | |
105 buffer); | |
106 } | |
107 | |
108 Status EncryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm, | |
109 const blink::WebCryptoKey& key, | |
110 const CryptoData& data, | |
111 std::vector<uint8>* buffer) { | |
112 platform::PublicKey* public_key; | |
113 Status status = ToPlatformPublicKey(key, &public_key); | |
114 if (status.IsError()) | |
115 return status; | |
116 | |
117 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams(); | |
118 if (!params) | |
119 return Status::ErrorUnexpected(); | |
120 | |
121 return platform::EncryptRsaOaep(public_key, | |
122 key.algorithm().rsaHashedParams()->hash(), | |
123 CryptoData(params->optionalLabel()), | |
124 data, | |
125 buffer); | |
126 } | |
127 | |
128 Status DecryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm, | |
129 const blink::WebCryptoKey& key, | |
130 const CryptoData& data, | |
131 std::vector<uint8>* buffer) { | |
132 platform::PrivateKey* private_key; | |
133 Status status = ToPlatformPrivateKey(key, &private_key); | |
134 if (status.IsError()) | |
135 return status; | |
136 | |
137 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams(); | |
138 if (!params) | |
139 return Status::ErrorUnexpected(); | |
140 | |
141 return platform::DecryptRsaOaep(private_key, | |
142 key.algorithm().rsaHashedParams()->hash(), | |
143 CryptoData(params->optionalLabel()), | |
144 data, | |
145 buffer); | |
146 } | |
147 | |
148 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm, | |
149 const blink::WebCryptoKey& key, | |
150 const CryptoData& data, | |
151 std::vector<uint8>* buffer) { | |
152 platform::SymKey* sym_key; | |
153 Status status = ToPlatformSymKey(key, &sym_key); | |
154 if (status.IsError()) | |
155 return status; | |
156 | |
157 return platform::SignHmac( | |
158 sym_key, key.algorithm().hmacParams()->hash(), data, buffer); | |
159 } | |
160 | |
161 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm, | |
162 const blink::WebCryptoKey& key, | |
163 const CryptoData& signature, | |
164 const CryptoData& data, | |
165 bool* signature_match) { | |
166 std::vector<uint8> result; | |
167 Status status = SignHmac(algorithm, key, data, &result); | |
168 if (status.IsError()) | |
169 return status; | |
170 | |
171 // Do not allow verification of truncated MACs. | |
172 *signature_match = | |
173 result.size() == signature.byte_length() && | |
174 crypto::SecureMemEqual( | |
175 Uint8VectorStart(result), signature.bytes(), signature.byte_length()); | |
176 | |
177 return Status::Success(); | |
178 } | |
179 | |
180 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, | |
181 const blink::WebCryptoKey& key, | |
182 const CryptoData& data, | |
183 std::vector<uint8>* buffer) { | |
184 platform::PrivateKey* private_key; | |
185 Status status = ToPlatformPrivateKey(key, &private_key); | |
186 if (status.IsError()) | |
187 return status; | |
188 | |
189 return platform::SignRsaSsaPkcs1v1_5( | |
190 private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer); | |
191 } | |
192 | |
193 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, | |
194 const blink::WebCryptoKey& key, | |
195 const CryptoData& signature, | |
196 const CryptoData& data, | |
197 bool* signature_match) { | |
198 platform::PublicKey* public_key; | |
199 Status status = ToPlatformPublicKey(key, &public_key); | |
200 if (status.IsError()) | |
201 return status; | |
202 | |
203 return platform::VerifyRsaSsaPkcs1v1_5( | |
204 public_key, | |
205 key.algorithm().rsaHashedParams()->hash(), | |
206 signature, | |
207 data, | |
208 signature_match); | |
209 } | |
210 | |
211 // Note that this function may be called from the target Blink thread. | |
212 Status ImportKeyRaw(const CryptoData& key_data, | |
213 const blink::WebCryptoAlgorithm& algorithm, | |
214 bool extractable, | |
215 blink::WebCryptoKeyUsageMask usage_mask, | |
216 blink::WebCryptoKey* key) { | |
217 switch (algorithm.id()) { | |
218 case blink::WebCryptoAlgorithmIdAesCtr: | |
219 case blink::WebCryptoAlgorithmIdAesCbc: | |
220 case blink::WebCryptoAlgorithmIdAesGcm: | |
221 case blink::WebCryptoAlgorithmIdAesKw: | |
222 if (!IsValidAesKeyLengthBytes(key_data.byte_length())) { | |
223 return key_data.byte_length() == 24 | |
224 ? Status::ErrorAes192BitUnsupported() | |
225 : Status::ErrorImportAesKeyLength(); | |
226 } | |
227 // Fallthrough intentional! | |
228 case blink::WebCryptoAlgorithmIdHmac: | |
229 return platform::ImportKeyRaw( | |
230 algorithm, key_data, extractable, usage_mask, key); | |
231 default: | |
232 return Status::ErrorUnsupported(); | |
233 } | |
234 } | |
235 | |
236 // Returns the key format to use for structured cloning. | |
237 blink::WebCryptoKeyFormat GetCloneFormatForKeyType( | |
238 blink::WebCryptoKeyType type) { | |
239 switch (type) { | |
240 case blink::WebCryptoKeyTypeSecret: | |
241 return blink::WebCryptoKeyFormatRaw; | |
242 case blink::WebCryptoKeyTypePublic: | |
243 return blink::WebCryptoKeyFormatSpki; | |
244 case blink::WebCryptoKeyTypePrivate: | |
245 return blink::WebCryptoKeyFormatPkcs8; | |
246 } | |
247 | |
248 NOTREACHED(); | |
249 return blink::WebCryptoKeyFormatRaw; | |
250 } | |
251 | |
252 // Converts a KeyAlgorithm into an equivalent Algorithm for import. | |
253 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( | |
254 const blink::WebCryptoKeyAlgorithm& algorithm) { | |
255 switch (algorithm.paramsType()) { | |
256 case blink::WebCryptoKeyAlgorithmParamsTypeAes: | |
257 return CreateAlgorithm(algorithm.id()); | |
258 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: | |
259 return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id()); | |
260 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: | |
261 return CreateRsaHashedImportAlgorithm( | |
262 algorithm.id(), algorithm.rsaHashedParams()->hash().id()); | |
263 case blink::WebCryptoKeyAlgorithmParamsTypeNone: | |
264 break; | |
265 default: | |
266 break; | |
267 } | |
268 return blink::WebCryptoAlgorithm::createNull(); | |
269 } | |
270 | |
271 // There is some duplicated information in the serialized format used by | |
272 // structured clone (since the KeyAlgorithm is serialized separately from the | |
273 // key data). Use this extra information to further validate what was | |
274 // deserialized from the key data. | |
275 // | |
276 // A failure here implies either a bug in the code, or that the serialized data | |
277 // was corrupted. | |
278 bool ValidateDeserializedKey(const blink::WebCryptoKey& key, | |
279 const blink::WebCryptoKeyAlgorithm& algorithm, | |
280 blink::WebCryptoKeyType type) { | |
281 if (algorithm.id() != key.algorithm().id()) | |
282 return false; | |
283 | |
284 if (key.type() != type) | |
285 return false; | |
286 | |
287 switch (algorithm.paramsType()) { | |
288 case blink::WebCryptoKeyAlgorithmParamsTypeAes: | |
289 if (algorithm.aesParams()->lengthBits() != | |
290 key.algorithm().aesParams()->lengthBits()) | |
291 return false; | |
292 break; | |
293 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: | |
294 if (algorithm.rsaHashedParams()->modulusLengthBits() != | |
295 key.algorithm().rsaHashedParams()->modulusLengthBits()) | |
296 return false; | |
297 if (algorithm.rsaHashedParams()->publicExponent().size() != | |
298 key.algorithm().rsaHashedParams()->publicExponent().size()) | |
299 return false; | |
300 if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(), | |
301 key.algorithm().rsaHashedParams()->publicExponent().data(), | |
302 key.algorithm().rsaHashedParams()->publicExponent().size()) != | |
303 0) | |
304 return false; | |
305 break; | |
306 case blink::WebCryptoKeyAlgorithmParamsTypeNone: | |
307 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: | |
308 break; | |
309 default: | |
310 return false; | |
311 } | |
312 | |
313 return true; | |
314 } | |
315 | |
316 Status EncryptDecryptAesKw(EncryptOrDecrypt mode, | |
317 const blink::WebCryptoAlgorithm& algorithm, | |
318 const blink::WebCryptoKey& key, | |
319 const CryptoData& data, | |
320 std::vector<uint8>* buffer) { | |
321 platform::SymKey* sym_key; | |
322 Status status = ToPlatformSymKey(key, &sym_key); | |
323 if (status.IsError()) | |
324 return status; | |
325 | |
326 unsigned int min_length = mode == ENCRYPT ? 16 : 24; | |
327 | |
328 if (data.byte_length() < min_length) | |
329 return Status::ErrorDataTooSmall(); | |
330 if (data.byte_length() % 8) | |
331 return Status::ErrorInvalidAesKwDataLength(); | |
332 | |
333 if (status.IsError()) | |
334 return status; | |
335 return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer); | |
336 } | |
337 | |
338 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, | 22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, |
339 const blink::WebCryptoKey& key, | 23 const blink::WebCryptoKey& key, |
340 const CryptoData& data, | 24 const CryptoData& data, |
341 std::vector<uint8>* buffer) { | 25 std::vector<uint8>* buffer) { |
342 if (algorithm.id() != key.algorithm().id()) | 26 if (algorithm.id() != key.algorithm().id()) |
343 return Status::ErrorUnexpected(); | 27 return Status::ErrorUnexpected(); |
344 switch (algorithm.id()) { | 28 |
345 case blink::WebCryptoAlgorithmIdAesCbc: | 29 const AlgorithmImplementation* impl = NULL; |
346 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer); | 30 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
347 case blink::WebCryptoAlgorithmIdAesGcm: | 31 if (status.IsError()) |
348 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer); | 32 return status; |
349 case blink::WebCryptoAlgorithmIdRsaOaep: | 33 |
350 return DecryptRsaOaep(algorithm, key, data, buffer); | 34 return impl->Decrypt(algorithm, key, data, buffer); |
351 case blink::WebCryptoAlgorithmIdAesKw: | |
352 return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer); | |
353 default: | |
354 return Status::ErrorUnsupported(); | |
355 } | |
356 } | 35 } |
357 | 36 |
358 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, | 37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, |
359 const blink::WebCryptoKey& key, | 38 const blink::WebCryptoKey& key, |
360 const CryptoData& data, | 39 const CryptoData& data, |
361 std::vector<uint8>* buffer) { | 40 std::vector<uint8>* buffer) { |
362 if (algorithm.id() != key.algorithm().id()) | 41 if (algorithm.id() != key.algorithm().id()) |
363 return Status::ErrorUnexpected(); | 42 return Status::ErrorUnexpected(); |
364 switch (algorithm.id()) { | 43 |
365 case blink::WebCryptoAlgorithmIdAesCbc: | 44 const AlgorithmImplementation* impl = NULL; |
366 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer); | 45 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
367 case blink::WebCryptoAlgorithmIdAesGcm: | 46 if (status.IsError()) |
368 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer); | 47 return status; |
369 case blink::WebCryptoAlgorithmIdAesKw: | 48 |
370 return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer); | 49 return impl->Encrypt(algorithm, key, data, buffer); |
371 case blink::WebCryptoAlgorithmIdRsaOaep: | 50 } |
372 return EncryptRsaOaep(algorithm, key, data, buffer); | 51 |
| 52 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, |
| 53 const blink::WebCryptoKey& key, |
| 54 std::vector<uint8>* buffer) { |
| 55 const AlgorithmImplementation* impl = NULL; |
| 56 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl); |
| 57 if (status.IsError()) |
| 58 return status; |
| 59 |
| 60 switch (format) { |
| 61 case blink::WebCryptoKeyFormatRaw: |
| 62 return impl->ExportKeyRaw(key, buffer); |
| 63 case blink::WebCryptoKeyFormatSpki: |
| 64 return impl->ExportKeySpki(key, buffer); |
| 65 case blink::WebCryptoKeyFormatPkcs8: |
| 66 return impl->ExportKeyPkcs8(key, buffer); |
| 67 case blink::WebCryptoKeyFormatJwk: |
| 68 return impl->ExportKeyJwk(key, buffer); |
373 default: | 69 default: |
374 return Status::ErrorUnsupported(); | 70 return Status::ErrorUnsupported(); |
375 } | 71 } |
376 } | 72 } |
377 | 73 |
378 Status UnwrapKeyDecryptAndImport( | |
379 blink::WebCryptoKeyFormat format, | |
380 const CryptoData& wrapped_key_data, | |
381 const blink::WebCryptoKey& wrapping_key, | |
382 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
383 const blink::WebCryptoAlgorithm& algorithm, | |
384 bool extractable, | |
385 blink::WebCryptoKeyUsageMask usage_mask, | |
386 blink::WebCryptoKey* key) { | |
387 std::vector<uint8> buffer; | |
388 Status status = DecryptDontCheckKeyUsage( | |
389 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); | |
390 if (status.IsError()) | |
391 return status; | |
392 // NOTE that returning the details of ImportKey() failures may leak | |
393 // information about the plaintext of the encrypted key (for instance the JWK | |
394 // key_ops). As long as the ImportKey error messages don't describe actual | |
395 // key bytes however this should be OK. For more discussion see | |
396 // http://crubg.com/372040 | |
397 return ImportKey( | |
398 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); | |
399 } | |
400 | |
401 Status WrapKeyExportAndEncrypt( | |
402 blink::WebCryptoKeyFormat format, | |
403 const blink::WebCryptoKey& key_to_wrap, | |
404 const blink::WebCryptoKey& wrapping_key, | |
405 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
406 std::vector<uint8>* buffer) { | |
407 std::vector<uint8> exported_data; | |
408 Status status = ExportKey(format, key_to_wrap, &exported_data); | |
409 if (status.IsError()) | |
410 return status; | |
411 return EncryptDontCheckUsage( | |
412 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); | |
413 } | |
414 | |
415 // Returns the internal block size for SHA-* | |
416 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) { | |
417 switch (hash_id) { | |
418 case blink::WebCryptoAlgorithmIdSha1: | |
419 case blink::WebCryptoAlgorithmIdSha256: | |
420 return 64; | |
421 case blink::WebCryptoAlgorithmIdSha384: | |
422 case blink::WebCryptoAlgorithmIdSha512: | |
423 return 128; | |
424 default: | |
425 NOTREACHED(); | |
426 return 0; | |
427 } | |
428 } | |
429 | |
430 // Returns the mask of all key usages that are possible for |algorithm| and | |
431 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make | |
432 // sense, then returns 0 (no usages). | |
433 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType( | |
434 blink::WebCryptoAlgorithmId algorithm, | |
435 blink::WebCryptoKeyType key_type) { | |
436 if (IsAlgorithmAsymmetric(algorithm) == | |
437 (key_type == blink::WebCryptoKeyTypeSecret)) | |
438 return 0; | |
439 | |
440 switch (algorithm) { | |
441 case blink::WebCryptoAlgorithmIdAesCbc: | |
442 case blink::WebCryptoAlgorithmIdAesGcm: | |
443 case blink::WebCryptoAlgorithmIdAesCtr: | |
444 return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | | |
445 blink::WebCryptoKeyUsageWrapKey | | |
446 blink::WebCryptoKeyUsageUnwrapKey; | |
447 case blink::WebCryptoAlgorithmIdAesKw: | |
448 return blink::WebCryptoKeyUsageWrapKey | | |
449 blink::WebCryptoKeyUsageUnwrapKey; | |
450 case blink::WebCryptoAlgorithmIdHmac: | |
451 return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
452 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
453 switch (key_type) { | |
454 case blink::WebCryptoKeyTypePublic: | |
455 return blink::WebCryptoKeyUsageVerify; | |
456 case blink::WebCryptoKeyTypePrivate: | |
457 return blink::WebCryptoKeyUsageSign; | |
458 default: | |
459 return 0; | |
460 } | |
461 case blink::WebCryptoAlgorithmIdRsaOaep: | |
462 switch (key_type) { | |
463 case blink::WebCryptoKeyTypePublic: | |
464 return blink::WebCryptoKeyUsageEncrypt | | |
465 blink::WebCryptoKeyUsageWrapKey; | |
466 case blink::WebCryptoKeyTypePrivate: | |
467 return blink::WebCryptoKeyUsageDecrypt | | |
468 blink::WebCryptoKeyUsageUnwrapKey; | |
469 default: | |
470 return 0; | |
471 } | |
472 default: | |
473 return 0; | |
474 } | |
475 } | |
476 | |
477 // Returns Status::Success() if |usages| is a valid set of key usages for | |
478 // |algorithm| and |key_type|. Otherwise returns an error. | |
479 // In the case of JWK format the check is incomplete for asymmetric algorithms. | |
480 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm, | |
481 blink::WebCryptoKeyFormat format, | |
482 blink::WebCryptoKeyUsageMask usages) { | |
483 if (!IsAlgorithmAsymmetric(algorithm)) | |
484 return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages); | |
485 | |
486 // Try to infer the key type given the import format. | |
487 blink::WebCryptoKeyType key_type; | |
488 bool key_type_known = false; | |
489 | |
490 switch (format) { | |
491 case blink::WebCryptoKeyFormatRaw: | |
492 // TODO(eroman): The spec defines Diffie-Hellman raw import for public | |
493 // keys, so this will need to be updated in the future when DH is | |
494 // implemented. | |
495 return Status::ErrorUnexpected(); | |
496 case blink::WebCryptoKeyFormatSpki: | |
497 key_type = blink::WebCryptoKeyTypePublic; | |
498 key_type_known = true; | |
499 break; | |
500 case blink::WebCryptoKeyFormatPkcs8: | |
501 key_type = blink::WebCryptoKeyTypePrivate; | |
502 key_type_known = true; | |
503 break; | |
504 case blink::WebCryptoKeyFormatJwk: | |
505 key_type_known = false; | |
506 break; | |
507 default: | |
508 return Status::ErrorUnexpected(); | |
509 } | |
510 | |
511 if (key_type_known) | |
512 return CheckKeyUsages(algorithm, key_type, usages); | |
513 | |
514 // If the key type is not known, then the algorithm is asymmetric. Whether the | |
515 // key data describes a public or private key isn't known yet. But it must at | |
516 // least be ONE of those two. | |
517 DCHECK(IsAlgorithmAsymmetric(algorithm)); | |
518 | |
519 if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages) | |
520 .IsError() && | |
521 CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages) | |
522 .IsError()) { | |
523 return Status::ErrorCreateKeyBadUsages(); | |
524 } | |
525 | |
526 return Status::Success(); | |
527 } | |
528 | |
529 // Returns an error if |combined_usage_mask| is invalid for generating a key | |
530 // pair for |algorithm|. Otherwise returns Status::Success(), and fills | |
531 // |public_key_usages| with the usages for the public key, and | |
532 // |private_key_usages| with those for the private key. | |
533 Status CheckKeyUsagesForGenerateKeyPair( | |
534 blink::WebCryptoAlgorithmId algorithm, | |
535 blink::WebCryptoKeyUsageMask combined_usage_mask, | |
536 blink::WebCryptoKeyUsageMask* public_key_usages, | |
537 blink::WebCryptoKeyUsageMask* private_key_usages) { | |
538 DCHECK(IsAlgorithmAsymmetric(algorithm)); | |
539 | |
540 blink::WebCryptoKeyUsageMask all_public_key_usages = | |
541 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic); | |
542 blink::WebCryptoKeyUsageMask all_private_key_usages = | |
543 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate); | |
544 | |
545 if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages, | |
546 combined_usage_mask)) | |
547 return Status::ErrorCreateKeyBadUsages(); | |
548 | |
549 *public_key_usages = combined_usage_mask & all_public_key_usages; | |
550 *private_key_usages = combined_usage_mask & all_private_key_usages; | |
551 | |
552 return Status::Success(); | |
553 } | |
554 | |
555 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, | |
556 // to unsigned long. | |
557 bool BigIntegerToLong(const uint8* data, | |
558 unsigned int data_size, | |
559 unsigned long* result) { | |
560 // TODO(padolph): Is it correct to say that empty data is an error, or does it | |
561 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655 | |
562 if (data_size == 0) | |
563 return false; | |
564 | |
565 *result = 0; | |
566 for (size_t i = 0; i < data_size; ++i) { | |
567 size_t reverse_i = data_size - i - 1; | |
568 | |
569 if (reverse_i >= sizeof(unsigned long) && data[i]) | |
570 return false; // Too large for a long. | |
571 | |
572 *result |= data[i] << 8 * reverse_i; | |
573 } | |
574 return true; | |
575 } | |
576 | |
577 | |
578 } // namespace | 74 } // namespace |
579 | 75 |
580 void Init() { platform::Init(); } | |
581 | |
582 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, | 76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, |
583 const blink::WebCryptoKey& key, | 77 const blink::WebCryptoKey& key, |
584 const CryptoData& data, | 78 const CryptoData& data, |
585 std::vector<uint8>* buffer) { | 79 std::vector<uint8>* buffer) { |
586 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) | 80 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) |
587 return Status::ErrorUnexpected(); | 81 return Status::ErrorUnexpected(); |
588 return EncryptDontCheckUsage(algorithm, key, data, buffer); | 82 return EncryptDontCheckUsage(algorithm, key, data, buffer); |
589 } | 83 } |
590 | 84 |
591 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, | 85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, |
592 const blink::WebCryptoKey& key, | 86 const blink::WebCryptoKey& key, |
593 const CryptoData& data, | 87 const CryptoData& data, |
594 std::vector<uint8>* buffer) { | 88 std::vector<uint8>* buffer) { |
595 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) | 89 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) |
596 return Status::ErrorUnexpected(); | 90 return Status::ErrorUnexpected(); |
597 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); | 91 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); |
598 } | 92 } |
599 | 93 |
600 Status Digest(const blink::WebCryptoAlgorithm& algorithm, | 94 Status Digest(const blink::WebCryptoAlgorithm& algorithm, |
601 const CryptoData& data, | 95 const CryptoData& data, |
602 std::vector<uint8>* buffer) { | 96 std::vector<uint8>* buffer) { |
603 switch (algorithm.id()) { | 97 const AlgorithmImplementation* impl = NULL; |
604 case blink::WebCryptoAlgorithmIdSha1: | 98 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
605 case blink::WebCryptoAlgorithmIdSha256: | 99 if (status.IsError()) |
606 case blink::WebCryptoAlgorithmIdSha384: | 100 return status; |
607 case blink::WebCryptoAlgorithmIdSha512: | |
608 return platform::DigestSha(algorithm.id(), data, buffer); | |
609 default: | |
610 return Status::ErrorUnsupported(); | |
611 } | |
612 } | |
613 | 101 |
614 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( | 102 return impl->Digest(algorithm, data, buffer); |
615 blink::WebCryptoAlgorithmId algorithm) { | |
616 return platform::CreateDigestor(algorithm); | |
617 } | 103 } |
618 | 104 |
619 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, | 105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, |
620 bool extractable, | 106 bool extractable, |
621 blink::WebCryptoKeyUsageMask usage_mask, | 107 blink::WebCryptoKeyUsageMask usage_mask, |
622 blink::WebCryptoKey* key) { | 108 blink::WebCryptoKey* key) { |
623 Status status = | 109 const AlgorithmImplementation* impl = NULL; |
624 CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask); | 110 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
625 if (status.IsError()) | 111 if (status.IsError()) |
626 return status; | 112 return status; |
627 | 113 |
628 unsigned int keylen_bytes = 0; | 114 status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask); |
| 115 if (status.IsError()) |
| 116 return status; |
629 | 117 |
630 // Get the secret key length in bytes from generation parameters. | 118 return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key); |
631 // This resolves any defaults. | |
632 switch (algorithm.id()) { | |
633 case blink::WebCryptoAlgorithmIdAesCbc: | |
634 case blink::WebCryptoAlgorithmIdAesGcm: | |
635 case blink::WebCryptoAlgorithmIdAesKw: { | |
636 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits())) { | |
637 return algorithm.aesKeyGenParams()->lengthBits() == 192 | |
638 ? Status::ErrorAes192BitUnsupported() | |
639 : Status::ErrorGenerateKeyLength(); | |
640 } | |
641 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8; | |
642 break; | |
643 } | |
644 case blink::WebCryptoAlgorithmIdHmac: { | |
645 const blink::WebCryptoHmacKeyGenParams* params = | |
646 algorithm.hmacKeyGenParams(); | |
647 DCHECK(params); | |
648 if (params->hasLengthBits()) { | |
649 if (params->optionalLengthBits() % 8) | |
650 return Status::ErrorGenerateKeyLength(); | |
651 keylen_bytes = params->optionalLengthBits() / 8; | |
652 } else { | |
653 keylen_bytes = ShaBlockSizeBytes(params->hash().id()); | |
654 if (keylen_bytes == 0) | |
655 return Status::ErrorUnsupported(); | |
656 } | |
657 break; | |
658 } | |
659 | |
660 default: | |
661 return Status::ErrorUnsupported(); | |
662 } | |
663 | |
664 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should | |
665 // probably be able to allowed to generate them too. | |
666 if (keylen_bytes == 0) | |
667 return Status::ErrorGenerateKeyLength(); | |
668 | |
669 return platform::GenerateSecretKey( | |
670 algorithm, extractable, usage_mask, keylen_bytes, key); | |
671 } | 119 } |
672 | 120 |
673 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, | 121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, |
674 bool extractable, | 122 bool extractable, |
675 blink::WebCryptoKeyUsageMask combined_usage_mask, | 123 blink::WebCryptoKeyUsageMask combined_usage_mask, |
676 blink::WebCryptoKey* public_key, | 124 blink::WebCryptoKey* public_key, |
677 blink::WebCryptoKey* private_key) { | 125 blink::WebCryptoKey* private_key) { |
678 blink::WebCryptoKeyUsageMask public_key_usage_mask = 0; | 126 const AlgorithmImplementation* impl = NULL; |
679 blink::WebCryptoKeyUsageMask private_key_usage_mask = 0; | 127 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
680 | |
681 Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(), | |
682 combined_usage_mask, | |
683 &public_key_usage_mask, | |
684 &private_key_usage_mask); | |
685 if (status.IsError()) | 128 if (status.IsError()) |
686 return status; | 129 return status; |
687 | 130 |
688 // TODO(padolph): Handle other asymmetric algorithm key generation. | 131 blink::WebCryptoKeyUsageMask public_usage_mask; |
689 switch (algorithm.paramsType()) { | 132 blink::WebCryptoKeyUsageMask private_usage_mask; |
690 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: { | 133 status = impl->VerifyKeyUsagesBeforeGenerateKeyPair( |
691 const blink::WebCryptoRsaHashedKeyGenParams* params = | 134 combined_usage_mask, &public_usage_mask, &private_usage_mask); |
692 algorithm.rsaHashedKeyGenParams(); | 135 if (status.IsError()) |
| 136 return status; |
693 | 137 |
694 if (!params->modulusLengthBits()) | 138 return impl->GenerateKeyPair(algorithm, |
695 return Status::ErrorGenerateRsaZeroModulus(); | 139 extractable, |
696 | 140 public_usage_mask, |
697 unsigned long public_exponent = 0; | 141 private_usage_mask, |
698 if (!BigIntegerToLong(params->publicExponent().data(), | 142 public_key, |
699 params->publicExponent().size(), | 143 private_key); |
700 &public_exponent) || | |
701 (public_exponent != 3 && public_exponent != 65537)) { | |
702 return Status::ErrorGenerateKeyPublicExponent(); | |
703 } | |
704 | |
705 return platform::GenerateRsaKeyPair(algorithm, | |
706 extractable, | |
707 public_key_usage_mask, | |
708 private_key_usage_mask, | |
709 params->modulusLengthBits(), | |
710 public_exponent, | |
711 public_key, | |
712 private_key); | |
713 } | |
714 default: | |
715 return Status::ErrorUnsupported(); | |
716 } | |
717 } | 144 } |
718 | 145 |
719 // Note that this function may be called from the target Blink thread. | 146 // Note that this function may be called from the target Blink thread. |
720 Status ImportKey(blink::WebCryptoKeyFormat format, | 147 Status ImportKey(blink::WebCryptoKeyFormat format, |
721 const CryptoData& key_data, | 148 const CryptoData& key_data, |
722 const blink::WebCryptoAlgorithm& algorithm, | 149 const blink::WebCryptoAlgorithm& algorithm, |
723 bool extractable, | 150 bool extractable, |
724 blink::WebCryptoKeyUsageMask usage_mask, | 151 blink::WebCryptoKeyUsageMask usage_mask, |
725 blink::WebCryptoKey* key) { | 152 blink::WebCryptoKey* key) { |
726 // This is "best effort" because it is incomplete for JWK (for which the key | 153 const AlgorithmImplementation* impl = NULL; |
727 // type is not yet known). ImportKeyJwk() does extra checks on key usage once | 154 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
728 // the key type has been determined. | 155 if (status.IsError()) |
729 Status status = | 156 return status; |
730 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); | 157 |
| 158 status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); |
731 if (status.IsError()) | 159 if (status.IsError()) |
732 return status; | 160 return status; |
733 | 161 |
734 switch (format) { | 162 switch (format) { |
735 case blink::WebCryptoKeyFormatRaw: | 163 case blink::WebCryptoKeyFormatRaw: |
736 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key); | 164 return impl->ImportKeyRaw( |
| 165 key_data, algorithm, extractable, usage_mask, key); |
737 case blink::WebCryptoKeyFormatSpki: | 166 case blink::WebCryptoKeyFormatSpki: |
738 return platform::ImportKeySpki( | 167 return impl->ImportKeySpki( |
739 algorithm, key_data, extractable, usage_mask, key); | 168 key_data, algorithm, extractable, usage_mask, key); |
740 case blink::WebCryptoKeyFormatPkcs8: | 169 case blink::WebCryptoKeyFormatPkcs8: |
741 return platform::ImportKeyPkcs8( | 170 return impl->ImportKeyPkcs8( |
742 algorithm, key_data, extractable, usage_mask, key); | 171 key_data, algorithm, extractable, usage_mask, key); |
743 case blink::WebCryptoKeyFormatJwk: | 172 case blink::WebCryptoKeyFormatJwk: |
744 return ImportKeyJwk(key_data, algorithm, extractable, usage_mask, key); | 173 return impl->ImportKeyJwk( |
| 174 key_data, algorithm, extractable, usage_mask, key); |
745 default: | 175 default: |
746 return Status::ErrorUnsupported(); | 176 return Status::ErrorUnsupported(); |
747 } | 177 } |
748 } | |
749 | |
750 // TODO(eroman): Move this to anonymous namespace. | |
751 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, | |
752 const blink::WebCryptoKey& key, | |
753 std::vector<uint8>* buffer) { | |
754 switch (format) { | |
755 case blink::WebCryptoKeyFormatRaw: { | |
756 platform::SymKey* sym_key; | |
757 Status status = ToPlatformSymKey(key, &sym_key); | |
758 if (status.IsError()) | |
759 return status; | |
760 return platform::ExportKeyRaw(sym_key, buffer); | |
761 } | |
762 case blink::WebCryptoKeyFormatSpki: { | |
763 platform::PublicKey* public_key; | |
764 Status status = ToPlatformPublicKey(key, &public_key); | |
765 if (status.IsError()) | |
766 return status; | |
767 return platform::ExportKeySpki(public_key, buffer); | |
768 } | |
769 case blink::WebCryptoKeyFormatPkcs8: { | |
770 platform::PrivateKey* private_key; | |
771 Status status = ToPlatformPrivateKey(key, &private_key); | |
772 if (status.IsError()) | |
773 return status; | |
774 return platform::ExportKeyPkcs8(private_key, key.algorithm(), buffer); | |
775 } | |
776 case blink::WebCryptoKeyFormatJwk: | |
777 return ExportKeyJwk(key, buffer); | |
778 default: | |
779 return Status::ErrorUnsupported(); | |
780 } | |
781 } | 178 } |
782 | 179 |
783 Status ExportKey(blink::WebCryptoKeyFormat format, | 180 Status ExportKey(blink::WebCryptoKeyFormat format, |
784 const blink::WebCryptoKey& key, | 181 const blink::WebCryptoKey& key, |
785 std::vector<uint8>* buffer) { | 182 std::vector<uint8>* buffer) { |
786 if (!key.extractable()) | 183 if (!key.extractable()) |
787 return Status::ErrorKeyNotExtractable(); | 184 return Status::ErrorKeyNotExtractable(); |
788 return ExportKeyDontCheckExtractability(format, key, buffer); | 185 return ExportKeyDontCheckExtractability(format, key, buffer); |
789 } | 186 } |
790 | 187 |
791 Status Sign(const blink::WebCryptoAlgorithm& algorithm, | 188 Status Sign(const blink::WebCryptoAlgorithm& algorithm, |
792 const blink::WebCryptoKey& key, | 189 const blink::WebCryptoKey& key, |
793 const CryptoData& data, | 190 const CryptoData& data, |
794 std::vector<uint8>* buffer) { | 191 std::vector<uint8>* buffer) { |
795 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) | 192 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) |
796 return Status::ErrorUnexpected(); | 193 return Status::ErrorUnexpected(); |
797 if (algorithm.id() != key.algorithm().id()) | 194 if (algorithm.id() != key.algorithm().id()) |
798 return Status::ErrorUnexpected(); | 195 return Status::ErrorUnexpected(); |
799 | 196 |
800 switch (algorithm.id()) { | 197 const AlgorithmImplementation* impl = NULL; |
801 case blink::WebCryptoAlgorithmIdHmac: | 198 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
802 return SignHmac(algorithm, key, data, buffer); | 199 if (status.IsError()) |
803 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | 200 return status; |
804 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer); | 201 |
805 default: | 202 return impl->Sign(algorithm, key, data, buffer); |
806 return Status::ErrorUnsupported(); | |
807 } | |
808 } | 203 } |
809 | 204 |
810 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm, | 205 Status Verify(const blink::WebCryptoAlgorithm& algorithm, |
811 const blink::WebCryptoKey& key, | 206 const blink::WebCryptoKey& key, |
812 const CryptoData& signature, | 207 const CryptoData& signature, |
813 const CryptoData& data, | 208 const CryptoData& data, |
814 bool* signature_match) { | 209 bool* signature_match) { |
815 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) | 210 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) |
816 return Status::ErrorUnexpected(); | 211 return Status::ErrorUnexpected(); |
817 if (algorithm.id() != key.algorithm().id()) | 212 if (algorithm.id() != key.algorithm().id()) |
818 return Status::ErrorUnexpected(); | 213 return Status::ErrorUnexpected(); |
819 | 214 |
| 215 // TODO(eroman): Move this into implementation which need it instead. |
820 if (!signature.byte_length()) { | 216 if (!signature.byte_length()) { |
821 // None of the algorithms generate valid zero-length signatures so this | 217 // None of the algorithms generate valid zero-length signatures so this |
822 // will necessarily fail verification. Early return to protect | 218 // will necessarily fail verification. Early return to protect |
823 // implementations from dealing with a NULL signature pointer. | 219 // implementations from dealing with a NULL signature pointer. |
824 *signature_match = false; | 220 *signature_match = false; |
825 return Status::Success(); | 221 return Status::Success(); |
826 } | 222 } |
827 | 223 |
828 switch (algorithm.id()) { | 224 const AlgorithmImplementation* impl = NULL; |
829 case blink::WebCryptoAlgorithmIdHmac: | 225 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
830 return VerifyHmac(algorithm, key, signature, data, signature_match); | 226 if (status.IsError()) |
831 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | 227 return status; |
832 return VerifyRsaSsaPkcs1v1_5( | 228 |
833 algorithm, key, signature, data, signature_match); | 229 return impl->Verify(algorithm, key, signature, data, signature_match); |
834 default: | |
835 return Status::ErrorUnsupported(); | |
836 } | |
837 } | 230 } |
838 | 231 |
839 Status WrapKey(blink::WebCryptoKeyFormat format, | 232 Status WrapKey(blink::WebCryptoKeyFormat format, |
840 const blink::WebCryptoKey& key_to_wrap, | 233 const blink::WebCryptoKey& key_to_wrap, |
841 const blink::WebCryptoKey& wrapping_key, | 234 const blink::WebCryptoKey& wrapping_key, |
842 const blink::WebCryptoAlgorithm& wrapping_algorithm, | 235 const blink::WebCryptoAlgorithm& wrapping_algorithm, |
843 std::vector<uint8>* buffer) { | 236 std::vector<uint8>* buffer) { |
844 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) | 237 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) |
845 return Status::ErrorUnexpected(); | 238 return Status::ErrorUnexpected(); |
846 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | |
847 return Status::ErrorUnexpected(); | |
848 | 239 |
849 return WrapKeyExportAndEncrypt( | 240 std::vector<uint8> exported_data; |
850 format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer); | 241 Status status = ExportKey(format, key_to_wrap, &exported_data); |
| 242 if (status.IsError()) |
| 243 return status; |
| 244 return EncryptDontCheckUsage( |
| 245 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); |
851 } | 246 } |
852 | 247 |
853 Status UnwrapKey(blink::WebCryptoKeyFormat format, | 248 Status UnwrapKey(blink::WebCryptoKeyFormat format, |
854 const CryptoData& wrapped_key_data, | 249 const CryptoData& wrapped_key_data, |
855 const blink::WebCryptoKey& wrapping_key, | 250 const blink::WebCryptoKey& wrapping_key, |
856 const blink::WebCryptoAlgorithm& wrapping_algorithm, | 251 const blink::WebCryptoAlgorithm& wrapping_algorithm, |
857 const blink::WebCryptoAlgorithm& algorithm, | 252 const blink::WebCryptoAlgorithm& algorithm, |
858 bool extractable, | 253 bool extractable, |
859 blink::WebCryptoKeyUsageMask usage_mask, | 254 blink::WebCryptoKeyUsageMask usage_mask, |
860 blink::WebCryptoKey* key) { | 255 blink::WebCryptoKey* key) { |
861 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) | 256 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) |
862 return Status::ErrorUnexpected(); | 257 return Status::ErrorUnexpected(); |
863 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | 258 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) |
864 return Status::ErrorUnexpected(); | 259 return Status::ErrorUnexpected(); |
865 | 260 |
866 // Fail-fast if the key usages don't make sense. This avoids decrypting the | 261 // Fail fast if the import is doomed to fail. |
867 // key only to then have import fail. It is "best effort" because when | 262 const AlgorithmImplementation* import_impl = NULL; |
868 // unwrapping JWK for asymmetric algorithms the key type isn't known yet. | 263 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); |
869 Status status = | |
870 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); | |
871 if (status.IsError()) | 264 if (status.IsError()) |
872 return status; | 265 return status; |
873 | 266 |
874 return UnwrapKeyDecryptAndImport(format, | 267 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); |
875 wrapped_key_data, | 268 if (status.IsError()) |
876 wrapping_key, | 269 return status; |
877 wrapping_algorithm, | 270 |
878 algorithm, | 271 std::vector<uint8> buffer; |
879 extractable, | 272 status = DecryptDontCheckKeyUsage( |
880 usage_mask, | 273 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); |
881 key); | 274 if (status.IsError()) |
| 275 return status; |
| 276 |
| 277 // NOTE that returning the details of ImportKey() failures may leak |
| 278 // information about the plaintext of the encrypted key (for instance the JWK |
| 279 // key_ops). As long as the ImportKey error messages don't describe actual |
| 280 // key bytes however this should be OK. For more discussion see |
| 281 // http://crubg.com/372040 |
| 282 return ImportKey( |
| 283 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); |
882 } | 284 } |
883 | 285 |
884 // Note that this function is called from the target Blink thread. | 286 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( |
885 bool SerializeKeyForClone(const blink::WebCryptoKey& key, | 287 blink::WebCryptoAlgorithmId algorithm) { |
886 blink::WebVector<uint8>* key_data) { | 288 return CreatePlatformDigestor(algorithm); |
887 return static_cast<webcrypto::platform::Key*>(key.handle()) | |
888 ->ThreadSafeSerializeForClone(key_data); | |
889 } | |
890 | |
891 // Note that this function is called from the target Blink thread. | |
892 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, | |
893 blink::WebCryptoKeyType type, | |
894 bool extractable, | |
895 blink::WebCryptoKeyUsageMask usage_mask, | |
896 const CryptoData& key_data, | |
897 blink::WebCryptoKey* key) { | |
898 // TODO(eroman): This should not call into the platform crypto layer. | |
899 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks | |
900 // are held. | |
901 // | |
902 // An alternate approach is to defer the key import until the key is used. | |
903 // However this means that any deserialization errors would have to be | |
904 // surfaced as WebCrypto errors, leading to slightly different behaviors. For | |
905 // instance you could clone a key which fails to be deserialized. | |
906 Status status = ImportKey(GetCloneFormatForKeyType(type), | |
907 key_data, | |
908 KeyAlgorithmToImportAlgorithm(algorithm), | |
909 extractable, | |
910 usage_mask, | |
911 key); | |
912 if (status.IsError()) | |
913 return false; | |
914 return ValidateDeserializedKey(*key, algorithm, type); | |
915 } | |
916 | |
917 Status ToPlatformSymKey(const blink::WebCryptoKey& key, | |
918 platform::SymKey** out) { | |
919 *out = static_cast<platform::Key*>(key.handle())->AsSymKey(); | |
920 if (!*out) | |
921 return Status::ErrorUnexpectedKeyType(); | |
922 return Status::Success(); | |
923 } | |
924 | |
925 Status ToPlatformPublicKey(const blink::WebCryptoKey& key, | |
926 platform::PublicKey** out) { | |
927 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey(); | |
928 if (!*out) | |
929 return Status::ErrorUnexpectedKeyType(); | |
930 return Status::Success(); | |
931 } | |
932 | |
933 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key, | |
934 platform::PrivateKey** out) { | |
935 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey(); | |
936 if (!*out) | |
937 return Status::ErrorUnexpectedKeyType(); | |
938 return Status::Success(); | |
939 } | |
940 | |
941 // Returns Status::Success() if |usages| is a valid set of key usages for | |
942 // |algorithm| and |key_type|. Otherwise returns an error. | |
943 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm, | |
944 blink::WebCryptoKeyType key_type, | |
945 blink::WebCryptoKeyUsageMask usages) { | |
946 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type), | |
947 usages)) | |
948 return Status::ErrorCreateKeyBadUsages(); | |
949 | |
950 return Status::Success(); | |
951 } | 289 } |
952 | 290 |
953 } // namespace webcrypto | 291 } // namespace webcrypto |
954 | 292 |
955 } // namespace content | 293 } // namespace content |
OLD | NEW |