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

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: rebase 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 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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