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

Unified Diff: content/child/webcrypto/platform_crypto_nss.cc

Issue 275943004: Add support for RSA-OAEP when using NSS 3.16.2 or later (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix ifdef Created 6 years, 7 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/child/webcrypto/platform_crypto.h ('k') | content/child/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..59002d9f9e3855bd6b32dd2d145b06cc02e5f2bf 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,38 @@ 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,
+ void*);
+
+// Signature for PK11_PrivDecrypt
+typedef SECStatus (*PK11_PrivDecryptFunction)(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_priv_decrypt_func_ &&
+ internal_slot_does_oaep_;
+ }
// Returns NULL if unsupported.
PK11_EncryptDecryptFunction pk11_encrypt_func() const {
@@ -85,14 +115,27 @@ 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_PrivDecryptFunction pk11_priv_decrypt_func() const {
+ return pk11_priv_decrypt_func_;
+ }
+
private:
- friend struct base::DefaultLazyInstanceTraits<AesGcmSupport>;
+ friend struct base::DefaultLazyInstanceTraits<NssRuntimeSupport>;
- AesGcmSupport() {
+ NssRuntimeSupport() : internal_slot_does_oaep_(false) {
#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_priv_decrypt_func_ = PK11_PrivDecrypt;
+ internal_slot_does_oaep_ = true;
#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 +146,34 @@ class AesGcmSupport {
dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
+
+ // Even though NSS's pk11wrap layer may support
+ // PK11_PubEncrypt/PK11_PubDecrypt (introduced in NSS 3.16.2), it may have
+ // loaded a softoken that does not include OAEP support.
+ pk11_pub_encrypt_func_ = reinterpret_cast<PK11_PubEncryptFunction>(
+ dlsym(RTLD_DEFAULT, "PK11_PubEncrypt"));
+ pk11_priv_decrypt_func_ = reinterpret_cast<PK11_PrivDecryptFunction>(
+ dlsym(RTLD_DEFAULT, "PK11_PrivDecrypt"));
+ if (pk11_priv_decrypt_func_ && pk11_pub_encrypt_func_) {
+ crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
+ internal_slot_does_oaep_ =
+ !!PK11_DoesMechanism(slot.get(), CKM_RSA_PKCS_OAEP);
+ }
#endif
}
PK11_EncryptDecryptFunction pk11_encrypt_func_;
PK11_EncryptDecryptFunction pk11_decrypt_func_;
+ PK11_PubEncryptFunction pk11_pub_encrypt_func_;
+ PK11_PrivDecryptFunction pk11_priv_decrypt_func_;
+ bool internal_slot_does_oaep_;
};
-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 +321,56 @@ 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;
+ }
+}
+
+bool 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);
+ oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash);
+
+ if (oaep_params->mgf == CKM_INVALID_MECHANISM ||
+ oaep_params->hashAlg == CKM_INVALID_MECHANISM) {
+ return false;
+ }
+
+ return true;
+}
+
Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
SymKey* key,
const CryptoData& iv,
@@ -337,7 +448,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 +494,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 +633,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;
@@ -973,9 +1084,12 @@ Status ExportKeyPkcs8(PrivateKey* key,
std::vector<uint8>* buffer) {
// TODO(eroman): Support other RSA key types as they are added to Blink.
if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 &&
- key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5)
+ key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 &&
+ key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaOaep)
return Status::ErrorUnsupported();
+// TODO(rsleevi): Implement OAEP support according to the spec.
+
#if defined(USE_NSS)
// PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
@@ -1176,6 +1290,89 @@ Status DecryptRsaEsPkcs1v1_5(PrivateKey* key,
}
// -----------------------------------
+// RsaOaep
+// -----------------------------------
+
+Status EncryptRsaOaep(PublicKey* key,
+ 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};
+ if (!InitializeRsaOaepParams(hash, label, &oaep_params))
+ return Status::ErrorUnsupported();
+
+ 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,
+ &param,
+ buffer_data,
+ &output_len,
+ buffer->size(),
+ data.bytes(),
+ data.byte_length(),
+ NULL) != 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())
+ return Status::ErrorUnsupported();
+
+ CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
+ if (!InitializeRsaOaepParams(hash, label, &oaep_params))
+ return Status::ErrorUnsupported();
+
+ 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_priv_decrypt_func()(
+ key->key(),
+ CKM_RSA_PKCS_OAEP,
+ &param,
+ 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
// -----------------------------------
@@ -1287,6 +1484,11 @@ Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoAlgorithm& hash_or_null,
blink::WebCryptoKey* public_key,
blink::WebCryptoKey* private_key) {
+ if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep &&
+ !g_nss_runtime_support.Get().IsRsaOaepSupported()) {
+ return Status::ErrorUnsupported();
+ }
+
crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
if (!slot)
return Status::OperationError();
« no previous file with comments | « content/child/webcrypto/platform_crypto.h ('k') | content/child/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698