text: /*
   * Copyright (c) 2017 Linaro Limited
   * Copyright (c) 2018-2019 Foundries.io
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  #define LOG_MODULE_NAME net_lwm2m_obj_security
  #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
  
  #include <logging/log.h>
  LOG_MODULE_REGISTER(LOG_MODULE_NAME);
  
  #include <stdint.h>
  #include <init.h>
  
  #include "lwm2m_object.h"
  #include "lwm2m_engine.h"
  
  #define SECURITY_VERSION_MAJOR 1
  #if defined(CONFIG_LWM2M_SECURITY_OBJECT_VERSION_1_1)
  #define SECURITY_VERSION_MINOR 1
  #define SECURITY_MAX_ID 18
  #ifdef CONFIG_LWM2M_SECURITY_DTLS_TLS_CIPHERSUITE_MAX
  #define DTLS_TLS_CIPHERSUITE_MAX CONFIG_LWM2M_SECURITY_DTLS_TLS_CIPHERSUITE_MAX
  #else
  #define DTLS_TLS_CIPHERSUITE_MAX 0
  #endif /* CONFIG_LWM2M_SECURITY_DTLS_TLS_CIPHERSUITE_MAX */
  #else
  #define SECURITY_VERSION_MINOR 0
  #define SECURITY_MAX_ID 13
  #endif /* defined(CONFIG_LWM2M_SECURITY_OBJECT_VERSION_1_1) */
  
  /* Security resource IDs */
  #define SECURITY_SERVER_URI_ID			0
  #define SECURITY_BOOTSTRAP_FLAG_ID		1
  #define SECURITY_MODE_ID			2
  #define SECURITY_CLIENT_PK_ID			3
  #define SECURITY_SERVER_PK_ID			4
  #define SECURITY_SECRET_KEY_ID			5
  #define SECURITY_SMS_MODE_ID			6
  #define SECURITY_SMS_BINDING_KEY_PARAM_ID	7
  #define SECURITY_SMS_BINDING_SECRET_KEY_ID	8
  #define SECURITY_LWM2M_SERVER_SMS_NUM_ID	9
  #define SECURITY_SHORT_SERVER_ID		10
  #define SECURITY_CLIENT_HOLD_OFF_TIME_ID	11
  #define SECURITY_BS_SERVER_ACCOUNT_TIMEOUT_ID	12
  #if defined(CONFIG_LWM2M_SECURITY_OBJECT_VERSION_1_1)
  #define SECURITY_MATCHING_TYPE_ID		13
  #define SECURITY_SNI_ID				14
  #define SECURITY_CERTIFICATE_USAGE_ID		15
  #define SECURITY_DTLS_TLS_CIPHERSUITE_ID	16
  #define SECURITY_OSCORE_SEC_MODE_ID		17
  #endif
  
  #define MAX_INSTANCE_COUNT		CONFIG_LWM2M_SECURITY_INSTANCE_COUNT
  
  #define SECURITY_URI_LEN		255
  #define IDENTITY_LEN			128
  #define KEY_LEN				CONFIG_LWM2M_SECURITY_KEY_SIZE
  
  /*
   * Calculate resource instances as follows:
   * start with SECURITY_MAX_ID
   *
   * If using object version 1.1
   * subtract MULTI resources because their counts include 0 resource (1)
   * add DTLS_TLS_CIPHERSUITE_MAX for DTLS_TLS_CIPHERSUITE resource instances
   */
  #if defined(CONFIG_LWM2M_SECURITY_OBJECT_VERSION_1_1)
  #define RESOURCE_INSTANCE_COUNT (SECURITY_MAX_ID - 1 + DTLS_TLS_CIPHERSUITE_MAX)
  #else
  #define RESOURCE_INSTANCE_COUNT	(SECURITY_MAX_ID)
  #endif
  
  /* resource state variables */
  static char  security_uri[MAX_INSTANCE_COUNT][SECURITY_URI_LEN];
  static uint8_t  client_identity[MAX_INSTANCE_COUNT][IDENTITY_LEN];
  static uint8_t  server_pk[MAX_INSTANCE_COUNT][KEY_LEN];
  static uint8_t  secret_key[MAX_INSTANCE_COUNT][KEY_LEN];
  static bool  bootstrap_flag[MAX_INSTANCE_COUNT];
  static uint8_t  security_mode[MAX_INSTANCE_COUNT];
  static uint16_t short_server_id[MAX_INSTANCE_COUNT];
  
  static struct lwm2m_engine_obj security;
  static struct lwm2m_engine_obj_field fields[] = {
  	OBJ_FIELD_DATA(SECURITY_SERVER_URI_ID, RW, STRING),
  	OBJ_FIELD_DATA(SECURITY_BOOTSTRAP_FLAG_ID, W, BOOL),
  	OBJ_FIELD_DATA(SECURITY_MODE_ID, W, U8),
  	OBJ_FIELD_DATA(SECURITY_CLIENT_PK_ID, W, OPAQUE),
  	OBJ_FIELD_DATA(SECURITY_SERVER_PK_ID, W, OPAQUE),
  	OBJ_FIELD_DATA(SECURITY_SECRET_KEY_ID, W, OPAQUE),
  	OBJ_FIELD_DATA(SECURITY_SMS_MODE_ID, W_OPT, U8),
  	OBJ_FIELD_DATA(SECURITY_SMS_BINDING_KEY_PARAM_ID, W_OPT, OPAQUE),
  	OBJ_FIELD_DATA(SECURITY_SMS_BINDING_SECRET_KEY_ID, W_OPT, OPAQUE),
  	OBJ_FIELD_DATA(SECURITY_LWM2M_SERVER_SMS_NUM_ID, W_OPT, STRING),
  	OBJ_FIELD_DATA(SECURITY_SHORT_SERVER_ID, W_OPT, U16),
  	OBJ_FIELD_DATA(SECURITY_CLIENT_HOLD_OFF_TIME_ID, W_OPT, S32),
  	OBJ_FIELD_DATA(SECURITY_BS_SERVER_ACCOUNT_TIMEOUT_ID, W_OPT, S32),
  #if defined(CONFIG_LWM2M_SECURITY_OBJECT_VERSION_1_1)
  	OBJ_FIELD_DATA(SECURITY_MATCHING_TYPE_ID, W_OPT, S32),
  	OBJ_FIELD_DATA(SECURITY_SNI_ID, W_OPT, STRING),
  	OBJ_FIELD_DATA(SECURITY_CERTIFICATE_USAGE_ID, W_OPT, U32),
  	OBJ_FIELD_DATA(SECURITY_DTLS_TLS_CIPHERSUITE_ID, W_OPT, U32),
  	OBJ_FIELD_DATA(SECURITY_OSCORE_SEC_MODE_ID, W_OPT, OBJLNK)
  #endif
  };
  
  static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT];
  static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][SECURITY_MAX_ID];
  static struct lwm2m_engine_res_inst
  			res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT];
  
  static struct lwm2m_engine_obj_inst *security_create(uint16_t obj_inst_id)
  {
  	int index, i = 0, j = 0;
  
  	/* Check that there is no other instance with this ID */
  	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
  		if (inst[index].obj && inst[index].obj_inst_id == obj_inst_id) {
  			LOG_ERR("Can not create instance - "
  				"already existing: %u", obj_inst_id);
  			return NULL;
  		}
  	}
  
  	for (index = 0; index < MAX_INSTANCE_COUNT; index++) {
  		if (!inst[index].obj) {
  			break;
  		}
  	}
  
  	if (index >= MAX_INSTANCE_COUNT) {
  		LOG_ERR("Can not create instance - "
  			"no more room: %u", obj_inst_id);
  		return NULL;
  	}
  
  	/* default values */
  	security_uri[index][0] = '\0';
  	client_identity[index][0] = '\0';
  	bootstrap_flag[index] = 0;
  	security_mode[index] = 0U;
  	short_server_id[index] = 0U;
  
  	(void)memset(res[index], 0,
  		     sizeof(res[index][0]) * ARRAY_SIZE(res[index]));
  	init_res_instance(res_inst[index], ARRAY_SIZE(res_inst[index]));
  
  	/* initialize instance resource data */
  	INIT_OBJ_RES_DATA(SECURITY_SERVER_URI_ID, res[index], i,
  			  res_inst[index], j,
  			  security_uri[index], SECURITY_URI_LEN);
  	INIT_OBJ_RES_DATA(SECURITY_BOOTSTRAP_FLAG_ID, res[index], i,
  			  res_inst[index], j,
  			  &bootstrap_flag[index], sizeof(*bootstrap_flag));
  	INIT_OBJ_RES_DATA(SECURITY_MODE_ID, res[index], i,
  			  res_inst[index], j,
  			  &security_mode[index], sizeof(*security_mode));
  	INIT_OBJ_RES_DATA(SECURITY_CLIENT_PK_ID, res[index], i,
  			  res_inst[index], j,
  			  &client_identity[index], IDENTITY_LEN);
  	INIT_OBJ_RES_DATA(SECURITY_SERVER_PK_ID, res[index], i,
  			  res_inst[index], j,
  			  &server_pk[index], KEY_LEN);
  	INIT_OBJ_RES_DATA(SECURITY_SECRET_KEY_ID, res[index], i,
  			  res_inst[index], j,
  			  &secret_key[index], KEY_LEN);
  	INIT_OBJ_RES_DATA(SECURITY_SHORT_SERVER_ID, res[index], i,
  			  res_inst[index], j,
  			  &short_server_id[index], sizeof(*short_server_id));
  #if defined(CONFIG_LWM2M_SECURITY_OBJECT_VERSION_1_1)
  	INIT_OBJ_RES_OPTDATA(SECURITY_MATCHING_TYPE_ID, res[index], i, res_inst[index], j);
  	INIT_OBJ_RES_OPTDATA(SECURITY_SNI_ID, res[index], i, res_inst[index], j);
  	INIT_OBJ_RES_OPTDATA(SECURITY_CERTIFICATE_USAGE_ID, res[index], i, res_inst[index], j);
  	INIT_OBJ_RES_MULTI_OPTDATA(SECURITY_DTLS_TLS_CIPHERSUITE_ID, res[index], i,
  				   res_inst[index], j, DTLS_TLS_CIPHERSUITE_MAX, false);
  	INIT_OBJ_RES_OPTDATA(SECURITY_OSCORE_SEC_MODE_ID, res[index], i, res_inst[index], j);
  #endif
  
  	inst[index].resources = res[index];
  	inst[index].resource_count = i;
  	LOG_DBG("Create LWM2M security instance: %d", obj_inst_id);
  
  	return &inst[index];
  }
  
  int lwm2m_security_inst_id_to_index(uint16_t obj_inst_id)
  {
  	int i;
  
  	for (i = 0; i < MAX_INSTANCE_COUNT; i++) {
  		if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) {
  			return i;
  		}
  	}
  
  	return -ENOENT;
  }
  
  int lwm2m_security_index_to_inst_id(int index)
  {
  	if (index >= MAX_INSTANCE_COUNT) {
  		return -EINVAL;
  	}
  
  	/* not instanstiated */
  	if (!inst[index].obj) {
  		return -ENOENT;
  	}
  
  	return inst[index].obj_inst_id;
  }
  
  static int lwm2m_security_init(const struct device *dev)
  {
  	struct lwm2m_engine_obj_inst *obj_inst = NULL;
  	int ret = 0;
  
  	security.obj_id = LWM2M_OBJECT_SECURITY_ID;
  	security.version_major = SECURITY_VERSION_MAJOR;
  	security.version_minor = SECURITY_VERSION_MINOR;
  	security.is_core = true;
  	security.fields = fields;
  	security.field_count = ARRAY_SIZE(fields);
  	security.max_instance_count = MAX_INSTANCE_COUNT;
  	security.create_cb = security_create;
  	lwm2m_register_obj(&security);
  
  	/* auto create the first instance */
  	ret = lwm2m_create_obj_inst(LWM2M_OBJECT_SECURITY_ID, 0, &obj_inst);
  	if (ret < 0) {
  		LOG_ERR("Create LWM2M security instance 0 error: %d", ret);
  	}
  
  	return ret;
  }
  
  SYS_INIT(lwm2m_security_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
  