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

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: rebase 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,
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 UnwrapKeyDecryptAndImport(
300 blink::WebCryptoKeyFormat format,
301 const CryptoData& wrapped_key_data,
302 const blink::WebCryptoKey& wrapping_key,
303 const blink::WebCryptoAlgorithm& wrapping_algorithm,
304 const blink::WebCryptoAlgorithm& algorithm_or_null,
305 bool extractable,
306 blink::WebCryptoKeyUsageMask usage_mask,
307 blink::WebCryptoKey* key) {
308 blink::WebArrayBuffer buffer;
309 Status status =
310 Decrypt(wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
311 if (status.IsError())
312 return status;
313 status = ImportKey(format,
314 CryptoData(buffer),
315 algorithm_or_null,
316 extractable,
317 usage_mask,
318 key);
319 // NOTE! Returning the details of any ImportKey() failure here would leak
320 // information about the plaintext internals of the encrypted key. Instead,
321 // collapse any error into the generic Status::Error().
322 return status.IsError() ? Status::Error() : Status::Success();
323 }
324
325 Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm,
326 const blink::WebCryptoKey& key,
327 const CryptoData& data,
328 blink::WebArrayBuffer* buffer) {
329 platform::SymKey* sym_key;
330 Status status = ToPlatformSymKey(key, &sym_key);
331 if (status.IsError())
332 return status;
333 status = CheckAesKwInputSize(data);
334 if (status.IsError())
335 return status;
336 return platform::DecryptAesKw(sym_key, data, buffer);
337 }
338
236 } // namespace 339 } // namespace
237 340
238 void Init() { platform::Init(); } 341 void Init() { platform::Init(); }
239 342
240 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 343 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
241 const blink::WebCryptoKey& key, 344 const blink::WebCryptoKey& key,
242 const CryptoData& data, 345 const CryptoData& data,
243 blink::WebArrayBuffer* buffer) { 346 blink::WebArrayBuffer* buffer) {
244 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) 347 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
245 return Status::ErrorUnexpected(); 348 return Status::ErrorUnexpected();
246 if (algorithm.id() != key.algorithm().id()) 349 if (algorithm.id() != key.algorithm().id())
247 return Status::ErrorUnexpected(); 350 return Status::ErrorUnexpected();
248 351
249 switch (algorithm.id()) { 352 switch (algorithm.id()) {
250 case blink::WebCryptoAlgorithmIdAesCbc: 353 case blink::WebCryptoAlgorithmIdAesCbc:
251 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer); 354 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer);
252 case blink::WebCryptoAlgorithmIdAesGcm: 355 case blink::WebCryptoAlgorithmIdAesGcm:
253 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer); 356 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer);
254 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 357 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
255 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, buffer); 358 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
256 default: 359 default:
257 return Status::ErrorUnsupported(); 360 return Status::ErrorUnsupported();
258 } 361 }
259 } 362 }
260 363
261 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, 364 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
262 const blink::WebCryptoKey& key, 365 const blink::WebCryptoKey& key,
263 const CryptoData& data, 366 const CryptoData& data,
264 blink::WebArrayBuffer* buffer) { 367 blink::WebArrayBuffer* buffer) {
265 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
266 return Status::ErrorUnexpected();
267 if (algorithm.id() != key.algorithm().id()) 368 if (algorithm.id() != key.algorithm().id())
268 return Status::ErrorUnexpected(); 369 return Status::ErrorUnexpected();
269 370
270 switch (algorithm.id()) { 371 switch (algorithm.id()) {
271 case blink::WebCryptoAlgorithmIdAesCbc: 372 case blink::WebCryptoAlgorithmIdAesCbc:
373 case blink::WebCryptoAlgorithmIdAesGcm:
374 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
eroman 2014/03/17 19:47:47 I don't like having an extra switch for verifying
padolph 2014/03/17 22:12:49 Done.
375 return Status::ErrorUnexpected();
376 break;
377 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
378 if (!KeyUsageAllowsAnyOf(key,
379 blink::WebCryptoKeyUsageDecrypt |
380 blink::WebCryptoKeyUsageUnwrapKey))
381 return Status::ErrorUnexpected();
382 break;
383 case blink::WebCryptoAlgorithmIdAesKw:
384 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageUnwrapKey))
385 return Status::ErrorUnexpected();
386 break;
387 default:
388 return Status::ErrorUnsupported();
389 }
390
391 switch (algorithm.id()) {
392 case blink::WebCryptoAlgorithmIdAesCbc:
272 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer); 393 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer);
273 case blink::WebCryptoAlgorithmIdAesGcm: 394 case blink::WebCryptoAlgorithmIdAesGcm:
274 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer); 395 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer);
275 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 396 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
276 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer); 397 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
398 case blink::WebCryptoAlgorithmIdAesKw:
399 return DecryptAesKw(algorithm, key, data, buffer);
277 default: 400 default:
278 return Status::ErrorUnsupported(); 401 return Status::ErrorUnsupported();
279 } 402 }
280 } 403 }
281 404
282 Status Digest(const blink::WebCryptoAlgorithm& algorithm, 405 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
283 const CryptoData& data, 406 const CryptoData& data,
284 blink::WebArrayBuffer* buffer) { 407 blink::WebArrayBuffer* buffer) {
285 switch (algorithm.id()) { 408 switch (algorithm.id()) {
286 case blink::WebCryptoAlgorithmIdSha1: 409 case blink::WebCryptoAlgorithmIdSha1:
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 return status; 540 return status;
418 return platform::ExportKeyRaw(sym_key, buffer); 541 return platform::ExportKeyRaw(sym_key, buffer);
419 } 542 }
420 case blink::WebCryptoKeyFormatSpki: { 543 case blink::WebCryptoKeyFormatSpki: {
421 platform::PublicKey* public_key; 544 platform::PublicKey* public_key;
422 Status status = ToPlatformPublicKey(key, &public_key); 545 Status status = ToPlatformPublicKey(key, &public_key);
423 if (status.IsError()) 546 if (status.IsError())
424 return status; 547 return status;
425 return platform::ExportKeySpki(public_key, buffer); 548 return platform::ExportKeySpki(public_key, buffer);
426 } 549 }
550 case blink::WebCryptoKeyFormatJwk:
551 return ExportKeyJwk(key, buffer);
427 case blink::WebCryptoKeyFormatPkcs8: 552 case blink::WebCryptoKeyFormatPkcs8:
428 case blink::WebCryptoKeyFormatJwk:
429 // TODO(eroman): 553 // TODO(eroman):
430 return Status::ErrorUnsupported(); 554 return Status::ErrorUnsupported();
431 default: 555 default:
432 return Status::ErrorUnsupported(); 556 return Status::ErrorUnsupported();
433 } 557 }
434 } 558 }
435 559
436 Status Sign(const blink::WebCryptoAlgorithm& algorithm, 560 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
437 const blink::WebCryptoKey& key, 561 const blink::WebCryptoKey& key,
438 const CryptoData& data, 562 const CryptoData& data,
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 const blink::WebCryptoAlgorithm& wrapping_algorithm, 656 const blink::WebCryptoAlgorithm& wrapping_algorithm,
533 const blink::WebCryptoAlgorithm& algorithm_or_null, 657 const blink::WebCryptoAlgorithm& algorithm_or_null,
534 bool extractable, 658 bool extractable,
535 blink::WebCryptoKeyUsageMask usage_mask, 659 blink::WebCryptoKeyUsageMask usage_mask,
536 blink::WebCryptoKey* key) { 660 blink::WebCryptoKey* key) {
537 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) 661 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
538 return Status::ErrorUnexpected(); 662 return Status::ErrorUnexpected();
539 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 663 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
540 return Status::ErrorUnexpected(); 664 return Status::ErrorUnexpected();
541 665
542 // TODO(padolph): Handle formats other than raw 666 switch (format) {
543 if (format != blink::WebCryptoKeyFormatRaw) 667 case blink::WebCryptoKeyFormatRaw:
544 return Status::ErrorUnsupported(); 668 return UnwrapKeyRaw(wrapped_key_data,
545 669 wrapping_key,
546 // Must provide an algorithm when unwrapping a raw key 670 wrapping_algorithm,
547 if (format == blink::WebCryptoKeyFormatRaw && algorithm_or_null.isNull()) 671 algorithm_or_null,
548 return Status::ErrorMissingAlgorithmUnwrapRawKey(); 672 extractable,
549 673 usage_mask,
550 // TODO(padolph): Handle other wrapping algorithms 674 key);
551 switch (wrapping_algorithm.id()) { 675 case blink::WebCryptoKeyFormatJwk:
552 case blink::WebCryptoAlgorithmIdAesKw: { 676 return UnwrapKeyDecryptAndImport(format,
553 platform::SymKey* platform_wrapping_key; 677 wrapped_key_data,
554 Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key); 678 wrapping_key,
555 if (status.IsError()) 679 wrapping_algorithm,
556 return status; 680 algorithm_or_null,
557 // AES-KW requires the wrapped key data size must be at least 24 bytes and 681 extractable,
558 // also a multiple of 8 bytes. 682 usage_mask,
559 if (wrapped_key_data.byte_length() < 24) 683 key);
560 return Status::ErrorDataTooSmall(); 684 case blink::WebCryptoKeyFormatSpki:
561 if (wrapped_key_data.byte_length() % 8) 685 case blink::WebCryptoKeyFormatPkcs8:
562 return Status::ErrorInvalidAesKwDataLength(); 686 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: 687 default:
688 NOTREACHED();
586 return Status::ErrorUnsupported(); 689 return Status::ErrorUnsupported();
587 } 690 }
588 } 691 }
589 692
590 } // namespace webcrypto 693 } // namespace webcrypto
591 694
592 } // namespace content 695 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698