demo/secure_element/commands.c
/*******************************************************************************
* # License
* Copyright 2019 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/
#include "common.h"
/*************************************************************************************************
* Return the current SE status
*/
{
uint8_t response_buffer[128];
gos_msgpack_write_dict_marker(&msgpack, 2);
gos_msgpack_write_dict_bool(&msgpack, "configured", is_configured);
}
/*************************************************************************************************
* Initialize the SE and return details about it
*/
{
gos_result_t result;
uint8_t public_key[ATCA_PUB_KEY_SIZE];
uint8_t response_buffer[256];
MSGPACK_INIT_WITH_BUFFER(msgpack, response_buffer, sizeof(response_buffer));
// Calculate the device's public key
{
create_response_message(&msgpack, "Failed to generate public key, err:%d", result);
}
else
{
char temp_str[48];
gos_msgpack_write_dict_marker(&msgpack, 2);
gos_atca_get_serial_number_str(temp_str);
gos_msgpack_write_dict_str(&msgpack, "serial_number", temp_str);
gos_msgpack_write_dict_bool(&msgpack, "provisioned", is_provisioned);
gos_msgpack_write_dict_bool(&msgpack, "configured", is_configured);
}
return gos_cmd_write_response(GOS_CMD_RESULT(result), response_buffer, MSGPACK_BUFFER_USED(&msgpack));
}
/*************************************************************************************************
* Reset the SE to 'unprovisioned'
*/
{
gos_result_t result;
uint8_t metadata[SLOT8_SIZE];
uint8_t response_buffer[256];
MSGPACK_INIT_WITH_BUFFER(msgpack, response_buffer, sizeof(response_buffer));
memset(metadata, 0, sizeof(metadata));
// Reset the metadata 'slot'
// This will clear the 'provision_flag' from the metadata
{
create_response_message(&msgpack, "Failed to clear metadata, err:%d", result);
}
else
{
create_response_message(&msgpack, "Success");
}
return gos_cmd_write_response(GOS_CMD_RESULT(result), response_buffer, MSGPACK_BUFFER_USED(&msgpack));
}
/*************************************************************************************************
* Generate a certificate signing request (CSR) for the device certificate
*/
{
gos_result_t result;
uint8_t csr_buffer[1024];
gos_buffer_t buffer =
{
.data = csr_buffer,
.size = sizeof(csr_buffer)
};
uint8_t response_buffer[sizeof(csr_buffer)+32];
MSGPACK_INIT_WITH_BUFFER(msgpack, response_buffer, sizeof(response_buffer));
// Invoke the SE to generate a Certificate Signing Request (CSR)
{
create_response_message(&msgpack, "Failed to generate device cert CSR, err:%d", result);
}
else
{
gos_msgpack_write_dict_marker(&msgpack, 1);
}
return gos_cmd_write_response(GOS_CMD_RESULT(result), response_buffer, MSGPACK_BUFFER_USED(&msgpack));
}
/*************************************************************************************************
* Save the generated credentials to the SE
*/
{
#define CREDS_PAYLOAD_TIMEOUT_MS 15000
gos_result_t result;
uint8_t *payload = NULL;
gos_msgpack_object_t *root_obj = NULL;
uint8_t response_buffer[256];
intmax_t payload_length;
MSGPACK_INIT_WITH_BUFFER(msgpack, response_buffer, sizeof(response_buffer));
// Get the size of the payload
{
create_response_message(&msgpack, "Failed to payload length argument, err:%d", result);
}
// Allocate a buffer to hold the payload
{
create_response_message(&msgpack, "Failed allocate buffer for payload, err:%d", result);
}
// Read the payload from the command
else if(GOS_FAILED(result, gos_cmd_read_data(payload, (uint32_t)payload_length, NULL, CREDS_PAYLOAD_TIMEOUT_MS)))
{
create_response_message(&msgpack, "Failed to read payload, err:%d", result);
}
// Decode the msgpack payload into msgpack objects
else if(GOS_FAILED(result, gos_msgpack_deserialize_with_buffer(&root_obj, payload, (uint32_t)payload_length, MSGPACK_FLAGS_NONE)))
{
create_response_message(&msgpack, "Failed to decode msgpack payload, err:%d", result);
}
else
{
uint8_t temp_buffer[2048];
uint8_t public_key[ATCA_PUB_KEY_SIZE];
gos_buffer_t buffer;
se_metadata_t metadata;
const uint8_t *cert_data;
uint32_t cert_length;
// Ensure the necessary fields are were in the payload
if(signer_ca_pub_obj == NULL ||
signer_cert_obj == NULL ||
device_cert_obj == NULL ||
hostname_obj == NULL)
{
result = GOS_BADARG;
create_response_message(&msgpack, "Payload missing required fields");
goto exit;
}
// Write the root CA cert's public key to the corresponding slot
{
create_response_message(&msgpack, "Failed to write signer CA public key, err:%d", result);
goto exit;
}
// Write the signer cert
cert_data = MSGPACK_BIN_VALUE(signer_cert_obj);
cert_length = MSGPACK_BIN_LENGTH(signer_cert_obj);
{
create_response_message(&msgpack, "Failed to write signer cert, err:%d", result);
goto exit;
}
// Read back the signer cert
buffer.data = temp_buffer;
buffer.size = sizeof(temp_buffer);
{
create_response_message(&msgpack, "Failed to read back signer cert, err:%d", result);
goto exit;
}
// Validate the signer cert against the root CA's public key
if(GOS_FAILED(result, gos_atca_verify_cert(&g_cert_def_1_signer, public_key, buffer.data, buffer.size)))
{
create_response_message(&msgpack, "Failed to verify signer cert, err:%d", result);
goto exit;
}
// Extract the public key from the signer cert
if(GOS_FAILED(result, gos_atca_get_cert_public_key(&g_cert_def_1_signer, buffer.data, buffer.size, public_key)))
{
create_response_message(&msgpack, "Failed to retrieve public key from signer cert, err:%d", result);
goto exit;
}
// Write the device cert
cert_data = MSGPACK_BIN_VALUE(device_cert_obj);
cert_length = MSGPACK_BIN_LENGTH(device_cert_obj);
{
create_response_message(&msgpack, "Failed to write device cert, err:%d", result);
goto exit;
}
// Read back the device cert
buffer.data = temp_buffer;
buffer.size = sizeof(temp_buffer);
{
create_response_message(&msgpack, "Failed to read back device cert, err:%d", result);
goto exit;
}
// Validate the device cert against the signer cert's public key
if(GOS_FAILED(result, gos_atca_verify_cert(&g_cert_def_2_device, public_key, buffer.data, buffer.size)))
{
create_response_message(&msgpack, "Failed to verify device cert, err:%d", result);
goto exit;
}
// Read the currently stored metadata
{
create_response_message(&msgpack, "Failed to read metadata, err:%d", result);
goto exit;
}
// Copy the hostname and set the 'provision_flag'
char hostname[SLOT8_HOSTNAME_SIZE];
memset(metadata.hostname, 0, sizeof(metadata.hostname));
metadata.hostname_size = strlen(hostname);
memcpy(metadata.hostname, hostname, metadata.hostname_size);
metadata.provision_flag = SLOT8_PROVISIONED_FLAG_VALUE;
// Write the updated metadata to the SE
{
create_response_message(&msgpack, "Failed to write metadata, err:%d", result);
goto exit;
}
// At this point all the credentials have been written to the SE
// and the SE is fully provisioned
}
exit:
gos_free(payload);
gos_msgpack_free_objects(root_obj);
{
create_response_message(&msgpack, "Success");
}
return gos_cmd_write_response(GOS_CMD_RESULT(result), response_buffer, MSGPACK_BUFFER_USED(&msgpack));
}
/*************************************************************************************************
* Dump the public credentials stored in the SE to the log bus
*/
{
uint8_t temp_buffer[2048];
uint8_t public_key[ATCA_PUB_KEY_SIZE];
gos_result_t result;
gos_buffer_t buffer =
{
.data = temp_buffer,
.size = sizeof(temp_buffer)
};
{
goto exit;
}
{
goto exit;
}
if(GOS_FAILED(result, gos_atca_get_cert_public_key(&g_cert_def_1_signer, buffer.data, buffer.size, public_key)))
{
goto exit;
}
GOS_DUMP_UINT8_BUFFER(public_key, ATCA_PUB_KEY_SIZE, "Signer cert public key");
buffer.data = temp_buffer;
buffer.size = sizeof(temp_buffer);
{
goto exit;
}
if(GOS_FAILED(result, gos_atca_get_cert_public_key(&g_cert_def_2_device, buffer.data, buffer.size, public_key)))
{
goto exit;
}
GOS_DUMP_UINT8_BUFFER(public_key, ATCA_PUB_KEY_SIZE, "Device cert public key");
exit:
return GOS_CMD_RESULT(result);
}
/*************************************************************************************************/
{
char fmt_buffer[256];
va_list args;
va_start(args, fmt);
vsnprintf(fmt_buffer, sizeof(fmt_buffer), fmt, args);
va_end(args);
gos_msgpack_write_dict_marker(msgpack, 1);
gos_msgpack_write_dict_str(msgpack, "msg", fmt_buffer);
}