You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
6.0 KiB
167 lines
6.0 KiB
/*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <keymaster/authorization_set.h>
|
|
#include <keymaster/key.h>
|
|
#include <keymaster/operation.h>
|
|
|
|
namespace keymaster {
|
|
|
|
bool OperationFactory::supported(keymaster_padding_t padding) const {
|
|
size_t padding_count;
|
|
const keymaster_padding_t* supported_paddings = SupportedPaddingModes(&padding_count);
|
|
for (size_t i = 0; i < padding_count; ++i)
|
|
if (padding == supported_paddings[i]) return true;
|
|
return false;
|
|
}
|
|
|
|
bool OperationFactory::supported(keymaster_block_mode_t block_mode) const {
|
|
size_t block_mode_count;
|
|
const keymaster_block_mode_t* supported_block_modes = SupportedBlockModes(&block_mode_count);
|
|
for (size_t i = 0; i < block_mode_count; ++i)
|
|
if (block_mode == supported_block_modes[i]) return true;
|
|
return false;
|
|
}
|
|
|
|
bool OperationFactory::supported(keymaster_digest_t digest) const {
|
|
size_t digest_count;
|
|
const keymaster_digest_t* supported_digests = SupportedDigests(&digest_count);
|
|
for (size_t i = 0; i < digest_count; ++i)
|
|
if (digest == supported_digests[i]) return true;
|
|
return false;
|
|
}
|
|
|
|
inline bool is_public_key_algorithm(keymaster_algorithm_t algorithm) {
|
|
switch (algorithm) {
|
|
case KM_ALGORITHM_HMAC:
|
|
case KM_ALGORITHM_AES:
|
|
case KM_ALGORITHM_TRIPLE_DES:
|
|
return false;
|
|
case KM_ALGORITHM_RSA:
|
|
case KM_ALGORITHM_EC:
|
|
return true;
|
|
}
|
|
|
|
// Unreachable.
|
|
assert(false);
|
|
return false;
|
|
}
|
|
|
|
bool OperationFactory::is_public_key_operation() const {
|
|
KeyType key_type = registry_key();
|
|
|
|
if (!is_public_key_algorithm(key_type.algorithm)) return false;
|
|
|
|
switch (key_type.purpose) {
|
|
case KM_PURPOSE_VERIFY:
|
|
case KM_PURPOSE_ENCRYPT:
|
|
case KM_PURPOSE_WRAP:
|
|
return true;
|
|
case KM_PURPOSE_SIGN:
|
|
case KM_PURPOSE_DECRYPT:
|
|
case KM_PURPOSE_DERIVE_KEY:
|
|
case KM_PURPOSE_AGREE_KEY:
|
|
case KM_PURPOSE_ATTEST_KEY:
|
|
return false;
|
|
};
|
|
|
|
// Unreachable.
|
|
assert(false);
|
|
return false;
|
|
}
|
|
|
|
bool OperationFactory::GetAndValidatePadding(const AuthorizationSet& begin_params, const Key& key,
|
|
keymaster_padding_t* padding,
|
|
keymaster_error_t* error) const {
|
|
*error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
|
|
if (!begin_params.GetTagValue(TAG_PADDING, padding)) {
|
|
LOG_E("%d padding modes specified in begin params", begin_params.GetTagCount(TAG_PADDING));
|
|
return false;
|
|
} else if (!supported(*padding)) {
|
|
LOG_E("Padding mode %d not supported", *padding);
|
|
return false;
|
|
} else if (
|
|
// If it's a public key operation, all padding modes are authorized.
|
|
!is_public_key_operation() &&
|
|
// Otherwise the key needs to authorize the specific mode.
|
|
!key.authorizations().Contains(TAG_PADDING, *padding) &&
|
|
!key.authorizations().Contains(TAG_PADDING_OLD, *padding)) {
|
|
LOG_E("Padding mode %d was specified, but not authorized by key", *padding);
|
|
*error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
|
|
return false;
|
|
}
|
|
|
|
*error = KM_ERROR_OK;
|
|
return true;
|
|
}
|
|
|
|
bool OperationFactory::GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
|
|
keymaster_digest_t* digest,
|
|
keymaster_error_t* error) const {
|
|
return GetAndValidateDigest(begin_params, key, digest, error, false);
|
|
}
|
|
|
|
bool OperationFactory::GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
|
|
keymaster_digest_t* digest, keymaster_error_t* error,
|
|
bool require_explicit_digest) const {
|
|
*error = KM_ERROR_UNSUPPORTED_DIGEST;
|
|
if (!begin_params.GetTagValue(TAG_DIGEST, digest)) {
|
|
if (require_explicit_digest) {
|
|
return false;
|
|
}
|
|
if (key.authorizations().Contains(TAG_DIGEST, KM_DIGEST_NONE)) {
|
|
*digest = KM_DIGEST_NONE;
|
|
} else {
|
|
LOG_E("%d digests specified in begin params and NONE not authorized",
|
|
begin_params.GetTagCount(TAG_DIGEST));
|
|
return false;
|
|
}
|
|
} else if (!supported(*digest)) {
|
|
LOG_E("Digest %d not supported", *digest);
|
|
return false;
|
|
} else if (
|
|
// If it's a public key operation, all digests are authorized.
|
|
!is_public_key_operation() &&
|
|
// Otherwise the key needs to authorize the specific digest.
|
|
!key.authorizations().Contains(TAG_DIGEST, *digest) &&
|
|
!key.authorizations().Contains(TAG_DIGEST_OLD, *digest)) {
|
|
LOG_E("Digest %d was specified, but not authorized by key", *digest);
|
|
*error = KM_ERROR_INCOMPATIBLE_DIGEST;
|
|
return false;
|
|
}
|
|
*error = KM_ERROR_OK;
|
|
return true;
|
|
}
|
|
|
|
keymaster_error_t Operation::UpdateForFinish(const AuthorizationSet& input_params,
|
|
const Buffer& input) {
|
|
if (!input_params.empty() || input.available_read()) {
|
|
size_t input_consumed;
|
|
Buffer output;
|
|
AuthorizationSet output_params;
|
|
keymaster_error_t error =
|
|
Update(input_params, input, &output_params, &output, &input_consumed);
|
|
if (error != KM_ERROR_OK) return error;
|
|
assert(input_consumed == input.available_read());
|
|
assert(output_params.empty());
|
|
assert(output.available_read() == 0);
|
|
}
|
|
|
|
return KM_ERROR_OK;
|
|
}
|
|
|
|
} // namespace keymaster
|