Chromium Code Reviews| Index: content/renderer/webcrypto/webcrypto_impl_nss.cc |
| diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc |
| index 452d2a7c91dd34a52df66934b85ed8cd4e179627..e12031a3c1905c9ca536feb42ba15b1c3d6777bf 100644 |
| --- a/content/renderer/webcrypto/webcrypto_impl_nss.cc |
| +++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc |
| @@ -24,10 +24,7 @@ namespace { |
| class SymKeyHandle : public WebKit::WebCryptoKeyHandle { |
| public: |
| - explicit SymKeyHandle(crypto::ScopedPK11SymKey key) { |
| - DCHECK(!key_.get()); |
| - key_ = key.Pass(); |
| - } |
| + explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} |
| PK11SymKey* key() { return key_.get(); } |
| @@ -37,6 +34,32 @@ class SymKeyHandle : public WebKit::WebCryptoKeyHandle { |
| DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); |
| }; |
| +class PublicKeyHandle : public WebKit::WebCryptoKeyHandle { |
| + public: |
| + explicit PublicKeyHandle(crypto::ScopedSECKEYPublicKey key) |
| + : key_(key.Pass()) {} |
| + |
| + SECKEYPublicKey* key() { return key_.get(); } |
| + |
| + private: |
| + crypto::ScopedSECKEYPublicKey key_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PublicKeyHandle); |
| +}; |
| + |
| +class PrivateKeyHandle : public WebKit::WebCryptoKeyHandle { |
| + public: |
| + explicit PrivateKeyHandle(crypto::ScopedSECKEYPrivateKey key) |
| + : key_(key.Pass()) {} |
| + |
| + SECKEYPrivateKey* key() { return key_.get(); } |
| + |
| + private: |
| + crypto::ScopedSECKEYPrivateKey key_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PrivateKeyHandle); |
| +}; |
| + |
| HASH_HashType WebCryptoAlgorithmToNSSHashType( |
| const WebKit::WebCryptoAlgorithm& algorithm) { |
| switch (algorithm.id()) { |
| @@ -102,7 +125,7 @@ bool AesCbcEncryptDecrypt( |
| if (!context.get()) |
| return false; |
| - // Oddly PK11_CipherOp takes input and output lenths as "int" rather than |
| + // Oddly PK11_CipherOp takes input and output lengths as "int" rather than |
| // "unsigned". Do some checks now to avoid integer overflowing. |
| if (data_size >= INT_MAX - AES_BLOCK_SIZE) { |
| // TODO(eroman): Handle this by chunking the input fed into NSS. Right now |
| @@ -193,6 +216,28 @@ unsigned int WebCryptoHmacAlgorithmToBlockSize( |
| } |
| } |
| +// Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, |
| +// to unsigned long. |
| +bool BigIntegerToLong(const uint8* data, |
| + unsigned data_size, |
| + unsigned long* result) { |
| + // TODO(padolph): Is it correct to say that empty data is an error, or does it |
| + // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655 |
| + if (data_size == 0) |
| + return false; |
| + |
| + *result = 0; |
| + for (size_t i = 0; i < data_size; ++i) { |
| + size_t reverse_i = data_size - i - 1; |
| + |
| + if (reverse_i >= sizeof(unsigned long) && data[i]) |
| + return false; // Too large for a long. |
| + |
| + *result |= data[i] << 8 * reverse_i; |
| + } |
| + return true; |
| +} |
| + |
| } // namespace |
| void WebCryptoImpl::Init() { |
| @@ -324,6 +369,94 @@ bool WebCryptoImpl::GenerateKeyInternal( |
| return true; |
| } |
| +bool WebCryptoImpl::GenerateKeyPairInternal( |
| + const WebKit::WebCryptoAlgorithm& algorithm, |
| + bool extractable, |
| + WebKit::WebCryptoKeyUsageMask usage_mask, |
| + WebKit::WebCryptoKey* public_key, |
| + WebKit::WebCryptoKey* private_key) { |
| + |
| + // TODO(padolph): Handle other asymmetric algorithm key generation. |
| + switch (algorithm.id()) { |
| + case WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
| + case WebKit::WebCryptoAlgorithmIdRsaOaep: |
| + case WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { |
| + const WebKit::WebCryptoRsaKeyGenParams* const params = |
| + algorithm.rsaKeyGenParams(); |
| + DCHECK(params); |
| + |
| + crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); |
| + unsigned long public_exponent; |
| + if (!slot || !params->modulusLength() || |
| + !BigIntegerToLong(params->publicExponent().data(), |
| + params->publicExponent().size(), |
| + &public_exponent) || |
| + !public_exponent) { |
| + return false; |
| + } |
| + |
| + PK11RSAGenParams rsa_gen_params; |
| + rsa_gen_params.keySizeInBits = params->modulusLength(); |
| + rsa_gen_params.pe = public_exponent; |
| + |
| + // Flags are verified at the Blink layer; here the flags are set to all |
| + // possible operations for the given key type. |
| + CK_FLAGS operation_flags; |
| + switch (algorithm.id()) { |
| + case WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
| + case WebKit::WebCryptoAlgorithmIdRsaOaep: |
| + operation_flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; |
| + break; |
| + case WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: |
| + operation_flags = CKF_SIGN | CKF_VERIFY; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + return false; |
| + } |
| + const CK_FLAGS operation_flags_mask = CKF_ENCRYPT | CKF_DECRYPT | |
| + CKF_SIGN | CKF_VERIFY | CKF_WRAP | |
| + CKF_UNWRAP; |
| + const PK11AttrFlags attribute_flags = 0; // Default all PK11_ATTR_ flags. |
| + |
| + // Note: NSS does not generate an sec_public_key if the call below fails, |
| + // so there is no danger of a leaked sec_public_key. |
| + SECKEYPublicKey* sec_public_key; |
| + crypto::ScopedSECKEYPrivateKey scoped_sec_private_key( |
| + PK11_GenerateKeyPairWithOpFlags(slot.get(), |
| + CKM_RSA_PKCS_KEY_PAIR_GEN, |
| + &rsa_gen_params, |
| + &sec_public_key, |
| + attribute_flags, |
| + operation_flags, |
| + operation_flags_mask, |
| + NULL)); |
| + if (!private_key) { |
| + return false; |
| + } |
| + |
| + // The 'extractable' input parameter applies to the private key here. |
| + // Make the public key always extractable. |
|
eroman
2013/10/31 22:18:36
I don't see anything about this in the spec.
My i
Ryan Sleevi
2013/10/31 22:23:20
File a spec bug. Current spec indicates both keys
eroman
2013/10/31 22:30:07
Done: https://www.w3.org/Bugs/Public/show_bug.cgi?
padolph
2013/11/01 20:35:31
Done.
|
| + *public_key = WebKit::WebCryptoKey::create( |
| + new PublicKeyHandle( |
| + crypto::ScopedSECKEYPublicKey(sec_public_key).Pass()), |
|
eroman
2013/10/31 22:18:36
Is the .Pass() needed ?
padolph
2013/11/01 20:35:31
No. Done.
|
| + WebKit::WebCryptoKeyTypePublic, |
| + true, |
| + algorithm, |
| + usage_mask); |
| + *private_key = WebKit::WebCryptoKey::create( |
| + new PrivateKeyHandle(scoped_sec_private_key.Pass()), |
| + WebKit::WebCryptoKeyTypePrivate, |
| + extractable, |
| + algorithm, |
| + usage_mask); |
| + |
| + return true; |
| + } |
| + default: |
| + return false; |
| + } |
| +} |
| bool WebCryptoImpl::ImportKeyInternal( |
| WebKit::WebCryptoKeyFormat format, |