167 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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
 |