demo/secure_element/main.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"
#include "example_app_util.h"
// Time to debounce the button
#define BUTTON_DEBOUNCE_TIME_MS (50) // ms
// Time to wait for the button to be pressed before invoking the handler
#define BUTTON_PRESS_TIME_MS (1000) // ms
// Period this app will issue a HTTPs request
#define REQUEST_PERIOD_MS (5000)
// The URL used by the HTTPS request
#define URL_FMT "https://%s:4433/index.html"
// The root CA cert, this is stored on the File System
#define CA_CERT_FILE "self-signed-root-ca.crt"
// The device cert and key stored in the SE
// The filename prefix: 'SE::' tells Gecko OS this cert is stored in the secure element
// See atca_se_load_certificate_callback() in the secure element lib for more details
#define CERT_FILE "SE::device.crt"
#define KEY_FILE "SE::device.key"
// The hostname read from the SE
char se_hostname[128];
// Indicates if the SE has been configured
// i.e. If the SE's configuration has been written and locked
bool is_configured;
// Indicates if the SE has be provisioned
// i.e. If the generated credentials have been written to the SE
bool is_provisioned;
/*************************************************************************************************
* The starting point for the app
*/
void gos_app_init(void)
{
gos_result_t result;
// Button1 config
const gos_button_config_t btn_config =
{
.active_level = PLATFORM_BUTTON_ACTIVE_STATE,
.debounce = BUTTON_DEBOUNCE_TIME_MS,
.press_time = BUTTON_PRESS_TIME_MS,
.event_handler.press = button_pressed_event_handler,
};
GOS_LOG("Secure Element example starting ...");
gos_button_init(PLATFORM_STD_BUTTON, &btn_config, NULL);
// Initialize the secure element
if(GOS_FAILED(result, secure_element_init()))
{
GOS_LOG("Failed to init secure element, err:%d", result);
return;
}
// If the SE has been provisioned then attempt to bring up the network
if(is_provisioned)
{
GOS_LOG("Secure element is provisioned");
if (GOS_FAILED(result, example_app_util_network_up(GOS_INTERFACE_DEFAULT, false, network_event_handler)))
{
}
}
else
{
GOS_LOG("Secure element is NOT provisioned, run generation scripts then re-program this app before continuing");
}
}
/*************************************************************************************************
* Handler which is invoked when the network is brought up or down
*/
static void network_event_handler(bool is_up)
{
if(is_up && is_provisioned)
{
GOS_LOG("Network up, starting request loop ...");
gos_event_issue(issue_https_request_event_handler, NULL, GOS_EVENT_FLAG_NONE);
}
}
/*************************************************************************************************
* Handler that is periodically called to issue a HTTPS request to the server
*/
static void issue_https_request_event_handler(void *unused)
{
gos_result_t result;
gos_handle_t handle;
char url_buffer[256];
// Request config
const gos_http_request_t request =
{
.method = GOS_HTTP_GET,
.url = url_buffer,
.content_length = 0, // -1 means 'chunked' transfer-encoding
.certs.ca = CA_CERT_FILE, // CA cert stored on FS
.certs.cert = CERT_FILE, // Device cert stored in SE
.certs.key = KEY_FILE, // Device key stored in SE
.use_secure_element = true // Indicates that this request should use the SE
};
// Response config
{
.timeout = 60*1000,
.flags = GOS_HTTP_RESPONSE_AUTO_CLEANUP,
.max_size = 2048
};
// Populate the hostname from the SE into the formatted URL
snprintf(url_buffer, sizeof(url_buffer), URL_FMT, se_hostname);
GOS_LOG("Issuing http_post request ... ");
// Issue the HTTPS request
if (GOS_FAILED(result, gos_http_open_request(&request, &handle)))
{
GOS_LOG("Request failed: %d", result);
return;
}
GOS_LOG("Receiving response ... ");
// Wait for the response
if (GOS_FAILED(result, gos_http_receive_response_with_config(handle, &response, &config)))
{
GOS_LOG("Response failed: %d", result);
return;
}
GOS_LOG("Response code: %d", response.code);
GOS_LOG("Response length: %d", response.content_length);
GOS_LOG("Response:");
// Print the response body to the log bus
for(;;)
{
gos_buffer_t buffer = {.size = UINT16_MAX};
if (GOS_FAILED(result, gos_http_read_with_buffer(handle, &buffer)))
{
break;
}
else if(buffer.size == 0)
{
break;
}
gos_write_log((char*)buffer.data, buffer.size);
}
// Cleanup the connection
gos_http_close(handle);
GOS_LOG("Success\r\n");
// Schedule another request to be issued in a little bit
gos_event_register_timed(issue_https_request_event_handler, NULL, REQUEST_PERIOD_MS, GOS_EVENT_FLAG_NONE);
}
/*************************************************************************************************
* Initialize the secure element
*/
static gos_result_t secure_element_init(void)
{
gos_result_t result;
char str_buffer[128];
static const uint16_t key_exchange_slots[] = {SE_KEY_EXCHANGE_SLOT};
const gos_atca_config_t config =
{
.i2c.port = PLATFORM_STD_I2C, // Use the standard I2C port
.device =
{
.cert_def = &g_cert_def_2_device, // Specify the generated device cert template
.key_slot = SE_DEVICE_KEY_SLOT // Specify the device cert key 'slot'
},
.signer =
{
.cert_def = &g_cert_def_1_signer, // Specify the generated signer cert template
.ca_public_key_slot = SE_SIGNER_CA_PUBLIC_KEY_SLOT // Specify the slot the signer cert's CA public key is stored
},
.key_exhange = // Specify the slot(s) used for exchanging keys during a TLS handshake
{
.slots = key_exchange_slots,
.slot_count = ARRAY_COUNT(key_exchange_slots)
}
};
// Register Elliptic Curve mBedTLS callbacks
// Gecko OS will invoke these callbacks during a TLS handshake when necessary
// This allows use of the SE during a TLS handshake
// Initialize an board specific hardware
{
GOS_LOG("Failed to init board specific hw, err:%d", result);
goto exit;
}
GOS_LOG("Initializing secure element ...");
// Initialize the SE library
if(GOS_FAILED(result, gos_atca_init(&config)))
{
goto exit;
}
// Retrieve the SE's revision number
if(GOS_FAILED(result, gos_atca_get_revision_str(str_buffer)))
{
goto exit;
}
GOS_LOG("SE revision: %s", str_buffer);
// Retrieve the SE's serial number
if(GOS_FAILED(result, gos_atca_get_serial_number_str(str_buffer)))
{
goto exit;
}
GOS_LOG("SE serial number: %s", str_buffer);
// Check if the SE has been configured
if(GOS_FAILED(result, se_is_configured(&is_configured)))
{
goto exit;
}
// Return error if the SE has NOT been configured
if(!is_configured)
{
GOS_LOG("\r\n\r\nSE not configured!");
GOS_LOG("Press and hold button 1 to configure SE now");
GOS_LOG("WARN: This operation is irreversible!!");
GOS_LOG(" Once the SE is programmed with this example's configuration,");
GOS_LOG(" it cannot be programmed again!\r\n\r\n");
result = GOS_ABORTED;
goto exit;
}
// Check if the SE has been provisioned
if(GOS_FAILED(result, se_is_provisioned(&is_provisioned)))
{
goto exit;
}
// Retrieve the hostname from the SE's metadata
// if it has been provisioned
if(is_provisioned)
{
if(GOS_FAILED(result, se_get_hostname(se_hostname)))
{
goto exit;
}
GOS_LOG("SE hostname: %s", se_hostname);
GOS_LOG("SE ready");
}
exit:
return result;
}
/*************************************************************************************************
* This is invoked when button 1 is pressed
*/
static void button_pressed_event_handler(void *unused)
{
gos_result_t result;
// If the SE has NOT been configured then do so now
if(!is_configured)
{
GOS_LOG("Configuring Secure element");
GOS_LOG("WARN: This operation is irreversible!");
if(GOS_FAILED(result, se_configure()))
{
GOS_LOG("Failed to configure and lock SE, err:%d", result);
}
else
{
GOS_LOG("Secure element successfully configured");
GOS_LOG("Rebooting system now");
}
}
}