blob: 85caee5f9ac6b25f8ec9fe48486b39dab3069df6 [file] [log] [blame]
/*
*
* Copyright (c) 2022 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 "FactoryDataParser.h"
#include <zcbor_decode.h>
#include <zephyr/logging/log.h>
#include <ctype.h>
#include <string.h>
#define MAX_FACTORY_DATA_NESTING_LEVEL 3
LOG_MODULE_DECLARE(app, CONFIG_MATTER_LOG_LEVEL);
static inline bool uint16_decode(zcbor_state_t * states, uint16_t * value)
{
uint32_t u32;
if (zcbor_uint32_decode(states, &u32))
{
*value = (uint16_t) u32;
return true;
}
return false;
}
static bool DecodeEntry(zcbor_state_t * states, void * buffer, size_t bufferSize, size_t * outlen)
{
struct zcbor_string tempString;
int32_t tempInt = 0;
// Try to decode entry as string
bool res = zcbor_tstr_decode(states, &tempString);
if (res)
{
if (bufferSize < tempString.len)
{
return false;
}
memcpy(buffer, tempString.value, tempString.len);
*outlen = tempString.len;
return res;
}
// Try to decode entry as int32
res = zcbor_int32_decode(states, &tempInt);
if (res)
{
if (bufferSize < sizeof(tempInt))
{
return false;
}
memcpy(buffer, &tempInt, sizeof(tempInt));
*outlen = sizeof(tempInt);
return res;
}
return res;
}
bool FindUserDataEntry(struct FactoryData * factoryData, const char * entry, void * buffer, size_t bufferSize, size_t * outlen)
{
if ((!factoryData) || (!factoryData->user.data) || (!buffer) || (!outlen))
{
return false;
}
ZCBOR_STATE_D(states, MAX_FACTORY_DATA_NESTING_LEVEL - 1, factoryData->user.data, factoryData->user.len, 1);
bool res = zcbor_map_start_decode(states);
bool keyFound = false;
struct zcbor_string currentString;
while (res)
{
res = zcbor_tstr_decode(states, &currentString);
if (!res)
{
break;
}
if (strncmp(entry, (const char *) currentString.value, currentString.len) == 0)
{
res = DecodeEntry(states, buffer, bufferSize, outlen);
keyFound = true;
break;
}
else
{
res = res && zcbor_any_skip(states, NULL);
}
}
return res && keyFound && zcbor_list_map_end_force_decode(states);
}
bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData * factoryData)
{
memset(factoryData, 0, sizeof(*factoryData));
ZCBOR_STATE_D(states, MAX_FACTORY_DATA_NESTING_LEVEL, buffer, bufferSize, 1);
bool res = zcbor_map_start_decode(states);
struct zcbor_string currentString;
while (res)
{
res = zcbor_tstr_decode(states, &currentString);
if (!res)
{
res = true;
break;
}
if (strncmp("version", (const char *) currentString.value, currentString.len) == 0)
{
res = res && uint16_decode(states, &factoryData->version);
}
else if (strncmp("hw_ver", (const char *) currentString.value, currentString.len) == 0)
{
res = res && uint16_decode(states, &factoryData->hw_ver);
factoryData->hwVerPresent = res;
}
else if (strncmp("spake2_it", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_uint32_decode(states, &factoryData->spake2_it);
}
else if (strncmp("vendor_id", (const char *) currentString.value, currentString.len) == 0)
{
res = res && uint16_decode(states, &factoryData->vendor_id);
factoryData->vendorIdPresent = res;
}
else if (strncmp("product_id", (const char *) currentString.value, currentString.len) == 0)
{
res = res && uint16_decode(states, &factoryData->product_id);
factoryData->productIdPresent = res;
}
else if (strncmp("discriminator", (const char *) currentString.value, currentString.len) == 0)
{
res = res && uint16_decode(states, &factoryData->discriminator);
factoryData->discriminatorPresent = res;
}
else if (strncmp("passcode", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_uint32_decode(states, &factoryData->passcode);
}
else if (strncmp("sn", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->sn);
}
else if (strncmp("date", (const char *) currentString.value, currentString.len) == 0)
{
// Date format is YYYY-MM-DD, so format needs to be validated and string parse to integer parts.
struct zcbor_string date;
res = res && zcbor_bstr_decode(states, &date);
if (date.len == 10 && isdigit(date.value[0]) && isdigit(date.value[1]) && isdigit(date.value[2]) &&
isdigit(date.value[3]) && date.value[4] == '-' && isdigit(date.value[5]) && isdigit(date.value[6]) &&
date.value[7] == '-' && isdigit(date.value[8]) && isdigit(date.value[9]))
{
factoryData->date_year =
1000 * (date.value[0] - '0') + 100 * (date.value[1] - '0') + 10 * (date.value[2] - '0') + date.value[3] - '0';
factoryData->date_month = 10 * (date.value[5] - '0') + date.value[6] - '0';
factoryData->date_day = 10 * (date.value[8] - '0') + date.value[9] - '0';
}
else
{
LOG_ERR("Parsing error - wrong date format");
}
}
else if (strncmp("hw_ver_str", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->hw_ver_str);
}
else if (strncmp("rd_uid", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->rd_uid);
}
else if (strncmp("dac_cert", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_cert);
}
else if (strncmp("dac_key", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_priv_key);
}
else if (strncmp("pai_cert", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->pai_cert);
}
else if (strncmp("spake2_salt", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_salt);
}
else if (strncmp("spake2_verifier", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_verifier);
}
else if (strncmp("vendor_name", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->vendor_name);
}
else if (strncmp("product_name", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_name);
}
else if (strncmp("part_number", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->part_number);
}
else if (strncmp("product_url", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_url);
}
else if (strncmp("product_label", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_label);
}
else if (strncmp("enable_key", (const char *) currentString.value, currentString.len) == 0)
{
res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->enable_key);
}
else if (strncmp("user", (const char *) currentString.value, currentString.len) == 0)
{
factoryData->user.data = (void *) states->payload;
res = res && zcbor_any_skip(states, NULL);
factoryData->user.len = (void *) states->payload - factoryData->user.data;
}
else
{
res = res && zcbor_any_skip(states, NULL);
}
}
return res && zcbor_list_map_end_force_decode(states);
}