| 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 35c2ff3ba5f57c0532f5d462aed1cccb5c39c982..c8ba3ce38fff5eace411385d3b2fe02cac63afac 100644
|
| --- a/content/child/webcrypto/platform_crypto_nss.cc
|
| +++ b/content/child/webcrypto/platform_crypto_nss.cc
|
| @@ -486,6 +486,71 @@ Status WebCryptoAlgorithmToNssMechFlags(
|
| return Status::Success();
|
| }
|
|
|
| +Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
|
| + SymKey* wrapping_key,
|
| + CK_MECHANISM_TYPE mechanism,
|
| + CK_FLAGS flags,
|
| + crypto::ScopedPK11SymKey* unwrapped_key) {
|
| + DCHECK_GE(wrapped_key_data.byte_length(), 24u);
|
| + DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
|
| +
|
| + SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
|
| + crypto::ScopedSECItem param_item(
|
| + PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
|
| + if (!param_item)
|
| + return Status::ErrorUnexpected();
|
| +
|
| + SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
|
| +
|
| + // The plaintext length is always 64 bits less than the data size.
|
| + const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
|
| +
|
| + crypto::ScopedPK11SymKey new_key(PK11_UnwrapSymKey(wrapping_key->key(),
|
| + CKM_NSS_AES_KEY_WRAP,
|
| + param_item.get(),
|
| + &cipher_text,
|
| + mechanism,
|
| + flags,
|
| + plaintext_length));
|
| + // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
|
| + // accurate error, providing if doesn't leak any information to web pages
|
| + // about other web crypto users, key details, etc.
|
| + if (!new_key)
|
| + return Status::Error();
|
| +
|
| +// TODO(padolph): Change to "defined(USE_NSS)" once the NSS fix for
|
| +// https://bugzilla.mozilla.org/show_bug.cgi?id=981170 rolls into chromium.
|
| +#if 1
|
| + // ------- Start NSS bug workaround
|
| + // Workaround for https://code.google.com/p/chromium/issues/detail?id=349939
|
| + // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey, with
|
| + // a reasonable length but with key data pointing to uninitialized memory.
|
| + // This workaround re-wraps the key and compares the result with the incoming
|
| + // data, and fails if there is a difference. This prevents returning a bad key
|
| + // to the caller.
|
| + const unsigned int output_length = wrapped_key_data.byte_length();
|
| + std::vector<unsigned char> buffer(output_length, 0);
|
| + SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(buffer));
|
| + if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
|
| + param_item.get(),
|
| + wrapping_key->key(),
|
| + new_key.get(),
|
| + &wrapped_key_item)) {
|
| + return Status::Error();
|
| + }
|
| + if (wrapped_key_item.len != wrapped_key_data.byte_length() ||
|
| + memcmp(wrapped_key_item.data,
|
| + wrapped_key_data.bytes(),
|
| + wrapped_key_item.len) != 0) {
|
| + return Status::Error();
|
| + }
|
| +// ------- End NSS bug workaround
|
| +#endif
|
| +
|
| + *unwrapped_key = new_key.Pass();
|
| + return Status::Success();
|
| +}
|
| +
|
| } // namespace
|
|
|
| Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
|
| @@ -1145,20 +1210,6 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
|
| bool extractable,
|
| blink::WebCryptoKeyUsageMask usage_mask,
|
| blink::WebCryptoKey* key) {
|
| - DCHECK_GE(wrapped_key_data.byte_length(), 24u);
|
| - DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u);
|
| -
|
| - SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
|
| - crypto::ScopedSECItem param_item(
|
| - PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item));
|
| - if (!param_item)
|
| - return Status::ErrorUnexpected();
|
| -
|
| - SECItem cipher_text = MakeSECItemForBuffer(wrapped_key_data);
|
| -
|
| - // The plaintext length is always 64 bits less than the data size.
|
| - const unsigned int plaintext_length = wrapped_key_data.byte_length() - 8;
|
| -
|
| // Determine the proper NSS key properties from the input algorithm.
|
| CK_MECHANISM_TYPE mechanism;
|
| CK_FLAGS flags;
|
| @@ -1167,50 +1218,15 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
|
| if (status.IsError())
|
| return status;
|
|
|
| - crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(wrapping_key->key(),
|
| - CKM_NSS_AES_KEY_WRAP,
|
| - param_item.get(),
|
| - &cipher_text,
|
| - mechanism,
|
| - flags,
|
| - plaintext_length));
|
| - // TODO(padolph): Use NSS PORT_GetError() and friends to report a more
|
| - // accurate error, providing if doesn't leak any information to web pages
|
| - // about other web crypto users, key details, etc.
|
| - if (!unwrapped_key)
|
| - return Status::Error();
|
| -
|
| -// TODO(padolph): Change to "defined(USE_NSS)" once the NSS fix for
|
| -// https://bugzilla.mozilla.org/show_bug.cgi?id=981170 rolls into chromium.
|
| -#if 1
|
| - // ------- Start NSS bug workaround
|
| - // Workaround for https://code.google.com/p/chromium/issues/detail?id=349939
|
| - // If unwrap fails, NSS nevertheless returns a valid-looking PK11SymKey, with
|
| - // a reasonable length but with key data pointing to uninitialized memory.
|
| - // This workaround re-wraps the key and compares the result with the incoming
|
| - // data, and fails if there is a difference. This prevents returning a bad key
|
| - // to the caller.
|
| - const unsigned int output_length = wrapped_key_data.byte_length();
|
| - std::vector<unsigned char> buffer(output_length, 0);
|
| - SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(buffer));
|
| - if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
|
| - param_item.get(),
|
| - wrapping_key->key(),
|
| - unwrapped_key.get(),
|
| - &wrapped_key_item)) {
|
| - return Status::Error();
|
| - }
|
| - if (wrapped_key_item.len != wrapped_key_data.byte_length() ||
|
| - memcmp(wrapped_key_item.data,
|
| - wrapped_key_data.bytes(),
|
| - wrapped_key_item.len) != 0) {
|
| - return Status::Error();
|
| - }
|
| - // ------- End NSS bug workaround
|
| -#endif
|
| + crypto::ScopedPK11SymKey unwrapped_key;
|
| + status = DoUnwrapSymKeyAesKw(
|
| + wrapped_key_data, wrapping_key, mechanism, flags, &unwrapped_key);
|
| + if (status.IsError())
|
| + return status;
|
|
|
| blink::WebCryptoKeyAlgorithm key_algorithm;
|
| - if (!CreateSecretKeyAlgorithm(algorithm, plaintext_length, &key_algorithm))
|
| + if (!CreateSecretKeyAlgorithm(
|
| + algorithm, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm))
|
| return Status::ErrorUnexpected();
|
|
|
| *key = blink::WebCryptoKey::create(new SymKey(unwrapped_key.Pass()),
|
| @@ -1221,6 +1237,29 @@ Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
|
| return Status::Success();
|
| }
|
|
|
| +Status DecryptAesKw(SymKey* wrapping_key,
|
| + const CryptoData& data,
|
| + blink::WebArrayBuffer* buffer) {
|
| + // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be
|
| + // temporarily viewed as a symmetric key to be unwrapped (decrypted).
|
| + crypto::ScopedPK11SymKey decrypted;
|
| + Status status = DoUnwrapSymKeyAesKw(
|
| + data, wrapping_key, CKK_GENERIC_SECRET, CKA_ENCRYPT, &decrypted);
|
| + if (status.IsError())
|
| + return status;
|
| +
|
| + // Once the decrypt is complete, extract the resultant raw bytes from NSS and
|
| + // return them to the caller.
|
| + if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess)
|
| + return Status::Error();
|
| + const SECItem* const key_data = PK11_GetKeyData(decrypted.get());
|
| + if (!key_data)
|
| + return Status::Error();
|
| + *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
|
| +
|
| + return Status::Success();
|
| +}
|
| +
|
| Status WrapSymKeyRsaEs(PublicKey* wrapping_key,
|
| SymKey* key,
|
| blink::WebArrayBuffer* buffer) {
|
|
|