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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 buffer_data + output_len, | 174 buffer_data + output_len, |
175 &final_output_chunk_len, | 175 &final_output_chunk_len, |
176 output_max_len - output_len)) { | 176 output_max_len - output_len)) { |
177 return false; | 177 return false; |
178 } | 178 } |
179 | 179 |
180 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); | 180 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); |
181 return true; | 181 return true; |
182 } | 182 } |
183 | 183 |
184 // Constants for RFC 3394 AES Key Wrap / Unwrap. | |
185 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP; | |
186 // The Default IV. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1. | |
187 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; | |
188 | |
189 // Performs RFC 3394 AES Key Wrap (encryption) of the input data. | |
190 bool AesKwEncrypt( | |
191 const blink::WebCryptoKey& key, | |
192 const unsigned char* data, | |
193 unsigned data_size, | |
194 blink::WebArrayBuffer* buffer) { | |
195 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
196 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
197 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages()); | |
198 | |
199 // The data size must be at least 16 bytes and a multiple of 8 bytes. | |
200 if (data_size < 16 || data_size % 8) | |
201 return false; | |
202 DCHECK(data); | |
203 | |
204 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
205 arraysize(kAesIv)}; | |
206 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
207 DCHECK(param_item); | |
208 | |
209 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS | |
210 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a | |
211 // generic secret blob, since we can't be certain what it is at this point. | |
Bryan Eyler
2014/01/15 19:30:17
Will we be hitting any issues with unwrapping a no
padolph
2014/01/15 22:58:52
Good point. I don't think using an asym key as an
eroman
2014/01/15 23:45:03
I have asked rsleevi to comment on this, hopefully
| |
212 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
213 crypto::ScopedPK11SymKey key_to_be_wrapped( | |
214 PK11_ImportSymKey(PK11_GetInternalSlot(), | |
215 CKK_GENERIC_SECRET, | |
216 PK11_OriginGenerated, | |
217 CKA_ENCRYPT, | |
218 &data_item, | |
219 0)); | |
220 if (!key_to_be_wrapped) | |
221 return false; | |
222 | |
223 // AES Key Wrap always adds 8 bytes to the input data size. RFC 3394 does not | |
224 // specify a maximum allowed data length, but since we are only wrapping keys, | |
225 // which are usually small, a reasonable max size is whatever will fit into an | |
226 // unsigned. | |
227 if (data_size > UINT_MAX - 8) | |
228 return false; | |
229 const unsigned int output_length = data_size + 8; | |
230 | |
231 *buffer = blink::WebArrayBuffer::create(output_length, 1); | |
232 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
233 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; | |
234 | |
235 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
236 | |
237 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism, | |
238 param_item.get(), | |
239 wrapping_key->key(), | |
240 key_to_be_wrapped.get(), | |
241 &wrapped_key_item)) { | |
242 return false; | |
243 } | |
244 if (output_length != wrapped_key_item.len) { | |
245 buffer->reset(); | |
246 return false; | |
247 } | |
248 | |
249 return true; | |
250 } | |
251 | |
252 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data. | |
253 bool AesKwDecrypt( | |
254 const blink::WebCryptoKey& key, | |
255 const unsigned char* data, | |
256 unsigned data_size, | |
257 blink::WebArrayBuffer* buffer) { | |
258 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
259 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
260 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages()); | |
261 | |
262 // The ciphertext data size must be at least 24 bytes and a multiple of | |
263 // 8 bytes. | |
264 if (data_size < 24 || data_size % 8 != 0) | |
265 return false; | |
266 DCHECK(data); | |
267 | |
268 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
269 | |
270 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
271 arraysize(kAesIv)}; | |
272 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
273 DCHECK(param_item); | |
274 | |
275 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
276 | |
277 // The plaintext length is always 64 bits less than the data size. | |
278 const unsigned int plaintext_length = data_size - 8; | |
279 | |
280 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey( | |
281 wrapping_key->key(), | |
282 kAesKwMechanism, | |
283 param_item.get(), | |
284 &cipher_text, | |
285 CKK_GENERIC_SECRET, // Import the key material without knowing its kind. | |
286 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key. | |
287 plaintext_length)); | |
288 if (!unwrapped_key) | |
289 return false; | |
290 | |
291 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess) | |
292 return false; | |
293 | |
294 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get()); | |
295 if (!key_data || key_data->len != plaintext_length) | |
296 return false; | |
297 | |
298 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | |
299 | |
300 return true; | |
301 } | |
302 | |
184 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | 303 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( |
185 const blink::WebCryptoAlgorithm& algorithm) { | 304 const blink::WebCryptoAlgorithm& algorithm) { |
186 switch (algorithm.id()) { | 305 switch (algorithm.id()) { |
187 case blink::WebCryptoAlgorithmIdAesCbc: | 306 case blink::WebCryptoAlgorithmIdAesCbc: |
188 case blink::WebCryptoAlgorithmIdAesGcm: | 307 case blink::WebCryptoAlgorithmIdAesGcm: |
189 case blink::WebCryptoAlgorithmIdAesKw: | 308 case blink::WebCryptoAlgorithmIdAesKw: |
190 return CKM_AES_KEY_GEN; | 309 return CKM_AES_KEY_GEN; |
191 case blink::WebCryptoAlgorithmIdHmac: | 310 case blink::WebCryptoAlgorithmIdHmac: |
192 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); | 311 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); |
193 default: | 312 default: |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 const blink::WebCryptoAlgorithm& algorithm, | 614 const blink::WebCryptoAlgorithm& algorithm, |
496 const blink::WebCryptoKey& key, | 615 const blink::WebCryptoKey& key, |
497 const unsigned char* data, | 616 const unsigned char* data, |
498 unsigned data_size, | 617 unsigned data_size, |
499 blink::WebArrayBuffer* buffer) { | 618 blink::WebArrayBuffer* buffer) { |
500 | 619 |
501 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 620 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
502 DCHECK(key.handle()); | 621 DCHECK(key.handle()); |
503 DCHECK(buffer); | 622 DCHECK(buffer); |
504 | 623 |
624 // TODO(padolph): Convert to switch statement. | |
505 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 625 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
506 return AesCbcEncryptDecrypt( | 626 return AesCbcEncryptDecrypt( |
507 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | 627 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
628 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
629 return AesKwEncrypt(key, data, data_size, buffer); | |
508 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 630 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
509 | 631 |
510 // RSAES encryption does not support empty input | 632 // RSAES encryption does not support empty input |
511 if (!data_size) | 633 if (!data_size) |
512 return false; | 634 return false; |
513 DCHECK(data); | 635 DCHECK(data); |
514 | 636 |
515 if (key.type() != blink::WebCryptoKeyTypePublic) | 637 if (key.type() != blink::WebCryptoKeyTypePublic) |
516 return false; | 638 return false; |
517 | 639 |
(...skipping 29 matching lines...) Expand all Loading... | |
547 const blink::WebCryptoAlgorithm& algorithm, | 669 const blink::WebCryptoAlgorithm& algorithm, |
548 const blink::WebCryptoKey& key, | 670 const blink::WebCryptoKey& key, |
549 const unsigned char* data, | 671 const unsigned char* data, |
550 unsigned data_size, | 672 unsigned data_size, |
551 blink::WebArrayBuffer* buffer) { | 673 blink::WebArrayBuffer* buffer) { |
552 | 674 |
553 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 675 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
554 DCHECK(key.handle()); | 676 DCHECK(key.handle()); |
555 DCHECK(buffer); | 677 DCHECK(buffer); |
556 | 678 |
679 // TODO(padolph): Convert to switch statement. | |
557 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 680 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
558 return AesCbcEncryptDecrypt( | 681 return AesCbcEncryptDecrypt( |
559 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | 682 CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
683 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
684 return AesKwDecrypt(key, data, data_size, buffer); | |
560 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 685 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
561 | 686 |
562 // RSAES decryption does not support empty input | 687 // RSAES decryption does not support empty input |
563 if (!data_size) | 688 if (!data_size) |
564 return false; | 689 return false; |
565 DCHECK(data); | 690 DCHECK(data); |
566 | 691 |
567 if (key.type() != blink::WebCryptoKeyTypePrivate) | 692 if (key.type() != blink::WebCryptoKeyTypePrivate) |
568 return false; | 693 return false; |
569 | 694 |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
992 | 1117 |
993 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1118 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), |
994 blink::WebCryptoKeyTypePublic, | 1119 blink::WebCryptoKeyTypePublic, |
995 extractable, | 1120 extractable, |
996 algorithm, | 1121 algorithm, |
997 usage_mask); | 1122 usage_mask); |
998 return true; | 1123 return true; |
999 } | 1124 } |
1000 | 1125 |
1001 } // namespace content | 1126 } // namespace content |
OLD | NEW |