| 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,
|
| + ¶m,
|
| + 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,
|
| + ¶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
|
| // -----------------------------------
|
|
|
| @@ -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();
|
|
|