OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
9 #include <sechash.h> | 9 #include <sechash.h> |
10 | 10 |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 size_t reverse_i = data_size - i - 1; | 231 size_t reverse_i = data_size - i - 1; |
232 | 232 |
233 if (reverse_i >= sizeof(unsigned long) && data[i]) | 233 if (reverse_i >= sizeof(unsigned long) && data[i]) |
234 return false; // Too large for a long. | 234 return false; // Too large for a long. |
235 | 235 |
236 *result |= data[i] << 8 * reverse_i; | 236 *result |= data[i] << 8 * reverse_i; |
237 } | 237 } |
238 return true; | 238 return true; |
239 } | 239 } |
240 | 240 |
| 241 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { |
| 242 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
| 243 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || |
| 244 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
| 245 } |
| 246 |
| 247 bool ImportKeyInternalRaw( |
| 248 const unsigned char* key_data, |
| 249 unsigned key_data_size, |
| 250 const blink::WebCryptoAlgorithm& algorithm, |
| 251 bool extractable, |
| 252 blink::WebCryptoKeyUsageMask usage_mask, |
| 253 blink::WebCryptoKey* key) { |
| 254 |
| 255 DCHECK(!algorithm.isNull()); |
| 256 |
| 257 blink::WebCryptoKeyType type; |
| 258 switch (algorithm.id()) { |
| 259 case blink::WebCryptoAlgorithmIdHmac: |
| 260 case blink::WebCryptoAlgorithmIdAesCbc: |
| 261 type = blink::WebCryptoKeyTypeSecret; |
| 262 break; |
| 263 // TODO(bryaneyler): Support more key types. |
| 264 default: |
| 265 return false; |
| 266 } |
| 267 |
| 268 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. |
| 269 // Currently only supporting symmetric. |
| 270 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; |
| 271 // Flags are verified at the Blink layer; here the flags are set to all |
| 272 // possible operations for this key type. |
| 273 CK_FLAGS flags = 0; |
| 274 |
| 275 switch (algorithm.id()) { |
| 276 case blink::WebCryptoAlgorithmIdHmac: { |
| 277 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); |
| 278 if (!params) { |
| 279 return false; |
| 280 } |
| 281 |
| 282 mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash()); |
| 283 if (mechanism == CKM_INVALID_MECHANISM) { |
| 284 return false; |
| 285 } |
| 286 |
| 287 flags |= CKF_SIGN | CKF_VERIFY; |
| 288 |
| 289 break; |
| 290 } |
| 291 case blink::WebCryptoAlgorithmIdAesCbc: { |
| 292 mechanism = CKM_AES_CBC; |
| 293 flags |= CKF_ENCRYPT | CKF_DECRYPT; |
| 294 break; |
| 295 } |
| 296 default: |
| 297 return false; |
| 298 } |
| 299 |
| 300 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); |
| 301 DCHECK_NE(0ul, flags); |
| 302 |
| 303 SECItem key_item = { |
| 304 siBuffer, |
| 305 const_cast<unsigned char*>(key_data), |
| 306 key_data_size |
| 307 }; |
| 308 |
| 309 crypto::ScopedPK11SymKey pk11_sym_key( |
| 310 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(), |
| 311 mechanism, |
| 312 PK11_OriginUnwrap, |
| 313 CKA_FLAGS_ONLY, |
| 314 &key_item, |
| 315 flags, |
| 316 false, |
| 317 NULL)); |
| 318 if (!pk11_sym_key.get()) { |
| 319 return false; |
| 320 } |
| 321 |
| 322 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), |
| 323 type, extractable, algorithm, usage_mask); |
| 324 return true; |
| 325 } |
| 326 |
| 327 typedef scoped_ptr_malloc< |
| 328 CERTSubjectPublicKeyInfo, |
| 329 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, |
| 330 SECKEY_DestroySubjectPublicKeyInfo> > |
| 331 ScopedCERTSubjectPublicKeyInfo; |
| 332 |
| 333 bool ImportKeyInternalSpki( |
| 334 const unsigned char* key_data, |
| 335 unsigned key_data_size, |
| 336 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 337 bool extractable, |
| 338 blink::WebCryptoKeyUsageMask usage_mask, |
| 339 blink::WebCryptoKey* key) { |
| 340 |
| 341 DCHECK(key); |
| 342 |
| 343 if (!key_data_size) |
| 344 return false; |
| 345 |
| 346 DCHECK(key_data); |
| 347 |
| 348 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject |
| 349 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. |
| 350 SECItem spki_item = { |
| 351 siBuffer, |
| 352 const_cast<uint8*>(key_data), |
| 353 key_data_size |
| 354 }; |
| 355 const ScopedCERTSubjectPublicKeyInfo spki( |
| 356 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); |
| 357 if (!spki) |
| 358 return false; |
| 359 |
| 360 crypto::ScopedSECKEYPublicKey sec_public_key( |
| 361 SECKEY_ExtractPublicKey(spki.get())); |
| 362 if (!sec_public_key) |
| 363 return false; |
| 364 |
| 365 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); |
| 366 |
| 367 // Validate the sec_key_type against the input algorithm. Some NSS KeyType's |
| 368 // contain enough information to fabricate a Web Crypto Algorithm, which will |
| 369 // be used if the input algorithm isNull(). Others like 'rsaKey' do not (see |
| 370 // below). |
| 371 blink::WebCryptoAlgorithm algorithm = |
| 372 blink::WebCryptoAlgorithm::createNull(); |
| 373 switch (sec_key_type) { |
| 374 case rsaKey: |
| 375 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and |
| 376 // according to RFC 4055 this can be used for both encryption and |
| 377 // signatures. However, this is not specific enough to build a compatible |
| 378 // Web Crypto algorithm, since in Web Crypto RSA encryption and signature |
| 379 // algorithms are distinct. So if the input algorithm isNull() here, we |
| 380 // have to fail. |
| 381 if (algorithm_or_null.isNull() || !IsAlgorithmRsa(algorithm_or_null)) |
| 382 return false; |
| 383 algorithm = algorithm_or_null; |
| 384 break; |
| 385 case dsaKey: |
| 386 case ecKey: |
| 387 case rsaPssKey: |
| 388 case rsaOaepKey: |
| 389 // TODO(padolph): Handle other key types. |
| 390 return false; |
| 391 default: |
| 392 return false; |
| 393 } |
| 394 |
| 395 *key = blink::WebCryptoKey::create( |
| 396 new PublicKeyHandle(sec_public_key.Pass()), |
| 397 blink::WebCryptoKeyTypePublic, |
| 398 extractable, |
| 399 algorithm, |
| 400 usage_mask); |
| 401 |
| 402 return true; |
| 403 } |
| 404 |
| 405 bool ExportKeyInternalSpki( |
| 406 const blink::WebCryptoKey& key, |
| 407 blink::WebArrayBuffer* buffer) { |
| 408 |
| 409 DCHECK(key.handle()); |
| 410 DCHECK(buffer); |
| 411 |
| 412 if (key.type() != blink::WebCryptoKeyTypePublic || !key.extractable()) |
| 413 return false; |
| 414 |
| 415 PublicKeyHandle* const pub_key = |
| 416 reinterpret_cast<PublicKeyHandle*>(key.handle()); |
| 417 |
| 418 const crypto::ScopedSECItem spki_der( |
| 419 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key())); |
| 420 if (!spki_der) |
| 421 return false; |
| 422 |
| 423 DCHECK(spki_der->data); |
| 424 DCHECK(spki_der->len); |
| 425 |
| 426 *buffer = blink::WebArrayBuffer::create(spki_der->len, 1); |
| 427 memcpy(buffer->data(), spki_der->data, spki_der->len); |
| 428 |
| 429 return true; |
| 430 } |
| 431 |
241 } // namespace | 432 } // namespace |
242 | 433 |
243 void WebCryptoImpl::Init() { | 434 void WebCryptoImpl::Init() { |
244 crypto::EnsureNSSInit(); | 435 crypto::EnsureNSSInit(); |
245 } | 436 } |
246 | 437 |
247 bool WebCryptoImpl::EncryptInternal( | 438 bool WebCryptoImpl::EncryptInternal( |
248 const blink::WebCryptoAlgorithm& algorithm, | 439 const blink::WebCryptoAlgorithm& algorithm, |
249 const blink::WebCryptoKey& key, | 440 const blink::WebCryptoKey& key, |
250 const unsigned char* data, | 441 const unsigned char* data, |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 | 628 |
438 // One extractable input parameter is provided, and the Web Crypto API | 629 // One extractable input parameter is provided, and the Web Crypto API |
439 // spec at this time says it applies to both members of the key pair. | 630 // spec at this time says it applies to both members of the key pair. |
440 // This is probably not correct: it makes more operational sense to have | 631 // This is probably not correct: it makes more operational sense to have |
441 // extractable apply only to the private key and make the public key | 632 // extractable apply only to the private key and make the public key |
442 // always extractable. For now implement what the spec says and track the | 633 // always extractable. For now implement what the spec says and track the |
443 // spec bug here: https://www.w3.org/Bugs/Public/show_bug.cgi?id=23695 | 634 // spec bug here: https://www.w3.org/Bugs/Public/show_bug.cgi?id=23695 |
444 *public_key = blink::WebCryptoKey::create( | 635 *public_key = blink::WebCryptoKey::create( |
445 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), | 636 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), |
446 blink::WebCryptoKeyTypePublic, | 637 blink::WebCryptoKeyTypePublic, |
447 extractable, // probably should be 'true' always | 638 extractable, // probably should be 'true' always |
448 algorithm, | 639 algorithm, |
449 usage_mask); | 640 usage_mask); |
450 *private_key = blink::WebCryptoKey::create( | 641 *private_key = blink::WebCryptoKey::create( |
451 new PrivateKeyHandle(scoped_sec_private_key.Pass()), | 642 new PrivateKeyHandle(scoped_sec_private_key.Pass()), |
452 blink::WebCryptoKeyTypePrivate, | 643 blink::WebCryptoKeyTypePrivate, |
453 extractable, | 644 extractable, |
454 algorithm, | 645 algorithm, |
455 usage_mask); | 646 usage_mask); |
456 | 647 |
457 return true; | 648 return true; |
458 } | 649 } |
459 default: | 650 default: |
460 return false; | 651 return false; |
461 } | 652 } |
462 } | 653 } |
463 | 654 |
464 bool WebCryptoImpl::ImportKeyInternal( | 655 bool WebCryptoImpl::ImportKeyInternal( |
465 blink::WebCryptoKeyFormat format, | 656 blink::WebCryptoKeyFormat format, |
466 const unsigned char* key_data, | 657 const unsigned char* key_data, |
467 unsigned key_data_size, | 658 unsigned key_data_size, |
468 const blink::WebCryptoAlgorithm& algorithm_or_null, | 659 const blink::WebCryptoAlgorithm& algorithm_or_null, |
469 bool extractable, | 660 bool extractable, |
470 blink::WebCryptoKeyUsageMask usage_mask, | 661 blink::WebCryptoKeyUsageMask usage_mask, |
471 blink::WebCryptoKey* key) { | 662 blink::WebCryptoKey* key) { |
472 // TODO(eroman): Currently expects algorithm to always be specified, as it is | |
473 // required for raw format. | |
474 if (algorithm_or_null.isNull()) | |
475 return false; | |
476 const blink::WebCryptoAlgorithm& algorithm = algorithm_or_null; | |
477 | 663 |
478 blink::WebCryptoKeyType type; | 664 switch (format) { |
479 switch (algorithm.id()) { | 665 case blink::WebCryptoKeyFormatRaw: |
480 case blink::WebCryptoAlgorithmIdHmac: | 666 // A 'raw'-formatted key import requires an input algorithm. |
481 case blink::WebCryptoAlgorithmIdAesCbc: | 667 if (algorithm_or_null.isNull()) |
482 type = blink::WebCryptoKeyTypeSecret; | 668 return false; |
483 break; | 669 return ImportKeyInternalRaw(key_data, |
484 // TODO(bryaneyler): Support more key types. | 670 key_data_size, |
| 671 algorithm_or_null, |
| 672 extractable, |
| 673 usage_mask, |
| 674 key); |
| 675 case blink::WebCryptoKeyFormatSpki: |
| 676 return ImportKeyInternalSpki(key_data, |
| 677 key_data_size, |
| 678 algorithm_or_null, |
| 679 extractable, |
| 680 usage_mask, |
| 681 key); |
| 682 case blink::WebCryptoKeyFormatPkcs8: |
| 683 // TODO(padolph): Handle PKCS#8 private key import |
| 684 return false; |
485 default: | 685 default: |
486 return false; | 686 return false; |
487 } | 687 } |
| 688 } |
488 | 689 |
489 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | 690 bool WebCryptoImpl::ExportKeyInternal( |
490 // Currently only supporting symmetric. | 691 blink::WebCryptoKeyFormat format, |
491 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | 692 const blink::WebCryptoKey& key, |
492 // Flags are verified at the Blink layer; here the flags are set to all | 693 blink::WebArrayBuffer* buffer) { |
493 // possible operations for this key type. | 694 switch (format) { |
494 CK_FLAGS flags = 0; | 695 case blink::WebCryptoKeyFormatRaw: |
495 | 696 // TODO(padolph): Implement raw export |
496 switch(algorithm.id()) { | 697 return false; |
497 case blink::WebCryptoAlgorithmIdHmac: { | 698 case blink::WebCryptoKeyFormatSpki: |
498 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 699 return ExportKeyInternalSpki(key, buffer); |
499 if (!params) { | 700 case blink::WebCryptoKeyFormatPkcs8: |
500 return false; | 701 // TODO(padolph): Implement pkcs8 export |
501 } | 702 return false; |
502 | |
503 mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash()); | |
504 if (mechanism == CKM_INVALID_MECHANISM) { | |
505 return false; | |
506 } | |
507 | |
508 flags |= CKF_SIGN | CKF_VERIFY; | |
509 | |
510 break; | |
511 } | |
512 case blink::WebCryptoAlgorithmIdAesCbc: { | |
513 mechanism = CKM_AES_CBC; | |
514 flags |= CKF_ENCRYPT | CKF_DECRYPT; | |
515 break; | |
516 } | |
517 default: | 703 default: |
518 return false; | 704 return false; |
519 } | 705 } |
520 | |
521 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | |
522 DCHECK_NE(0ul, flags); | |
523 | |
524 SECItem key_item = { siBuffer, NULL, 0 }; | |
525 | |
526 switch (format) { | |
527 case blink::WebCryptoKeyFormatRaw: | |
528 key_item.data = const_cast<unsigned char*>(key_data); | |
529 key_item.len = key_data_size; | |
530 break; | |
531 // TODO(bryaneyler): Handle additional formats. | |
532 default: | |
533 return false; | |
534 } | |
535 | |
536 crypto::ScopedPK11SymKey pk11_sym_key( | |
537 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(), | |
538 mechanism, | |
539 PK11_OriginUnwrap, | |
540 CKA_FLAGS_ONLY, | |
541 &key_item, | |
542 flags, | |
543 false, | |
544 NULL)); | |
545 if (!pk11_sym_key.get()) { | |
546 return false; | |
547 } | |
548 | |
549 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), | |
550 type, extractable, algorithm, usage_mask); | |
551 return true; | |
552 } | 706 } |
553 | 707 |
554 bool WebCryptoImpl::SignInternal( | 708 bool WebCryptoImpl::SignInternal( |
555 const blink::WebCryptoAlgorithm& algorithm, | 709 const blink::WebCryptoAlgorithm& algorithm, |
556 const blink::WebCryptoKey& key, | 710 const blink::WebCryptoKey& key, |
557 const unsigned char* data, | 711 const unsigned char* data, |
558 unsigned data_size, | 712 unsigned data_size, |
559 blink::WebArrayBuffer* buffer) { | 713 blink::WebArrayBuffer* buffer) { |
560 blink::WebArrayBuffer result; | 714 blink::WebArrayBuffer result; |
561 | 715 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 break; | 796 break; |
643 } | 797 } |
644 default: | 798 default: |
645 return false; | 799 return false; |
646 } | 800 } |
647 | 801 |
648 return true; | 802 return true; |
649 } | 803 } |
650 | 804 |
651 } // namespace content | 805 } // namespace content |
OLD | NEW |