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

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

Issue 62633004: [webcrypto] Add RSA public key SPKI import/export for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: reabse Created 7 years, 1 month 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
11 #include <algorithm>
11 #include <vector> 12 #include <vector>
12 13
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "crypto/nss_util.h" 15 #include "crypto/nss_util.h"
15 #include "crypto/scoped_nss_types.h" 16 #include "crypto/scoped_nss_types.h"
16 #include "crypto/secure_util.h" 17 #include "crypto/secure_util.h"
17 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" 18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" 19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
20 21
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 size_t reverse_i = data_size - i - 1; 232 size_t reverse_i = data_size - i - 1;
232 233
233 if (reverse_i >= sizeof(unsigned long) && data[i]) 234 if (reverse_i >= sizeof(unsigned long) && data[i])
234 return false; // Too large for a long. 235 return false; // Too large for a long.
235 236
236 *result |= data[i] << 8 * reverse_i; 237 *result |= data[i] << 8 * reverse_i;
237 } 238 }
238 return true; 239 return true;
239 } 240 }
240 241
242 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) {
243 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
244 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep ||
245 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
246 }
247
248 bool ImportKeyInternalRaw(
249 const unsigned char* key_data,
250 unsigned key_data_size,
251 const blink::WebCryptoAlgorithm& algorithm,
252 bool extractable,
253 blink::WebCryptoKeyUsageMask usage_mask,
254 blink::WebCryptoKey* key) {
255
256 DCHECK(!algorithm.isNull());
257
258 blink::WebCryptoKeyType type;
259 switch (algorithm.id()) {
260 case blink::WebCryptoAlgorithmIdHmac:
261 case blink::WebCryptoAlgorithmIdAesCbc:
262 type = blink::WebCryptoKeyTypeSecret;
263 break;
264 // TODO(bryaneyler): Support more key types.
265 default:
266 return false;
267 }
268
269 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
270 // Currently only supporting symmetric.
271 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
272 // Flags are verified at the Blink layer; here the flags are set to all
273 // possible operations for this key type.
274 CK_FLAGS flags = 0;
275
276 switch (algorithm.id()) {
277 case blink::WebCryptoAlgorithmIdHmac: {
278 const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
279 if (!params) {
280 return false;
281 }
282
283 mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash());
284 if (mechanism == CKM_INVALID_MECHANISM) {
285 return false;
286 }
287
288 flags |= CKF_SIGN | CKF_VERIFY;
289
290 break;
291 }
292 case blink::WebCryptoAlgorithmIdAesCbc: {
293 mechanism = CKM_AES_CBC;
294 flags |= CKF_ENCRYPT | CKF_DECRYPT;
295 break;
296 }
297 default:
298 return false;
299 }
300
301 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
302 DCHECK_NE(0ul, flags);
303
304 SECItem key_item = {
305 siBuffer,
306 const_cast<unsigned char*>(key_data),
307 key_data_size
308 };
309
310 crypto::ScopedPK11SymKey pk11_sym_key(
311 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(),
312 mechanism,
313 PK11_OriginUnwrap,
314 CKA_FLAGS_ONLY,
315 &key_item,
316 flags,
317 false,
318 NULL));
319 if (!pk11_sym_key.get()) {
320 return false;
321 }
322
323 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
324 type, extractable, algorithm, usage_mask);
325 return true;
326 }
327
328 typedef scoped_ptr_malloc<
329 CERTSubjectPublicKeyInfo,
330 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
331 SECKEY_DestroySubjectPublicKeyInfo> >
332 ScopedCERTSubjectPublicKeyInfo;
333
334 bool ImportKeyInternalSpki(
335 const unsigned char* key_data,
336 unsigned key_data_size,
337 const blink::WebCryptoAlgorithm& algorithm_or_null,
338 bool extractable,
339 blink::WebCryptoKeyUsageMask usage_mask,
340 blink::WebCryptoKey* key) {
341
342 DCHECK(key);
343
344 if (!key_data_size)
345 return false;
346
347 DCHECK(key_data);
348
349 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
350 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
351 SECItem spki_item = {
352 siBuffer,
353 const_cast<uint8*>(key_data),
354 key_data_size
355 };
356 const ScopedCERTSubjectPublicKeyInfo spki(
357 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
358 if (!spki)
359 return false;
360
361 crypto::ScopedSECKEYPublicKey sec_public_key(
362 SECKEY_ExtractPublicKey(spki.get()));
363 if (!sec_public_key)
364 return false;
365
366 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
367
368 // Validate the sec_key_type against the input algorithm. Some NSS KeyType's
369 // contain enough information to fabricate a Web Crypto Algorithm, which will
370 // be used if the input algorithm isNull(). Others like 'rsaKey' do not (see
371 // below).
372 blink::WebCryptoAlgorithm algorithm =
373 blink::WebCryptoAlgorithm::createNull();
374 switch (sec_key_type) {
375 case rsaKey:
376 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and
377 // according to RFC 4055 this can be used for both encryption and
378 // signatures. However, this is not specific enough to build a compatible
379 // Web Crypto algorithm, since in Web Crypto RSA encryption and signature
380 // algorithms are distinct. So if the input algorithm isNull() here, we
381 // have to fail.
382 if (algorithm_or_null.isNull() || !IsAlgorithmRsa(algorithm_or_null))
383 return false;
384 algorithm = algorithm_or_null;
385 break;
386 case dsaKey:
387 case ecKey:
388 case rsaPssKey:
389 case rsaOaepKey:
390 // TODO(padolph): Handle other key types.
391 return false;
392 default:
393 return false;
394 }
395
396 *key = blink::WebCryptoKey::create(
397 new PublicKeyHandle(sec_public_key.Pass()),
398 blink::WebCryptoKeyTypePublic,
399 extractable,
400 algorithm,
401 usage_mask);
402
403 return true;
404 }
405
406 bool ExportKeyInternalSpki(
407 const blink::WebCryptoKey& key,
408 blink::WebArrayBuffer* buffer) {
409
410 DCHECK(key.handle());
411 DCHECK(buffer);
412
413 if (key.type() != blink::WebCryptoKeyTypePublic || !key.extractable())
414 return false;
415
416 PublicKeyHandle* const pub_key =
417 reinterpret_cast<PublicKeyHandle*>(key.handle());
418
419 const crypto::ScopedSECItem spki_der(
420 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key()));
421 if (!spki_der)
422 return false;
423
424 DCHECK(spki_der->data);
425 DCHECK(spki_der->len);
426
427 *buffer = blink::WebArrayBuffer::create(spki_der->len, 1);
428 std::copy(spki_der->data,
429 spki_der->data + spki_der->len,
430 static_cast<unsigned char*>(buffer->data()));
Ryan Sleevi 2013/11/21 01:19:12 Why use std::copy? Why not simply memcpy? You're n
padolph 2013/11/21 02:13:36 Done.
431
432 return true;
433 }
434
241 } // namespace 435 } // namespace
242 436
243 void WebCryptoImpl::Init() { 437 void WebCryptoImpl::Init() {
244 crypto::EnsureNSSInit(); 438 crypto::EnsureNSSInit();
245 } 439 }
246 440
247 bool WebCryptoImpl::EncryptInternal( 441 bool WebCryptoImpl::EncryptInternal(
248 const blink::WebCryptoAlgorithm& algorithm, 442 const blink::WebCryptoAlgorithm& algorithm,
249 const blink::WebCryptoKey& key, 443 const blink::WebCryptoKey& key,
250 const unsigned char* data, 444 const unsigned char* data,
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 631
438 // One extractable input parameter is provided, and the Web Crypto API 632 // 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. 633 // 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 634 // 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 635 // 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 636 // 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 637 // spec bug here: https://www.w3.org/Bugs/Public/show_bug.cgi?id=23695
444 *public_key = blink::WebCryptoKey::create( 638 *public_key = blink::WebCryptoKey::create(
445 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), 639 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)),
446 blink::WebCryptoKeyTypePublic, 640 blink::WebCryptoKeyTypePublic,
447 extractable, // probably should be 'true' always 641 extractable, // probably should be 'true' always
448 algorithm, 642 algorithm,
449 usage_mask); 643 usage_mask);
450 *private_key = blink::WebCryptoKey::create( 644 *private_key = blink::WebCryptoKey::create(
451 new PrivateKeyHandle(scoped_sec_private_key.Pass()), 645 new PrivateKeyHandle(scoped_sec_private_key.Pass()),
452 blink::WebCryptoKeyTypePrivate, 646 blink::WebCryptoKeyTypePrivate,
453 extractable, 647 extractable,
454 algorithm, 648 algorithm,
455 usage_mask); 649 usage_mask);
456 650
457 return true; 651 return true;
458 } 652 }
459 default: 653 default:
460 return false; 654 return false;
461 } 655 }
462 } 656 }
463 657
464 bool WebCryptoImpl::ImportKeyInternal( 658 bool WebCryptoImpl::ImportKeyInternal(
465 blink::WebCryptoKeyFormat format, 659 blink::WebCryptoKeyFormat format,
466 const unsigned char* key_data, 660 const unsigned char* key_data,
467 unsigned key_data_size, 661 unsigned key_data_size,
468 const blink::WebCryptoAlgorithm& algorithm_or_null, 662 const blink::WebCryptoAlgorithm& algorithm_or_null,
469 bool extractable, 663 bool extractable,
470 blink::WebCryptoKeyUsageMask usage_mask, 664 blink::WebCryptoKeyUsageMask usage_mask,
471 blink::WebCryptoKey* key) { 665 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 666
478 blink::WebCryptoKeyType type; 667 switch (format) {
479 switch (algorithm.id()) { 668 case blink::WebCryptoKeyFormatRaw:
480 case blink::WebCryptoAlgorithmIdHmac: 669 // A 'raw'-formatted key import requires an input algorithm.
481 case blink::WebCryptoAlgorithmIdAesCbc: 670 if (algorithm_or_null.isNull())
482 type = blink::WebCryptoKeyTypeSecret; 671 return false;
483 break; 672 return ImportKeyInternalRaw(key_data,
484 // TODO(bryaneyler): Support more key types. 673 key_data_size,
674 algorithm_or_null,
675 extractable,
676 usage_mask,
677 key);
678 case blink::WebCryptoKeyFormatSpki:
679 return ImportKeyInternalSpki(key_data,
680 key_data_size,
681 algorithm_or_null,
682 extractable,
683 usage_mask,
684 key);
685 case blink::WebCryptoKeyFormatPkcs8:
686 // TODO(padolph): Handle PKCS#8 private key import
687 return false;
485 default: 688 default:
486 return false; 689 return false;
487 } 690 }
691 }
488 692
489 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. 693 bool WebCryptoImpl::ExportKeyInternal(
490 // Currently only supporting symmetric. 694 blink::WebCryptoKeyFormat format,
491 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; 695 const blink::WebCryptoKey& key,
492 // Flags are verified at the Blink layer; here the flags are set to all 696 blink::WebArrayBuffer* buffer) {
493 // possible operations for this key type. 697 switch (format) {
494 CK_FLAGS flags = 0; 698 case blink::WebCryptoKeyFormatRaw:
495 699 // TODO(padolph): Implement raw export
496 switch(algorithm.id()) { 700 return false;
497 case blink::WebCryptoAlgorithmIdHmac: { 701 case blink::WebCryptoKeyFormatSpki:
498 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); 702 return ExportKeyInternalSpki(key, buffer);
499 if (!params) { 703 case blink::WebCryptoKeyFormatPkcs8:
500 return false; 704 // TODO(padolph): Implement pkcs8 export
501 } 705 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: 706 default:
518 return false; 707 return false;
519 } 708 }
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 } 709 }
553 710
554 bool WebCryptoImpl::SignInternal( 711 bool WebCryptoImpl::SignInternal(
555 const blink::WebCryptoAlgorithm& algorithm, 712 const blink::WebCryptoAlgorithm& algorithm,
556 const blink::WebCryptoKey& key, 713 const blink::WebCryptoKey& key,
557 const unsigned char* data, 714 const unsigned char* data,
558 unsigned data_size, 715 unsigned data_size,
559 blink::WebArrayBuffer* buffer) { 716 blink::WebArrayBuffer* buffer) {
560 blink::WebArrayBuffer result; 717 blink::WebArrayBuffer result;
561 718
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 break; 799 break;
643 } 800 }
644 default: 801 default:
645 return false; 802 return false;
646 } 803 }
647 804
648 return true; 805 return true;
649 } 806 }
650 807
651 } // namespace content 808 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/webcrypto/webcrypto_impl.cc ('k') | content/renderer/webcrypto/webcrypto_impl_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698