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

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 118623002: [webcrypto] Add raw symmetric key AES-KW wrap/unwrap for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixes for bryaneyler Created 7 years 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
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 buffer_data + output_len, 168 buffer_data + output_len,
169 &final_output_chunk_len, 169 &final_output_chunk_len,
170 output_max_len - output_len)) { 170 output_max_len - output_len)) {
171 return false; 171 return false;
172 } 172 }
173 173
174 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); 174 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
175 return true; 175 return true;
176 } 176 }
177 177
178 // The RFC 3394 AES Key Wrap / Unwrap Mechanism.
179 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP;
180
181 // Creates an NSS SECItem representing the Default IV specified for AES Key
182 // Wrap. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1.
183 crypto::ScopedSECItem CreateAesKwIvItem() {
184 const unsigned int kAesKwIvLength = 8;
eroman 2013/12/20 01:58:14 Can you instead define this in terms of: arraysi
padolph 2013/12/23 19:58:33 Done.
185 const unsigned char kAesIv[kAesKwIvLength] = {0xA6, 0xA6, 0xA6, 0xA6,
186 0xA6, 0xA6, 0xA6, 0xA6};
187 SECItem iv_item =
188 {siBuffer, const_cast<unsigned char*>(kAesIv), kAesKwIvLength};
189 SECItem* param_item = PK11_ParamFromIV(kAesKwMechanism, &iv_item);
eroman 2013/12/20 01:58:14 I will have to verify this, but my expectation is
padolph 2013/12/23 19:58:33 This function was not saving too much code duplica
190 DCHECK(param_item);
191 return crypto::ScopedSECItem(param_item);
192 }
193
194 // Performs RFC 3394 AES Key Wrap (encryption) of the input data.
195 bool AesKwEncrypt(
196 const blink::WebCryptoKey& key,
197 const unsigned char* data,
198 unsigned data_size,
199 blink::WebArrayBuffer* buffer) {
200 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
201 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
202 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages());
203
204 // The data size must be at least 16 bytes and a multiple of 8 bytes.
205 // TODO(padolph): Should this be a DCHECK() instead?
eroman 2013/12/20 01:58:14 This must be a runtime check since blink layer doe
padolph 2013/12/23 19:58:33 Done.
206 if (data_size < 16 || data_size % 8)
207 return false;
208 DCHECK(data);
209
210 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS
211 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a
212 // generic secret blob, since we can't be certain what it is at this point.
213 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size};
214 crypto::ScopedPK11SymKey key_to_be_wrapped(
215 PK11_ImportSymKey(PK11_GetInternalSlot(),
216 CKK_GENERIC_SECRET,
217 PK11_OriginGenerated,
218 CKA_ENCRYPT,
219 &data_item,
220 0));
221 if (!key_to_be_wrapped)
222 return false;
223
224 // AES Key Wrap always adds 8 bytes to the input data size.
225 const unsigned int output_length = data_size + 8;
eroman 2013/12/20 01:58:14 Paranoia: possibility of integer overflow? I shoul
padolph 2013/12/23 19:58:33 RFC 3394 does not specify the max allowed input le
226
227 *buffer = blink::WebArrayBuffer::create(output_length, 1);
228 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
229 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
230
231 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
232
233 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism,
234 CreateAesKwIvItem().get(),
235 wrapping_key->key(),
236 key_to_be_wrapped.get(),
237 &wrapped_key_item)) {
238 return false;
239 }
240 DCHECK_EQ(output_length, wrapped_key_item.len);
eroman 2013/12/20 01:58:14 Please make this a runtime check and fail if they
padolph 2013/12/23 19:58:33 Done.
241
242 return true;
243 }
244
245 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data.
246 bool AesKwDecrypt(
247 const blink::WebCryptoKey& key,
248 const unsigned char* data,
249 unsigned data_size,
250 blink::WebArrayBuffer* buffer) {
251 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
252 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
253 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages());
254
255 // The ciphertext data size must be at least 24 bytes and a multiple of
256 // 8 bytes. This is a DCHECK() because this function is not callable with
257 // arbitrary data: it only receives data representing an assumed-good internal
258 // key to be wrapped.
259 DCHECK(data_size >= 24 && data_size % 8 == 0);
260 DCHECK(data);
261
262 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
263
264 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size};
265
266 // The plaintext length is always 64 bits less than the data size.
267 const unsigned int plaintext_length = data_size - 8;
eroman 2013/12/20 01:58:14 Isn't it possible to have 0-length keys? In fact w
padolph 2013/12/23 19:58:33 Done.
268
269 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(
270 wrapping_key->key(),
271 kAesKwMechanism,
272 CreateAesKwIvItem().get(),
273 &cipher_text,
274 CKK_GENERIC_SECRET, // Import the key material without knowing its kind.
275 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key.
276 plaintext_length));
277 if (!unwrapped_key)
278 return false;
279
280 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess)
281 return false;
282
283 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get());
284 if (!key_data)
285 return false;
286 DCHECK_EQ(plaintext_length, key_data->len);
287
288 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
289
290 return true;
291 }
292
178 CK_MECHANISM_TYPE HmacAlgorithmToGenMechanism( 293 CK_MECHANISM_TYPE HmacAlgorithmToGenMechanism(
179 const blink::WebCryptoAlgorithm& algorithm) { 294 const blink::WebCryptoAlgorithm& algorithm) {
180 DCHECK_EQ(algorithm.id(), blink::WebCryptoAlgorithmIdHmac); 295 DCHECK_EQ(algorithm.id(), blink::WebCryptoAlgorithmIdHmac);
181 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); 296 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams();
182 DCHECK(params); 297 DCHECK(params);
183 switch (params->hash().id()) { 298 switch (params->hash().id()) {
184 case blink::WebCryptoAlgorithmIdSha1: 299 case blink::WebCryptoAlgorithmIdSha1:
185 return CKM_SHA_1_HMAC; 300 return CKM_SHA_1_HMAC;
186 case blink::WebCryptoAlgorithmIdSha256: 301 case blink::WebCryptoAlgorithmIdSha256:
187 return CKM_SHA256_HMAC; 302 return CKM_SHA256_HMAC;
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 const blink::WebCryptoAlgorithm& algorithm, 633 const blink::WebCryptoAlgorithm& algorithm,
519 const blink::WebCryptoKey& key, 634 const blink::WebCryptoKey& key,
520 const unsigned char* data, 635 const unsigned char* data,
521 unsigned data_size, 636 unsigned data_size,
522 blink::WebArrayBuffer* buffer) { 637 blink::WebArrayBuffer* buffer) {
523 638
524 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 639 DCHECK_EQ(algorithm.id(), key.algorithm().id());
525 DCHECK(key.handle()); 640 DCHECK(key.handle());
526 DCHECK(buffer); 641 DCHECK(buffer);
527 642
528 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 643 switch (algorithm.id()) {
eroman 2013/12/20 01:58:14 switching to a switch statement would best be left
padolph 2013/12/23 19:58:33 Reverted and added a TODO.
529 return AesCbcEncryptDecrypt( 644 case blink::WebCryptoAlgorithmIdAesCbc: {
530 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); 645 return AesCbcEncryptDecrypt(
531 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 646 CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
647 }
648 case blink::WebCryptoAlgorithmIdAesKw: {
649 return AesKwEncrypt(key, data, data_size, buffer);
650 }
651 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: {
652 // RSAES encryption does not support empty input
653 if (!data_size)
654 return false;
655 DCHECK(data);
532 656
533 // RSAES encryption does not support empty input 657 if (key.type() != blink::WebCryptoKeyTypePublic)
534 if (!data_size) 658 return false;
535 return false;
536 DCHECK(data);
537 659
538 if (key.type() != blink::WebCryptoKeyTypePublic) 660 PublicKeyHandle* const public_key =
539 return false; 661 reinterpret_cast<PublicKeyHandle*>(key.handle());
540 662
541 PublicKeyHandle* const public_key = 663 const unsigned encrypted_length_bytes =
542 reinterpret_cast<PublicKeyHandle*>(key.handle()); 664 SECKEY_PublicKeyStrength(public_key->key());
543 665
544 const unsigned encrypted_length_bytes = 666 // RSAES can operate on messages up to a length of k - 11, where k is the
545 SECKEY_PublicKeyStrength(public_key->key()); 667 // octet length of the RSA modulus.
668 if (encrypted_length_bytes < 11 ||
669 encrypted_length_bytes - 11 < data_size) {
670 return false;
671 }
546 672
547 // RSAES can operate on messages up to a length of k - 11, where k is the 673 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1);
548 // octet length of the RSA modulus. 674 unsigned char* const buffer_data =
549 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size) 675 reinterpret_cast<unsigned char*>(buffer->data());
550 return false;
551 676
552 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); 677 if (PK11_PubEncryptPKCS1(public_key->key(),
553 unsigned char* const buffer_data = 678 buffer_data,
554 reinterpret_cast<unsigned char*>(buffer->data()); 679 const_cast<unsigned char*>(data),
555 680 data_size,
556 if (PK11_PubEncryptPKCS1(public_key->key(), 681 NULL) != SECSuccess) {
557 buffer_data, 682 return false;
558 const_cast<unsigned char*>(data), 683 }
559 data_size, 684 return true;
560 NULL) != SECSuccess) { 685 }
686 default: {
561 return false; 687 return false;
562 } 688 }
563 return true;
564 } 689 }
565
566 return false;
567 } 690 }
568 691
569 bool WebCryptoImpl::DecryptInternal( 692 bool WebCryptoImpl::DecryptInternal(
570 const blink::WebCryptoAlgorithm& algorithm, 693 const blink::WebCryptoAlgorithm& algorithm,
571 const blink::WebCryptoKey& key, 694 const blink::WebCryptoKey& key,
572 const unsigned char* data, 695 const unsigned char* data,
573 unsigned data_size, 696 unsigned data_size,
574 blink::WebArrayBuffer* buffer) { 697 blink::WebArrayBuffer* buffer) {
575 698
576 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 699 DCHECK_EQ(algorithm.id(), key.algorithm().id());
577 DCHECK(key.handle()); 700 DCHECK(key.handle());
578 DCHECK(buffer); 701 DCHECK(buffer);
579 702
580 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 703 switch (algorithm.id()) {
eroman 2013/12/20 01:58:14 Same comment.
padolph 2013/12/23 19:58:33 Reverted and added a TODO.
581 return AesCbcEncryptDecrypt( 704 case blink::WebCryptoAlgorithmIdAesCbc: {
582 CKA_DECRYPT, algorithm, key, data, data_size, buffer); 705 return AesCbcEncryptDecrypt(
583 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 706 CKA_DECRYPT, algorithm, key, data, data_size, buffer);
707 }
708 case blink::WebCryptoAlgorithmIdAesKw: {
709 return AesKwDecrypt(key, data, data_size, buffer);
710 }
711 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: {
712 // RSAES decryption does not support empty input
713 if (!data_size)
714 return false;
715 DCHECK(data);
584 716
585 // RSAES decryption does not support empty input 717 if (key.type() != blink::WebCryptoKeyTypePrivate)
586 if (!data_size) 718 return false;
587 return false;
588 DCHECK(data);
589 719
590 if (key.type() != blink::WebCryptoKeyTypePrivate) 720 PrivateKeyHandle* const private_key =
591 return false; 721 reinterpret_cast<PrivateKeyHandle*>(key.handle());
592 722
593 PrivateKeyHandle* const private_key = 723 const int modulus_length_bytes =
594 reinterpret_cast<PrivateKeyHandle*>(key.handle()); 724 PK11_GetPrivateModulusLen(private_key->key());
725 if (modulus_length_bytes <= 0)
726 return false;
727 const unsigned max_output_length_bytes = modulus_length_bytes;
595 728
596 const int modulus_length_bytes = 729 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1);
597 PK11_GetPrivateModulusLen(private_key->key()); 730 unsigned char* const buffer_data =
598 if (modulus_length_bytes <= 0) 731 reinterpret_cast<unsigned char*>(buffer->data());
599 return false;
600 const unsigned max_output_length_bytes = modulus_length_bytes;
601 732
602 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); 733 unsigned output_length_bytes = 0;
603 unsigned char* const buffer_data = 734 if (PK11_PrivDecryptPKCS1(private_key->key(),
604 reinterpret_cast<unsigned char*>(buffer->data()); 735 buffer_data,
605 736 &output_length_bytes,
606 unsigned output_length_bytes = 0; 737 max_output_length_bytes,
607 if (PK11_PrivDecryptPKCS1(private_key->key(), 738 const_cast<unsigned char*>(data),
608 buffer_data, 739 data_size) != SECSuccess) {
609 &output_length_bytes, 740 return false;
610 max_output_length_bytes, 741 }
611 const_cast<unsigned char*>(data), 742 DCHECK_LE(output_length_bytes, max_output_length_bytes);
612 data_size) != SECSuccess) { 743 webcrypto::ShrinkBuffer(buffer, output_length_bytes);
744 return true;
745 }
746 default: {
613 return false; 747 return false;
614 } 748 }
615 DCHECK_LE(output_length_bytes, max_output_length_bytes);
616 webcrypto::ShrinkBuffer(buffer, output_length_bytes);
617 return true;
618 } 749 }
619
620 return false;
621 } 750 }
622 751
623 bool WebCryptoImpl::DigestInternal( 752 bool WebCryptoImpl::DigestInternal(
624 const blink::WebCryptoAlgorithm& algorithm, 753 const blink::WebCryptoAlgorithm& algorithm,
625 const unsigned char* data, 754 const unsigned char* data,
626 unsigned data_size, 755 unsigned data_size,
627 blink::WebArrayBuffer* buffer) { 756 blink::WebArrayBuffer* buffer) {
628 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); 757 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm);
629 if (hash_type == HASH_AlgNULL) { 758 if (hash_type == HASH_AlgNULL) {
630 return false; 759 return false;
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 1140
1012 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), 1141 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()),
1013 blink::WebCryptoKeyTypePublic, 1142 blink::WebCryptoKeyTypePublic,
1014 extractable, 1143 extractable,
1015 algorithm, 1144 algorithm,
1016 usage_mask); 1145 usage_mask);
1017 return true; 1146 return true;
1018 } 1147 }
1019 1148
1020 } // namespace content 1149 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698