Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(570)

Side by Side Diff: content/child/webcrypto/shared_crypto.cc

Issue 195983010: [webcrypto] Add JWK symmetric key AES-KW unwrap for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixes for eroman Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/shared_crypto.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "content/child/webcrypto/crypto_data.h" 8 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/platform_crypto.h" 9 #include "content/child/webcrypto/platform_crypto.h"
10 #include "content/child/webcrypto/webcrypto_util.h" 10 #include "content/child/webcrypto/webcrypto_util.h"
11 #include "crypto/secure_util.h" 11 #include "crypto/secure_util.h"
12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" 12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKey.h" 14 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
16 16
17 namespace content { 17 namespace content {
18 18
19 namespace webcrypto { 19 namespace webcrypto {
20 20
21 namespace { 21 namespace {
22 22
23 // TODO(eroman): Move this helper to WebCryptoKey. 23 // TODO(eroman): Move this helper to WebCryptoKey.
24 bool KeyUsageAllows(const blink::WebCryptoKey& key, 24 bool KeyUsageAllows(const blink::WebCryptoKey& key,
25 const blink::WebCryptoKeyUsage usage) { 25 const blink::WebCryptoKeyUsage usage) {
26 return ((key.usages() & usage) != 0); 26 return ((key.usages() & usage) != 0);
27 } 27 }
28 28
29 bool KeyUsageAllowsAnyOf(const blink::WebCryptoKey& key,
eroman 2014/03/18 01:02:13 This is unused, and why the commit queue failed it
padolph 2014/03/18 01:23:02 Done.
30 const blink::WebCryptoKeyUsageMask usage_mask) {
31 return ((key.usages() & usage_mask) != 0);
32 }
33
29 bool IsValidAesKeyLengthBits(unsigned int length_bits) { 34 bool IsValidAesKeyLengthBits(unsigned int length_bits) {
30 return length_bits == 128 || length_bits == 192 || length_bits == 256; 35 return length_bits == 128 || length_bits == 192 || length_bits == 256;
31 } 36 }
32 37
33 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) { 38 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) {
34 return length_bytes == 16 || length_bytes == 24 || length_bytes == 32; 39 return length_bytes == 16 || length_bytes == 24 || length_bytes == 32;
35 } 40 }
36 41
37 Status ToPlatformSymKey(const blink::WebCryptoKey& key, 42 Status ToPlatformSymKey(const blink::WebCryptoKey& key,
38 platform::SymKey** out) { 43 platform::SymKey** out) {
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 return Status::Error(); 231 return Status::Error();
227 // Fallthrough intentional! 232 // Fallthrough intentional!
228 case blink::WebCryptoAlgorithmIdHmac: 233 case blink::WebCryptoAlgorithmIdHmac:
229 return platform::ImportKeyRaw( 234 return platform::ImportKeyRaw(
230 algorithm_or_null, key_data, extractable, usage_mask, key); 235 algorithm_or_null, key_data, extractable, usage_mask, key);
231 default: 236 default:
232 return Status::ErrorUnsupported(); 237 return Status::ErrorUnsupported();
233 } 238 }
234 } 239 }
235 240
241 // Validates the size of data input to AES-KW. AES-KW requires the input data
242 // size to be at least 24 bytes and a multiple of 8 bytes.
243 Status CheckAesKwInputSize(const CryptoData& aeskw_input_data) {
244 if (aeskw_input_data.byte_length() < 24)
245 return Status::ErrorDataTooSmall();
246 if (aeskw_input_data.byte_length() % 8)
247 return Status::ErrorInvalidAesKwDataLength();
248 return Status::Success();
249 }
250
251 Status UnwrapKeyRaw(const CryptoData& wrapped_key_data,
252 const blink::WebCryptoKey& wrapping_key,
253 const blink::WebCryptoAlgorithm& wrapping_algorithm,
254 const blink::WebCryptoAlgorithm& algorithm_or_null,
255 bool extractable,
256 blink::WebCryptoKeyUsageMask usage_mask,
257 blink::WebCryptoKey* key) {
258 // Must provide an algorithm when unwrapping a raw key
259 if (algorithm_or_null.isNull())
260 return Status::ErrorMissingAlgorithmUnwrapRawKey();
261
262 // TODO(padolph): Handle other wrapping algorithms
263 switch (wrapping_algorithm.id()) {
264 case blink::WebCryptoAlgorithmIdAesKw: {
265 platform::SymKey* platform_wrapping_key;
266 Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key);
267 if (status.IsError())
268 return status;
269 status = CheckAesKwInputSize(wrapped_key_data);
270 if (status.IsError())
271 return status;
272 return platform::UnwrapSymKeyAesKw(wrapped_key_data,
273 platform_wrapping_key,
274 algorithm_or_null,
275 extractable,
276 usage_mask,
277 key);
278 }
279 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: {
280 platform::PrivateKey* platform_wrapping_key;
281 Status status =
282 ToPlatformPrivateKey(wrapping_key, &platform_wrapping_key);
283 if (status.IsError())
284 return status;
285 if (!wrapped_key_data.byte_length())
286 return Status::ErrorDataTooSmall();
287 return platform::UnwrapSymKeyRsaEs(wrapped_key_data,
288 platform_wrapping_key,
289 algorithm_or_null,
290 extractable,
291 usage_mask,
292 key);
293 }
294 default:
295 return Status::ErrorUnsupported();
296 }
297 }
298
299 Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm,
300 const blink::WebCryptoKey& key,
301 const CryptoData& data,
302 blink::WebArrayBuffer* buffer) {
303 platform::SymKey* sym_key;
304 Status status = ToPlatformSymKey(key, &sym_key);
305 if (status.IsError())
306 return status;
307 status = CheckAesKwInputSize(data);
308 if (status.IsError())
309 return status;
310 return platform::DecryptAesKw(sym_key, data, buffer);
311 }
312
313 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
314 const blink::WebCryptoKey& key,
315 const CryptoData& data,
316 blink::WebArrayBuffer* buffer) {
317 if (algorithm.id() != key.algorithm().id())
318 return Status::ErrorUnexpected();
319 switch (algorithm.id()) {
320 case blink::WebCryptoAlgorithmIdAesCbc:
321 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer);
322 case blink::WebCryptoAlgorithmIdAesGcm:
323 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer);
324 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
325 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
326 case blink::WebCryptoAlgorithmIdAesKw:
327 return DecryptAesKw(algorithm, key, data, buffer);
328 default:
329 return Status::ErrorUnsupported();
330 }
331 }
332
333 Status UnwrapKeyDecryptAndImport(
334 blink::WebCryptoKeyFormat format,
335 const CryptoData& wrapped_key_data,
336 const blink::WebCryptoKey& wrapping_key,
337 const blink::WebCryptoAlgorithm& wrapping_algorithm,
338 const blink::WebCryptoAlgorithm& algorithm_or_null,
339 bool extractable,
340 blink::WebCryptoKeyUsageMask usage_mask,
341 blink::WebCryptoKey* key) {
342 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
343 return Status::ErrorUnexpected();
344 blink::WebArrayBuffer buffer;
345 Status status = DecryptDontCheckKeyUsage(
346 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
347 if (status.IsError())
348 return status;
349 status = ImportKey(format,
350 CryptoData(buffer),
351 algorithm_or_null,
352 extractable,
353 usage_mask,
354 key);
355 // NOTE! Returning the details of any ImportKey() failure here would leak
356 // information about the plaintext internals of the encrypted key. Instead,
357 // collapse any error into the generic Status::Error().
358 return status.IsError() ? Status::Error() : Status::Success();
359 }
360
236 } // namespace 361 } // namespace
237 362
238 void Init() { platform::Init(); } 363 void Init() { platform::Init(); }
239 364
240 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 365 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
241 const blink::WebCryptoKey& key, 366 const blink::WebCryptoKey& key,
242 const CryptoData& data, 367 const CryptoData& data,
243 blink::WebArrayBuffer* buffer) { 368 blink::WebArrayBuffer* buffer) {
244 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) 369 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
245 return Status::ErrorUnexpected(); 370 return Status::ErrorUnexpected();
(...skipping 11 matching lines...) Expand all
257 return Status::ErrorUnsupported(); 382 return Status::ErrorUnsupported();
258 } 383 }
259 } 384 }
260 385
261 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, 386 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
262 const blink::WebCryptoKey& key, 387 const blink::WebCryptoKey& key,
263 const CryptoData& data, 388 const CryptoData& data,
264 blink::WebArrayBuffer* buffer) { 389 blink::WebArrayBuffer* buffer) {
265 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) 390 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
266 return Status::ErrorUnexpected(); 391 return Status::ErrorUnexpected();
267 if (algorithm.id() != key.algorithm().id()) 392 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
268 return Status::ErrorUnexpected();
269
270 switch (algorithm.id()) {
271 case blink::WebCryptoAlgorithmIdAesCbc:
272 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer);
273 case blink::WebCryptoAlgorithmIdAesGcm:
274 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer);
275 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
276 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
277 default:
278 return Status::ErrorUnsupported();
279 }
280 } 393 }
281 394
282 Status Digest(const blink::WebCryptoAlgorithm& algorithm, 395 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
283 const CryptoData& data, 396 const CryptoData& data,
284 blink::WebArrayBuffer* buffer) { 397 blink::WebArrayBuffer* buffer) {
285 switch (algorithm.id()) { 398 switch (algorithm.id()) {
286 case blink::WebCryptoAlgorithmIdSha1: 399 case blink::WebCryptoAlgorithmIdSha1:
287 case blink::WebCryptoAlgorithmIdSha256: 400 case blink::WebCryptoAlgorithmIdSha256:
288 case blink::WebCryptoAlgorithmIdSha384: 401 case blink::WebCryptoAlgorithmIdSha384:
289 case blink::WebCryptoAlgorithmIdSha512: 402 case blink::WebCryptoAlgorithmIdSha512:
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 return status; 530 return status;
418 return platform::ExportKeyRaw(sym_key, buffer); 531 return platform::ExportKeyRaw(sym_key, buffer);
419 } 532 }
420 case blink::WebCryptoKeyFormatSpki: { 533 case blink::WebCryptoKeyFormatSpki: {
421 platform::PublicKey* public_key; 534 platform::PublicKey* public_key;
422 Status status = ToPlatformPublicKey(key, &public_key); 535 Status status = ToPlatformPublicKey(key, &public_key);
423 if (status.IsError()) 536 if (status.IsError())
424 return status; 537 return status;
425 return platform::ExportKeySpki(public_key, buffer); 538 return platform::ExportKeySpki(public_key, buffer);
426 } 539 }
540 case blink::WebCryptoKeyFormatJwk:
541 return ExportKeyJwk(key, buffer);
427 case blink::WebCryptoKeyFormatPkcs8: 542 case blink::WebCryptoKeyFormatPkcs8:
428 case blink::WebCryptoKeyFormatJwk:
429 // TODO(eroman): 543 // TODO(eroman):
430 return Status::ErrorUnsupported(); 544 return Status::ErrorUnsupported();
431 default: 545 default:
432 return Status::ErrorUnsupported(); 546 return Status::ErrorUnsupported();
433 } 547 }
434 } 548 }
435 549
436 Status Sign(const blink::WebCryptoAlgorithm& algorithm, 550 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
437 const blink::WebCryptoKey& key, 551 const blink::WebCryptoKey& key,
438 const CryptoData& data, 552 const CryptoData& data,
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 const blink::WebCryptoAlgorithm& wrapping_algorithm, 646 const blink::WebCryptoAlgorithm& wrapping_algorithm,
533 const blink::WebCryptoAlgorithm& algorithm_or_null, 647 const blink::WebCryptoAlgorithm& algorithm_or_null,
534 bool extractable, 648 bool extractable,
535 blink::WebCryptoKeyUsageMask usage_mask, 649 blink::WebCryptoKeyUsageMask usage_mask,
536 blink::WebCryptoKey* key) { 650 blink::WebCryptoKey* key) {
537 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) 651 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
538 return Status::ErrorUnexpected(); 652 return Status::ErrorUnexpected();
539 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 653 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
540 return Status::ErrorUnexpected(); 654 return Status::ErrorUnexpected();
541 655
542 // TODO(padolph): Handle formats other than raw 656 switch (format) {
543 if (format != blink::WebCryptoKeyFormatRaw) 657 case blink::WebCryptoKeyFormatRaw:
544 return Status::ErrorUnsupported(); 658 return UnwrapKeyRaw(wrapped_key_data,
545 659 wrapping_key,
546 // Must provide an algorithm when unwrapping a raw key 660 wrapping_algorithm,
547 if (format == blink::WebCryptoKeyFormatRaw && algorithm_or_null.isNull()) 661 algorithm_or_null,
548 return Status::ErrorMissingAlgorithmUnwrapRawKey(); 662 extractable,
549 663 usage_mask,
550 // TODO(padolph): Handle other wrapping algorithms 664 key);
551 switch (wrapping_algorithm.id()) { 665 case blink::WebCryptoKeyFormatJwk:
552 case blink::WebCryptoAlgorithmIdAesKw: { 666 return UnwrapKeyDecryptAndImport(format,
553 platform::SymKey* platform_wrapping_key; 667 wrapped_key_data,
554 Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key); 668 wrapping_key,
555 if (status.IsError()) 669 wrapping_algorithm,
556 return status; 670 algorithm_or_null,
557 // AES-KW requires the wrapped key data size must be at least 24 bytes and 671 extractable,
558 // also a multiple of 8 bytes. 672 usage_mask,
559 if (wrapped_key_data.byte_length() < 24) 673 key);
560 return Status::ErrorDataTooSmall(); 674 case blink::WebCryptoKeyFormatSpki:
561 if (wrapped_key_data.byte_length() % 8) 675 case blink::WebCryptoKeyFormatPkcs8:
562 return Status::ErrorInvalidAesKwDataLength(); 676 return Status::ErrorUnsupported(); // TODO(padolph)
563 return platform::UnwrapSymKeyAesKw(wrapped_key_data,
564 platform_wrapping_key,
565 algorithm_or_null,
566 extractable,
567 usage_mask,
568 key);
569 }
570 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: {
571 platform::PrivateKey* platform_wrapping_key;
572 Status status =
573 ToPlatformPrivateKey(wrapping_key, &platform_wrapping_key);
574 if (status.IsError())
575 return status;
576 if (!wrapped_key_data.byte_length())
577 return Status::ErrorDataTooSmall();
578 return platform::UnwrapSymKeyRsaEs(wrapped_key_data,
579 platform_wrapping_key,
580 algorithm_or_null,
581 extractable,
582 usage_mask,
583 key);
584 }
585 default: 677 default:
678 NOTREACHED();
586 return Status::ErrorUnsupported(); 679 return Status::ErrorUnsupported();
587 } 680 }
588 } 681 }
589 682
590 } // namespace webcrypto 683 } // namespace webcrypto
591 684
592 } // namespace content 685 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/platform_crypto_nss.cc ('k') | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698