Commit f572a536 authored by Jozef Kralik's avatar Jozef Kralik

esp32 as secure device

parent 00fd830c
......@@ -8,7 +8,7 @@ ESP32
- git clone --recursive https://github.com/espressif/esp-idf.git
- ./esp-idf/install.sh
- . ./esp-idf/export.sh
- [CommonSteps][]
- [CommonSteps](#common-steps)
## Windows
- [install] (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html)
......@@ -16,16 +16,29 @@ ESP32
- Install CMake
- Set PATH env to cmake, python
- Run esp-idf commandline
- [CommonSteps][]
## Common steps [CommonSteps] ##
```
idf.py set-target esp32
idf.py menuconfig // set wifi + mbedtls
( cd esp-idf/components/mbedtls/mbedtls && git am ../../../../patches/mbedtls/*.patch )
( cd esp-idf && git am ../patches/esp-idf/*.patch )
idf.py build
idf.py -p (PORT) flash monitor
```
- [CommonSteps](#common-steps)
## Common steps
- idf.py set-target esp32
- idf.py menuconfig // set wifi, mbedtls
- ( cd esp-idf/components/mbedtls/mbedtls && git am ../../../../patches/mbedtls/*.patch )
- ( cd esp-idf && git am ../patches/esp-idf/*.patch )
- idf.py build
- idf.py -p (PORT) flash monitor
# Known issues
- after own and onboard lot's of the heap is consumed (just 50KB are free). When the device was rebooted 130KB are free.
- partition nvs must be resize (extended) because storage store data to nvs
- when cloud is enabled OC_DYNAMIC_ALLOCATION must be set because OC_COLLECTIONS is not supported without OC_DYNAMIC_ALLOCATION
- max_app_data_size must be set to 6+KB(otherwise credentials are not stored to the storage) and less then 8KB(otherwise esp aborts(heap is exhausted) during own and onboard)
- compiler performance optimalization(-O2) must be set otherwise heap is exhausted during own and onboard
# Performance
| Setup | free heap size |
| SECURE, TCP, IPV4, fresh | 170KB |
| SECURE, TCP, IPV4, just owned | 89KB |
| SECURE, TCP, IPV4, owned, rebooted | 162KB |
| SECURE, TCP, IPV4, just owned, onboarded to the cloud | 53KB / crash for exhausted heap |
| SECURE, TCP, IPV4, owned, rebooted, onboarded to the cloud | 134KB |
......@@ -34,7 +34,6 @@ oc_clock_time(void)
time = (oc_clock_time_t)t.tv_sec * OC_CLOCK_SECOND +
(oc_clock_time_t)ceil(t.tv_nsec / (1.e09 / OC_CLOCK_SECOND));
}
OC_DBG("oc_clock_time (ts.tv_sec = %ld, ts.tv_nsec = %ld) %llu", t.tv_sec, t.tv_nsec, time);
return time;
}
......@@ -45,7 +44,6 @@ oc_clock_seconds(void)
struct timespec t;
if (clock_gettime(CLOCK_REALTIME, &t) != -1)
{
OC_DBG("oc_clock_seconds (ts.tv_sec = %ld, ts.tv_nsec = %ld)", t.tv_sec, t.tv_nsec);
return t.tv_sec;
}
return 0;
......
......@@ -1741,14 +1741,30 @@ int oc_connectivity_init(size_t device)
#endif /* OC_NETWORK_MONITOR */
ifchange_initialized = true;
}
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0 ) {
OC_ERR("pthread_attr_init");
return -1;
}
if (pthread_attr_setstacksize(&attr, 24000) != 0 ) {
OC_ERR("pthread_attr_setstacksize");
return -1;
}
if (pthread_create(&dev->event_thread, NULL, &network_event_thread, dev) !=
if (pthread_create(&dev->event_thread, &attr, &network_event_thread, dev) !=
0)
{
OC_ERR("creating network polling thread");
return -1;
}
if (pthread_attr_destroy(&attr) != 0 ) {
OC_ERR("pthread_attr_destroy");
return -1;
}
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &got_ip6_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &got_ip_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, NULL));
......
This diff is collapsed.
......@@ -20,8 +20,9 @@
#ifdef OC_STORAGE
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "nvs_flash.h"
#include "debug_print.h"
#define STORE_PATH_SIZE 64
......@@ -35,7 +36,8 @@ int oc_storage_config(const char *store)
if (store_path_len >= STORE_PATH_SIZE)
return -ENOENT;
strncpy(store_path, store, store_path_len);
memcpy(store_path, store, store_path_len);
store_path[store_path_len] = '\0';
path_set = true;
return 0;
......@@ -43,41 +45,62 @@ int oc_storage_config(const char *store)
long oc_storage_read(const char *store, uint8_t *buf, size_t size)
{
FILE *fp = 0;
size_t store_len = strlen(store);
if (!path_set || (1 + store_len + store_path_len >= STORE_PATH_SIZE))
APP_DBG("oc_storage_read: %s", store);
if (!path_set)
{
return -ENOENT;
}
nvs_handle_t handle;
esp_err_t err = nvs_open(store_path, NVS_READONLY, &handle);
if (err != ESP_OK)
{
APP_DBG("oc_storage_read cannot nvs_open %s: %d", store, err);
return -EINVAL;
}
store_path[store_path_len] = '/';
strncpy(store_path + store_path_len + 1, store, store_len);
store_path[1 + store_path_len + store_len] = '\0';
fp = fopen(store_path, "rb");
if (!fp)
err = nvs_get_blob(handle, store, buf, &size);
if (err != ESP_OK)
{
APP_DBG("oc_storage_read cannot nvs_get_blob %s: %d", store, err);
nvs_close(handle);
return -EINVAL;
}
size = fread(buf, 1, size, fp);
fclose(fp);
nvs_close(handle);
return size;
}
long oc_storage_write(const char *store, uint8_t *buf, size_t size)
{
FILE *fp;
size_t store_len = strlen(store);
if (!path_set || (store_len + store_path_len >= STORE_PATH_SIZE))
//APP_DBG("oc_storage_write: %s", store);
if (!path_set)
{
return -ENOENT;
}
nvs_handle_t handle;
esp_err_t err = nvs_open(store_path, NVS_READWRITE, &handle);
if (err != ESP_OK)
{
APP_DBG("oc_storage_write cannot nvs_open %s: %d", store, err);
return -EINVAL;
}
err = nvs_set_blob(handle, store, buf, size);
if (err != ESP_OK)
{
APP_DBG("oc_storage_write cannot nvs_set_blob %s: %d", store, err);
nvs_close(handle);
return -EINVAL;
}
store_path[store_path_len] = '/';
strncpy(store_path + store_path_len + 1, store, store_len);
store_path[1 + store_path_len + store_len] = '\0';
fp = fopen(store_path, "wb");
if (!fp)
err = nvs_commit(handle);
if (err != ESP_OK)
{
APP_DBG("oc_storage_write cannot nvs_commit %s: %d", store, err);
nvs_close(handle);
return -EINVAL;
}
size = fwrite(buf, 1, size, fp);
fclose(fp);
return size;
}
#endif /* OC_SECURITY */
......@@ -36,6 +36,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include "vfs_pipe.h"
#include "esp_netif.h"
#ifdef OC_TCP
......@@ -102,8 +103,6 @@ get_assigned_tcp_port(int sock, struct sockaddr_storage *sock_info)
static int
get_interface_index(int sock)
{
int interface_index = -1;
struct sockaddr_storage addr;
socklen_t socklen = sizeof(addr);
if (getsockname(sock, (struct sockaddr *)&addr, &socklen) == -1)
......@@ -111,44 +110,46 @@ get_interface_index(int sock)
OC_ERR("obtaining socket information %d", errno);
return -1;
}
OC_ERR("get_interface_index is not implemented");
return -1;
//TODO
#if 0
struct ifaddrs *ifs = NULL, *interface = NULL;
if (getifaddrs(&ifs) < 0) {
OC_ERR("querying interfaces: %d", errno);
return -1;
}
for (interface = ifs; interface != NULL; interface = interface->ifa_next) {
if (!(interface->ifa_flags & IFF_UP) || interface->ifa_flags & IFF_LOOPBACK)
for (esp_netif_t *esp_netif = esp_netif_next(NULL); esp_netif; esp_netif = esp_netif_next(esp_netif))
{
if (!esp_netif_is_netif_up(esp_netif))
{
continue;
if (addr.ss_family == interface->ifa_addr->sa_family) {
if (addr.ss_family == AF_INET6) {
struct sockaddr_in6 *a = (struct sockaddr_in6 *)interface->ifa_addr;
struct sockaddr_in6 *b = (struct sockaddr_in6 *)&addr;
if (memcmp(a->sin6_addr.s6_addr, b->sin6_addr.s6_addr, 16) == 0) {
interface_index = if_nametoindex(interface->ifa_name);
break;
}
}
if (addr.ss_family == AF_INET)
{
esp_netif_ip_info_t ip_info;
if (esp_netif_get_ip_info(esp_netif, &ip_info) != ESP_OK)
{
continue;
}
#ifdef OC_IPV4
else if (addr.ss_family == AF_INET) {
struct sockaddr_in *a = (struct sockaddr_in *)interface->ifa_addr;
struct sockaddr_in *b = (struct sockaddr_in *)&addr;
if (a->sin_addr.s_addr == b->sin_addr.s_addr) {
interface_index = if_nametoindex(interface->ifa_name);
break;
struct sockaddr_in *b = (struct sockaddr_in *)&addr;
if (b->sin_addr.s_addr == ip_info.ip.addr)
{
return esp_netif_get_netif_impl_index(esp_netif);
}
}
if (addr.ss_family == AF_INET6)
{
struct sockaddr_in6 *b = (struct sockaddr_in6 *)&addr;
esp_ip6_addr_t if_ip6[LWIP_IPV6_NUM_ADDRESSES];
int num = esp_netif_get_all_ip6(esp_netif, if_ip6);
for (int i = 0; i < num; ++i)
{
if (ip6_addr_isany(&if_ip6[i]) || ip6_addr_isloopback(&if_ip6[i]))
{
continue;
}
if (memcmp(&if_ip6[i].addr, b->sin6_addr.s6_addr, 16) == 0)
{
return esp_netif_get_netif_impl_index(esp_netif);
}
}
#endif /* OC_IPV4 */
}
}
freeifaddrs(ifs);
return interface_index;
#endif
OC_ERR("interface not found");
return -1;
}
void oc_tcp_add_socks_to_fd_set(ip_context_t *dev)
......@@ -398,6 +399,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message)
else if (FD_ISSET(dev->tcp.connect_pipe[0], fds))
{
ssize_t len = read(dev->tcp.connect_pipe[0], message->data, OC_PDU_SIZE);
OC_DBG("oc_tcp_receive_message select: dev->tcp.connect_pipe[0]: %d", (int)len);
if (len < 0)
{
OC_ERR("read error! %d", errno);
......@@ -508,7 +510,7 @@ connect_nonb(int sockfd, const struct sockaddr *r, int r_len, int nsec)
{
int flags, n, error;
socklen_t len;
fd_set rset, wset;
fd_set wset;
struct timeval tval;
flags = fcntl(sockfd, F_GETFL, 0);
......@@ -536,20 +538,19 @@ connect_nonb(int sockfd, const struct sockaddr *r, int r_len, int nsec)
goto done; /* connect completed immediately */
}
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
FD_ZERO(&wset);
FD_SET(sockfd, &wset);
tval.tv_sec = nsec;
tval.tv_usec = 0;
if ((n = select(sockfd + 1, &rset, &wset, NULL, nsec ? &tval : NULL)) == 0)
if ((n = select(sockfd + 1, NULL, &wset, NULL, nsec ? &tval : NULL)) == 0)
{
/* timeout */
errno = ETIMEDOUT;
return -1;
}
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset))
if (FD_ISSET(sockfd, &wset))
{
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
......@@ -564,7 +565,6 @@ connect_nonb(int sockfd, const struct sockaddr *r, int r_len, int nsec)
done:
if (error < 0)
{
close(sockfd); /* just in case */
errno = error;
return -1;
}
......@@ -762,7 +762,6 @@ tcp_connectivity_ipv4_init(ip_context_t *dev)
OC_DBG("Successfully initialized TCP adapter IPv4 for device %zd",
dev->device);
return 0;
}
#endif /* OC_IPV4 */
......@@ -775,7 +774,6 @@ int oc_tcp_connectivity_init(ip_context_t *dev)
{
oc_abort("error initializing TCP adapter mutex");
}
memset(&dev->tcp.server, 0, sizeof(struct sockaddr_storage));
struct sockaddr_in6 *l = (struct sockaddr_in6 *)&dev->tcp.server;
l->sin6_family = AF_INET6;
......
......@@ -53,8 +53,6 @@ set(sources
${CMAKE_CURRENT_SOURCE_DIR}/../../../messaging/coap/separate.c
${CMAKE_CURRENT_SOURCE_DIR}/../../../messaging/coap/transactions.c
${CMAKE_CURRENT_SOURCE_DIR}/lightbulb.c
${CMAKE_CURRENT_SOURCE_DIR}/light_bulb_main.c
main.c
)
......@@ -96,7 +94,6 @@ endif()
if (CONFIG_SECURE)
add_definitions(-DOC_SECURITY -DOC_PKI -DAPP_DEBUG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation")
list(APPEND sources
${CMAKE_CURRENT_SOURCE_DIR}/../../../security/oc_acl.c
${CMAKE_CURRENT_SOURCE_DIR}/../../../security/oc_ael.c
......@@ -131,6 +128,8 @@ endif()
#add_definitions(-DOC_CLIENT)
#add_definitions(-DOC_SERVER)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation")
idf_component_register(
SRCS
${sources}
......
......@@ -25,27 +25,43 @@ config APP_DEBUG
config DYNAMIC
bool "DYNAMIC"
default true
help
enable or disable DYNAMIC
config SECURE
bool "SECURE"
default true
help
enable or disable SECURE
config IPV4
bool "IPV4"
default true
help
enable or disable IPV4
config TCP
bool "TCP"
default true
help
enable or disable TCP
config CLOUD
bool "CLOUD"
default true
help
enable or disable CLOUD
config BLINK_GPIO
int "Blink GPIO number"
range 0 34
default 13
help
GPIO number (IOxx) to blink on and off.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.
GPIOs 35-39 are input-only so cannot be used as outputs.
endmenu
/* lightbulb damon task
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "debug_print.h"
#include "lightbulb.h"
void lightbulb_damon_task(void *pvParameter)
{
//APP_DBG("start lightbulb damon task...");
lightbulb_init();
bulb_state_t *esp_bulb_current_state = NULL;
while (1)
{
esp_bulb_current_state = get_current_bulb_state();
/*
APP_DBG("[update] on/off:%d interval:%d H:%f S:%f B:%d",
esp_bulb_current_state->set_on, esp_bulb_current_state->flash_interval,
esp_bulb_current_state->hue_value, esp_bulb_current_state->saturation_value, esp_bulb_current_state->brightness_value);
*/
// set light state to GPIO
lightbulb_set_hue(&(esp_bulb_current_state->hue_value));
lightbulb_set_saturation(&(esp_bulb_current_state->saturation_value));
lightbulb_set_brightness(&(esp_bulb_current_state->brightness_value));
lightbulb_set_on(&(esp_bulb_current_state->set_on));
vTaskDelay(10 / portTICK_RATE_MS);
// flash or not
if (esp_bulb_current_state->flash_interval != 0)
{
lightbulb_set_off();
vTaskDelay(esp_bulb_current_state->flash_interval);
}
}
(void)vTaskDelete(NULL);
}
/* lightbulb implement
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "driver/ledc.h"
#include "esp_log.h"
#include "lightbulb.h"
#include "debug_print.h"
// default:
// GPIO4 -> Red
// GPIO5 -> Green
// GPIO21 -> Blue
#define LEDC_IO_0 (4)
#define LEDC_IO_1 (5)
#define LEDC_IO_2 (21)
#define PWM_DEPTH (1023)
#define PWM_TARGET_DUTY 8192
typedef struct rgb
{
uint8_t r; // 0-100 %
uint8_t g; // 0-100 %
uint8_t b; // 0-100 %
} rgb_t;
typedef struct hsp
{
uint16_t h; // 0-360
uint16_t s; // 0-100
uint16_t b; // 0-100
} hsp_t;
static hsp_t s_hsb_val;
static uint16_t s_brightness;
static bool s_on = false;
static bulb_state_t s_bulb_state = {false, 0, 0, 0, 0};
static const char *TAG = "light bulb";
/**
* @brief transform lightbulb's "RGB" and other parameter
*/
static void lightbulb_set_aim(uint32_t r, uint32_t g, uint32_t b, uint32_t cw, uint32_t ww, uint32_t period)
{
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, r);
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, g);
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, b);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2);
}
/**
* @brief transform lightbulb's "HSV" to "RGB"
*/
static bool lightbulb_set_hsb2rgb(uint16_t h, uint16_t s, uint16_t v, rgb_t *rgb)
{
bool res = true;
uint16_t hi, F, P, Q, T;
if (!rgb)
{
return false;
}
if (h > 360)
{
return false;
}
if (s > 100)
{
return false;
}
if (v > 100)
{
return false;
}
hi = (h / 60) % 6;
F = 100 * h / 60 - 100 * hi;
P = v * (100 - s) / 100;
Q = v * (10000 - F * s) / 10000;
T = v * (10000 - s * (100 - F)) / 10000;
switch (hi)
{
case 0:
rgb->r = v;
rgb->g = T;
rgb->b = P;
break;
case 1:
rgb->r = Q;
rgb->g = v;
rgb->b = P;
break;
case 2:
rgb->r = P;
rgb->g = v;
rgb->b = T;
break;
case 3:
rgb->r = P;
rgb->g = Q;
rgb->b = v;
break;
case 4:
rgb->r = T;
rgb->g = P;
rgb->b = v;
break;
case 5:
rgb->r = v;
rgb->g = P;
rgb->b = Q;
break;
default:
return false;
}
return res;
}
/**
* @brief set the lightbulb's "HSV"
*/
static bool lightbulb_set_aim_hsv(uint16_t h, uint16_t s, uint16_t v)
{
rgb_t rgb_tmp;
bool ret = lightbulb_set_hsb2rgb(h, s, v, &rgb_tmp);
if (ret == false)
{
ESP_LOGE(TAG, "lightbulb_set_hsb2rgb failed");
return false;
}
lightbulb_set_aim(rgb_tmp.r * PWM_TARGET_DUTY / 100, rgb_tmp.g * PWM_TARGET_DUTY / 100,