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.
161 lines
5.6 KiB
161 lines
5.6 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 "operation.h" |
|
|
|
#include <keymaster/authorization_set.h> |
|
#include <keymaster/keymaster_context.h> |
|
|
|
#include "key.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: |
|
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: |
|
return true; |
|
case KM_PURPOSE_SIGN: |
|
case KM_PURPOSE_DECRYPT: |
|
case KM_PURPOSE_DERIVE_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 { |
|
*error = KM_ERROR_UNSUPPORTED_DIGEST; |
|
if (!begin_params.GetTagValue(TAG_DIGEST, digest)) { |
|
LOG_E("%d digests specified in begin params", 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::CreateOperationHandle(const KeymasterContext& context, |
|
keymaster_operation_handle_t* op_handle) { |
|
return context.GenerateRandom(reinterpret_cast<uint8_t*>(op_handle), sizeof(*op_handle)); |
|
} |
|
|
|
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
|
|
|