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 |
// ----------------------------------- |