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

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: minor refactoring 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
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;
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);
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::WebCryptoAlgorithm& algorithm,
197 const blink::WebCryptoKey& key,
198 const unsigned char* data,
199 unsigned data_size,
200 blink::WebArrayBuffer* buffer) {
201 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, algorithm.id());
202 DCHECK_EQ(algorithm.id(), key.algorithm().id());
Bryan Eyler 2013/12/18 23:30:32 Is this right? Isn't algorithm the key wrap algor
padolph 2013/12/19 00:07:15 In key wrapping terms that is correct. But this fu
203 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
204
205 // The data size must be at least 16 bytes and a multiple of 8 bytes.
206 // TODO(padolph): Should this be a DCHECK() instead?
207 if (data_size < 16 || data_size % 8)
208 return false;
209 DCHECK(data);
210
211 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS
212 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a
213 // generic secret blob, since we can't be certain what it is at this point.
214 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size};
215 crypto::ScopedPK11SymKey key_to_be_wrapped(
216 PK11_ImportSymKey(PK11_GetInternalSlot(),
217 CKK_GENERIC_SECRET,
218 PK11_OriginGenerated,
219 CKA_ENCRYPT,
220 &data_item,
221 0));
222 if (!key_to_be_wrapped)
223 return false;
224
225 // AES Key Wrap always adds 8 bytes to the input data size.
226 const unsigned int output_length = data_size + 8;
227
228 *buffer = blink::WebArrayBuffer::create(output_length, 1);
229 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
230 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
231
232 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
233
234 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism,
235 CreateAesKwIvItem().get(),
236 wrapping_key->key(),
237 key_to_be_wrapped.get(),
238 &wrapped_key_item)) {
239 return false;
240 }
241 DCHECK_EQ(output_length, wrapped_key_item.len);
242
243 return true;
244 }
245
246 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data.
247 bool AesKwDecrypt(
248 const blink::WebCryptoAlgorithm& algorithm,
249 const blink::WebCryptoKey& key,
250 const unsigned char* data,
251 unsigned data_size,
252 blink::WebArrayBuffer* buffer) {
253 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, algorithm.id());
254 DCHECK_EQ(algorithm.id(), key.algorithm().id());
Bryan Eyler 2013/12/18 23:30:32 Same here.
padolph 2013/12/19 00:07:15 See above.
255 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
256
257 // The ciphertext data size must be at least 24 bytes and a multiple of
258 // 8 bytes. This is a DCHECK() because this function is not callable with
259 // arbitrary data: it only receives data representing an assumed-good internal
260 // key to be wrapped.
261 DCHECK(data_size >= 24 && data_size % 8 == 0);
262 DCHECK(data);
263
264 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
265
266 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size};
267
268 // The plaintext length is always 64 bits less than the data size.
269 const unsigned int plaintext_length = data_size - 8;
270
271 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(
272 wrapping_key->key(),
273 kAesKwMechanism,
274 CreateAesKwIvItem().get(),
275 &cipher_text,
276 CKK_GENERIC_SECRET, // Import the key material without knowing its kind.
277 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key.
278 plaintext_length));
279 if (!unwrapped_key)
280 return false;
281
282 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess)
283 return false;
284
285 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get());
286 if (!key_data)
287 return false;
288 DCHECK_EQ(plaintext_length, key_data->len);
289
290 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
291
292 return true;
293 }
294
178 CK_MECHANISM_TYPE HmacAlgorithmToGenMechanism( 295 CK_MECHANISM_TYPE HmacAlgorithmToGenMechanism(
179 const blink::WebCryptoAlgorithm& algorithm) { 296 const blink::WebCryptoAlgorithm& algorithm) {
180 DCHECK_EQ(algorithm.id(), blink::WebCryptoAlgorithmIdHmac); 297 DCHECK_EQ(algorithm.id(), blink::WebCryptoAlgorithmIdHmac);
181 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); 298 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams();
182 DCHECK(params); 299 DCHECK(params);
183 switch (params->hash().id()) { 300 switch (params->hash().id()) {
184 case blink::WebCryptoAlgorithmIdSha1: 301 case blink::WebCryptoAlgorithmIdSha1:
185 return CKM_SHA_1_HMAC; 302 return CKM_SHA_1_HMAC;
186 case blink::WebCryptoAlgorithmIdSha256: 303 case blink::WebCryptoAlgorithmIdSha256:
187 return CKM_SHA256_HMAC; 304 return CKM_SHA256_HMAC;
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 const blink::WebCryptoAlgorithm& algorithm, 635 const blink::WebCryptoAlgorithm& algorithm,
519 const blink::WebCryptoKey& key, 636 const blink::WebCryptoKey& key,
520 const unsigned char* data, 637 const unsigned char* data,
521 unsigned data_size, 638 unsigned data_size,
522 blink::WebArrayBuffer* buffer) { 639 blink::WebArrayBuffer* buffer) {
523 640
524 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 641 DCHECK_EQ(algorithm.id(), key.algorithm().id());
525 DCHECK(key.handle()); 642 DCHECK(key.handle());
526 DCHECK(buffer); 643 DCHECK(buffer);
527 644
528 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 645 switch (algorithm.id()) {
529 return AesCbcEncryptDecrypt( 646 case blink::WebCryptoAlgorithmIdAesCbc: {
530 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); 647 return AesCbcEncryptDecrypt(
531 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 648 CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
649 }
650 case blink::WebCryptoAlgorithmIdAesKw: {
Bryan Eyler 2013/12/18 23:30:32 According to the spec, the encrypt() function is n
padolph 2013/12/19 00:07:15 The spec indeed says that you cannot do AES-KW fro
651 return AesKwEncrypt(algorithm, key, data, data_size, buffer);
652 }
653 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: {
654 // RSAES encryption does not support empty input
655 if (!data_size)
656 return false;
657 DCHECK(data);
532 658
533 // RSAES encryption does not support empty input 659 if (key.type() != blink::WebCryptoKeyTypePublic)
534 if (!data_size) 660 return false;
535 return false;
536 DCHECK(data);
537 661
538 if (key.type() != blink::WebCryptoKeyTypePublic) 662 PublicKeyHandle* const public_key =
539 return false; 663 reinterpret_cast<PublicKeyHandle*>(key.handle());
540 664
541 PublicKeyHandle* const public_key = 665 const unsigned encrypted_length_bytes =
542 reinterpret_cast<PublicKeyHandle*>(key.handle()); 666 SECKEY_PublicKeyStrength(public_key->key());
543 667
544 const unsigned encrypted_length_bytes = 668 // RSAES can operate on messages up to a length of k - 11, where k is the
545 SECKEY_PublicKeyStrength(public_key->key()); 669 // octet length of the RSA modulus.
670 if (encrypted_length_bytes < 11 ||
671 encrypted_length_bytes - 11 < data_size) {
672 return false;
673 }
546 674
547 // RSAES can operate on messages up to a length of k - 11, where k is the 675 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1);
548 // octet length of the RSA modulus. 676 unsigned char* const buffer_data =
549 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size) 677 reinterpret_cast<unsigned char*>(buffer->data());
550 return false;
551 678
552 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); 679 if (PK11_PubEncryptPKCS1(public_key->key(),
553 unsigned char* const buffer_data = 680 buffer_data,
554 reinterpret_cast<unsigned char*>(buffer->data()); 681 const_cast<unsigned char*>(data),
555 682 data_size,
556 if (PK11_PubEncryptPKCS1(public_key->key(), 683 NULL) != SECSuccess) {
557 buffer_data, 684 return false;
558 const_cast<unsigned char*>(data), 685 }
559 data_size, 686 return true;
560 NULL) != SECSuccess) { 687 }
688 default: {
561 return false; 689 return false;
562 } 690 }
563 return true;
564 } 691 }
565
566 return false;
567 } 692 }
568 693
569 bool WebCryptoImpl::DecryptInternal( 694 bool WebCryptoImpl::DecryptInternal(
570 const blink::WebCryptoAlgorithm& algorithm, 695 const blink::WebCryptoAlgorithm& algorithm,
571 const blink::WebCryptoKey& key, 696 const blink::WebCryptoKey& key,
572 const unsigned char* data, 697 const unsigned char* data,
573 unsigned data_size, 698 unsigned data_size,
574 blink::WebArrayBuffer* buffer) { 699 blink::WebArrayBuffer* buffer) {
575 700
576 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 701 DCHECK_EQ(algorithm.id(), key.algorithm().id());
577 DCHECK(key.handle()); 702 DCHECK(key.handle());
578 DCHECK(buffer); 703 DCHECK(buffer);
579 704
580 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 705 switch (algorithm.id()) {
581 return AesCbcEncryptDecrypt( 706 case blink::WebCryptoAlgorithmIdAesCbc: {
582 CKA_DECRYPT, algorithm, key, data, data_size, buffer); 707 return AesCbcEncryptDecrypt(
583 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 708 CKA_DECRYPT, algorithm, key, data, data_size, buffer);
709 }
710 case blink::WebCryptoAlgorithmIdAesKw: {
Bryan Eyler 2013/12/18 23:30:32 Same here.
padolph 2013/12/19 00:07:15 See above.
711 return AesKwDecrypt(algorithm, key, data, data_size, buffer);
712 }
713 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: {
714 // RSAES decryption does not support empty input
715 if (!data_size)
716 return false;
717 DCHECK(data);
584 718
585 // RSAES decryption does not support empty input 719 if (key.type() != blink::WebCryptoKeyTypePrivate)
586 if (!data_size) 720 return false;
587 return false;
588 DCHECK(data);
589 721
590 if (key.type() != blink::WebCryptoKeyTypePrivate) 722 PrivateKeyHandle* const private_key =
591 return false; 723 reinterpret_cast<PrivateKeyHandle*>(key.handle());
592 724
593 PrivateKeyHandle* const private_key = 725 const int modulus_length_bytes =
594 reinterpret_cast<PrivateKeyHandle*>(key.handle()); 726 PK11_GetPrivateModulusLen(private_key->key());
727 if (modulus_length_bytes <= 0)
728 return false;
729 const unsigned max_output_length_bytes = modulus_length_bytes;
595 730
596 const int modulus_length_bytes = 731 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1);
597 PK11_GetPrivateModulusLen(private_key->key()); 732 unsigned char* const buffer_data =
598 if (modulus_length_bytes <= 0) 733 reinterpret_cast<unsigned char*>(buffer->data());
599 return false;
600 const unsigned max_output_length_bytes = modulus_length_bytes;
601 734
602 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); 735 unsigned output_length_bytes = 0;
603 unsigned char* const buffer_data = 736 if (PK11_PrivDecryptPKCS1(private_key->key(),
604 reinterpret_cast<unsigned char*>(buffer->data()); 737 buffer_data,
605 738 &output_length_bytes,
606 unsigned output_length_bytes = 0; 739 max_output_length_bytes,
607 if (PK11_PrivDecryptPKCS1(private_key->key(), 740 const_cast<unsigned char*>(data),
608 buffer_data, 741 data_size) != SECSuccess) {
609 &output_length_bytes, 742 return false;
610 max_output_length_bytes, 743 }
611 const_cast<unsigned char*>(data), 744 DCHECK_LE(output_length_bytes, max_output_length_bytes);
612 data_size) != SECSuccess) { 745 webcrypto::ShrinkBuffer(buffer, output_length_bytes);
746 return true;
747 }
748 default: {
613 return false; 749 return false;
614 } 750 }
615 DCHECK_LE(output_length_bytes, max_output_length_bytes);
616 webcrypto::ShrinkBuffer(buffer, output_length_bytes);
617 return true;
618 } 751 }
619
620 return false;
621 } 752 }
622 753
623 bool WebCryptoImpl::DigestInternal( 754 bool WebCryptoImpl::DigestInternal(
624 const blink::WebCryptoAlgorithm& algorithm, 755 const blink::WebCryptoAlgorithm& algorithm,
625 const unsigned char* data, 756 const unsigned char* data,
626 unsigned data_size, 757 unsigned data_size,
627 blink::WebArrayBuffer* buffer) { 758 blink::WebArrayBuffer* buffer) {
628 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); 759 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm);
629 if (hash_type == HASH_AlgNULL) { 760 if (hash_type == HASH_AlgNULL) {
630 return false; 761 return false;
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 1142
1012 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), 1143 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()),
1013 blink::WebCryptoKeyTypePublic, 1144 blink::WebCryptoKeyTypePublic,
1014 extractable, 1145 extractable,
1015 algorithm, 1146 algorithm,
1016 usage_mask); 1147 usage_mask);
1017 return true; 1148 return true;
1018 } 1149 }
1019 1150
1020 } // namespace content 1151 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698