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
3 // found in the LICENSE file.
5 #include "content/renderer/webcrypto/webcrypto_impl.h"
13 #include "base/logging.h"
14 #include "content/renderer/webcrypto/webcrypto_util.h"
15 #include "crypto/nss_util.h"
16 #include "crypto/scoped_nss_types.h"
17 #include "crypto/secure_util.h"
18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h"
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
26 class SymKeyHandle
: public blink::WebCryptoKeyHandle
{
28 explicit SymKeyHandle(crypto::ScopedPK11SymKey key
) : key_(key
.Pass()) {}
30 PK11SymKey
* key() { return key_
.get(); }
33 crypto::ScopedPK11SymKey key_
;
35 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle
);
38 class PublicKeyHandle
: public blink::WebCryptoKeyHandle
{
40 explicit PublicKeyHandle(crypto::ScopedSECKEYPublicKey key
)
43 SECKEYPublicKey
* key() { return key_
.get(); }
46 crypto::ScopedSECKEYPublicKey key_
;
48 DISALLOW_COPY_AND_ASSIGN(PublicKeyHandle
);
51 class PrivateKeyHandle
: public blink::WebCryptoKeyHandle
{
53 explicit PrivateKeyHandle(crypto::ScopedSECKEYPrivateKey key
)
56 SECKEYPrivateKey
* key() { return key_
.get(); }
59 crypto::ScopedSECKEYPrivateKey key_
;
61 DISALLOW_COPY_AND_ASSIGN(PrivateKeyHandle
);
64 HASH_HashType
WebCryptoAlgorithmToNSSHashType(
65 const blink::WebCryptoAlgorithm
& algorithm
) {
66 switch (algorithm
.id()) {
67 case blink::WebCryptoAlgorithmIdSha1
:
69 case blink::WebCryptoAlgorithmIdSha224
:
70 return HASH_AlgSHA224
;
71 case blink::WebCryptoAlgorithmIdSha256
:
72 return HASH_AlgSHA256
;
73 case blink::WebCryptoAlgorithmIdSha384
:
74 return HASH_AlgSHA384
;
75 case blink::WebCryptoAlgorithmIdSha512
:
76 return HASH_AlgSHA512
;
78 // Not a digest algorithm.
83 CK_MECHANISM_TYPE
WebCryptoHashToHMACMechanism(
84 const blink::WebCryptoAlgorithm
& algorithm
) {
85 switch (algorithm
.id()) {
86 case blink::WebCryptoAlgorithmIdSha1
:
87 return CKM_SHA_1_HMAC
;
88 case blink::WebCryptoAlgorithmIdSha224
:
89 return CKM_SHA224_HMAC
;
90 case blink::WebCryptoAlgorithmIdSha256
:
91 return CKM_SHA256_HMAC
;
92 case blink::WebCryptoAlgorithmIdSha384
:
93 return CKM_SHA384_HMAC
;
94 case blink::WebCryptoAlgorithmIdSha512
:
95 return CKM_SHA512_HMAC
;
97 // Not a supported algorithm.
98 return CKM_INVALID_MECHANISM
;
102 bool AesCbcEncryptDecrypt(
103 CK_ATTRIBUTE_TYPE operation
,
104 const blink::WebCryptoAlgorithm
& algorithm
,
105 const blink::WebCryptoKey
& key
,
106 const unsigned char* data
,
108 blink::WebArrayBuffer
* buffer
) {
109 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc
, algorithm
.id());
110 DCHECK_EQ(algorithm
.id(), key
.algorithm().id());
111 DCHECK_EQ(blink::WebCryptoKeyTypeSecret
, key
.type());
112 DCHECK(operation
== CKA_ENCRYPT
|| operation
== CKA_DECRYPT
);
114 SymKeyHandle
* sym_key
= reinterpret_cast<SymKeyHandle
*>(key
.handle());
116 const blink::WebCryptoAesCbcParams
* params
= algorithm
.aesCbcParams();
117 if (params
->iv().size() != AES_BLOCK_SIZE
)
121 iv_item
.type
= siBuffer
;
122 iv_item
.data
= const_cast<unsigned char*>(params
->iv().data());
123 iv_item
.len
= params
->iv().size();
125 crypto::ScopedSECItem
param(PK11_ParamFromIV(CKM_AES_CBC_PAD
, &iv_item
));
129 crypto::ScopedPK11Context
context(PK11_CreateContextBySymKey(
130 CKM_AES_CBC_PAD
, operation
, sym_key
->key(), param
.get()));
135 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than
136 // "unsigned". Do some checks now to avoid integer overflowing.
137 if (data_size
>= INT_MAX
- AES_BLOCK_SIZE
) {
138 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now
139 // it doesn't make much difference since the one-shot API would end up
140 // blowing out the memory and crashing anyway. However a newer version of
141 // the spec allows for a sequence<CryptoData> so this will be relevant.
145 // PK11_CipherOp does an invalid memory access when given empty decryption
146 // input, or input which is not a multiple of the block size. See also
147 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687.
148 if (operation
== CKA_DECRYPT
&&
149 (data_size
== 0 || (data_size
% AES_BLOCK_SIZE
!= 0))) {
153 // TODO(eroman): Refine the output buffer size. It can be computed exactly for
154 // encryption, and can be smaller for decryption.
155 unsigned output_max_len
= data_size
+ AES_BLOCK_SIZE
;
156 CHECK_GT(output_max_len
, data_size
);
158 *buffer
= blink::WebArrayBuffer::create(output_max_len
, 1);
160 unsigned char* buffer_data
= reinterpret_cast<unsigned char*>(buffer
->data());
163 if (SECSuccess
!= PK11_CipherOp(context
.get(),
166 buffer
->byteLength(),
172 unsigned int final_output_chunk_len
;
173 if (SECSuccess
!= PK11_DigestFinal(context
.get(),
174 buffer_data
+ output_len
,
175 &final_output_chunk_len
,
176 output_max_len
- output_len
)) {
180 webcrypto::ShrinkBuffer(buffer
, final_output_chunk_len
+ output_len
);
184 CK_MECHANISM_TYPE
WebCryptoAlgorithmToGenMechanism(
185 const blink::WebCryptoAlgorithm
& algorithm
) {
186 switch (algorithm
.id()) {
187 case blink::WebCryptoAlgorithmIdAesCbc
:
188 case blink::WebCryptoAlgorithmIdAesGcm
:
189 case blink::WebCryptoAlgorithmIdAesKw
:
190 return CKM_AES_KEY_GEN
;
191 case blink::WebCryptoAlgorithmIdHmac
:
192 return WebCryptoHashToHMACMechanism(algorithm
.hmacKeyParams()->hash());
194 return CKM_INVALID_MECHANISM
;
198 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
200 bool BigIntegerToLong(const uint8
* data
,
202 unsigned long* result
) {
203 // TODO(padolph): Is it correct to say that empty data is an error, or does it
204 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
209 for (size_t i
= 0; i
< data_size
; ++i
) {
210 size_t reverse_i
= data_size
- i
- 1;
212 if (reverse_i
>= sizeof(unsigned long) && data
[i
])
213 return false; // Too large for a long.
215 *result
|= data
[i
] << 8 * reverse_i
;
220 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm
& algorithm
) {
221 return algorithm
.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5
||
222 algorithm
.id() == blink::WebCryptoAlgorithmIdRsaOaep
||
223 algorithm
.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
;
226 bool ImportKeyInternalRaw(
227 const unsigned char* key_data
,
228 unsigned key_data_size
,
229 const blink::WebCryptoAlgorithm
& algorithm
,
231 blink::WebCryptoKeyUsageMask usage_mask
,
232 blink::WebCryptoKey
* key
) {
234 DCHECK(!algorithm
.isNull());
236 blink::WebCryptoKeyType type
;
237 switch (algorithm
.id()) {
238 case blink::WebCryptoAlgorithmIdHmac
:
239 case blink::WebCryptoAlgorithmIdAesCbc
:
240 case blink::WebCryptoAlgorithmIdAesKw
:
241 type
= blink::WebCryptoKeyTypeSecret
;
243 // TODO(bryaneyler): Support more key types.
248 CK_MECHANISM_TYPE mechanism
= CKM_INVALID_MECHANISM
;
249 // Flags are verified at the Blink layer; here the flags are set to all
250 // possible operations for this key type.
253 switch (algorithm
.id()) {
254 case blink::WebCryptoAlgorithmIdHmac
: {
255 const blink::WebCryptoHmacParams
* params
= algorithm
.hmacParams();
260 mechanism
= WebCryptoHashToHMACMechanism(params
->hash());
261 if (mechanism
== CKM_INVALID_MECHANISM
) {
265 flags
|= CKF_SIGN
| CKF_VERIFY
;
269 case blink::WebCryptoAlgorithmIdAesCbc
: {
270 mechanism
= CKM_AES_CBC
;
271 flags
|= CKF_ENCRYPT
| CKF_DECRYPT
;
274 case blink::WebCryptoAlgorithmIdAesKw
: {
275 mechanism
= CKM_NSS_AES_KEY_WRAP
;
276 flags
|= CKF_WRAP
| CKF_WRAP
;
283 DCHECK_NE(CKM_INVALID_MECHANISM
, mechanism
);
284 DCHECK_NE(0ul, flags
);
288 const_cast<unsigned char*>(key_data
),
292 crypto::ScopedPK11Slot
slot(PK11_GetInternalSlot());
293 crypto::ScopedPK11SymKey
pk11_sym_key(
294 PK11_ImportSymKeyWithFlags(slot
.get(),
302 if (!pk11_sym_key
.get()) {
306 *key
= blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key
.Pass()),
307 type
, extractable
, algorithm
, usage_mask
);
311 bool ExportKeyInternalRaw(
312 const blink::WebCryptoKey
& key
,
313 blink::WebArrayBuffer
* buffer
) {
315 DCHECK(key
.handle());
318 if (key
.type() != blink::WebCryptoKeyTypeSecret
|| !key
.extractable())
321 SymKeyHandle
* sym_key
= reinterpret_cast<SymKeyHandle
*>(key
.handle());
323 if (PK11_ExtractKeyValue(sym_key
->key()) != SECSuccess
)
326 const SECItem
* key_data
= PK11_GetKeyData(sym_key
->key());
330 *buffer
= webcrypto::CreateArrayBuffer(key_data
->data
, key_data
->len
);
335 typedef scoped_ptr
<CERTSubjectPublicKeyInfo
,
336 crypto::NSSDestroyer
<CERTSubjectPublicKeyInfo
,
337 SECKEY_DestroySubjectPublicKeyInfo
> >
338 ScopedCERTSubjectPublicKeyInfo
;
340 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes
341 // contain enough information to fabricate a Web Crypto algorithm, which is
342 // returned if the input algorithm isNull(). This function indicates failure by
343 // returning a Null algorithm.
344 blink::WebCryptoAlgorithm
ResolveNssKeyTypeWithInputAlgorithm(
346 const blink::WebCryptoAlgorithm
& algorithm_or_null
) {
349 // NSS's rsaKey KeyType maps to keys with SEC_OID_PKCS1_RSA_ENCRYPTION and
350 // according to RFCs 4055/5756 this can be used for both encryption and
351 // signatures. However, this is not specific enough to build a compatible
352 // Web Crypto algorithm, since in Web Crypto, RSA encryption and signature
353 // algorithms are distinct. So if the input algorithm isNull() here, we
355 if (!algorithm_or_null
.isNull() && IsAlgorithmRsa(algorithm_or_null
))
356 return algorithm_or_null
;
362 // TODO(padolph): Handle other key types.
367 return blink::WebCryptoAlgorithm::createNull();
370 bool ImportKeyInternalSpki(
371 const unsigned char* key_data
,
372 unsigned key_data_size
,
373 const blink::WebCryptoAlgorithm
& algorithm_or_null
,
375 blink::WebCryptoKeyUsageMask usage_mask
,
376 blink::WebCryptoKey
* key
) {
384 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
385 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
386 SECItem spki_item
= {siBuffer
, const_cast<uint8
*>(key_data
), key_data_size
};
387 const ScopedCERTSubjectPublicKeyInfo
spki(
388 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item
));
392 crypto::ScopedSECKEYPublicKey
sec_public_key(
393 SECKEY_ExtractPublicKey(spki
.get()));
397 const KeyType sec_key_type
= SECKEY_GetPublicKeyType(sec_public_key
.get());
398 blink::WebCryptoAlgorithm algorithm
=
399 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type
, algorithm_or_null
);
400 if (algorithm
.isNull())
403 *key
= blink::WebCryptoKey::create(
404 new PublicKeyHandle(sec_public_key
.Pass()),
405 blink::WebCryptoKeyTypePublic
,
413 bool ExportKeyInternalSpki(
414 const blink::WebCryptoKey
& key
,
415 blink::WebArrayBuffer
* buffer
) {
417 DCHECK(key
.handle());
420 if (key
.type() != blink::WebCryptoKeyTypePublic
|| !key
.extractable())
423 PublicKeyHandle
* const pub_key
=
424 reinterpret_cast<PublicKeyHandle
*>(key
.handle());
426 const crypto::ScopedSECItem
spki_der(
427 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key
->key()));
431 DCHECK(spki_der
->data
);
432 DCHECK(spki_der
->len
);
434 *buffer
= webcrypto::CreateArrayBuffer(spki_der
->data
, spki_der
->len
);
439 bool ImportKeyInternalPkcs8(
440 const unsigned char* key_data
,
441 unsigned key_data_size
,
442 const blink::WebCryptoAlgorithm
& algorithm_or_null
,
444 blink::WebCryptoKeyUsageMask usage_mask
,
445 blink::WebCryptoKey
* key
) {
453 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
454 // private key info object.
455 SECItem pki_der
= {siBuffer
, const_cast<uint8
*>(key_data
), key_data_size
};
457 SECKEYPrivateKey
* seckey_private_key
= NULL
;
458 crypto::ScopedPK11Slot
slot(PK11_GetInternalSlot());
459 if (PK11_ImportDERPrivateKeyInfoAndReturnKey(
468 NULL
) != SECSuccess
) {
471 DCHECK(seckey_private_key
);
472 crypto::ScopedSECKEYPrivateKey
private_key(seckey_private_key
);
474 const KeyType sec_key_type
= SECKEY_GetPrivateKeyType(private_key
.get());
475 blink::WebCryptoAlgorithm algorithm
=
476 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type
, algorithm_or_null
);
477 if (algorithm
.isNull())
480 *key
= blink::WebCryptoKey::create(
481 new PrivateKeyHandle(private_key
.Pass()),
482 blink::WebCryptoKeyTypePrivate
,
492 void WebCryptoImpl::Init() {
493 crypto::EnsureNSSInit();
496 bool WebCryptoImpl::EncryptInternal(
497 const blink::WebCryptoAlgorithm
& algorithm
,
498 const blink::WebCryptoKey
& key
,
499 const unsigned char* data
,
501 blink::WebArrayBuffer
* buffer
) {
503 DCHECK_EQ(algorithm
.id(), key
.algorithm().id());
504 DCHECK(key
.handle());
507 if (algorithm
.id() == blink::WebCryptoAlgorithmIdAesCbc
) {
508 return AesCbcEncryptDecrypt(
509 CKA_ENCRYPT
, algorithm
, key
, data
, data_size
, buffer
);
510 } else if (algorithm
.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5
) {
512 // RSAES encryption does not support empty input
517 if (key
.type() != blink::WebCryptoKeyTypePublic
)
520 PublicKeyHandle
* const public_key
=
521 reinterpret_cast<PublicKeyHandle
*>(key
.handle());
523 const unsigned encrypted_length_bytes
=
524 SECKEY_PublicKeyStrength(public_key
->key());
526 // RSAES can operate on messages up to a length of k - 11, where k is the
527 // octet length of the RSA modulus.
528 if (encrypted_length_bytes
< 11 || encrypted_length_bytes
- 11 < data_size
)
531 *buffer
= blink::WebArrayBuffer::create(encrypted_length_bytes
, 1);
532 unsigned char* const buffer_data
=
533 reinterpret_cast<unsigned char*>(buffer
->data());
535 if (PK11_PubEncryptPKCS1(public_key
->key(),
537 const_cast<unsigned char*>(data
),
539 NULL
) != SECSuccess
) {
548 bool WebCryptoImpl::DecryptInternal(
549 const blink::WebCryptoAlgorithm
& algorithm
,
550 const blink::WebCryptoKey
& key
,
551 const unsigned char* data
,
553 blink::WebArrayBuffer
* buffer
) {
555 DCHECK_EQ(algorithm
.id(), key
.algorithm().id());
556 DCHECK(key
.handle());
559 if (algorithm
.id() == blink::WebCryptoAlgorithmIdAesCbc
) {
560 return AesCbcEncryptDecrypt(
561 CKA_DECRYPT
, algorithm
, key
, data
, data_size
, buffer
);
562 } else if (algorithm
.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5
) {
564 // RSAES decryption does not support empty input
569 if (key
.type() != blink::WebCryptoKeyTypePrivate
)
572 PrivateKeyHandle
* const private_key
=
573 reinterpret_cast<PrivateKeyHandle
*>(key
.handle());
575 const int modulus_length_bytes
=
576 PK11_GetPrivateModulusLen(private_key
->key());
577 if (modulus_length_bytes
<= 0)
579 const unsigned max_output_length_bytes
= modulus_length_bytes
;
581 *buffer
= blink::WebArrayBuffer::create(max_output_length_bytes
, 1);
582 unsigned char* const buffer_data
=
583 reinterpret_cast<unsigned char*>(buffer
->data());
585 unsigned output_length_bytes
= 0;
586 if (PK11_PrivDecryptPKCS1(private_key
->key(),
588 &output_length_bytes
,
589 max_output_length_bytes
,
590 const_cast<unsigned char*>(data
),
591 data_size
) != SECSuccess
) {
594 DCHECK_LE(output_length_bytes
, max_output_length_bytes
);
595 webcrypto::ShrinkBuffer(buffer
, output_length_bytes
);
602 bool WebCryptoImpl::DigestInternal(
603 const blink::WebCryptoAlgorithm
& algorithm
,
604 const unsigned char* data
,
606 blink::WebArrayBuffer
* buffer
) {
607 HASH_HashType hash_type
= WebCryptoAlgorithmToNSSHashType(algorithm
);
608 if (hash_type
== HASH_AlgNULL
) {
612 HASHContext
* context
= HASH_Create(hash_type
);
619 HASH_Update(context
, data
, data_size
);
621 unsigned hash_result_length
= HASH_ResultLenContext(context
);
622 DCHECK_LE(hash_result_length
, static_cast<size_t>(HASH_LENGTH_MAX
));
624 *buffer
= blink::WebArrayBuffer::create(hash_result_length
, 1);
626 unsigned char* digest
= reinterpret_cast<unsigned char*>(buffer
->data());
628 unsigned result_length
= 0;
629 HASH_End(context
, digest
, &result_length
, hash_result_length
);
631 HASH_Destroy(context
);
633 return result_length
== hash_result_length
;
636 bool WebCryptoImpl::GenerateKeyInternal(
637 const blink::WebCryptoAlgorithm
& algorithm
,
639 blink::WebCryptoKeyUsageMask usage_mask
,
640 blink::WebCryptoKey
* key
) {
642 CK_MECHANISM_TYPE mech
= WebCryptoAlgorithmToGenMechanism(algorithm
);
643 unsigned int keylen_bytes
= 0;
644 blink::WebCryptoKeyType key_type
= blink::WebCryptoKeyTypeSecret
;
646 if (mech
== CKM_INVALID_MECHANISM
) {
650 switch (algorithm
.id()) {
651 case blink::WebCryptoAlgorithmIdAesCbc
:
652 case blink::WebCryptoAlgorithmIdAesGcm
:
653 case blink::WebCryptoAlgorithmIdAesKw
: {
654 const blink::WebCryptoAesKeyGenParams
* params
=
655 algorithm
.aesKeyGenParams();
657 // Ensure the key length is a multiple of 8 bits. Let NSS verify further
658 // algorithm-specific length restrictions.
659 if (params
->lengthBits() % 8)
661 keylen_bytes
= params
->lengthBits() / 8;
662 key_type
= blink::WebCryptoKeyTypeSecret
;
665 case blink::WebCryptoAlgorithmIdHmac
: {
666 const blink::WebCryptoHmacKeyParams
* params
= algorithm
.hmacKeyParams();
668 if (params
->hasLengthBytes()) {
669 keylen_bytes
= params
->optionalLengthBytes();
671 keylen_bytes
= webcrypto::ShaBlockSizeBytes(params
->hash().id());
674 key_type
= blink::WebCryptoKeyTypeSecret
;
683 if (keylen_bytes
== 0) {
687 crypto::ScopedPK11Slot
slot(PK11_GetInternalKeySlot());
692 crypto::ScopedPK11SymKey
pk11_key(
693 PK11_KeyGen(slot
.get(), mech
, NULL
, keylen_bytes
, NULL
));
699 *key
= blink::WebCryptoKey::create(
700 new SymKeyHandle(pk11_key
.Pass()),
701 key_type
, extractable
, algorithm
, usage_mask
);
705 bool WebCryptoImpl::GenerateKeyPairInternal(
706 const blink::WebCryptoAlgorithm
& algorithm
,
708 blink::WebCryptoKeyUsageMask usage_mask
,
709 blink::WebCryptoKey
* public_key
,
710 blink::WebCryptoKey
* private_key
) {
712 // TODO(padolph): Handle other asymmetric algorithm key generation.
713 switch (algorithm
.id()) {
714 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5
:
715 case blink::WebCryptoAlgorithmIdRsaOaep
:
716 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
: {
717 const blink::WebCryptoRsaKeyGenParams
* const params
=
718 algorithm
.rsaKeyGenParams();
721 crypto::ScopedPK11Slot
slot(PK11_GetInternalKeySlot());
722 unsigned long public_exponent
;
723 if (!slot
|| !params
->modulusLengthBits() ||
724 !BigIntegerToLong(params
->publicExponent().data(),
725 params
->publicExponent().size(),
731 PK11RSAGenParams rsa_gen_params
;
732 rsa_gen_params
.keySizeInBits
= params
->modulusLengthBits();
733 rsa_gen_params
.pe
= public_exponent
;
735 // Flags are verified at the Blink layer; here the flags are set to all
736 // possible operations for the given key type.
737 CK_FLAGS operation_flags
;
738 switch (algorithm
.id()) {
739 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5
:
740 case blink::WebCryptoAlgorithmIdRsaOaep
:
741 operation_flags
= CKF_ENCRYPT
| CKF_DECRYPT
| CKF_WRAP
| CKF_UNWRAP
;
743 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
:
744 operation_flags
= CKF_SIGN
| CKF_VERIFY
;
750 const CK_FLAGS operation_flags_mask
= CKF_ENCRYPT
| CKF_DECRYPT
|
751 CKF_SIGN
| CKF_VERIFY
| CKF_WRAP
|
753 const PK11AttrFlags attribute_flags
= 0; // Default all PK11_ATTR_ flags.
755 // Note: NSS does not generate an sec_public_key if the call below fails,
756 // so there is no danger of a leaked sec_public_key.
757 SECKEYPublicKey
* sec_public_key
;
758 crypto::ScopedSECKEYPrivateKey
scoped_sec_private_key(
759 PK11_GenerateKeyPairWithOpFlags(slot
.get(),
760 CKM_RSA_PKCS_KEY_PAIR_GEN
,
765 operation_flags_mask
,
771 *public_key
= blink::WebCryptoKey::create(
772 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key
)),
773 blink::WebCryptoKeyTypePublic
,
777 *private_key
= blink::WebCryptoKey::create(
778 new PrivateKeyHandle(scoped_sec_private_key
.Pass()),
779 blink::WebCryptoKeyTypePrivate
,
791 bool WebCryptoImpl::ImportKeyInternal(
792 blink::WebCryptoKeyFormat format
,
793 const unsigned char* key_data
,
794 unsigned key_data_size
,
795 const blink::WebCryptoAlgorithm
& algorithm_or_null
,
797 blink::WebCryptoKeyUsageMask usage_mask
,
798 blink::WebCryptoKey
* key
) {
801 case blink::WebCryptoKeyFormatRaw
:
802 // A 'raw'-formatted key import requires an input algorithm.
803 if (algorithm_or_null
.isNull())
805 return ImportKeyInternalRaw(key_data
,
811 case blink::WebCryptoKeyFormatSpki
:
812 return ImportKeyInternalSpki(key_data
,
818 case blink::WebCryptoKeyFormatPkcs8
:
819 return ImportKeyInternalPkcs8(key_data
,
826 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above.
831 bool WebCryptoImpl::ExportKeyInternal(
832 blink::WebCryptoKeyFormat format
,
833 const blink::WebCryptoKey
& key
,
834 blink::WebArrayBuffer
* buffer
) {
836 case blink::WebCryptoKeyFormatRaw
:
837 return ExportKeyInternalRaw(key
, buffer
);
838 case blink::WebCryptoKeyFormatSpki
:
839 return ExportKeyInternalSpki(key
, buffer
);
840 case blink::WebCryptoKeyFormatPkcs8
:
841 // TODO(padolph): Implement pkcs8 export
848 bool WebCryptoImpl::SignInternal(
849 const blink::WebCryptoAlgorithm
& algorithm
,
850 const blink::WebCryptoKey
& key
,
851 const unsigned char* data
,
853 blink::WebArrayBuffer
* buffer
) {
854 blink::WebArrayBuffer result
;
856 switch (algorithm
.id()) {
857 case blink::WebCryptoAlgorithmIdHmac
: {
858 const blink::WebCryptoHmacParams
* params
= algorithm
.hmacParams();
863 SymKeyHandle
* sym_key
= reinterpret_cast<SymKeyHandle
*>(key
.handle());
865 DCHECK_EQ(PK11_GetMechanism(sym_key
->key()),
866 WebCryptoHashToHMACMechanism(params
->hash()));
867 DCHECK_NE(0, key
.usages() & blink::WebCryptoKeyUsageSign
);
869 SECItem param_item
= { siBuffer
, NULL
, 0 };
870 SECItem data_item
= {
872 const_cast<unsigned char*>(data
),
875 // First call is to figure out the length.
876 SECItem signature_item
= { siBuffer
, NULL
, 0 };
878 if (PK11_SignWithSymKey(sym_key
->key(),
879 PK11_GetMechanism(sym_key
->key()),
882 &data_item
) != SECSuccess
) {
887 DCHECK_NE(0u, signature_item
.len
);
889 result
= blink::WebArrayBuffer::create(signature_item
.len
, 1);
890 signature_item
.data
= reinterpret_cast<unsigned char*>(result
.data());
892 if (PK11_SignWithSymKey(sym_key
->key(),
893 PK11_GetMechanism(sym_key
->key()),
896 &data_item
) != SECSuccess
) {
901 DCHECK_EQ(result
.byteLength(), signature_item
.len
);
913 bool WebCryptoImpl::VerifySignatureInternal(
914 const blink::WebCryptoAlgorithm
& algorithm
,
915 const blink::WebCryptoKey
& key
,
916 const unsigned char* signature
,
917 unsigned signature_size
,
918 const unsigned char* data
,
920 bool* signature_match
) {
921 switch (algorithm
.id()) {
922 case blink::WebCryptoAlgorithmIdHmac
: {
923 blink::WebArrayBuffer result
;
924 if (!SignInternal(algorithm
, key
, data
, data_size
, &result
)) {
928 // Handling of truncated signatures is underspecified in the WebCrypto
929 // spec, so here we fail verification if a truncated signature is being
931 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097
933 result
.byteLength() == signature_size
&&
934 crypto::SecureMemEqual(result
.data(), signature
, signature_size
);
945 bool WebCryptoImpl::ImportRsaPublicKeyInternal(
946 const unsigned char* modulus_data
,
947 unsigned modulus_size
,
948 const unsigned char* exponent_data
,
949 unsigned exponent_size
,
950 const blink::WebCryptoAlgorithm
& algorithm
,
952 blink::WebCryptoKeyUsageMask usage_mask
,
953 blink::WebCryptoKey
* key
) {
955 if (!modulus_size
|| !exponent_size
)
957 DCHECK(modulus_data
);
958 DCHECK(exponent_data
);
960 // NSS does not provide a way to create an RSA public key directly from the
961 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
962 // with these values and create the public key from that. The code below
963 // follows the recommendation described in
964 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
966 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
967 // set up an ASN.1 encoder template for it.
968 struct RsaPublicKeyData
{
972 const RsaPublicKeyData pubkey_in
= {
973 {siUnsignedInteger
, const_cast<unsigned char*>(modulus_data
),
975 {siUnsignedInteger
, const_cast<unsigned char*>(exponent_data
),
977 const SEC_ASN1Template rsa_public_key_template
[] = {
978 {SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(RsaPublicKeyData
)},
979 {SEC_ASN1_INTEGER
, offsetof(RsaPublicKeyData
, modulus
), },
980 {SEC_ASN1_INTEGER
, offsetof(RsaPublicKeyData
, exponent
), },
983 // DER-encode the public key.
984 crypto::ScopedSECItem
pubkey_der(SEC_ASN1EncodeItem(
985 NULL
, NULL
, &pubkey_in
, rsa_public_key_template
));
989 // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
990 crypto::ScopedSECKEYPublicKey
pubkey(
991 SECKEY_ImportDERPublicKey(pubkey_der
.get(), CKK_RSA
));
995 *key
= blink::WebCryptoKey::create(new PublicKeyHandle(pubkey
.Pass()),
996 blink::WebCryptoKeyTypePublic
,
1003 } // namespace content