/*
* 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 "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::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