| /* |
| * |
| * Copyright (c) 2023 Project CHIP Authors |
| * |
| * 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 "ASRFactoryDataParser.h" |
| |
| #if CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER |
| /* Logic partition on flash devices for matter */ |
| const matter_partition_t asr_matter_partitions_table[] = |
| { |
| [ASR_VERSION_PARTITION] = |
| { |
| .partition_name = "version", |
| }, |
| [ASR_CONFIG_PARTITION] = |
| { |
| .partition_name = "config", |
| }, |
| [ASR_ITERATION_COUNT_PARTITION] = |
| { |
| .partition_name = "iteration-count", |
| }, |
| [ASR_SALT_PARTITION] = |
| { |
| .partition_name = "salt", |
| }, |
| [ASR_VERIFIER_PARTITION] = |
| { |
| .partition_name = "verifier", |
| }, |
| [ASR_DISCRIMINATOR_PARTITION] = |
| { |
| .partition_name = "discriminator", |
| }, |
| [ASR_DAC_CERT_PARTITION] = |
| { |
| .partition_name = "dac-cert", |
| }, |
| [ASR_DAC_KEY_PARTITION] = |
| { |
| .partition_name = "dac-pri-key", |
| }, |
| [ASR_DAC_PUB_KEY_PARTITION] = |
| { |
| .partition_name = "dac-pub-key", |
| }, |
| [ASR_PAI_CERT_PARTITION] = |
| { |
| .partition_name = "pai-cert", |
| }, |
| [ASR_CERT_DCLRN_PARTITION] = |
| { |
| .partition_name = "cert-dclrn", |
| }, |
| [ASR_CHIP_ID_PARTITION] = |
| { |
| .partition_name = "chip-id", |
| }, |
| #if CONFIG_ENABLE_ASR_FACTORY_DEVICE_INFO_PROVIDER |
| [ASR_VENDOR_NAME_PARTITION] = |
| { |
| .partition_name = "vendor-name", |
| }, |
| [ASR_VENDOR_ID_PARTITION] = |
| { |
| .partition_name = "vendor-id", |
| }, |
| [ASR_PRODUCT_NAME_PARTITION] = |
| { |
| .partition_name = "product-name", |
| }, |
| [ASR_PRODUCT_ID_PARTITION] = |
| { |
| .partition_name = "product-id", |
| }, |
| [ASR_ROTATING_UNIQUE_ID_PARTITION] = |
| { |
| .partition_name = "rd-id-uid", |
| }, |
| [ASR_MANUFACTURY_DATE_PARTITION] = |
| { |
| .partition_name = "mfg-date", |
| }, |
| [ASR_SERIAL_NUMBER_PARTITION] = |
| { |
| .partition_name = "serial-num", |
| }, |
| [ASR_HARDWARE_VERSION_PARTITION] = |
| { |
| .partition_name = "hardware-ver", |
| }, |
| [ASR_HARDWARE_VERSION_STR_PARTITION] = |
| { |
| .partition_name = "hw-ver-str", |
| }, |
| [ASR_PRODUCT_URL_PARTITION] = |
| { |
| .partition_name = "product-url", |
| }, |
| [ASR_PRODUCT_LABEL_PARTITION] = |
| { |
| .partition_name = "product-label", |
| }, |
| [ASR_PART_NUMBER_PARTITION] = |
| { |
| .partition_name = "part-number", |
| }, |
| #endif |
| [ASR_MATTER_PARTITION_MAX] = |
| { |
| .partition_name = NULL, //for end don't change, |
| } |
| }; |
| |
| static asr_tlv_context matter_tlv_ctx; |
| |
| static factory_error_t asr_matter_find_by_name(const char * name, uint8_t * buf, uint32_t buf_len, uint32_t * out_len) |
| { |
| tlv_header_t tlv; |
| |
| if (asr_tlv_find_by_name(&matter_tlv_ctx, &tlv, MIXCLASS_MATTERCONFIG_TAG, |
| (char *) name)) // parse the data according to the tlv packaging tool |
| { |
| uint32_t value_len = tlv_htons(tlv->data_len); |
| |
| value_len -= MAX_NAME_LEN; |
| |
| if (value_len > buf_len) |
| { |
| return FACTORY_BUFFER_TOO_SMALL; |
| } |
| |
| *out_len = value_len; |
| |
| memcpy(buf, tlv->data + MAX_NAME_LEN, value_len); |
| |
| return FACTORY_NO_ERROR; |
| } |
| else |
| { |
| return FACTORY_VALUE_NOT_FOUND; |
| } |
| } |
| |
| static uint32_t asr_find_factory_version() |
| { |
| uint8_t buf[4]; |
| size_t outlen = 0; |
| uint32_t value = 0; |
| if (FACTORY_NO_ERROR == |
| asr_matter_find_by_name((const char *) asr_matter_partitions_table[ASR_VERSION_PARTITION].partition_name, buf, |
| sizeof(uint32_t), (uint32_t *) &outlen)) |
| { |
| value = *(uint32_t *) buf; |
| } |
| return value; |
| } |
| |
| static uint32_t asr_find_factory_config() |
| { |
| uint8_t buf[4]; |
| size_t outlen = 0; |
| uint32_t value = 0; |
| if (FACTORY_NO_ERROR == |
| asr_matter_find_by_name((const char *) asr_matter_partitions_table[ASR_CONFIG_PARTITION].partition_name, buf, |
| sizeof(uint32_t), (uint32_t *) &outlen)) |
| { |
| value = *(uint32_t *) buf; |
| } |
| return value; |
| } |
| |
| static factory_error_t asr_factory_dac_prvkey_get(uint8_t * pRdBuf, uint32_t * pOutLen) |
| { |
| static constexpr uint32_t kDACPrivateKeySize = 32; |
| if (NULL == pRdBuf || NULL == pOutLen) |
| { |
| return FACTORY_INVALID_INPUT; |
| } |
| |
| if (asr_find_factory_config() & ASR_CONFIG_MATTER_NO_KEY) |
| { |
| #if defined(CFG_PLF_RV32) || defined(CFG_PLF_DUET) |
| uint32_t off_set; |
| uint8_t ucCipher[kDACPrivateKeySize]; |
| tlv_area_header_t tlv_headr_p = (tlv_area_header_t) MATTER_FLASH_START_ADDR; |
| off_set = tlv_headr_p->data_len + 3 * sizeof(uint32_t); // magic_num,crc32_value,data_len |
| // get DAC cipher |
| if (asr_flash_read(ASR_CONFIG_BASE, (uint32_t *) &off_set, (void *) ucCipher, kDACPrivateKeySize) == 0) |
| { |
| if (asr_factory_decrypt_dac_prvkey(ucCipher, kDACPrivateKeySize, pRdBuf, pOutLen) == 0) |
| { |
| return FACTORY_NO_ERROR; |
| } |
| } |
| #endif |
| return FACTORY_NOT_SUPPORTED; |
| } |
| else |
| { |
| return asr_matter_find_by_name((const char *) asr_matter_partitions_table[ASR_DAC_KEY_PARTITION].partition_name, pRdBuf, |
| kDACPrivateKeySize, pOutLen); |
| } |
| } |
| |
| static int asr_partition_members_count_cb(tlv_header_t tlv, void * arg1, void * arg2) |
| { |
| int * count = (int *) arg1; |
| |
| *count = *count + 1; |
| |
| return 0; |
| } |
| |
| static factory_error_t asr_partition_table_load(void) |
| { |
| int table_members = 0; |
| |
| if (asr_tlv_poll_class_members(&matter_tlv_ctx, MIXCLASS_MATTERCONFIG_TAG, asr_partition_members_count_cb, &table_members, |
| NULL)) |
| { |
| if (table_members > 0) |
| { |
| if (asr_find_factory_version() == ASR_MATTER_FACTORY_VERSION) |
| { |
| return FACTORY_NO_ERROR; |
| } |
| else |
| { |
| return FACTORY_VERSION_MISMATCH; |
| } |
| } |
| } |
| return FACTORY_DATA_CHECK_FAILED; |
| } |
| |
| factory_error_t asr_factory_config_read(asr_matter_partition_t matter_partition, uint8_t * buf, uint32_t buf_len, |
| uint32_t * out_len) |
| { |
| |
| if (matter_partition >= ASR_MATTER_PARTITION_MAX) |
| { |
| return FACTORY_INVALID_INPUT; |
| } |
| |
| if (matter_partition == ASR_DAC_KEY_PARTITION) |
| { |
| return asr_factory_dac_prvkey_get(buf, out_len); |
| } |
| |
| return asr_matter_find_by_name((const char *) asr_matter_partitions_table[matter_partition].partition_name, buf, buf_len, |
| out_len); |
| } |
| |
| factory_error_t asr_factory_check() |
| { |
| if (asr_tlv_init(&matter_tlv_ctx, MATTER_FLASH_START_ADDR) != 0) |
| { |
| return FACTORY_DATA_INIT_FAILED; |
| } |
| |
| return asr_partition_table_load(); |
| } |
| #endif // CONFIG_ENABLE_ASR_FACTORY_DATA_PROVIDER |