summaryrefslogtreecommitdiff
path: root/keymaster/ta/parameters.c
diff options
context:
space:
mode:
authorVictor Chong <victor.chong@linaro.org>2018-06-21 18:35:12 +0900
committerVictor Chong <victor.chong@linaro.org>2018-10-08 12:39:26 +0900
commit33cdf4fdcacca5f86cf6cb27df5262dafbc36da4 (patch)
treefb674a2ba16924d0f772b1657981b90094930236 /keymaster/ta/parameters.c
downloadapps-33cdf4fdcacca5f86cf6cb27df5262dafbc36da4.tar.gz
initial commit
Diffstat (limited to 'keymaster/ta/parameters.c')
-rw-r--r--keymaster/ta/parameters.c1107
1 files changed, 1107 insertions, 0 deletions
diff --git a/keymaster/ta/parameters.c b/keymaster/ta/parameters.c
new file mode 100644
index 0000000..565fcc5
--- /dev/null
+++ b/keymaster/ta/parameters.c
@@ -0,0 +1,1107 @@
+/*
+ *
+ * Copyright (C) 2017 GlobalLogic
+ *
+ * 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 "parameters.h"
+
+const size_t kMinGcmTagLength = 12 * 8;
+const size_t kMaxGcmTagLength = 16 * 8;
+
+void TA_free_params(keymaster_key_param_set_t *params)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ if (!params->params)
+ return;
+ for (size_t i = 0; i < params->length; i++) {
+ if (keymaster_tag_get_type(params->params[i].tag) == KM_BIGNUM
+ || keymaster_tag_get_type(params->
+ params[i].tag) == KM_BYTES) {
+ TEE_Free(params->params[i].key_param.blob.data);
+ }
+ }
+ TEE_Free(params->params);
+}
+
+void TA_free_cert_chain(keymaster_cert_chain_t *cert_chain)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ if (!cert_chain->entries) {
+ return;
+ }
+
+ for (size_t i = 0; i < cert_chain->entry_count; i++) {
+ if (cert_chain->entries[i].data)
+ TEE_Free(cert_chain->entries[i].data);
+ }
+ TEE_Free(cert_chain->entries);
+}
+
+void TA_add_to_params(keymaster_key_param_set_t *params,
+ const uint32_t key_size,
+ const uint64_t rsa_public_exponent,
+ const uint32_t curve)
+{
+ bool was_added = false;
+ DMSG("%s %d", __func__, __LINE__);
+
+ if (key_size != UNDEFINED) {
+ for (size_t i = 0; i < params->length; i++) {
+ if (params->params[i].tag == KM_TAG_KEY_SIZE) {
+ was_added = true;
+ params->params[i].key_param.integer = key_size;
+ break;
+ }
+ }
+ if (!was_added) {
+ (params->params + params->length)->tag = KM_TAG_KEY_SIZE;
+ (params->params + params->length)->
+ key_param.integer = key_size;
+ params->length++;
+ }
+ }
+
+ if (rsa_public_exponent != UNDEFINED) {
+ was_added = false;
+ for (size_t i = 0; i < params->length; i++) {
+ if (params->params[i].tag == KM_TAG_RSA_PUBLIC_EXPONENT) {
+ was_added = true;
+ params->params[i].key_param.integer = rsa_public_exponent;
+ break;
+ }
+ }
+ if (!was_added) {
+ (params->params + params->length)->tag = KM_TAG_RSA_PUBLIC_EXPONENT;
+ (params->params + params->length)->
+ key_param.integer = rsa_public_exponent;
+ params->length++;
+ }
+ }
+
+ if (curve != UNDEFINED && key_size != UNDEFINED) {
+ was_added = false;
+ for (size_t i = 0; i < params->length; i++) {
+ if (params->params[i].tag == KM_TAG_EC_CURVE) {
+ was_added = true;
+ params->params[i].key_param.enumerated =
+ TA_size_to_ECcurve(key_size);
+ break;
+ }
+ }
+ if (!was_added) {
+ (params->params + params->length)->tag = KM_TAG_EC_CURVE;
+ (params->params + params->length)->
+ key_param.enumerated =
+ TA_size_to_ECcurve(key_size);
+ params->length++;
+ }
+ }
+}
+
+uint32_t get_digest_size(const keymaster_digest_t *digest)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ switch (*digest) {
+ case KM_DIGEST_MD5:
+ return KM_DIGEST_MD5_SIZE;
+ case KM_DIGEST_SHA1:
+ return KM_DIGEST_SHA1_SIZE;
+ case KM_DIGEST_SHA_2_224:
+ return KM_DIGEST_SHA_2_224_SIZE;
+ case KM_DIGEST_SHA_2_256:
+ return KM_DIGEST_SHA_2_256_SIZE;
+ case KM_DIGEST_SHA_2_384:
+ return KM_DIGEST_SHA_2_384_SIZE;
+ case KM_DIGEST_SHA_2_512:
+ return KM_DIGEST_SHA_2_512_SIZE;
+ default:
+ return 0;
+ }
+}
+
+void TA_push_param(keymaster_key_param_set_t *enforced,
+ const keymaster_key_param_t *param)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ enforced->params[enforced->length] = *param;
+ enforced->length++;
+}
+
+keymaster_error_t TA_parse_params(const keymaster_key_param_set_t params_t,
+ keymaster_algorithm_t *key_algorithm,
+ uint32_t *key_size,
+ uint64_t *key_rsa_public_exponent,
+ keymaster_digest_t *key_digest,
+ const bool import)
+{
+ bool check_min_mac_length = false;
+ uint32_t min_mac_length = UNDEFINED;
+ uint32_t digest_count = 0;
+ bool is_ec_curve = false;
+ keymaster_ec_curve_t ec_curve = KM_EC_CURVE_UNKNOWN;
+ *key_size = UNDEFINED; /*set default value*/
+
+ DMSG("%s %d", __func__, __LINE__);
+ for (size_t i = 0; i < params_t.length; i++) {
+ switch ((params_t.params + i)->tag) {
+ case KM_TAG_ALGORITHM:
+ *key_algorithm = (keymaster_algorithm_t)
+ (params_t.params + i)->key_param.integer;
+ break;
+ case KM_TAG_KEY_SIZE:
+ *key_size = (params_t.params + i)->key_param.integer;
+ break;
+ case KM_TAG_RSA_PUBLIC_EXPONENT:
+ *key_rsa_public_exponent =
+ (params_t.params + i)->key_param.long_integer;
+ break;
+ case KM_TAG_BLOCK_MODE:
+ if (!check_min_mac_length && KM_MODE_GCM ==
+ (params_t.params + i)->
+ key_param.enumerated) {
+ check_min_mac_length = true;
+ }
+ break;
+ case KM_TAG_MIN_MAC_LENGTH:
+ min_mac_length = (params_t.params + i)->
+ key_param.integer;
+ break;
+ case KM_TAG_DIGEST:
+ digest_count++;
+ if (*key_digest == UNDEFINED) {
+ *key_digest = (keymaster_digest_t)
+ (params_t.params + i)->key_param.
+ enumerated;
+ }
+ break;
+ case KM_TAG_EC_CURVE:
+ is_ec_curve = true;
+ ec_curve = (keymaster_ec_curve_t)
+ (params_t.params + i)->
+ key_param.enumerated;
+ break;
+ default:
+ DMSG("Unused parameter with TAG = %x",
+ (params_t.params + i)->tag);
+ }
+ }
+ //Check:
+ if (*key_algorithm == KM_ALGORITHM_RSA && (*key_size % 8 != 0 ||
+ *key_size > MAX_KEY_RSA)
+ && !import) {
+ EMSG("RSA key size must be multiple of 8 and less than %u",
+ MAX_KEY_RSA);
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ if (*key_algorithm == KM_ALGORITHM_RSA &&
+ *key_rsa_public_exponent == 3 && import) {
+ EMSG("RSA import public exponent '3' doesn't match the key");
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ }
+ if (*key_algorithm == KM_ALGORITHM_RSA && *key_size != UNDEFINED
+ && *key_size > 1024 && import) {
+ EMSG("RSA import key size %d must be less than 1024", *key_size);
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ }
+ if (*key_algorithm == KM_ALGORITHM_HMAC && (*key_size % 8 != 0 ||
+ *key_size > MAX_KEY_HMAC ||
+ *key_size < MIN_KEY_HMAC)
+ && !import) {
+ EMSG("HMAC key size must be multiple of 8 and in range from %d to %d",
+ MIN_KEY_HMAC, MAX_KEY_HMAC);
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ if (min_mac_length == UNDEFINED && ((*key_algorithm == KM_ALGORITHM_AES &&
+ check_min_mac_length) ||
+ *key_algorithm == KM_ALGORITHM_HMAC)) {
+ EMSG("Min MAC length must be specified for AES GCM mode and HMAC");
+ return KM_ERROR_MISSING_MIN_MAC_LENGTH;
+ }
+ if (*key_algorithm == KM_ALGORITHM_AES && check_min_mac_length &&
+ (min_mac_length % 8 != 0 || min_mac_length < MIN_MML
+ || min_mac_length > MAX_MML)) {
+ EMSG("Min MAC length must be multiple of 8 in range from 96 to 128");
+ return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+ }
+ if (*key_algorithm == KM_ALGORITHM_HMAC && (min_mac_length % 8 != 0
+ || min_mac_length < MIN_MML_HMAC)) {
+ EMSG("Min MAC length must be multiple and at least 64");
+ return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+ }
+ if (*key_algorithm == KM_ALGORITHM_HMAC && digest_count != 1) {
+ EMSG("For MAC algorithm only one digest must be specified");
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ }
+ if (*key_algorithm == KM_ALGORITHM_EC) {
+ /*EC key generation requests may have tag EC_CURVE, KEY_SIZE or both*/
+ if (*key_size != UNDEFINED && is_ec_curve == true) {
+ /*If the request contains both,
+ * use the curve specified by Tag::EC_CURVE,
+ * and validate that the specified key size is appropriate*/
+ if (ec_curve != TA_size_to_ECcurve(*key_size)) {
+ EMSG("For EC algorithm specified key size"
+ "is not appropriate for that curve");
+ return KM_ERROR_INVALID_ARGUMENT;
+ } else {
+ *key_size = TA_ECcurve_to_size(ec_curve);
+ }
+ } else if (*key_size == UNDEFINED && is_ec_curve == true) {
+ /*If the request only contains Tag::EC_CURVE, use the specified*/
+ *key_size = TA_ECcurve_to_size(ec_curve);
+ }
+
+ if ((*key_size == 224 || ec_curve == KM_EC_CURVE_P_224) && import) {
+ EMSG("EC import key size must be greater than '224'");
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ }
+ }
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TA_fill_characteristics(
+ keymaster_key_characteristics_t *characteristics,
+ const keymaster_key_param_set_t *params,
+ uint32_t *size)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ /* Freed before characteristics is destoyed by caller */
+ characteristics->hw_enforced.params = TEE_Malloc(
+ MAX_ENFORCED_PARAMS_COUNT *
+ sizeof(keymaster_key_param_t),
+ TEE_MALLOC_FILL_ZERO);
+ if (!characteristics->hw_enforced.params) {
+ EMSG("Failed to allocate memory for hw_enforced.params");
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ characteristics->hw_enforced.length = 0;
+ /* Freed before characteristics is destoyed by caller */
+ characteristics->sw_enforced.params = TEE_Malloc(
+ MAX_ENFORCED_PARAMS_COUNT *
+ sizeof(keymaster_key_param_t),
+ TEE_MALLOC_FILL_ZERO);
+ if (!characteristics->sw_enforced.params) {
+ EMSG("Failed to allocate memory for sw_enforced.params");
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ characteristics->sw_enforced.length = 0;
+ *size = 2 * SIZE_LENGTH; /* room of hw and sw size values */
+
+ for (size_t i = 0; i < params->length; i++) {
+ *size += sizeof(params->params[i]);
+ if (keymaster_tag_get_type(params->params[i].tag) == KM_BIGNUM
+ || keymaster_tag_get_type(params->
+ params[i].tag) == KM_BYTES) {
+ *size += SIZE_LENGTH;
+ *size += params->params[i].key_param.blob.data_length;
+ }
+
+ switch (params->params[i].tag) {
+ case KM_TAG_INVALID:
+ case KM_TAG_BOOTLOADER_ONLY:
+ case KM_TAG_NONCE:
+ case KM_TAG_AUTH_TOKEN:
+ case KM_TAG_MAC_LENGTH:
+ case KM_TAG_ASSOCIATED_DATA:
+ case KM_TAG_UNIQUE_ID:
+ EMSG("Unexpected TAG %x", params->params[i].tag);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ case KM_TAG_ROLLBACK_RESISTANT:
+ case KM_TAG_APPLICATION_ID:
+ case KM_TAG_APPLICATION_DATA:
+ case KM_TAG_ALL_APPLICATIONS:
+ case KM_TAG_ROOT_OF_TRUST:
+ case KM_TAG_RESET_SINCE_ID_ROTATION:
+ case KM_TAG_ALLOW_WHILE_ON_BODY:
+ case KM_TAG_ATTESTATION_CHALLENGE:
+ /* Ignore these. */
+ DMSG("Ignore these TAG %x", params->params[i].tag);
+ break;
+ case KM_TAG_ORIGIN:
+ case KM_TAG_PURPOSE:
+ case KM_TAG_ALGORITHM:
+ case KM_TAG_KEY_SIZE:
+ case KM_TAG_RSA_PUBLIC_EXPONENT:
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ case KM_TAG_PADDING:
+ case KM_TAG_BLOCK_MODE:
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ case KM_TAG_MAX_USES_PER_BOOT:
+ case KM_TAG_USER_SECURE_ID:
+ case KM_TAG_NO_AUTH_REQUIRED:
+ case KM_TAG_AUTH_TIMEOUT:
+ case KM_TAG_CALLER_NONCE:
+ case KM_TAG_MIN_MAC_LENGTH:
+ case KM_TAG_KDF:
+ case KM_TAG_EC_CURVE:
+ case KM_TAG_ECIES_SINGLE_HASH_MODE:
+ case KM_TAG_DIGEST:
+ case KM_TAG_OS_VERSION:
+ case KM_TAG_OS_PATCHLEVEL:
+ TA_push_param(&characteristics->
+ hw_enforced, params->params + i);
+ break;
+ case KM_TAG_USER_AUTH_TYPE:
+ if ((hw_authenticator_type_t) params->params[i]
+ .key_param.enumerated ==
+ HW_AUTH_PASSWORD)
+ TA_push_param(&characteristics->
+ hw_enforced, params->params + i);
+ else
+ TA_push_param(&characteristics->
+ sw_enforced, params->params + i);
+ break;
+ case KM_TAG_ACTIVE_DATETIME:
+ case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+ case KM_TAG_USAGE_EXPIRE_DATETIME:
+ case KM_TAG_USER_ID:
+ case KM_TAG_ALL_USERS:
+ case KM_TAG_CREATION_DATETIME:
+ case KM_TAG_INCLUDE_UNIQUE_ID:
+ case KM_TAG_EXPORTABLE:
+ TA_push_param(&characteristics->
+ sw_enforced, params->params + i);
+ break;
+ default:
+ DMSG("Unused parameter with TAG = %x",
+ params->params[i].tag);
+ break;
+ }
+ }
+ return KM_ERROR_OK;
+}
+
+inline uint32_t TA_blob_size(const keymaster_blob_t *blob)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ return BLOB_SIZE(blob);
+}
+
+uint32_t TA_characteristics_size(
+ const keymaster_key_characteristics_t *characteristics)
+{
+ uint32_t size = 0;
+ DMSG("%s %d", __func__, __LINE__);
+
+ size += SIZE_LENGTH;
+ for (size_t i = 0; i < characteristics->hw_enforced.length; i++) {
+ size += SIZE_OF_ITEM(characteristics->hw_enforced.params);
+ if (keymaster_tag_get_type(characteristics->
+ hw_enforced.params[i].tag) == KM_BIGNUM ||
+ keymaster_tag_get_type(characteristics->
+ hw_enforced.params[i].tag) == KM_BYTES) {
+ size += TA_blob_size(&((characteristics->hw_enforced.params + i)->
+ key_param.blob));
+ }
+ }
+
+ size += SIZE_LENGTH;
+ for (size_t i = 0; i < characteristics->sw_enforced.length; i++) {
+ size += SIZE_OF_ITEM(characteristics->sw_enforced.params);
+ if (keymaster_tag_get_type(characteristics->
+ sw_enforced.params[i].tag) == KM_BIGNUM ||
+ keymaster_tag_get_type(characteristics->
+ sw_enforced.params[i].tag) == KM_BYTES) {
+ size += TA_blob_size(&((characteristics->sw_enforced.params + i)->
+ key_param.blob));
+ }
+ }
+
+ return size;
+}
+
+uint32_t TA_param_set_size(
+ const keymaster_key_param_set_t *params)
+{
+ uint32_t size = 0;
+ DMSG("%s %d", __func__, __LINE__);
+
+ size += SIZE_LENGTH;
+ for (size_t i = 0; i < params->length; i++) {
+ size += SIZE_OF_ITEM(params->params);
+
+ if (keymaster_tag_get_type(params->params[i].tag) == KM_BIGNUM
+ || keymaster_tag_get_type(params->
+ params[i].tag) == KM_BYTES) {
+ size += TA_blob_size(&(params->params[i].key_param.blob));
+ }
+ }
+
+ return size;
+}
+
+uint32_t TA_cert_chain_size(
+ const keymaster_cert_chain_t *cert_chain)
+{
+ uint32_t size = 0;
+ DMSG("%s %d", __func__, __LINE__);
+
+ size += SIZE_LENGTH;
+ for (size_t i = 0; i < cert_chain->entry_count; i++) {
+ size += SIZE_LENGTH;
+ size += cert_chain->entries[i].data_length;
+ }
+ return size;
+}
+
+void TA_add_origin(keymaster_key_param_set_t *params_t,
+ const keymaster_key_origin_t origin, const bool replace_origin)
+{
+ bool origin_added = false;
+ DMSG("%s %d", __func__, __LINE__);
+
+ for (size_t i = 0; i < params_t->length; i++) {
+ if (params_t->params[i].tag == KM_TAG_ORIGIN) {
+ origin_added = true;
+ if (replace_origin) {
+ params_t->params[i].key_param.enumerated
+ = (uint32_t) origin;
+ }
+ break;
+ }
+ }
+ if (!origin_added) {
+ (params_t->params + params_t->length)->tag = KM_TAG_ORIGIN;
+ (params_t->params + params_t->length)->
+ key_param.enumerated = origin;
+ params_t->length++;
+ }
+}
+
+void TA_add_creation_datetime(keymaster_key_param_set_t *params_t, bool replace)
+{
+ bool datetime_added = false;
+ TEE_Time time;
+ TEE_GetSystemTime(&time);
+ DMSG("%s %d", __func__, __LINE__);
+
+ /*Replace if present*/
+ for (size_t i = 0; i < params_t->length; i++) {
+ if (params_t->params[i].tag == KM_TAG_CREATION_DATETIME) {
+ datetime_added = true;
+ if (replace) {
+ params_t->params[i].key_param.date_time =
+ (uint64_t)(time.seconds * 1000 +
+ time.millis);
+ }
+ break;
+ }
+ }
+ /*Add parameter*/
+ if (!datetime_added) {
+ (params_t->params + params_t->length)->tag = KM_TAG_CREATION_DATETIME;
+ (params_t->params + params_t->length)->
+ key_param.date_time
+ = (uint64_t)(time.seconds * 1000
+ + time.millis);
+ params_t->length++;
+ }
+}
+
+void TA_add_os_version_patchlevel(keymaster_key_param_set_t *params_t,
+ uint32_t os_version,
+ uint32_t os_patchlevel)
+{
+ size_t i;
+ DMSG("%s %d", __func__, __LINE__);
+
+ for (i = 0; i < params_t->length; i++) {
+ if (params_t->params[i].tag == KM_TAG_OS_VERSION) {
+ params_t->params[i].key_param.integer = os_version;
+ break;
+ }
+ }
+ if (i == params_t->length) {
+ (params_t->params + params_t->length)->tag = KM_TAG_OS_VERSION;
+ (params_t->params + params_t->length)->
+ key_param.integer = os_version;
+ params_t->length++;
+ }
+
+ for (i = 0; i < params_t->length; i++) {
+ if (params_t->params[i].tag == KM_TAG_OS_PATCHLEVEL) {
+ params_t->params[i].key_param.integer = os_patchlevel;
+ break;
+ }
+ }
+ if (i == params_t->length) {
+ (params_t->params + params_t->length)->tag = KM_TAG_OS_PATCHLEVEL;
+ (params_t->params + params_t->length)->
+ key_param.integer = os_patchlevel;
+ params_t->length++;
+ }
+}
+
+void TA_add_ec_curve(keymaster_key_param_set_t *params_t, uint32_t key_size)
+{
+ bool tag_added = false;
+ keymaster_ec_curve_t curve = TA_size_to_ECcurve(key_size);
+ DMSG("%s %d", __func__, __LINE__);
+
+ for (size_t i = 0; i < params_t->length; i++) {
+ if (params_t->params[i].tag == KM_TAG_EC_CURVE)
+ tag_added = true;
+ }
+ if (!tag_added) {
+ (params_t->params + params_t->length)->tag = KM_TAG_EC_CURVE;
+ (params_t->params + params_t->length)->
+ key_param.integer =
+ (uint32_t)curve;
+ params_t->length++;
+ }
+}
+
+bool cmpBlobParam(const keymaster_blob_t blob,
+ const keymaster_key_param_t param)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ return blob.data_length != param.key_param.blob.data_length ||
+ TEE_MemCompare(blob.data, param.key_param.blob.data,
+ blob.data_length);
+}
+
+keymaster_error_t TA_check_params(keymaster_key_blob_t *key,
+ const keymaster_key_param_set_t *key_params,
+ const keymaster_key_param_set_t *in_params,
+ keymaster_algorithm_t *algorithm,
+ const keymaster_purpose_t op_purpose,
+ keymaster_digest_t *op_digest,
+ keymaster_block_mode_t *op_mode,
+ keymaster_padding_t *op_padding,
+ uint32_t *mac_length,
+ keymaster_blob_t *nonce,
+ uint32_t *min_sec, bool *do_auth)
+{
+ hw_auth_token_t auth_token;
+ hw_authenticator_type_t auth_type = HW_AUTH_NONE;
+ keymaster_blob_t client_id = {.data = NULL, .data_length = 0};
+ keymaster_blob_t app_data = {.data = NULL, .data_length = 0};
+ keymaster_digest_t digest[7];
+ uint32_t digest_count = 0;
+ keymaster_padding_t padding[6];
+ uint32_t padding_count = 0;
+ keymaster_block_mode_t block_mode[4];
+ uint32_t block_mode_count = 0;
+ keymaster_purpose_t purpose[4];
+ uint32_t purpose_count = 0;
+ uint64_t suid[MAX_SUID];
+ uint32_t suid_count = 0;
+ uint32_t max_uses = UNDEFINED;
+ uint32_t auth_timeout = UNDEFINED;
+ uint32_t min_mac_length = UNDEFINED;
+ uint32_t key_size = UNDEFINED;
+ bool soft_fail = false;
+ bool supported_purpose = false;
+ bool caller_nonce_fail = false;
+ bool no_auth_req = false;
+ bool match;
+ bool caller_nonce = false;
+ keymaster_error_t res = KM_ERROR_OK;
+
+ DMSG("%s %d", __func__, __LINE__);
+ for (size_t i = 0; i < key_params->length; i++) {
+ switch (key_params->params[i].tag) {
+ case KM_TAG_KEY_SIZE:
+ DMSG("KM_TAG_KEY_SIZE");
+ key_size = key_params->params[i].key_param.integer;
+ break;
+ case KM_TAG_ALGORITHM:
+ DMSG("KM_TAG_ALGORITHM");
+ *algorithm = (keymaster_algorithm_t)
+ key_params->params[i].key_param.integer;
+ break;
+ case KM_TAG_APPLICATION_ID:
+ DMSG("KM_TAG_APPLICATION_ID");
+ client_id = key_params->params[i].key_param.blob;
+ break;
+ case KM_TAG_APPLICATION_DATA:
+ DMSG("KM_TAG_APPLICATION_DATA");
+ app_data = key_params->params[i].key_param.blob;
+ break;
+ case KM_TAG_PURPOSE:
+ DMSG("KM_TAG_PURPOSE");
+ purpose[purpose_count] = (keymaster_purpose_t)
+ key_params->params[i].key_param.enumerated;
+ purpose_count++;
+ break;
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ DMSG("KM_TAG_MIN_SECONDS_BETWEEN_OPS");
+ *min_sec = key_params->params[i].key_param.integer;
+ break;
+ case KM_TAG_MAX_USES_PER_BOOT:
+ DMSG("KM_TAG_MAX_USES_PER_BOOT");
+ max_uses = key_params->params[i].key_param.integer;
+ break;
+ case KM_TAG_USER_SECURE_ID:
+ DMSG("KM_TAG_USER_SECURE_ID");
+ if (suid_count + 1 > MAX_SUID) {
+ EMSG("To many SUID. Expected max count %u",
+ MAX_SUID);
+ break;
+ }
+ suid[suid_count] =
+ key_params->params[i].key_param.long_integer;
+ suid_count++;
+ break;
+ case KM_TAG_CALLER_NONCE:
+ DMSG("KM_TAG_CALLER_NONCE");
+ caller_nonce =
+ key_params->params[i].key_param.boolean;
+ break;
+ case KM_TAG_AUTH_TIMEOUT:
+ DMSG("KM_TAG_AUTH_TIMEOUT");
+ auth_timeout =
+ key_params->params[i].key_param.integer;
+ break;
+ case KM_TAG_USER_AUTH_TYPE:
+ DMSG("KM_TAG_USER_AUTH_TYPE");
+ auth_type = (hw_authenticator_type_t)
+ key_params->params[i].key_param.enumerated;
+ break;
+ case KM_TAG_BLOCK_MODE:
+ DMSG("KM_TAG_BLOCK_MODE");
+ block_mode[block_mode_count] =
+ (keymaster_block_mode_t) key_params->
+ params[i].key_param.integer;
+ block_mode_count++;
+ break;
+ case KM_TAG_DIGEST:
+ DMSG("KM_TAG_DIGEST");
+ digest[digest_count] = (keymaster_digest_t)
+ key_params->params[i].key_param.integer;
+ digest_count++;
+ break;
+ case KM_TAG_PADDING:
+ DMSG("KM_TAG_PADDING");
+ padding[padding_count] = (keymaster_padding_t)
+ key_params->params[i].key_param.integer;
+ padding_count++;
+ break;
+ case KM_TAG_MIN_MAC_LENGTH:
+ DMSG("KM_TAG_MIN_MAC_LENGTH");
+ min_mac_length =
+ key_params->params[i].key_param.integer;
+ break;
+ case KM_TAG_NO_AUTH_REQUIRED:
+ DMSG("KM_TAG_NO_AUTH_REQUIRED");
+ no_auth_req =
+ key_params->params[i].key_param.boolean;
+ break;
+ case KM_TAG_MAC_LENGTH:
+ DMSG("KM_TAG_MAC_LENGTH");
+ *mac_length =
+ in_params->params[i].key_param.integer;
+ break;
+ default:
+ DMSG("Unused parameter with tag %x",
+ key_params->params[i].tag);
+ }
+ }
+
+ for (uint32_t z = 0; z < purpose_count; z++) {
+ DMSG("purpose[%u] = %d", z, purpose[z]);
+ }
+ DMSG("op_purpose = %d purpose_count = %u",
+ op_purpose, purpose_count);
+
+ if (*algorithm == KM_ALGORITHM_EC &&
+ (op_purpose == KM_PURPOSE_ENCRYPT ||
+ op_purpose == KM_PURPOSE_DECRYPT)) {
+ EMSG("Decrypt/encrypt operation is not supported by EC algorithm");
+ res = KM_ERROR_UNSUPPORTED_PURPOSE;
+ goto out_cp;
+ }
+ if (*algorithm == KM_ALGORITHM_HMAC &&
+ (op_purpose == KM_PURPOSE_ENCRYPT ||
+ op_purpose == KM_PURPOSE_DECRYPT)) {
+ EMSG("Decrypt/encrypt operation is not supported by HMAC algorithm");
+ res = KM_ERROR_UNSUPPORTED_PURPOSE;
+ goto out_cp;
+ }
+ soft_fail = (*algorithm == KM_ALGORITHM_RSA ||
+ *algorithm == KM_ALGORITHM_EC) &&
+ (op_purpose == KM_PURPOSE_ENCRYPT ||
+ op_purpose == KM_PURPOSE_VERIFY);
+ if (!soft_fail) {
+ for (uint32_t z = 0; z < purpose_count; z++) {
+ if (purpose[z] == op_purpose) {
+ supported_purpose = true;
+ break;
+ }
+ }
+ if (!supported_purpose) {
+ EMSG("Key does not support such purpose");
+ res = KM_ERROR_INCOMPATIBLE_PURPOSE;
+ goto out_cp;
+ }
+ }
+
+ for (size_t j = 0; j < in_params->length; j++) {
+ DMSG("in_params->params[%zu].tag = %d",
+ j, in_params->params[j].tag);
+ switch (in_params->params[j].tag) {
+ case KM_TAG_APPLICATION_ID:
+ if (cmpBlobParam(client_id,
+ in_params->params[j])) {
+ EMSG("Wrong client_id");
+ res = KM_ERROR_INVALID_KEY_BLOB;
+ goto out_cp;
+ }
+ break;
+ case KM_TAG_APPLICATION_DATA:
+ if (cmpBlobParam(app_data,
+ in_params->params[j])) {
+ EMSG("Wrong app_data");
+ res = KM_ERROR_INVALID_KEY_BLOB;
+ goto out_cp;
+ }
+ break;
+ case KM_TAG_CALLER_NONCE:
+ caller_nonce_fail = !caller_nonce &&
+ in_params->params[j].key_param.boolean;
+ break;
+ case KM_TAG_AUTH_TOKEN:
+ TEE_MemMove(&auth_token,
+ in_params->params[j].key_param.blob.data,
+ in_params->params[j].
+ key_param.blob.data_length);
+ break;
+ case KM_TAG_BLOCK_MODE:
+ if (*op_mode != UNDEFINED) {
+ EMSG("To many block mode tags");
+ res = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+ goto out_cp;
+ }
+ *op_mode = (keymaster_block_mode_t)
+ in_params->params[j].key_param.enumerated;
+ break;
+ case KM_TAG_DIGEST:
+ if (*op_digest != UNDEFINED) {
+ EMSG("To many digest tags");
+ res = KM_ERROR_UNSUPPORTED_DIGEST;
+ goto out_cp;
+ }
+ *op_digest = (keymaster_digest_t)
+ in_params->params[j].key_param.enumerated;
+ break;
+ case KM_TAG_PADDING:
+ if (*op_padding != UNDEFINED) {
+ EMSG("To many padding tags");
+ res = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ goto out_cp;
+ }
+ *op_padding = (keymaster_padding_t)
+ in_params->params[j].key_param.enumerated;
+ break;
+ case KM_TAG_NONCE:
+ caller_nonce_fail = !caller_nonce;
+ *nonce = in_params->params[j].key_param.blob;
+ break;
+ case KM_TAG_MAC_LENGTH:
+ if (*mac_length == UNDEFINED)
+ *mac_length =
+ in_params->params[j].key_param.integer;
+ break;
+ default:
+ DMSG("Unused parameter with tag %x",
+ in_params->params[j].tag);
+ }
+ }
+ if (*algorithm == KM_ALGORITHM_RSA) {
+ if ((*op_padding == KM_PAD_RSA_PKCS1_1_5_SIGN ||
+ *op_padding == KM_PAD_RSA_PSS) &&
+ op_purpose != KM_PURPOSE_SIGN &&
+ op_purpose != KM_PURPOSE_VERIFY) {
+ EMSG("Padding modes KM_PAD_RSA_PKCS1_1_5_SIGN and KM_PAD_RSA_PSS "
+ "supports only SIGN and VERIFY purposes");
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ } else if ((*op_padding == KM_PAD_RSA_PKCS1_1_5_ENCRYPT ||
+ *op_padding == KM_PAD_RSA_OAEP) &&
+ op_purpose != KM_PURPOSE_ENCRYPT &&
+ op_purpose != KM_PURPOSE_DECRYPT) {
+ EMSG("Padding modes KM_PAD_RSA_PKCS1_1_5_SIGN and KM_PAD_RSA_PSS "
+ "supports only SIGN and VERIFY purposes");
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ }
+ if (*op_padding == KM_PAD_RSA_PSS &&
+ *op_digest == KM_DIGEST_NONE &&
+ get_digest_size(op_digest) + 22 > key_size) {
+ EMSG("RSA padding mode KM_PAD_RSA_PSS can not be used with "
+ "KM_DIGEST_NONE and key size must be at least 22 bytes "
+ "larger than digest output size");
+ return KM_ERROR_INCOMPATIBLE_DIGEST;
+ }
+ if (*op_padding == KM_PAD_RSA_PSS &&
+ (get_digest_size(op_digest) * 2 + 16) > key_size) {
+ EMSG("RSA padding mode KM_PAD_RSA_PSS and key size must be larger than digest output size");
+ return KM_ERROR_INCOMPATIBLE_DIGEST;
+ }
+ if (*op_padding == KM_PAD_RSA_OAEP &&
+ *op_digest == KM_DIGEST_NONE) {
+ EMSG("RSA padding mode KM_PAD_RSA_OAEP can not be used with "
+ "KM_DIGEST_NONE");
+ return KM_ERROR_INCOMPATIBLE_DIGEST;
+ }
+ if (*op_padding == KM_PAD_PKCS7) {
+ EMSG("RSA padding mode KM_PAD_PKCS7 can not be used");
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ }
+ if (*op_padding == UNDEFINED) {
+ EMSG("RSA unsupported operation padding");
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ }
+ }
+ if (soft_fail) {
+ /* No need to do all other checks for public key operations */
+ goto out_cp;
+ }
+ /* RSA, EC, HMAC KM_PAD_RSA_PKCS1_1_5_ENCRYPT
+ * padding does not require a digest
+ */
+ if (*algorithm != KM_ALGORITHM_AES &&
+ *op_padding != KM_PAD_RSA_PKCS1_1_5_ENCRYPT) {
+ match = false;
+ if (*algorithm == KM_ALGORITHM_RSA &&
+ *op_padding == KM_PAD_NONE) {
+ if ((op_purpose == KM_PURPOSE_SIGN ||
+ op_purpose == KM_PURPOSE_VERIFY) &&
+ *op_digest != KM_DIGEST_NONE) {
+ EMSG("RSA with padding KM_PAD_NONE and purpose SIGN or VIRIFY "
+ "must use KM_DIGEST_NONE");
+ res = KM_ERROR_INCOMPATIBLE_DIGEST;
+ goto out_cp;
+ }
+ }
+ if (*op_digest == UNDEFINED &&
+ *algorithm != KM_ALGORITHM_RSA &&
+ *op_padding != KM_PAD_NONE &&
+ op_purpose != KM_PURPOSE_ENCRYPT &&
+ op_purpose != KM_PURPOSE_DECRYPT) {
+ EMSG("Operation digest is not set");
+ res = KM_ERROR_UNSUPPORTED_DIGEST;
+ goto out_cp;
+ }
+ for (uint32_t i = 0; i < digest_count; i++) {
+ if (*op_digest == digest[i]) {
+ match = true;
+ break;
+ }
+ }
+ if (*op_digest != UNDEFINED && !match) {
+ EMSG("Key does not support such digest");
+ res = KM_ERROR_INCOMPATIBLE_DIGEST;
+ goto out_cp;
+ }
+ }
+ if (*algorithm == KM_ALGORITHM_HMAC || (*algorithm == KM_ALGORITHM_AES
+ && *op_mode == KM_MODE_GCM)) {
+ /* HMAC, AES GCM */
+ if (min_mac_length == UNDEFINED) {
+ EMSG("Min MAC Length must be specified");
+ res = KM_ERROR_MISSING_MIN_MAC_LENGTH;
+ goto out_cp;
+ }
+ if (*mac_length == UNDEFINED) {
+ if (*algorithm == KM_ALGORITHM_AES) {
+ *mac_length = kMaxGcmTagLength;
+ } else if (*algorithm == KM_ALGORITHM_HMAC) {
+ *mac_length = min_mac_length;/*FIXME*/
+ } else {
+ EMSG("MAC Length must be specified");
+ res = KM_ERROR_MISSING_MAC_LENGTH;
+ goto out_cp;
+ }
+ }
+ if (min_mac_length % 8 != 0) {
+ EMSG("Min MAC Length must be a multiple of 8");
+ res = KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+ goto out_cp;
+ }
+ if (*mac_length % 8 != 0) {
+ EMSG("MAC Length (%u) must be a multiple of 8",
+ *mac_length);
+ res = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ goto out_cp;
+ }
+ if (*algorithm == KM_ALGORITHM_AES &&
+ (min_mac_length < kMinGcmTagLength ||
+ min_mac_length > kMaxGcmTagLength)) {
+ res = KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+ goto out_cp;
+ }
+ if (*mac_length < min_mac_length) {
+ EMSG("MAC length must be greater than Min MAC Length");
+ res = KM_ERROR_INVALID_MAC_LENGTH;
+ goto out_cp;
+ }
+ if (*algorithm == KM_ALGORITHM_HMAC) {
+ if (*mac_length > get_digest_size(op_digest)) {
+ EMSG("MAC Length is more than digest size");
+ res = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ }
+ } else {
+ if (*mac_length > MAX_GCM_MAC) {
+ EMSG("MAC Length of AES GCM must be less 128");
+ res = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ }
+ }
+ if (res != KM_ERROR_OK)
+ goto out_cp;
+ }
+ if (*algorithm != KM_ALGORITHM_HMAC&& *algorithm != KM_ALGORITHM_EC) {
+ /* AES, RSA */
+ match = false;
+ if (*op_padding == UNDEFINED) {
+ EMSG("Operation padding is not set");
+ res = KM_ERROR_UNSUPPORTED_PURPOSE;
+ goto out_cp;
+ }
+ for (uint32_t i = 0; i < padding_count; i++) {
+ if (*op_padding == padding[i]) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ EMSG("Key does not support such padding");
+ res = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+ goto out_cp;
+ }
+ if (*algorithm == KM_ALGORITHM_AES) {
+ /* AES */
+ match = false;
+ if (*op_mode == UNDEFINED) {
+ EMSG("Operation block mode is not set");
+ res = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+ goto out_cp;
+ }
+ for (uint32_t i = 0; i < block_mode_count; i++) {
+ if (*op_mode == block_mode[i]) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ EMSG("Key does not support such blobk mode");
+ res = KM_ERROR_INCOMPATIBLE_BLOCK_MODE;
+ goto out_cp;
+ }
+ if (((*op_mode == KM_MODE_GCM ||
+ *op_mode == KM_MODE_CTR) &&
+ *op_padding != KM_PAD_NONE) ||
+ ((*op_mode == KM_MODE_ECB ||
+ *op_mode == KM_MODE_CBC) &&
+ *op_padding != KM_PAD_NONE
+ && *op_padding != KM_PAD_PKCS7)) {
+ EMSG("Mode does not compatible with padding");
+ res = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+ goto out_cp;
+ }
+ if (nonce->data_length > 0 && nonce->data_length != 12 &&
+ nonce->data_length != 16) {
+ EMSG("Wrong nonce length is prohibited %ld", nonce->data_length);
+ res = KM_ERROR_INVALID_NONCE;
+ goto out_cp;
+ }
+ }
+ }
+ if (is_origination_purpose(op_purpose) && (caller_nonce_fail
+ || (!caller_nonce && nonce->data_length > 0
+ && nonce->data != NULL))) {
+ EMSG("Caller Nonce is prohibited for this key");
+ res = KM_ERROR_CALLER_NONCE_PROHIBITED;
+ goto out_cp;
+ }
+ if (!no_auth_req) {
+ if (auth_timeout == UNDEFINED && suid_count > 0)
+ *do_auth = true;
+ if (suid_count > 0 && auth_timeout != UNDEFINED) {
+ res = TA_check_auth_token(suid, suid_count,
+ auth_type, &auth_token);
+ if (res != KM_ERROR_OK)
+ goto out_cp;
+ } else {
+ EMSG("Authentication failed. Key can not be used");
+ res = KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+ goto out_cp;
+ }
+ }
+ if (*min_sec != UNDEFINED) {
+ res = TA_check_key_use_timer(key, *min_sec);
+ if (res != KM_ERROR_OK)
+ goto out_cp;
+ }
+ if (max_uses != UNDEFINED) {
+ res = TA_count_key_uses(*key, max_uses);
+ if (res != KM_ERROR_OK)
+ goto out_cp;
+ }
+out_cp:
+ return res;
+}
+
+inline bool is_origination_purpose(const keymaster_purpose_t purpose)
+{
+ DMSG("%s %d", __func__, __LINE__);
+ return purpose == KM_PURPOSE_ENCRYPT || purpose == KM_PURPOSE_SIGN;
+}
+
+keymaster_error_t TA_check_permission(const keymaster_key_param_set_t *params,
+ const keymaster_blob_t client_id,
+ const keymaster_blob_t app_data,
+ bool *exportable)
+{
+ bool client_id_checked = false;
+ bool app_data_checked = false;
+ bool client_id_same = false;
+ bool app_data_same = false;
+
+ DMSG("%s %d", __func__, __LINE__);
+ for (size_t i = 0; i < params->length; i++) {
+ DMSG("in_params->params[%zu].tag = %d", i, params->params[i].tag);
+ if (client_id_checked && app_data_checked && *exportable)
+ break;
+ switch (params->params[i].tag) {
+ case KM_TAG_APPLICATION_ID:
+ client_id_checked = true;
+ if (client_id.data_length != params->params[i].
+ key_param.blob.data_length)
+ break;
+ client_id_same = TEE_MemCompare(client_id.data,
+ params->params[i].key_param.blob.data,
+ client_id.data_length);
+ break;
+ case KM_TAG_APPLICATION_DATA:
+ app_data_checked = true;
+ if (app_data.data_length !=
+ params->params[i].key_param.blob.data_length)
+ break;
+ app_data_same = TEE_MemCompare(app_data.data,
+ params->params[i].key_param.blob.data,
+ app_data.data_length);
+ break;
+ case KM_TAG_EXPORTABLE:
+ *exportable = params->params[i].key_param.boolean;
+ break;
+ default:
+ break;
+ }
+ }
+ if ((app_data_checked && app_data_same != 0) ||
+ (client_id_checked && client_id_same != 0)) {
+ EMSG("Invalid client id or app data!");
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ return KM_ERROR_OK;
+}