Chromium Code Reviews| Index: content/child/webcrypto/platform_crypto_nss.cc |
| diff --git a/content/child/webcrypto/platform_crypto_nss.cc b/content/child/webcrypto/platform_crypto_nss.cc |
| index eebd9e071b445b39baec6ae805a7f52d6456405e..f922c970fe20a0d9759a47228005267c45ae95fe 100644 |
| --- a/content/child/webcrypto/platform_crypto_nss.cc |
| +++ b/content/child/webcrypto/platform_crypto_nss.cc |
| @@ -60,6 +60,8 @@ struct CK_GCM_PARAMS { |
| }; |
| #endif // !defined(CKM_AES_GCM) |
| +namespace { |
| + |
| // Signature for PK11_Encrypt and PK11_Decrypt. |
| typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*, |
| CK_MECHANISM_TYPE, |
| @@ -70,10 +72,36 @@ typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*, |
| const unsigned char*, |
| unsigned int); |
| +// Signature for PK11_PubEncrypt |
| +typedef SECStatus (*PK11_PubEncryptFunction)(SECKEYPublicKey*, |
| + CK_MECHANISM_TYPE, |
| + SECItem*, |
| + unsigned char*, |
| + unsigned int*, |
| + unsigned int, |
| + const unsigned char*, |
| + unsigned int); |
| + |
| +// Signature for PK11_PubDecrypt |
| +typedef SECStatus (*PK11_PubDecryptFunction)(SECKEYPrivateKey*, |
| + CK_MECHANISM_TYPE, |
| + SECItem*, |
| + unsigned char*, |
| + unsigned int*, |
| + unsigned int, |
| + const unsigned char*, |
| + unsigned int); |
| + |
| // Singleton to abstract away dynamically loading libnss3.so |
| -class AesGcmSupport { |
| +class NssRuntimeSupport { |
| public: |
| - bool IsSupported() const { return pk11_encrypt_func_ && pk11_decrypt_func_; } |
| + bool IsAesGcmSupported() const { |
| + return pk11_encrypt_func_ && pk11_decrypt_func_; |
| + } |
| + |
| + bool IsRsaOaepSupported() const { |
| + return pk11_pub_encrypt_func_ && pk11_pub_decrypt_func_; |
| + } |
|
Ryan Sleevi
2014/05/14 01:26:00
Note: For both the AES-GCM case and the RSA-OAEP,
|
| // Returns NULL if unsupported. |
| PK11_EncryptDecryptFunction pk11_encrypt_func() const { |
| @@ -85,14 +113,26 @@ class AesGcmSupport { |
| return pk11_decrypt_func_; |
| } |
| + // Returns NULL if unsupported. |
| + PK11_PubEncryptFunction pk11_pub_encrypt_func() const { |
| + return pk11_pub_encrypt_func_; |
| + } |
| + |
| + // Returns NULL if unsupported. |
| + PK11_PubDecryptFunction pk11_pub_decrypt_func() const { |
| + return pk11_pub_decrypt_func_; |
| + } |
| + |
| private: |
| - friend struct base::DefaultLazyInstanceTraits<AesGcmSupport>; |
| + friend struct base::DefaultLazyInstanceTraits<NssRuntimeSupport>; |
| - AesGcmSupport() { |
| + NssRuntimeSupport() { |
| #if !defined(USE_NSS) |
| // Using a bundled version of NSS that is guaranteed to have this symbol. |
| pk11_encrypt_func_ = PK11_Encrypt; |
| pk11_decrypt_func_ = PK11_Decrypt; |
| + pk11_pub_encrypt_func_ = PK11_PubEncrypt; |
| + pk11_pub_decrypt_func_ = PK11_PubDecrypt; |
| #else |
| // Using system NSS libraries and PCKS #11 modules, which may not have the |
| // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM). |
| @@ -103,16 +143,24 @@ class AesGcmSupport { |
| dlsym(RTLD_DEFAULT, "PK11_Encrypt")); |
| pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>( |
| dlsym(RTLD_DEFAULT, "PK11_Decrypt")); |
| + pk11_pub_encrypt_func_ = reinterpret_cast<PK11_PubEncryptFunction>( |
| + dlsym(RTLD_DEFAULT, "PK11_PubEncrypt")); |
| + pk11_pub_decrypt_func_ = reinterpret_cast<PK11_PubDecryptFunction>( |
| + dlsym(RTLD_DEFAULT, "PK11_PubDecrypt")); |
| #endif |
| } |
| PK11_EncryptDecryptFunction pk11_encrypt_func_; |
| PK11_EncryptDecryptFunction pk11_decrypt_func_; |
| + PK11_PubEncryptFunction pk11_pub_encrypt_func_; |
| + PK11_PubDecryptFunction pk11_pub_decrypt_func_; |
| }; |
| -base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = |
| +base::LazyInstance<NssRuntimeSupport>::Leaky g_nss_runtime_support = |
| LAZY_INSTANCE_INITIALIZER; |
| +} // namespace |
| + |
| namespace content { |
| namespace webcrypto { |
| @@ -260,6 +308,49 @@ CK_MECHANISM_TYPE WebCryptoHashToHMACMechanism( |
| } |
| } |
| +CK_MECHANISM_TYPE WebCryptoHashToDigestMechanism( |
| + const blink::WebCryptoAlgorithm& algorithm) { |
| + switch (algorithm.id()) { |
| + case blink::WebCryptoAlgorithmIdSha1: |
| + return CKM_SHA_1; |
| + case blink::WebCryptoAlgorithmIdSha256: |
| + return CKM_SHA256; |
| + case blink::WebCryptoAlgorithmIdSha384: |
| + return CKM_SHA384; |
| + case blink::WebCryptoAlgorithmIdSha512: |
| + return CKM_SHA512; |
| + default: |
| + // Not a supported algorithm. |
| + return CKM_INVALID_MECHANISM; |
| + } |
| +} |
| + |
| +CK_MECHANISM_TYPE WebCryptoHashToMGFMechanism( |
| + const blink::WebCryptoAlgorithm& algorithm) { |
| + switch (algorithm.id()) { |
| + case blink::WebCryptoAlgorithmIdSha1: |
| + return CKG_MGF1_SHA1; |
| + case blink::WebCryptoAlgorithmIdSha256: |
| + return CKG_MGF1_SHA256; |
| + case blink::WebCryptoAlgorithmIdSha384: |
| + return CKG_MGF1_SHA384; |
| + case blink::WebCryptoAlgorithmIdSha512: |
| + return CKG_MGF1_SHA512; |
| + default: |
| + return CKM_INVALID_MECHANISM; |
| + } |
| +} |
| + |
| +void InitializeRsaOaepParams(const blink::WebCryptoAlgorithm& hash, |
| + const CryptoData& label, |
| + CK_RSA_PKCS_OAEP_PARAMS* oaep_params) { |
| + oaep_params->source = CKZ_DATA_SPECIFIED; |
| + oaep_params->pSourceData = const_cast<unsigned char*>(label.bytes()); |
| + oaep_params->ulSourceDataLen = label.byte_length(); |
| + oaep_params->mgf = WebCryptoHashToMGFMechanism(hash); |
|
eroman
2014/05/14 01:50:47
What is the consequence of failure for WebCryptoHa
Ryan Sleevi
2014/05/14 06:09:57
Officially: "It depends".
Practically: No
PKCS#11
|
| + oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash); |
|
eroman
2014/05/14 01:50:47
Same question above, for the sake of future proofi
|
| +} |
| + |
| Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, |
| SymKey* key, |
| const CryptoData& iv, |
| @@ -337,7 +428,7 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, |
| const CryptoData& additional_data, |
| unsigned int tag_length_bits, |
| std::vector<uint8>* buffer) { |
| - if (!g_aes_gcm_support.Get().IsSupported()) |
| + if (!g_nss_runtime_support.Get().IsAesGcmSupported()) |
| return Status::ErrorUnsupported(); |
| unsigned int tag_length_bytes = tag_length_bits / 8; |
| @@ -383,8 +474,8 @@ Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, |
| unsigned char* buffer_data = Uint8VectorStart(buffer); |
| PK11_EncryptDecryptFunction func = |
| - (mode == ENCRYPT) ? g_aes_gcm_support.Get().pk11_encrypt_func() |
| - : g_aes_gcm_support.Get().pk11_decrypt_func(); |
| + (mode == ENCRYPT) ? g_nss_runtime_support.Get().pk11_encrypt_func() |
| + : g_nss_runtime_support.Get().pk11_decrypt_func(); |
| unsigned int output_len = 0; |
| SECStatus result = func(key->key(), |
| @@ -522,7 +613,7 @@ Status WebCryptoAlgorithmToNssMechFlags( |
| break; |
| } |
| case blink::WebCryptoAlgorithmIdAesGcm: { |
| - if (!g_aes_gcm_support.Get().IsSupported()) |
| + if (!g_nss_runtime_support.Get().IsAesGcmSupported()) |
| return Status::ErrorUnsupported(); |
| *mechanism = CKM_AES_GCM; |
| *flags = CKF_ENCRYPT | CKF_DECRYPT; |
| @@ -1176,6 +1267,86 @@ Status DecryptRsaEsPkcs1v1_5(PrivateKey* key, |
| } |
| // ----------------------------------- |
| +// RsaOaep |
| +// ----------------------------------- |
| +Status EncryptRsaOaep(PublicKey* key, |
|
eroman
2014/05/14 01:50:47
nit: for consistency add a new line after --------
|
| + const blink::WebCryptoAlgorithm& hash, |
| + const CryptoData& label, |
| + const CryptoData& data, |
| + std::vector<uint8>* buffer) { |
| + if (!g_nss_runtime_support.Get().IsRsaOaepSupported()) |
| + return Status::ErrorUnsupported(); |
| + |
| + CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0}; |
| + InitializeRsaOaepParams(hash, label, &oaep_params); |
| + |
|
padolph
2014/05/14 02:00:03
Do we need to check the length of the input |data|
|
| + SECItem param; |
| + param.type = siBuffer; |
| + param.data = reinterpret_cast<unsigned char*>(&oaep_params); |
| + param.len = sizeof(oaep_params); |
| + |
| + buffer->resize(SECKEY_PublicKeyStrength(key->key())); |
| + unsigned char* buffer_data = Uint8VectorStart(buffer); |
| + unsigned int output_len; |
| + if (g_nss_runtime_support.Get().pk11_pub_encrypt_func()( |
| + key->key(), |
| + CKM_RSA_PKCS_OAEP, |
| + ¶m, |
| + buffer_data, |
| + &output_len, |
| + buffer->size(), |
| + data.bytes(), |
| + data.byte_length() != SECSuccess)) { |
| + return Status::OperationError(); |
| + } |
| + |
| + DCHECK_LE(output_len, buffer->size()); |
| + buffer->resize(output_len); |
| + return Status::Success(); |
| +} |
| + |
| +Status DecryptRsaOaep(PrivateKey* key, |
| + const blink::WebCryptoAlgorithm& hash, |
| + const CryptoData& label, |
| + const CryptoData& data, |
| + std::vector<uint8>* buffer) { |
| + if (!g_nss_runtime_support.Get().IsRsaOaepSupported()) |
|
eroman
2014/05/14 01:50:47
We might consider failing with ErrorUnsupported du
Ryan Sleevi
2014/05/14 02:34:30
Good point.
|
| + return Status::ErrorUnsupported(); |
| + |
| + CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0}; |
| + InitializeRsaOaepParams(hash, label, &oaep_params); |
| + |
| + SECItem param; |
| + param.type = siBuffer; |
| + param.data = reinterpret_cast<unsigned char*>(&oaep_params); |
| + param.len = sizeof(oaep_params); |
| + |
| + const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key()); |
| + if (modulus_length_bytes <= 0) |
| + return Status::ErrorUnexpected(); |
| + |
| + buffer->resize(modulus_length_bytes); |
| + |
| + unsigned char* buffer_data = Uint8VectorStart(buffer); |
| + unsigned int output_len; |
| + if (g_nss_runtime_support.Get().pk11_pub_decrypt_func()( |
| + key->key(), |
| + CKM_RSA_PKCS_OAEP, |
| + ¶m, |
| + buffer_data, |
| + &output_len, |
| + buffer->size(), |
| + data.bytes(), |
| + data.byte_length() != SECSuccess)) { |
| + return Status::OperationError(); |
| + } |
| + |
| + DCHECK_LE(output_len, buffer->size()); |
| + buffer->resize(output_len); |
| + return Status::Success(); |
| +} |
| + |
| +// ----------------------------------- |
| // RsaSsaPkcs1v1_5 |
| // ----------------------------------- |