Commit 30a7b128 authored by eroman@chromium.org's avatar eroman@chromium.org

[webcrypto] Remove a special case for AES-KW wrapping/unwrapping.

Now the same export+encrypt / decrypt+import codepath is used as for other wrapping algorithms.

The new code is less efficient (creates a temporary raw key), however simplifies things, and allows wrapping to be done on non-raw keys (however because of size constraints is likely to fail).

BUG=373544,245025

Review URL: https://codereview.chromium.org/335463002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276890 0039d316-1c4b-4281-b951-d872f2087c98
parent 2f4fc026
......@@ -272,40 +272,16 @@ Status ExportKeyPkcs8(PrivateKey* key,
const blink::WebCryptoKeyAlgorithm& key_algorithm,
std::vector<uint8>* buffer);
// Performs AES-KW encryption/decryption on the input |data|.
// Preconditions:
// * |key| is non-null
// * |wrapping_key| is non-null
Status WrapSymKeyAesKw(SymKey* key,
SymKey* wrapping_key,
std::vector<uint8>* buffer);
// Unwraps (decrypts) |wrapped_key_data| using AES-KW and places the results in
// a WebCryptoKey. Raw key data remains inside NSS. This function should be used
// when the input |wrapped_key_data| is known to result in symmetric raw key
// data after AES-KW decryption.
// Preconditions:
// * |wrapping_key| is non-null
// * |key| is non-null
// * |wrapped_key_data| is at least 24 bytes and a multiple of 8 bytes
// * |algorithm.id()| is for a symmetric key algorithm.
// * usage_mask makes sense for the algorithm.
Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
SymKey* wrapping_key,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key);
// Performs AES-KW decryption on the input |data|. This function should be used
// when the input |data| does not directly represent a key and should instead be
// interpreted as generic bytes.
// Preconditions:
// * |key| is non-null
// * |data| is at least 24 bytes and a multiple of 8 bytes
// * |data| is multiple of 8 bytes. If encrypting it is at least 16 bytes, and
// if decrypting at least 24 bytes.
// * |buffer| is non-null.
Status DecryptAesKw(SymKey* key,
const CryptoData& data,
std::vector<uint8>* buffer);
Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
SymKey* key,
const CryptoData& data,
std::vector<uint8>* buffer);
} // namespace platform
......
......@@ -584,29 +584,28 @@ Status WebCryptoAlgorithmToNssMechFlags(
if (*mechanism == CKM_INVALID_MECHANISM)
return Status::ErrorUnsupported();
*flags = CKF_SIGN | CKF_VERIFY;
break;
return Status::Success();
}
case blink::WebCryptoAlgorithmIdAesCbc: {
*mechanism = CKM_AES_CBC;
*flags = CKF_ENCRYPT | CKF_DECRYPT;
break;
return Status::Success();
}
case blink::WebCryptoAlgorithmIdAesKw: {
*mechanism = CKM_NSS_AES_KEY_WRAP;
*flags = CKF_WRAP | CKF_WRAP;
break;
return Status::Success();
}
case blink::WebCryptoAlgorithmIdAesGcm: {
if (!g_nss_runtime_support.Get().IsAesGcmSupported())
return Status::ErrorUnsupported();
*mechanism = CKM_AES_GCM;
*flags = CKF_ENCRYPT | CKF_DECRYPT;
break;
return Status::Success();
}
default:
return Status::ErrorUnsupported();
}
return Status::Success();
}
Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
......@@ -883,8 +882,8 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey* key) {
DCHECK(!algorithm.isNull());
CK_MECHANISM_TYPE mechanism;
CK_FLAGS flags;
CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
CK_FLAGS flags = 0;
Status status =
WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
if (status.IsError())
......@@ -1764,7 +1763,7 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::Success();
}
Status WrapSymKeyAesKw(SymKey* key,
Status WrapSymKeyAesKw(PK11SymKey* key,
SymKey* wrapping_key,
std::vector<uint8>* buffer) {
// The data size must be at least 16 bytes and a multiple of 8 bytes.
......@@ -1772,13 +1771,11 @@ Status WrapSymKeyAesKw(SymKey* key,
// keys are being wrapped in this application (which are small), a reasonable
// max limit is whatever will fit into an unsigned. For the max size test,
// note that AES Key Wrap always adds 8 bytes to the input data size.
const unsigned int input_length = PK11_GetKeyLength(key->key());
if (input_length < 16)
return Status::ErrorDataTooSmall();
const unsigned int input_length = PK11_GetKeyLength(key);
DCHECK_GE(input_length, 16u);
DCHECK((input_length % 8) == 0);
if (input_length > UINT_MAX - 8)
return Status::ErrorDataTooLarge();
if (input_length % 8)
return Status::ErrorInvalidAesKwDataLength();
SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
crypto::ScopedSECItem param_item(
......@@ -1793,7 +1790,7 @@ Status WrapSymKeyAesKw(SymKey* key,
if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
param_item.get(),
wrapping_key->key(),
key->key(),
key,
&wrapped_key_item)) {
return Status::OperationError();
}
......@@ -1803,44 +1800,6 @@ Status WrapSymKeyAesKw(SymKey* key,
return Status::Success();
}
Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
SymKey* wrapping_key,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
// Determine the proper NSS key properties from the input algorithm.
CK_MECHANISM_TYPE mechanism;
CK_FLAGS flags;
Status status =
WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
if (status.IsError())
return status;
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, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm))
return Status::ErrorUnexpected();
scoped_ptr<SymKey> key_handle;
status = SymKey::Create(unwrapped_key.Pass(), &key_handle);
if (status.IsError())
return status;
*key = blink::WebCryptoKey::create(key_handle.release(),
blink::WebCryptoKeyTypeSecret,
extractable,
key_algorithm,
usage_mask);
return Status::Success();
}
Status DecryptAesKw(SymKey* wrapping_key,
const CryptoData& data,
std::vector<uint8>* buffer) {
......@@ -1864,6 +1823,33 @@ Status DecryptAesKw(SymKey* wrapping_key,
return Status::Success();
}
Status EncryptAesKw(SymKey* wrapping_key,
const CryptoData& data,
std::vector<uint8>* buffer) {
// Due to limitations in the NSS API for the AES-KW algorithm, |data| must be
// temporarily viewed as a symmetric key to be wrapped (encrypted).
SECItem data_item = MakeSECItemForBuffer(data);
crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
crypto::ScopedPK11SymKey data_as_sym_key(PK11_ImportSymKey(slot.get(),
CKK_GENERIC_SECRET,
PK11_OriginUnwrap,
CKA_SIGN,
&data_item,
NULL));
if (!data_as_sym_key)
return Status::OperationError();
return WrapSymKeyAesKw(data_as_sym_key.get(), wrapping_key, buffer);
}
Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
SymKey* wrapping_key,
const CryptoData& data,
std::vector<uint8>* buffer) {
return mode == ENCRYPT ? EncryptAesKw(wrapping_key, data, buffer)
: DecryptAesKw(wrapping_key, data, buffer);
}
} // namespace platform
} // namespace webcrypto
......
......@@ -494,26 +494,10 @@ Status ExportRsaPrivateKey(PrivateKey* key,
return Status::ErrorUnsupported();
}
Status WrapSymKeyAesKw(SymKey* key,
SymKey* wrapping_key,
std::vector<uint8>* buffer) {
// TODO(eroman): http://crbug.com/267888
return Status::ErrorUnsupported();
}
Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
SymKey* wrapping_key,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
// TODO(eroman): http://crbug.com/267888
return Status::ErrorUnsupported();
}
Status DecryptAesKw(SymKey* key,
const CryptoData& data,
std::vector<uint8>* buffer) {
Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
SymKey* key,
const CryptoData& data,
std::vector<uint8>* buffer) {
// TODO(eroman): http://crbug.com/267888
return Status::ErrorUnsupported();
}
......
......@@ -308,82 +308,26 @@ bool ValidateDeserializedKey(const blink::WebCryptoKey& key,
return true;
}
// Validates the size of data input to AES-KW. AES-KW requires the input data
// size to be at least 24 bytes and a multiple of 8 bytes.
Status CheckAesKwInputSize(const CryptoData& aeskw_input_data) {
if (aeskw_input_data.byte_length() < 24)
return Status::ErrorDataTooSmall();
if (aeskw_input_data.byte_length() % 8)
return Status::ErrorInvalidAesKwDataLength();
return Status::Success();
}
Status UnwrapKeyRaw(const CryptoData& wrapped_key_data,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& wrapping_algorithm,
const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
blink::WebCryptoKey* key) {
// TODO(padolph): Handle other wrapping algorithms
switch (wrapping_algorithm.id()) {
case blink::WebCryptoAlgorithmIdAesKw: {
platform::SymKey* platform_wrapping_key;
Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key);
if (status.IsError())
return status;
status = CheckAesKwInputSize(wrapped_key_data);
if (status.IsError())
return status;
return platform::UnwrapSymKeyAesKw(wrapped_key_data,
platform_wrapping_key,
algorithm,
extractable,
usage_mask,
key);
}
default:
return Status::ErrorUnsupported();
}
}
Status WrapKeyRaw(const blink::WebCryptoKey& key_to_wrap,
const blink::WebCryptoKey& wrapping_key,
const blink::WebCryptoAlgorithm& wrapping_algorithm,
std::vector<uint8>* buffer) {
// A raw key is always a symmetric key.
platform::SymKey* platform_key;
Status status = ToPlatformSymKey(key_to_wrap, &platform_key);
if (status.IsError())
return status;
// TODO(padolph): Handle other wrapping algorithms
switch (wrapping_algorithm.id()) {
case blink::WebCryptoAlgorithmIdAesKw: {
platform::SymKey* platform_wrapping_key;
status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key);
if (status.IsError())
return status;
return platform::WrapSymKeyAesKw(
platform_key, platform_wrapping_key, buffer);
}
default:
return Status::ErrorUnsupported();
}
}
Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) {
Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
const blink::WebCryptoAlgorithm& algorithm,
const blink::WebCryptoKey& key,
const CryptoData& data,
std::vector<uint8>* buffer) {
platform::SymKey* sym_key;
Status status = ToPlatformSymKey(key, &sym_key);
if (status.IsError())
return status;
status = CheckAesKwInputSize(data);
unsigned int min_length = mode == ENCRYPT ? 16 : 24;
if (data.byte_length() < min_length)
return Status::ErrorDataTooSmall();
if (data.byte_length() % 8)
return Status::ErrorInvalidAesKwDataLength();
if (status.IsError())
return status;
return platform::DecryptAesKw(sym_key, data, buffer);
return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer);
}
Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
......@@ -400,7 +344,7 @@ Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
case blink::WebCryptoAlgorithmIdRsaOaep:
return DecryptRsaOaep(algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdAesKw:
return DecryptAesKw(algorithm, key, data, buffer);
return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer);
default:
return Status::ErrorUnsupported();
}
......@@ -417,6 +361,8 @@ Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdAesGcm:
return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdAesKw:
return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdRsaOaep:
return EncryptRsaOaep(algorithm, key, data, buffer);
default:
......@@ -892,13 +838,6 @@ Status WrapKey(blink::WebCryptoKeyFormat format,
if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
return Status::ErrorUnexpected();
if (format == blink::WebCryptoKeyFormatRaw &&
wrapping_algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
// AES-KW is a special case, due to NSS's implementation only
// supporting C_Wrap/C_Unwrap with AES-KW
return WrapKeyRaw(key_to_wrap, wrapping_key, wrapping_algorithm, buffer);
}
return WrapKeyExportAndEncrypt(
format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer);
}
......@@ -924,19 +863,6 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format,
if (status.IsError())
return status;
if (format == blink::WebCryptoKeyFormatRaw &&
wrapping_algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
// AES-KW is a special case, due to NSS's implementation only
// supporting C_Wrap/C_Unwrap with AES-KW
return UnwrapKeyRaw(wrapped_key_data,
wrapping_key,
wrapping_algorithm,
algorithm,
extractable,
usage_mask,
key);
}
return UnwrapKeyDecryptAndImport(format,
wrapped_key_data,
wrapping_key,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment