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

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: 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 WebKit::WebCryptoAlgorithm& algorithm) {
243 return algorithm.id() == WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
244 algorithm.id() == WebKit::WebCryptoAlgorithmIdRsaOaep ||
245 algorithm.id() == WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
246 }
247
248 bool ImportKeyInternalRaw(
249 const unsigned char* key_data,
250 unsigned key_data_size,
251 const WebKit::WebCryptoAlgorithm& algorithm_or_null,
252 bool extractable,
253 WebKit::WebCryptoKeyUsageMask usage_mask,
254 WebKit::WebCryptoKey* key) {
255
256 // TODO(eroman): Currently expects algorithm to always be specified, as it is
eroman 2013/11/06 23:48:40 Not sure this needs a TODO anymore, since for "raw
padolph 2013/11/07 00:23:50 Done.
257 // required for raw format.
258 if (algorithm_or_null.isNull())
259 return false;
260 const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
261
262 WebKit::WebCryptoKeyType type;
263 switch (algorithm.id()) {
264 case WebKit::WebCryptoAlgorithmIdHmac:
265 case WebKit::WebCryptoAlgorithmIdAesCbc:
266 type = WebKit::WebCryptoKeyTypeSecret;
267 break;
268 // TODO(bryaneyler): Support more key types.
269 default:
270 return false;
271 }
272
273 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
274 // Currently only supporting symmetric.
eroman 2013/11/06 23:48:40 I presume nothing else changed in this function? (
padolph 2013/11/07 00:23:50 Yes, I made sure this was a strict copy-paste (asi
275 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
276 // Flags are verified at the Blink layer; here the flags are set to all
277 // possible operations for this key type.
278 CK_FLAGS flags = 0;
279
280 switch (algorithm.id()) {
281 case WebKit::WebCryptoAlgorithmIdHmac: {
282 const WebKit::WebCryptoHmacParams* params = algorithm.hmacParams();
283 if (!params) {
284 return false;
285 }
286
287 mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash());
288 if (mechanism == CKM_INVALID_MECHANISM) {
289 return false;
290 }
291
292 flags |= CKF_SIGN | CKF_VERIFY;
293
294 break;
295 }
296 case WebKit::WebCryptoAlgorithmIdAesCbc: {
297 mechanism = CKM_AES_CBC;
298 flags |= CKF_ENCRYPT | CKF_DECRYPT;
299 break;
300 }
301 default:
302 return false;
303 }
304
305 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
306 DCHECK_NE(0ul, flags);
307
308 SECItem key_item = {
309 siBuffer,
310 const_cast<unsigned char*>(key_data),
311 key_data_size
312 };
313
314 crypto::ScopedPK11SymKey pk11_sym_key(
315 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(),
316 mechanism,
317 PK11_OriginUnwrap,
318 CKA_FLAGS_ONLY,
319 &key_item,
320 flags,
321 false,
322 NULL));
323 if (!pk11_sym_key.get()) {
324 return false;
325 }
326
327 *key = WebKit::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
328 type, extractable, algorithm, usage_mask);
329 return true;
330 }
331
332 typedef scoped_ptr_malloc<
333 CERTSubjectPublicKeyInfo,
334 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
335 SECKEY_DestroySubjectPublicKeyInfo> >
336 ScopedCERTSubjectPublicKeyInfo;
337
338 bool ImportKeyInternalSpki(
339 const unsigned char* key_data,
340 unsigned key_data_size,
341 const WebKit::WebCryptoAlgorithm& algorithm_or_null,
342 bool extractable,
343 WebKit::WebCryptoKeyUsageMask usage_mask,
344 WebKit::WebCryptoKey* key) {
345
346 DCHECK(key_data);
347 DCHECK(key_data_size);
eroman 2013/11/06 23:48:40 These shouldn't be DCHECKs --> it is possible for
padolph 2013/11/07 00:23:50 Done.
348 DCHECK(key);
349
350 const WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
eroman 2013/11/06 23:48:40 The same thing could be accomplished by just renam
padolph 2013/11/07 00:23:50 Can't do it in the caller, since fail for null mig
351
352 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
353 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
354 SECItem spki_item = {
355 siBuffer,
356 const_cast<uint8*>(key_data),
357 key_data_size
358 };
359 const ScopedCERTSubjectPublicKeyInfo spki(
360 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
361 if (!spki)
362 return false;
363
364 crypto::ScopedSECKEYPublicKey sec_public_key(
365 SECKEY_ExtractPublicKey(spki.get()));
366 if (!sec_public_key)
367 return false;
368
369 // Validate the key type.
370 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
eroman 2013/11/06 23:48:40 FYI: I am not familiar with these specifics; I wil
371 switch (sec_key_type) {
372 case rsaKey:
373 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and
374 // according to RFC 4055 this can be used for both encryption and
375 // signatures. However, this is not specific enough to build a compatible
376 // Web Crypto algorithm, since in Web Crypto RSA encryption and signature
377 // algorithms are distinct. So if the input algorithm is NULL here, we
eroman 2013/11/06 23:48:40 Useful comment. Small wording nit: rather than "NU
padolph 2013/11/07 00:23:50 Done.
378 // have to fail.
379 if (algorithm.isNull() || !IsAlgorithmRsa(algorithm))
380 return false;
381 break;
382 case dsaKey:
383 case ecKey:
384 case rsaPssKey:
385 case rsaOaepKey:
386 // TODO(padolph): Handle other key types
387 return false;
388 default:
389 NOTREACHED();
eroman 2013/11/06 23:48:40 Only use NOTREACHED() for code which really can't
padolph 2013/11/07 00:23:50 Done.
390 return false;
391 }
392
393 *key = WebKit::WebCryptoKey::create(
394 new PublicKeyHandle(sec_public_key.Pass()),
395 WebKit::WebCryptoKeyTypePublic,
396 extractable,
397 algorithm,
398 usage_mask);
399
400 return true;
401 }
402
403 bool ExportKeyInternalSpki(
404 const WebKit::WebCryptoKey& key,
405 WebKit::WebArrayBuffer* buffer) {
406
407 DCHECK(key.handle());
408 DCHECK(buffer);
409
410 if (key.type() != WebKit::WebCryptoKeyTypePublic || !key.extractable())
411 return false;
412
413 PublicKeyHandle* const pub_key =
414 reinterpret_cast<PublicKeyHandle*>(key.handle());
415
416 const crypto::ScopedSECItem spki_der(
417 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key()));
418 if (!spki_der)
419 return false;
420
421 DCHECK(spki_der->data);
422 DCHECK(spki_der->len);
423
424 *buffer = WebKit::WebArrayBuffer::create(spki_der->len, 1);
425 std::copy(spki_der->data,
426 spki_der->data + spki_der->len,
427 static_cast<unsigned char*>(buffer->data()));
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 WebKit::WebCryptoAlgorithm& algorithm, 439 const WebKit::WebCryptoAlgorithm& algorithm,
249 const WebKit::WebCryptoKey& key, 440 const WebKit::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 = WebKit::WebCryptoKey::create( 635 *public_key = WebKit::WebCryptoKey::create(
445 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), 636 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)),
446 WebKit::WebCryptoKeyTypePublic, 637 WebKit::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 = WebKit::WebCryptoKey::create( 641 *private_key = WebKit::WebCryptoKey::create(
451 new PrivateKeyHandle(scoped_sec_private_key.Pass()), 642 new PrivateKeyHandle(scoped_sec_private_key.Pass()),
452 WebKit::WebCryptoKeyTypePrivate, 643 WebKit::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 WebKit::WebCryptoKeyFormat format, 656 WebKit::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 WebKit::WebCryptoAlgorithm& algorithm_or_null, 659 const WebKit::WebCryptoAlgorithm& algorithm_or_null,
469 bool extractable, 660 bool extractable,
470 WebKit::WebCryptoKeyUsageMask usage_mask, 661 WebKit::WebCryptoKeyUsageMask usage_mask,
471 WebKit::WebCryptoKey* key) { 662 WebKit::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 WebKit::WebCryptoAlgorithm& algorithm = algorithm_or_null;
477
478 WebKit::WebCryptoKeyType type;
479 switch (algorithm.id()) {
480 case WebKit::WebCryptoAlgorithmIdHmac:
481 case WebKit::WebCryptoAlgorithmIdAesCbc:
482 type = WebKit::WebCryptoKeyTypeSecret;
483 break;
484 // TODO(bryaneyler): Support more key types.
485 default:
486 return false;
487 }
488
489 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys.
490 // Currently only supporting symmetric.
491 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
492 // Flags are verified at the Blink layer; here the flags are set to all
493 // possible operations for this key type.
494 CK_FLAGS flags = 0;
495
496 switch(algorithm.id()) {
497 case WebKit::WebCryptoAlgorithmIdHmac: {
498 const WebKit::WebCryptoHmacParams* params = algorithm.hmacParams();
499 if (!params) {
500 return false;
501 }
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 WebKit::WebCryptoAlgorithmIdAesCbc: {
513 mechanism = CKM_AES_CBC;
514 flags |= CKF_ENCRYPT | CKF_DECRYPT;
515 break;
516 }
517 default:
518 return false;
519 }
520
521 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism);
522 DCHECK_NE(0ul, flags);
523
524 SECItem key_item = { siBuffer, NULL, 0 };
525 663
526 switch (format) { 664 switch (format) {
527 case WebKit::WebCryptoKeyFormatRaw: 665 case WebKit::WebCryptoKeyFormatRaw:
528 key_item.data = const_cast<unsigned char*>(key_data); 666 return ImportKeyInternalRaw(key_data,
529 key_item.len = key_data_size; 667 key_data_size,
530 break; 668 algorithm_or_null,
531 // TODO(bryaneyler): Handle additional formats. 669 extractable,
670 usage_mask,
671 key);
672 case WebKit::WebCryptoKeyFormatSpki:
673 return ImportKeyInternalSpki(key_data,
674 key_data_size,
675 algorithm_or_null,
676 extractable,
677 usage_mask,
678 key);
679 case WebKit::WebCryptoKeyFormatPkcs8:
680 // TODO(padolph): Handle PKCS#8 private key import
681 return false;
532 default: 682 default:
683 NOTREACHED();
eroman 2013/11/06 23:48:40 Please leave this off since it is reachable (i.e.
padolph 2013/11/07 00:23:50 Done.
533 return false; 684 return false;
534 } 685 }
686 }
535 687
536 crypto::ScopedPK11SymKey pk11_sym_key( 688 bool WebCryptoImpl::ExportKeyInternal(
537 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(), 689 WebKit::WebCryptoKeyFormat format,
538 mechanism, 690 const WebKit::WebCryptoKey& key,
539 PK11_OriginUnwrap, 691 WebKit::WebArrayBuffer* buffer) {
540 CKA_FLAGS_ONLY, 692 switch (format) {
541 &key_item, 693 case WebKit::WebCryptoKeyFormatRaw:
542 flags, 694 // TODO(padolph): Implement raw export
543 false, 695 NOTREACHED();
eroman 2013/11/06 23:48:40 Same comment here. Use NOTREACHED() only for code
padolph 2013/11/07 00:23:50 Done.
544 NULL)); 696 return false;
545 if (!pk11_sym_key.get()) { 697 case WebKit::WebCryptoKeyFormatSpki:
546 return false; 698 return ExportKeyInternalSpki(key, buffer);
699 case WebKit::WebCryptoKeyFormatPkcs8:
700 // TODO(padolph): Implement pkcs8 export
701 NOTREACHED();
702 return false;
703 default:
704 NOTREACHED();
705 return false;
547 } 706 }
548
549 *key = WebKit::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()),
550 type, extractable, algorithm, usage_mask);
551 return true;
552 } 707 }
553 708
554 bool WebCryptoImpl::SignInternal( 709 bool WebCryptoImpl::SignInternal(
555 const WebKit::WebCryptoAlgorithm& algorithm, 710 const WebKit::WebCryptoAlgorithm& algorithm,
556 const WebKit::WebCryptoKey& key, 711 const WebKit::WebCryptoKey& key,
557 const unsigned char* data, 712 const unsigned char* data,
558 unsigned data_size, 713 unsigned data_size,
559 WebKit::WebArrayBuffer* buffer) { 714 WebKit::WebArrayBuffer* buffer) {
560 WebKit::WebArrayBuffer result; 715 WebKit::WebArrayBuffer result;
561 716
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 break; 797 break;
643 } 798 }
644 default: 799 default:
645 return false; 800 return false;
646 } 801 }
647 802
648 return true; 803 return true;
649 } 804 }
650 805
651 } // namespace content 806 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698