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,38 +272,14 @@ Status ExportKeyPkcs8(PrivateKey* key, ...@@ -272,38 +272,14 @@ Status ExportKeyPkcs8(PrivateKey* key,
const blink::WebCryptoKeyAlgorithm& key_algorithm, const blink::WebCryptoKeyAlgorithm& key_algorithm,
std::vector<uint8>* buffer); std::vector<uint8>* buffer);
// Performs AES-KW encryption/decryption on the input |data|.
// Preconditions: // Preconditions:
// * |key| is non-null // * |key| is non-null
// * |wrapping_key| is non-null // * |data| is multiple of 8 bytes. If encrypting it is at least 16 bytes, and
Status WrapSymKeyAesKw(SymKey* key, // if decrypting at least 24 bytes.
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
// * |buffer| is non-null. // * |buffer| is non-null.
Status DecryptAesKw(SymKey* key, Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
SymKey* key,
const CryptoData& data, const CryptoData& data,
std::vector<uint8>* buffer); std::vector<uint8>* buffer);
......
...@@ -584,29 +584,28 @@ Status WebCryptoAlgorithmToNssMechFlags( ...@@ -584,29 +584,28 @@ Status WebCryptoAlgorithmToNssMechFlags(
if (*mechanism == CKM_INVALID_MECHANISM) if (*mechanism == CKM_INVALID_MECHANISM)
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
*flags = CKF_SIGN | CKF_VERIFY; *flags = CKF_SIGN | CKF_VERIFY;
break; return Status::Success();
} }
case blink::WebCryptoAlgorithmIdAesCbc: { case blink::WebCryptoAlgorithmIdAesCbc: {
*mechanism = CKM_AES_CBC; *mechanism = CKM_AES_CBC;
*flags = CKF_ENCRYPT | CKF_DECRYPT; *flags = CKF_ENCRYPT | CKF_DECRYPT;
break; return Status::Success();
} }
case blink::WebCryptoAlgorithmIdAesKw: { case blink::WebCryptoAlgorithmIdAesKw: {
*mechanism = CKM_NSS_AES_KEY_WRAP; *mechanism = CKM_NSS_AES_KEY_WRAP;
*flags = CKF_WRAP | CKF_WRAP; *flags = CKF_WRAP | CKF_WRAP;
break; return Status::Success();
} }
case blink::WebCryptoAlgorithmIdAesGcm: { case blink::WebCryptoAlgorithmIdAesGcm: {
if (!g_nss_runtime_support.Get().IsAesGcmSupported()) if (!g_nss_runtime_support.Get().IsAesGcmSupported())
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
*mechanism = CKM_AES_GCM; *mechanism = CKM_AES_GCM;
*flags = CKF_ENCRYPT | CKF_DECRYPT; *flags = CKF_ENCRYPT | CKF_DECRYPT;
break; return Status::Success();
} }
default: default:
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
} }
return Status::Success();
} }
Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
...@@ -883,8 +882,8 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, ...@@ -883,8 +882,8 @@ Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
blink::WebCryptoKey* key) { blink::WebCryptoKey* key) {
DCHECK(!algorithm.isNull()); DCHECK(!algorithm.isNull());
CK_MECHANISM_TYPE mechanism; CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
CK_FLAGS flags; CK_FLAGS flags = 0;
Status status = Status status =
WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags);
if (status.IsError()) if (status.IsError())
...@@ -1764,7 +1763,7 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -1764,7 +1763,7 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::Success(); return Status::Success();
} }
Status WrapSymKeyAesKw(SymKey* key, Status WrapSymKeyAesKw(PK11SymKey* key,
SymKey* wrapping_key, SymKey* wrapping_key,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
// The data size must be at least 16 bytes and a multiple of 8 bytes. // The data size must be at least 16 bytes and a multiple of 8 bytes.
...@@ -1772,13 +1771,11 @@ Status WrapSymKeyAesKw(SymKey* key, ...@@ -1772,13 +1771,11 @@ Status WrapSymKeyAesKw(SymKey* key,
// keys are being wrapped in this application (which are small), a reasonable // 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, // 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. // note that AES Key Wrap always adds 8 bytes to the input data size.
const unsigned int input_length = PK11_GetKeyLength(key->key()); const unsigned int input_length = PK11_GetKeyLength(key);
if (input_length < 16) DCHECK_GE(input_length, 16u);
return Status::ErrorDataTooSmall(); DCHECK((input_length % 8) == 0);
if (input_length > UINT_MAX - 8) if (input_length > UINT_MAX - 8)
return Status::ErrorDataTooLarge(); return Status::ErrorDataTooLarge();
if (input_length % 8)
return Status::ErrorInvalidAesKwDataLength();
SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv)));
crypto::ScopedSECItem param_item( crypto::ScopedSECItem param_item(
...@@ -1793,7 +1790,7 @@ Status WrapSymKeyAesKw(SymKey* key, ...@@ -1793,7 +1790,7 @@ Status WrapSymKeyAesKw(SymKey* key,
if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP,
param_item.get(), param_item.get(),
wrapping_key->key(), wrapping_key->key(),
key->key(), key,
&wrapped_key_item)) { &wrapped_key_item)) {
return Status::OperationError(); return Status::OperationError();
} }
...@@ -1803,44 +1800,6 @@ Status WrapSymKeyAesKw(SymKey* key, ...@@ -1803,44 +1800,6 @@ Status WrapSymKeyAesKw(SymKey* key,
return Status::Success(); 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, Status DecryptAesKw(SymKey* wrapping_key,
const CryptoData& data, const CryptoData& data,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
...@@ -1864,6 +1823,33 @@ Status DecryptAesKw(SymKey* wrapping_key, ...@@ -1864,6 +1823,33 @@ Status DecryptAesKw(SymKey* wrapping_key,
return Status::Success(); 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 platform
} // namespace webcrypto } // namespace webcrypto
......
...@@ -494,24 +494,8 @@ Status ExportRsaPrivateKey(PrivateKey* key, ...@@ -494,24 +494,8 @@ Status ExportRsaPrivateKey(PrivateKey* key,
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
} }
Status WrapSymKeyAesKw(SymKey* key, Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
SymKey* wrapping_key, SymKey* 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, const CryptoData& data,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
// TODO(eroman): http://crbug.com/267888 // TODO(eroman): http://crbug.com/267888
......
...@@ -308,71 +308,8 @@ bool ValidateDeserializedKey(const blink::WebCryptoKey& key, ...@@ -308,71 +308,8 @@ bool ValidateDeserializedKey(const blink::WebCryptoKey& key,
return true; return true;
} }
// Validates the size of data input to AES-KW. AES-KW requires the input data Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
// 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, 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 blink::WebCryptoKey& key,
const CryptoData& data, const CryptoData& data,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
...@@ -380,10 +317,17 @@ Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm, ...@@ -380,10 +317,17 @@ Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm,
Status status = ToPlatformSymKey(key, &sym_key); Status status = ToPlatformSymKey(key, &sym_key);
if (status.IsError()) if (status.IsError())
return status; 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()) if (status.IsError())
return status; return status;
return platform::DecryptAesKw(sym_key, data, buffer); return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer);
} }
Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
...@@ -400,7 +344,7 @@ Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, ...@@ -400,7 +344,7 @@ Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
case blink::WebCryptoAlgorithmIdRsaOaep: case blink::WebCryptoAlgorithmIdRsaOaep:
return DecryptRsaOaep(algorithm, key, data, buffer); return DecryptRsaOaep(algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdAesKw: case blink::WebCryptoAlgorithmIdAesKw:
return DecryptAesKw(algorithm, key, data, buffer); return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer);
default: default:
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
} }
...@@ -417,6 +361,8 @@ Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, ...@@ -417,6 +361,8 @@ Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer); return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdAesGcm: case blink::WebCryptoAlgorithmIdAesGcm:
return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer); return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdAesKw:
return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer);
case blink::WebCryptoAlgorithmIdRsaOaep: case blink::WebCryptoAlgorithmIdRsaOaep:
return EncryptRsaOaep(algorithm, key, data, buffer); return EncryptRsaOaep(algorithm, key, data, buffer);
default: default:
...@@ -892,13 +838,6 @@ Status WrapKey(blink::WebCryptoKeyFormat format, ...@@ -892,13 +838,6 @@ Status WrapKey(blink::WebCryptoKeyFormat format,
if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
return Status::ErrorUnexpected(); 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( return WrapKeyExportAndEncrypt(
format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer); format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer);
} }
...@@ -924,19 +863,6 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format, ...@@ -924,19 +863,6 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format,
if (status.IsError()) if (status.IsError())
return status; 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, return UnwrapKeyDecryptAndImport(format,
wrapped_key_data, wrapped_key_data,
wrapping_key, 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