From 1e6ca2784bac0a51eb1c426abb4a320af7c78996 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sat, 28 May 2022 11:03:49 +0100 Subject: [PATCH 01/32] Vendor in the highly customised tinyusb, rather than patching esp-iot-solution --- components/tinyusb/CMakeLists.txt | 106 ++ components/tinyusb/Kconfig | 267 ++++ .../tinyusb/additions/include/tinyusb.h | 103 ++ .../tinyusb/additions/include/tinyusb_types.h | 32 + .../tinyusb/additions/include/tusb_bth.h | 39 + .../tinyusb/additions/include/tusb_cdc_acm.h | 204 +++ .../tinyusb/additions/include/tusb_config.h | 134 ++ .../tinyusb/additions/include/tusb_console.h | 41 + .../tinyusb/additions/include/tusb_hid.h | 239 +++ .../tinyusb/additions/include/tusb_msc.h | 42 + .../tinyusb/additions/include/tusb_net.h | 49 + .../tinyusb/additions/include/tusb_tasks.h | 46 + .../tinyusb/additions/include}/u2f_hid.h | 0 .../tinyusb/additions/include/vfs_tinyusb.h | 42 + .../tinyusb/additions/include_private/cdc.h | 99 ++ .../include_private/descriptors_control.h | 171 +++ .../include_private/usb_descriptors.h | 34 + components/tinyusb/additions/src/cdc.c | 162 ++ .../additions/src/descriptors_control.c | 294 ++++ components/tinyusb/additions/src/tinyusb.c | 85 ++ components/tinyusb/additions/src/tusb_bth.c | 212 +++ .../tinyusb/additions/src/tusb_cdc_acm.c | 426 ++++++ .../tinyusb/additions/src/tusb_console.c | 142 ++ components/tinyusb/additions/src/tusb_dfu.c | 295 ++++ components/tinyusb/additions/src/tusb_hid.c | 143 ++ components/tinyusb/additions/src/tusb_msc.c | 291 ++++ components/tinyusb/additions/src/tusb_net.c | 93 ++ components/tinyusb/additions/src/tusb_tasks.c | 54 + .../tinyusb/additions/src/usb_descriptors.c | 153 ++ components/tinyusb/additions/src/usbd.c | 1349 +++++++++++++++++ .../tinyusb/additions/src/vfs_tinyusb.c | 297 ++++ .../additions/tusb/src/class/dfu/dfu.h | 119 ++ .../additions/tusb/src/class/dfu/dfu_device.c | 480 ++++++ .../additions/tusb/src/class/dfu/dfu_device.h | 124 ++ .../tusb/src/class/dfu/dfu_rt_device.c | 128 ++ .../tusb/src/class/dfu/dfu_rt_device.h | 54 + .../additions/tusb/src/class/net/net_device.c | 481 ++++++ .../additions/tusb/src/lib/networking/ndis.h | 266 ++++ .../tusb/src/lib/networking/rndis_protocol.h | 313 ++++ .../tusb/src/lib/networking/rndis_reports.c | 329 ++++ components/tinyusb/idf_component.yml | 10 + drivers/tidal_usb/tidal_usb_console.c | 13 +- scripts/build.sh | 4 +- tildamk6/sdkconfig.board | 23 +- 44 files changed, 7978 insertions(+), 10 deletions(-) create mode 100644 components/tinyusb/CMakeLists.txt create mode 100644 components/tinyusb/Kconfig create mode 100644 components/tinyusb/additions/include/tinyusb.h create mode 100644 components/tinyusb/additions/include/tinyusb_types.h create mode 100644 components/tinyusb/additions/include/tusb_bth.h create mode 100644 components/tinyusb/additions/include/tusb_cdc_acm.h create mode 100644 components/tinyusb/additions/include/tusb_config.h create mode 100644 components/tinyusb/additions/include/tusb_console.h create mode 100644 components/tinyusb/additions/include/tusb_hid.h create mode 100644 components/tinyusb/additions/include/tusb_msc.h create mode 100644 components/tinyusb/additions/include/tusb_net.h create mode 100644 components/tinyusb/additions/include/tusb_tasks.h rename {drivers/tidal_usb => components/tinyusb/additions/include}/u2f_hid.h (100%) create mode 100644 components/tinyusb/additions/include/vfs_tinyusb.h create mode 100644 components/tinyusb/additions/include_private/cdc.h create mode 100644 components/tinyusb/additions/include_private/descriptors_control.h create mode 100644 components/tinyusb/additions/include_private/usb_descriptors.h create mode 100644 components/tinyusb/additions/src/cdc.c create mode 100644 components/tinyusb/additions/src/descriptors_control.c create mode 100644 components/tinyusb/additions/src/tinyusb.c create mode 100644 components/tinyusb/additions/src/tusb_bth.c create mode 100644 components/tinyusb/additions/src/tusb_cdc_acm.c create mode 100644 components/tinyusb/additions/src/tusb_console.c create mode 100644 components/tinyusb/additions/src/tusb_dfu.c create mode 100644 components/tinyusb/additions/src/tusb_hid.c create mode 100644 components/tinyusb/additions/src/tusb_msc.c create mode 100644 components/tinyusb/additions/src/tusb_net.c create mode 100644 components/tinyusb/additions/src/tusb_tasks.c create mode 100644 components/tinyusb/additions/src/usb_descriptors.c create mode 100644 components/tinyusb/additions/src/usbd.c create mode 100644 components/tinyusb/additions/src/vfs_tinyusb.c create mode 100644 components/tinyusb/additions/tusb/src/class/dfu/dfu.h create mode 100644 components/tinyusb/additions/tusb/src/class/dfu/dfu_device.c create mode 100644 components/tinyusb/additions/tusb/src/class/dfu/dfu_device.h create mode 100644 components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.c create mode 100644 components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.h create mode 100644 components/tinyusb/additions/tusb/src/class/net/net_device.c create mode 100644 components/tinyusb/additions/tusb/src/lib/networking/ndis.h create mode 100644 components/tinyusb/additions/tusb/src/lib/networking/rndis_protocol.h create mode 100644 components/tinyusb/additions/tusb/src/lib/networking/rndis_reports.c create mode 100644 components/tinyusb/idf_component.yml diff --git a/components/tinyusb/CMakeLists.txt b/components/tinyusb/CMakeLists.txt new file mode 100644 index 0000000..a796321 --- /dev/null +++ b/components/tinyusb/CMakeLists.txt @@ -0,0 +1,106 @@ +idf_build_get_property(target IDF_TARGET) + +set(srcs) +set(includes_public) +set(includes_private) +set(compile_options) + + +if(CONFIG_TINYUSB) + set(tusb_mcu "OPT_MCU_ESP32S3") + set(tusb_family "esp32sx") + + list(APPEND compile_options + "-DCFG_TUSB_MCU=${tusb_mcu}" + "-DCFG_TUSB_DEBUG=${CONFIG_TINYUSB_DEBUG_LEVEL}" + ) + + idf_component_get_property(freertos_component_dir freertos COMPONENT_DIR) + + list(APPEND includes_private + "${IDF_PATH}/components/tinyusb/tinyusb/hw/bsp/" + "${IDF_PATH}/components/tinyusb/tinyusb/src/" + "${IDF_PATH}/components/tinyusb/tinyusb/src/device" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/bth" + #"additions/include_private" + ) + + list(APPEND includes_public + "${IDF_PATH}/components/tinyusb/tinyusb/src/" + "additions/include" + "additions/include_private" + "additions/tusb/src/lib/networking" + "additions/tusb/src/class/dfu" + # The FreeRTOS API include convention in tinyusb is different from esp-idf + "${freertos_component_dir}/include/freertos" + ) + + list(APPEND srcs + "${IDF_PATH}/components/tinyusb/tinyusb/src/portable/espressif/${tusb_family}/dcd_${tusb_family}.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/cdc/cdc_device.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/hid/hid_device.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/midi/midi_device.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/msc/msc_device.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/vendor/vendor_device.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/common/tusb_fifo.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/device/usbd_control.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/tusb.c" + "additions/src/usbd.c" + "additions/src/descriptors_control.c" + "additions/src/tinyusb.c" + "additions/src/tusb_tasks.c" + "additions/src/usb_descriptors.c" + ) + + # when no builtin class driver is enabled, an uint8_t data compared with `BUILTIN_DRIVER_COUNT` will always be false + set_source_files_properties("tinyusb/src/device/usbd.c" PROPERTIES COMPILE_FLAGS "-Wno-type-limits") + + if(CONFIG_TINYUSB_CDC_ENABLED) + list(APPEND srcs + "additions/src/cdc.c" + "additions/src/tusb_cdc_acm.c" + "additions/src/tusb_console.c" + "additions/src/vfs_tinyusb.c" + ) + endif() # CONFIG_TINYUSB_CDC_ENABLED + + if(CONFIG_TINYUSB_HID_ENABLED) + list(APPEND srcs + "additions/src/tusb_hid.c") + endif() + + if(CONFIG_TINYUSB_MSC_ENABLED) + list(APPEND srcs + "additions/src/tusb_msc.c") + endif() + + if(CONFIG_TINYUSB_NET_ENABLED) + list(APPEND srcs + "additions/src/tusb_net.c" + "additions/tusb/src/class/net/net_device.c" + "additions/tusb/src/lib/networking/rndis_reports.c") + endif() + + if(CONFIG_TINYUSB_BTH_ENABLED) + list(APPEND srcs + "additions/src/tusb_bth.c" + "${IDF_PATH}/components/tinyusb/tinyusb/src/class/bth/bth_device.c") + endif() + + if(CONFIG_TINYUSB_DFU_ENABLED) + list(APPEND srcs + "additions/src/tusb_dfu.c" + "additions/tusb/src/class/dfu/dfu_device.c") + endif() + +endif() # CONFIG_TINYUSB + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${includes_public} + PRIV_INCLUDE_DIRS ${includes_private} + PRIV_REQUIRES "vfs" "fatfs" "bt" "app_update" + ) + +if(CONFIG_TINYUSB) + target_compile_options(${COMPONENT_LIB} PRIVATE ${compile_options}) +endif() diff --git a/components/tinyusb/Kconfig b/components/tinyusb/Kconfig new file mode 100644 index 0000000..f695104 --- /dev/null +++ b/components/tinyusb/Kconfig @@ -0,0 +1,267 @@ +menu "TinyUSB Stack" + visible if USB_OTG_SUPPORTED + + config TINYUSB + bool "Use TinyUSB Stack" + depends on USB_OTG_SUPPORTED + default n + help + Enable TinyUSB stack support. + Note that, esp-idf only uses the device stack provided by TinyUSB. + + if TINYUSB + config TINYUSB_DEBUG_LEVEL + int "TinyUSB log level (0-3)" + default 0 + range 0 3 + help + Specify verbosity of TinyUSB log output. + + menu "TinyUSB task configuration" + config TINYUSB_NO_DEFAULT_TASK + bool "Do not create a TinyUSB task" + default n + help + This option allows to not create the FreeRTOS task during the driver initialization. + User will have to handle TinyUSB events manually. + + config TINYUSB_TASK_PRIORITY + int "TinyUSB task priority" + default 5 + depends on !TINYUSB_NO_DEFAULT_TASK + help + Set the priority of the default TinyUSB main task. + + config TINYUSB_TASK_STACK_SIZE + int "TinyUSB task stack size (bytes)" + default 4096 + depends on !TINYUSB_NO_DEFAULT_TASK + help + Set the stack size of the default TinyUSB main task. + endmenu + + menu "Descriptor configuration" + config TINYUSB_DESC_USE_ESPRESSIF_VID + bool "VID: Use Espressif's vendor ID" + default y + help + Enable this option, USB device will use Espressif's vendor ID as its VID. + This is helpful at product develop stage. + + config TINYUSB_DESC_CUSTOM_VID + hex "VID: Custom vendor ID" + default 0x1234 + depends on !TINYUSB_DESC_USE_ESPRESSIF_VID + help + Custom Vendor ID. + + config TINYUSB_DESC_USE_DEFAULT_PID + bool "PID: Use a default PID assigned to TinyUSB" + default y + help + Default TinyUSB PID assigning uses values 0x4000...0x4007. + + config TINYUSB_DESC_CUSTOM_PID + hex "PID: Custom product ID" + default 0x5678 + depends on !TINYUSB_DESC_USE_DEFAULT_PID + help + Custom Product ID. + + config TINYUSB_DESC_BCD_DEVICE + hex "bcdDevice" + default 0x0100 + help + Version of the firmware of the USB device. + + config TINYUSB_DESC_MANUFACTURER_STRING + string "Manufacturer name" + default "Espressif Systems" + help + Name of the manufacturer of the USB device. + + config TINYUSB_DESC_PRODUCT_STRING + string "Product name" + default "Espressif Device" + help + Name of the USB device. + + config TINYUSB_DESC_SERIAL_STRING + string "Serial string" + default "123456" + help + Serial number of the USB device. + + config TINYUSB_DESC_CDC_STRING + depends on TINYUSB_CDC_ENABLED + string "CDC Device String" + default "Espressif CDC Device" + help + Name of the CDC device. + + config TINYUSB_DESC_MSC_STRING + depends on TINYUSB_MSC_ENABLED + string "MSC Device String" + default "Espressif MSC Device" + help + Name of the MSC device. + + config TINYUSB_DESC_HID_STRING + depends on TINYUSB_HID_ENABLED + string "HID Device String" + default "Espressif HID Device" + help + Name of the HID device + config TINYUSB_DESC_NET_STRING + depends on TINYUSB_NET_ENABLED + string "NET Device String" + default "Espressif NET Device" + help + Name of the NET device. + config TINYUSB_DESC_BTH_STRING + depends on TINYUSB_BTH_ENABLED + string "BTH String" + default "Espressif BTH Device" + help + Name of the BTH device. + endmenu # "Descriptor configuration" + + menu "Massive Storage Class (MSC)" + config TINYUSB_MSC_ENABLED + bool "Enable TinyUSB MSC feature" + default n + help + Enable TinyUSB MSC feature. + + config TINYUSB_MSC_BUFSIZE + depends on TINYUSB_MSC_ENABLED + int "MSC FIFO size" + default 512 + help + MSC FIFO size, in bytes. + endmenu # "Massive Storage Class" + + menu "Communication Device Class (CDC)" + config TINYUSB_CDC_ENABLED + bool "Enable TinyUSB CDC feature" + default n + help + Enable TinyUSB CDC feature. + config TINYUSB_CDC_PORT_NUM + depends on TINYUSB_CDC_ENABLED + int "Number of Serial (CDC) Port" + default 1 + range 1 2 + help + Number of Serial (CDC) Port. + config TINYUSB_CDC_RX_BUFSIZE + depends on TINYUSB_CDC_ENABLED + int "CDC FIFO size of RX channel" + default 64 + help + CDC FIFO size of RX channel. + + config TINYUSB_CDC_TX_BUFSIZE + depends on TINYUSB_CDC_ENABLED + int "CDC FIFO size of TX channel" + default 64 + help + CDC FIFO size of TX channel. + endmenu # "Communication Device Class" + + menu "Human Interface Device Class (HID)" + config TINYUSB_HID_ENABLED + bool "Enable TinyUSB HID feature" + default n + help + Enable TinyUSB HID feature. + + config TINYUSB_U2FHID_ENABLED + bool "Enable TinyUSB U2FHID tunneling" + default n + help + Enable TinyUSB U2FHID feature. + + config TINYUSB_HIDKEYBOARD_ENABLED + bool "Enable TinyUSB HID Keyboard" + default n + help + Enable TinyUSB HID Keyboard. + + config TINYUSB_HID_BUFSIZE + int "HID FIFO size" + default 64 + depends on TINYUSB_HID_ENABLED + help + HID FIFO size + endmenu # "Human Interface Device Class" + + menu "USB Network Class (RNDIS, ECM)" + + config TINYUSB_NET_ENABLED + bool "Enable TinyUSB NET driver" + default n + help + Enable USB NET TinyUSB driver. + + config TINYUSB_RNDIS_VENDOR + string "USB Vendor" + default "Espressif Incorporated" + depends on TINYUSB_NET_ENABLED + help + Vendor description. + + choice TINYUSB_NET + prompt "Choose a network communication standard" + default TINYUSB_NET_RNDIS + depends on TINYUSB_NET_ENABLED + help + RNDIS and CDC-ECM + - Windows only works with RNDIS + - MacOS only works with CDC-ECM + - Linux will work on both + + config TINYUSB_NET_RNDIS + bool "RNDIS" + help + RNDIS. + config TINYUSB_NET_ECM + bool "CDC-ECM" + help + CDC-ECM. + endchoice + endmenu # "usb network" + + menu "Bluetooth Host Class (BTH)" + config TINYUSB_BTH_ENABLED + bool "Enable TinyUSB BTH feature" + default n + help + Enable TinyUSB BTH feature. + + config TINYUSB_BTH_ISO_ALT_COUNT + depends on TINYUSB_BTH_ENABLED + int "BTH ISO ALT COUNT" + default 0 + help + BTH ISO ALT COUNT. + endmenu # "Bluetooth Host Device Class" + + menu "Firmware Upgrade Class (DFU)" + config TINYUSB_DFU_ENABLED + bool "Enable TinyUSB DFU feature" + default n + help + Enable TinyUSB DFU feature. + + config TINYUSB_DFU_BUFSIZE + depends on TINYUSB_DFU_ENABLED + int "DFU XFER BUFFSIZE" + default 512 + help + DFU XFER BUFFSIZE. + endmenu # "Firmware Upgrade Class" + + endif # TINYUSB + +endmenu # "TinyUSB Stack" diff --git a/components/tinyusb/additions/include/tinyusb.h b/components/tinyusb/additions/include/tinyusb.h new file mode 100644 index 0000000..00da34c --- /dev/null +++ b/components/tinyusb/additions/include/tinyusb.h @@ -0,0 +1,103 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include +#include "tusb.h" +#include "tusb_option.h" +#include "tusb_config.h" +#include "tinyusb_types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* tinyusb uses buffers with type of uint8_t[] but in our driver we are reading them as a 32-bit word */ +#if (CFG_TUD_ENDPOINT0_SIZE < 4) +# define CFG_TUD_ENDPOINT0_SIZE 4 +# warning "CFG_TUD_ENDPOINT0_SIZE was too low and was set to 4" +#endif + +#if TUSB_OPT_DEVICE_ENABLED + +# if CFG_TUD_HID +# if (CFG_TUD_HID_BUFSIZE < 4) +# define CFG_TUD_HID_BUFSIZE 4 +# warning "CFG_TUD_HID_BUFSIZE was too low and was set to 4" +# endif +# endif + +# if CFG_TUD_CDC +# if (CFG_TUD_CDC_EP_BUFSIZE < 4) +# define CFG_TUD_CDC_EP_BUFSIZE 4 +# warning "CFG_TUD_CDC_EP_BUFSIZE was too low and was set to 4" +# endif +# endif + +# if CFG_TUD_MSC +# if (CFG_TUD_MSC_BUFSIZE < 4) +# define CFG_TUD_MSC_BUFSIZE 4 +# warning "CFG_TUD_MSC_BUFSIZE was too low and was set to 4" +# endif +# endif + +# if CFG_TUD_MIDI +# if (CFG_TUD_MIDI_EPSIZE < 4) +# define CFG_TUD_MIDI_EPSIZE 4 +# warning "CFG_TUD_MIDI_EPSIZE was too low and was set to 4" +# endif +# endif + +# if CFG_TUD_CUSTOM_CLASS +# warning "Please check that the buffer is more then 4 bytes" +# endif +#endif + +/** + * @brief Configuration structure of the tinyUSB core + */ +typedef struct { + tusb_desc_device_t *descriptor; /*!< Pointer to a device descriptor */ + const char **string_descriptor; /*!< Pointer to an array of string descriptors */ + const uint8_t *config_descriptor; /*!< Pointer to config descriptors */ + bool external_phy; /*!< Should USB use an external PHY */ +} tinyusb_config_t; + +/** + * @brief This is an all-in-one helper function, including: + * 1. USB device driver initialization + * 2. Descriptors preparation + * 3. TinyUSB stack initialization + * 4. Creates and start a task to handle usb events + * + * @note Don't change Custom descriptor, but if it has to be done, + * Suggest to define as follows in order to match the Interface Association Descriptor (IAD): + * bDeviceClass = TUSB_CLASS_MISC, + * bDeviceSubClass = MISC_SUBCLASS_COMMON, + * + * @param config tinyusb stack specific configuration + * @retval ESP_ERR_INVALID_ARG Install driver and tinyusb stack failed because of invalid argument + * @retval ESP_FAIL Install driver and tinyusb stack failed because of internal error + * @retval ESP_OK Install driver and tinyusb stack successfully + */ +esp_err_t tinyusb_driver_install(const tinyusb_config_t *config); + +// TODO esp_err_t tinyusb_driver_uninstall(void); (IDF-1474) + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tinyusb_types.h b/components/tinyusb/additions/include/tinyusb_types.h new file mode 100644 index 0000000..0f226f3 --- /dev/null +++ b/components/tinyusb/additions/include/tinyusb_types.h @@ -0,0 +1,32 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_ESPRESSIF_VID 0x303A +#define USB_STRING_DESCRIPTOR_ARRAY_SIZE 7 + +typedef enum{ + TINYUSB_USBDEV_0, +} tinyusb_usbdev_t; + +typedef const char *tusb_desc_strarray_device_t[USB_STRING_DESCRIPTOR_ARRAY_SIZE]; + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tusb_bth.h b/components/tinyusb/additions/include/tusb_bth.h new file mode 100644 index 0000000..55f7675 --- /dev/null +++ b/components/tinyusb/additions/include/tusb_bth.h @@ -0,0 +1,39 @@ +/** + * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * 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. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" +#include "tinyusb.h" + +/* HCI message type definitions (for H4 messages) */ +#define HCIT_TYPE_COMMAND 1 +#define HCIT_TYPE_ACL_DATA 2 +#define HCIT_TYPE_SCO_DATA 3 +#define HCIT_TYPE_EVENT 4 + +/** + * @brief Initialize BTH Device. + */ +void tusb_bth_init(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/tinyusb/additions/include/tusb_cdc_acm.h b/components/tinyusb/additions/include/tusb_cdc_acm.h new file mode 100644 index 0000000..c8942ee --- /dev/null +++ b/components/tinyusb/additions/include/tusb_cdc_acm.h @@ -0,0 +1,204 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/ringbuf.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "tusb.h" +#include "tinyusb.h" + +/** + * @brief CDC ports available to setup + */ +typedef enum{ + TINYUSB_CDC_ACM_0 = 0x0, + TINYUSB_CDC_ACM_1, + TINYUSB_CDC_TOTAL +}tinyusb_cdcacm_itf_t; + +/* Callbacks and events + ********************************************************************* */ + +/** + * @brief Data provided to the input of the `callback_rx_wanted_char` callback + */ +typedef struct { + char wanted_char; /*!< Wanted character */ +} cdcacm_event_rx_wanted_char_data_t; + +/** + * @brief Data provided to the input of the `callback_line_state_changed` callback + */ +typedef struct { + bool dtr; /*!< Data Terminal Ready (DTR) line state */ + bool rts; /*!< Request To Send (RTS) line state */ +} cdcacm_event_line_state_changed_data_t; + +/** + * @brief Data provided to the input of the `line_coding_changed` callback + */ +typedef struct { + cdc_line_coding_t const *p_line_coding; /*!< New line coding value */ +} cdcacm_event_line_coding_changed_data_t; + +/** + * @brief Types of CDC ACM events + */ +typedef enum { + CDC_EVENT_RX, + CDC_EVENT_RX_WANTED_CHAR, + CDC_EVENT_LINE_STATE_CHANGED, + CDC_EVENT_LINE_CODING_CHANGED +} cdcacm_event_type_t; + +/** + * @brief Describes an event passing to the input of a callbacks + */ +typedef struct { + cdcacm_event_type_t type; /*!< Event type */ + union { + cdcacm_event_rx_wanted_char_data_t rx_wanted_char_data; /*!< Data input of the `callback_rx_wanted_char` callback */ + cdcacm_event_line_state_changed_data_t line_state_changed_data; /*!< Data input of the `callback_line_state_changed` callback */ + cdcacm_event_line_coding_changed_data_t line_coding_changed_data; /*!< Data input of the `line_coding_changed` callback */ + }; +} cdcacm_event_t; + +/** + * @brief CDC-ACM callback type + */ +typedef void(*tusb_cdcacm_callback_t)(int itf, cdcacm_event_t *event); + +/*********************************************************************** Callbacks and events*/ +/* Other structs + ********************************************************************* */ + +/** + * @brief Configuration structure for CDC-ACM + */ +typedef struct { + tinyusb_usbdev_t usb_dev; /*!< Usb device to set up */ + tinyusb_cdcacm_itf_t cdc_port; /*!< CDC port */ + size_t rx_unread_buf_sz; /*!< Amount of data that can be passed to the AMC at once */ + tusb_cdcacm_callback_t callback_rx; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */ + tusb_cdcacm_callback_t callback_rx_wanted_char; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */ + tusb_cdcacm_callback_t callback_line_state_changed; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */ + tusb_cdcacm_callback_t callback_line_coding_changed; /*!< Pointer to the function with the `tusb_cdcacm_callback_t` type that will be handled as a callback */ +} tinyusb_config_cdcacm_t; + +/*********************************************************************** Other structs*/ +/* Public functions + ********************************************************************* */ +/** + * @brief Initialize CDC ACM. Initialization will be finished with + * the `tud_cdc_line_state_cb` callback + * + * @param cfg - init configuration structure + * @return esp_err_t + */ +esp_err_t tusb_cdc_acm_init(const tinyusb_config_cdcacm_t *cfg); + + +/** + * @brief Register a callback invoking on CDC event. If the callback had been + * already registered, it will be overwritten + * + * @param itf - number of a CDC object + * @param event_type - type of registered event for a callback + * @param callback - callback function + * @return esp_err_t - ESP_OK or ESP_ERR_INVALID_ARG + */ +esp_err_t tinyusb_cdcacm_register_callback(tinyusb_cdcacm_itf_t itf, + cdcacm_event_type_t event_type, + tusb_cdcacm_callback_t callback); + + +/** + * @brief Unregister a callback invoking on CDC event. + * + * @param itf - number of a CDC object + * @param event_type - type of registered event for a callback + * @return esp_err_t - ESP_OK or ESP_ERR_INVALID_ARG + */ +esp_err_t tinyusb_cdcacm_unregister_callback(tinyusb_cdcacm_itf_t itf, cdcacm_event_type_t event_type); + + +/** + * @brief Sent one character to a write buffer + * + * @param itf - number of a CDC object + * @param ch - character to send + * @return size_t - amount of queued bytes + */ +size_t tinyusb_cdcacm_write_queue_char(tinyusb_cdcacm_itf_t itf, char ch); + + +/** + * @brief Write data to write buffer from a byte array + * + * @param itf - number of a CDC object + * @param in_buf - a source array + * @param in_size - size to write from arr_src + * @return size_t - amount of queued bytes + */ +size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, uint8_t *in_buf, size_t in_size); + +/** + * @brief Send all data from a write buffer. Use `tinyusb_cdcacm_write_queue` to add data to the buffer. + * + * WARNING! TinyUSB can block output Endpoint for several RX callbacks, after will do additional flush + * after the each trasfer. That can leads to the situation when you requested a flush, but it will fail until + * ont of the next callbacks ends. + * SO USING OF THE FLUSH WITH TIMEOUTS IN CALLBACKS IS NOT RECOMENDED - YOU CAN GET A LOCK FOR THE TIMEOUT + * + * @param itf - number of a CDC object + * @param timeout_ticks - waiting until flush will be considered as failed + * @return esp_err_t - ESP_OK if (timeout_ticks > 0) and and flush was successful, + * ESP_ERR_TIMEOUT if timeout occurred3 or flush was successful with (timeout_ticks == 0) + * ESP_FAIL if flush was unsuccessful + */ +esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_ticks); + +/** + * @brief Read a content to the array, and defines it's size to the sz_store + * + * @param itf - number of a CDC object + * @param out_buf - to this array will be stored the object from a CDC buffer + * @param out_buf_sz - size of buffer for results + * @param rx_data_size - to this address will be stored the object's size + * @return esp_err_t ESP_OK, ESP_FAIL or ESP_ERR_INVALID_STATE + */ +esp_err_t tinyusb_cdcacm_read(tinyusb_cdcacm_itf_t itf, uint8_t *out_buf, size_t out_buf_sz, size_t *rx_data_size); + + +/** + * @brief Check if the ACM initialized + * + * @param itf - number of a CDC object + * @return true or false + */ +bool tusb_cdc_acm_initialized(tinyusb_cdcacm_itf_t itf); + +/*********************************************************************** Public functions*/ + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tusb_config.h b/components/tinyusb/additions/include/tusb_config.h new file mode 100644 index 0000000..6caaa5e --- /dev/null +++ b/components/tinyusb/additions/include/tusb_config.h @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org), + * Additions Copyright (c) 2020, Espressif Systems (Shanghai) PTE LTD + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#pragma once + +#include +#include "tusb_option.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONFIG_TINYUSB_CDC_ENABLED +# define CONFIG_TINYUSB_CDC_ENABLED 0 +# define CONFIG_TINYUSB_CDC_PORT_NUM 0 +#endif + +#ifndef CONFIG_TINYUSB_MSC_ENABLED +# define CONFIG_TINYUSB_MSC_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_HID_ENABLED +# define CONFIG_TINYUSB_HID_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_U2FHID_ENABLED +# define CONFIG_TINYUSB_U2FHID_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_HIDKEYBOARD_ENABLED +# define CONFIG_TINYUSB_HIDKEYBOARD_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_MIDI_ENABLED +# define CONFIG_TINYUSB_MIDI_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED +# define CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_NET_ENABLED +# define CONFIG_TINYUSB_NET_ENABLED 0 +#endif + +#ifndef CONFIG_TINYUSB_BTH_ENABLED +# define CONFIG_TINYUSB_BTH_ENABLED 0 +# define CONFIG_TINYUSB_BTH_ISO_ALT_COUNT 0 +#endif + +#ifndef CONFIG_TINYUSB_DFU_ENABLED +# define CONFIG_TINYUSB_DFU_ENABLED 0 +# define CONFIG_TINYUSB_DFU_BUFSIZE 512 +#endif + +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED +#define CFG_TUSB_OS OPT_OS_FREERTOS + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +# define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +# define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) +#endif + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +// CDC FIFO size of TX and RX +#define CFG_TUD_CDC_RX_BUFSIZE CONFIG_TINYUSB_CDC_RX_BUFSIZE +#define CFG_TUD_CDC_TX_BUFSIZE CONFIG_TINYUSB_CDC_TX_BUFSIZE + +// MSC Buffer size of Device Mass storage +#define CFG_TUD_MSC_BUFSIZE CONFIG_TINYUSB_MSC_BUFSIZE + +// HID buffer size Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_BUFSIZE CONFIG_TINYUSB_HID_BUFSIZE + +// Number of BTH ISO alternatives +#define CFG_TUD_BTH_ISO_ALT_COUNT CONFIG_TINYUSB_BTH_ISO_ALT_COUNT + +#define CFG_TUD_DFU_XFER_BUFSIZE CONFIG_TINYUSB_DFU_BUFSIZE + +// Enabled device class driver +#define CFG_TUD_CDC CONFIG_TINYUSB_CDC_PORT_NUM +#define CFG_TUD_MSC CONFIG_TINYUSB_MSC_ENABLED +#define CFG_TUD_HID_KBD CONFIG_TINYUSB_HIDKEYBOARD_ENABLED +#define CFG_TUD_U2FHID CONFIG_TINYUSB_U2FHID_ENABLED +#define CFG_TUD_HID CONFIG_TINYUSB_HID_ENABLED +#define CFG_TUD_MIDI CONFIG_TINYUSB_MIDI_ENABLED +#define CFG_TUD_CUSTOM_CLASS CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED +#define CFG_TUD_NET CONFIG_TINYUSB_NET_ENABLED +#define CFG_TUD_BTH CONFIG_TINYUSB_BTH_ENABLED +#define CFG_TUD_DFU CONFIG_TINYUSB_DFU_ENABLED + +/* TODO: will be removed if upstream feat: Add net xmit status cb for application can block to get it #1001*/ +__attribute__((weak)) void tud_network_idle_status_change_cb(bool idle); + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tusb_console.h b/components/tinyusb/additions/include/tusb_console.h new file mode 100644 index 0000000..530221d --- /dev/null +++ b/components/tinyusb/additions/include/tusb_console.h @@ -0,0 +1,41 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" + +/** + * @brief Redirect output to the USB serial + * @param cdc_intf - interface number of TinyUSB's CDC + * + * @return esp_err_t - ESP_OK, ESP_FAIL or an error code + */ +esp_err_t esp_tusb_init_console(int cdc_intf); + +/** + * @brief Switch log to the default output + * @param cdc_intf - interface number of TinyUSB's CDC + * + * @return esp_err_t + */ +esp_err_t esp_tusb_deinit_console(int cdc_intf); + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tusb_hid.h b/components/tinyusb/additions/include/tusb_hid.h new file mode 100644 index 0000000..5a3b6ca --- /dev/null +++ b/components/tinyusb/additions/include/tusb_hid.h @@ -0,0 +1,239 @@ +// Copyright 2020-2021 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "tusb.h" +#include "tinyusb.h" + + +/** + * @brief Report delta movement of mouse. + * + * @param x Current delta x movement of the mouse + * @param y Current delta y movement on the mouse + * @param vertical Current delta wheel movement on the mouse + * @param horizontal using AC Pan + */ +void tinyusb_hid_mouse_move_report(int8_t x, int8_t y, int8_t vertical, int8_t horizontal); + +/** + * @brief Report button click in the mouse, using bitmap here. + * eg. MOUSE_BUTTON_LEFT | MOUSE_BUTTON_RIGHT, if click left and right button at same time. + * + * @param buttons hid mouse button bit mask + */ +void tinyusb_hid_mouse_button_report(uint8_t buttons_map); + +/** + * @brief Report key press in the keyboard, using array here, contains six keys at most. + * + * @param keycode hid keyboard code array + */ +void tinyusb_hid_keyboard_report(uint8_t keycode[]); + +//--------------------------------------------------------------------+ +// HID MOUSE BUTTON BIT MASK +//--------------------------------------------------------------------+ +// MOUSE_BUTTON_LEFT = TU_BIT(0), ///< Left button +// MOUSE_BUTTON_RIGHT = TU_BIT(1), ///< Right button +// MOUSE_BUTTON_MIDDLE = TU_BIT(2), ///< Middle button +// MOUSE_BUTTON_BACKWARD = TU_BIT(3), ///< Backward button, +// MOUSE_BUTTON_FORWARD = TU_BIT(4), ///< Forward button, + + +//--------------------------------------------------------------------+ +// HID KEYCODE +//--------------------------------------------------------------------+ +// #define HID_KEY_NONE 0x00 +// #define HID_KEY_A 0x04 +// #define HID_KEY_B 0x05 +// #define HID_KEY_C 0x06 +// #define HID_KEY_D 0x07 +// #define HID_KEY_E 0x08 +// #define HID_KEY_F 0x09 +// #define HID_KEY_G 0x0A +// #define HID_KEY_H 0x0B +// #define HID_KEY_I 0x0C +// #define HID_KEY_J 0x0D +// #define HID_KEY_K 0x0E +// #define HID_KEY_L 0x0F +// #define HID_KEY_M 0x10 +// #define HID_KEY_N 0x11 +// #define HID_KEY_O 0x12 +// #define HID_KEY_P 0x13 +// #define HID_KEY_Q 0x14 +// #define HID_KEY_R 0x15 +// #define HID_KEY_S 0x16 +// #define HID_KEY_T 0x17 +// #define HID_KEY_U 0x18 +// #define HID_KEY_V 0x19 +// #define HID_KEY_W 0x1A +// #define HID_KEY_X 0x1B +// #define HID_KEY_Y 0x1C +// #define HID_KEY_Z 0x1D +// #define HID_KEY_1 0x1E +// #define HID_KEY_2 0x1F +// #define HID_KEY_3 0x20 +// #define HID_KEY_4 0x21 +// #define HID_KEY_5 0x22 +// #define HID_KEY_6 0x23 +// #define HID_KEY_7 0x24 +// #define HID_KEY_8 0x25 +// #define HID_KEY_9 0x26 +// #define HID_KEY_0 0x27 +// #define HID_KEY_ENTER 0x28 +// #define HID_KEY_ESCAPE 0x29 +// #define HID_KEY_BACKSPACE 0x2A +// #define HID_KEY_TAB 0x2B +// #define HID_KEY_SPACE 0x2C +// #define HID_KEY_MINUS 0x2D +// #define HID_KEY_EQUAL 0x2E +// #define HID_KEY_BRACKET_LEFT 0x2F +// #define HID_KEY_BRACKET_RIGHT 0x30 +// #define HID_KEY_BACKSLASH 0x31 +// #define HID_KEY_EUROPE_1 0x32 +// #define HID_KEY_SEMICOLON 0x33 +// #define HID_KEY_APOSTROPHE 0x34 +// #define HID_KEY_GRAVE 0x35 +// #define HID_KEY_COMMA 0x36 +// #define HID_KEY_PERIOD 0x37 +// #define HID_KEY_SLASH 0x38 +// #define HID_KEY_CAPS_LOCK 0x39 +// #define HID_KEY_F1 0x3A +// #define HID_KEY_F2 0x3B +// #define HID_KEY_F3 0x3C +// #define HID_KEY_F4 0x3D +// #define HID_KEY_F5 0x3E +// #define HID_KEY_F6 0x3F +// #define HID_KEY_F7 0x40 +// #define HID_KEY_F8 0x41 +// #define HID_KEY_F9 0x42 +// #define HID_KEY_F10 0x43 +// #define HID_KEY_F11 0x44 +// #define HID_KEY_F12 0x45 +// #define HID_KEY_PRINT_SCREEN 0x46 +// #define HID_KEY_SCROLL_LOCK 0x47 +// #define HID_KEY_PAUSE 0x48 +// #define HID_KEY_INSERT 0x49 +// #define HID_KEY_HOME 0x4A +// #define HID_KEY_PAGE_UP 0x4B +// #define HID_KEY_DELETE 0x4C +// #define HID_KEY_END 0x4D +// #define HID_KEY_PAGE_DOWN 0x4E +// #define HID_KEY_ARROW_RIGHT 0x4F +// #define HID_KEY_ARROW_LEFT 0x50 +// #define HID_KEY_ARROW_DOWN 0x51 +// #define HID_KEY_ARROW_UP 0x52 +// #define HID_KEY_NUM_LOCK 0x53 +// #define HID_KEY_KEYPAD_DIVIDE 0x54 +// #define HID_KEY_KEYPAD_MULTIPLY 0x55 +// #define HID_KEY_KEYPAD_SUBTRACT 0x56 +// #define HID_KEY_KEYPAD_ADD 0x57 +// #define HID_KEY_KEYPAD_ENTER 0x58 +// #define HID_KEY_KEYPAD_1 0x59 +// #define HID_KEY_KEYPAD_2 0x5A +// #define HID_KEY_KEYPAD_3 0x5B +// #define HID_KEY_KEYPAD_4 0x5C +// #define HID_KEY_KEYPAD_5 0x5D +// #define HID_KEY_KEYPAD_6 0x5E +// #define HID_KEY_KEYPAD_7 0x5F +// #define HID_KEY_KEYPAD_8 0x60 +// #define HID_KEY_KEYPAD_9 0x61 +// #define HID_KEY_KEYPAD_0 0x62 +// #define HID_KEY_KEYPAD_DECIMAL 0x63 +// #define HID_KEY_EUROPE_2 0x64 +// #define HID_KEY_APPLICATION 0x65 +// #define HID_KEY_POWER 0x66 +// #define HID_KEY_KEYPAD_EQUAL 0x67 +// #define HID_KEY_F13 0x68 +// #define HID_KEY_F14 0x69 +// #define HID_KEY_F15 0x6A +// #define HID_KEY_F16 0x6B +// #define HID_KEY_F17 0x6C +// #define HID_KEY_F18 0x6D +// #define HID_KEY_F19 0x6E +// #define HID_KEY_F20 0x6F +// #define HID_KEY_F21 0x70 +// #define HID_KEY_F22 0x71 +// #define HID_KEY_F23 0x72 +// #define HID_KEY_F24 0x73 +// #define HID_KEY_EXECUTE 0x74 +// #define HID_KEY_HELP 0x75 +// #define HID_KEY_MENU 0x76 +// #define HID_KEY_SELECT 0x77 +// #define HID_KEY_STOP 0x78 +// #define HID_KEY_AGAIN 0x79 +// #define HID_KEY_UNDO 0x7A +// #define HID_KEY_CUT 0x7B +// #define HID_KEY_COPY 0x7C +// #define HID_KEY_PASTE 0x7D +// #define HID_KEY_FIND 0x7E +// #define HID_KEY_MUTE 0x7F +// #define HID_KEY_VOLUME_UP 0x80 +// #define HID_KEY_VOLUME_DOWN 0x81 +// #define HID_KEY_LOCKING_CAPS_LOCK 0x82 +// #define HID_KEY_LOCKING_NUM_LOCK 0x83 +// #define HID_KEY_LOCKING_SCROLL_LOCK 0x84 +// #define HID_KEY_KEYPAD_COMMA 0x85 +// #define HID_KEY_KEYPAD_EQUAL_SIGN 0x86 +// #define HID_KEY_KANJI1 0x87 +// #define HID_KEY_KANJI2 0x88 +// #define HID_KEY_KANJI3 0x89 +// #define HID_KEY_KANJI4 0x8A +// #define HID_KEY_KANJI5 0x8B +// #define HID_KEY_KANJI6 0x8C +// #define HID_KEY_KANJI7 0x8D +// #define HID_KEY_KANJI8 0x8E +// #define HID_KEY_KANJI9 0x8F +// #define HID_KEY_LANG1 0x90 +// #define HID_KEY_LANG2 0x91 +// #define HID_KEY_LANG3 0x92 +// #define HID_KEY_LANG4 0x93 +// #define HID_KEY_LANG5 0x94 +// #define HID_KEY_LANG6 0x95 +// #define HID_KEY_LANG7 0x96 +// #define HID_KEY_LANG8 0x97 +// #define HID_KEY_LANG9 0x98 +// #define HID_KEY_ALTERNATE_ERASE 0x99 +// #define HID_KEY_SYSREQ_ATTENTION 0x9A +// #define HID_KEY_CANCEL 0x9B +// #define HID_KEY_CLEAR 0x9C +// #define HID_KEY_PRIOR 0x9D +// #define HID_KEY_RETURN 0x9E +// #define HID_KEY_SEPARATOR 0x9F +// #define HID_KEY_OUT 0xA0 +// #define HID_KEY_OPER 0xA1 +// #define HID_KEY_CLEAR_AGAIN 0xA2 +// #define HID_KEY_CRSEL_PROPS 0xA3 +// #define HID_KEY_EXSEL 0xA4 +// //RESERVED 0xA5-DF +// #define HID_KEY_CONTROL_LEFT 0xE0 +// #define HID_KEY_SHIFT_LEFT 0xE1 +// #define HID_KEY_ALT_LEFT 0xE2 +// #define HID_KEY_GUI_LEFT 0xE3 +// #define HID_KEY_CONTROL_RIGHT 0xE4 +// #define HID_KEY_SHIFT_RIGHT 0xE5 +// #define HID_KEY_ALT_RIGHT 0xE6 +// #define HID_KEY_GUI_RIGHT 0xE7 + + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tusb_msc.h b/components/tinyusb/additions/include/tusb_msc.h new file mode 100644 index 0000000..b6158e6 --- /dev/null +++ b/components/tinyusb/additions/include/tusb_msc.h @@ -0,0 +1,42 @@ +// Copyright 2020-2021 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "tusb.h" +#include "tinyusb.h" + +/** + * @brief Configuration structure for MSC + */ +typedef struct { + uint8_t pdrv; /* Physical drive nmuber (0..) */ +} tinyusb_config_msc_t; + +/** + * @brief Initialize MSC Device. + * + * @param cfg - init configuration structure + * @return esp_err_t + */ +esp_err_t tusb_msc_init(const tinyusb_config_msc_t *cfg); + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include/tusb_net.h b/components/tinyusb/additions/include/tusb_net.h new file mode 100644 index 0000000..38055b2 --- /dev/null +++ b/components/tinyusb/additions/include/tusb_net.h @@ -0,0 +1,49 @@ +/** + * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * 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. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_err.h" +#include "tinyusb.h" + +/** + * @brief Forward packets from Wi-Fi to USB. + * + * @param buffer - Data pointer + * + * @param len - Data length + * + * @return esp_err_t + */ +esp_err_t pkt_wifi2usb(void *buffer, uint16_t len, void *eb); + +/** + * @brief Initialize NET Device. + */ +void tusb_net_init(void); + +void ecm_close(void); + +void ecm_open(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/tinyusb/additions/include/tusb_tasks.h b/components/tinyusb/additions/include/tusb_tasks.h new file mode 100644 index 0000000..7f3209d --- /dev/null +++ b/components/tinyusb/additions/include/tusb_tasks.h @@ -0,0 +1,46 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief This helper function creates and starts a task which wraps `tud_task()`. + * + * The wrapper function basically wraps tud_task and some log. + * Default parameters: stack size and priority as configured, argument = NULL, not pinned to any core. + * If you have more requirements for this task, you can create your own task which calls tud_task as the last step. + * + * @retval ESP_OK run tinyusb main task successfully + * @retval ESP_FAIL run tinyusb main task failed of internal error + * @retval ESP_ERR_INVALID_STATE tinyusb main task has been created before + */ +esp_err_t tusb_run_task(void); + +/** + * @brief This helper function stops and destroys the task created by `tusb_run_task()` + * + * @retval ESP_OK stop and destory tinyusb main task successfully + * @retval ESP_ERR_INVALID_STATE tinyusb main task hasn't been created yet + */ +esp_err_t tusb_stop_task(void); + +#ifdef __cplusplus +} +#endif diff --git a/drivers/tidal_usb/u2f_hid.h b/components/tinyusb/additions/include/u2f_hid.h similarity index 100% rename from drivers/tidal_usb/u2f_hid.h rename to components/tinyusb/additions/include/u2f_hid.h diff --git a/components/tinyusb/additions/include/vfs_tinyusb.h b/components/tinyusb/additions/include/vfs_tinyusb.h new file mode 100644 index 0000000..233b7f1 --- /dev/null +++ b/components/tinyusb/additions/include/vfs_tinyusb.h @@ -0,0 +1,42 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Register TinyUSB CDC at VFS with path + * @param cdc_intf - interface number of TinyUSB's CDC + * @param path - path where the CDC will be registered, `/dev/tusb_cdc` will be used if left NULL. + * + * @return esp_err_t ESP_OK or ESP_FAIL + */ +esp_err_t esp_vfs_tusb_cdc_register(int cdc_intf, char const *path); + +/** + * @brief Unregister TinyUSB CDC from VFS + * @param path - path where the CDC will be unregistered if NULL will be used `/dev/tusb_cdc` + * + * @return esp_err_t ESP_OK or ESP_FAIL + */ +esp_err_t esp_vfs_tusb_cdc_unregister(char const *path); + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include_private/cdc.h b/components/tinyusb/additions/include_private/cdc.h new file mode 100644 index 0000000..b3aa870 --- /dev/null +++ b/components/tinyusb/additions/include_private/cdc.h @@ -0,0 +1,99 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/ringbuf.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "tusb.h" +#include "tinyusb_types.h" + +/* CDC classification + ********************************************************************* */ +typedef enum { + TINYUSB_CDC_DATA = 0x00, +} cdc_data_sublcass_type_t; // CDC120 specification + +/* Note:other classification is represented in the file components\tinyusb\tinyusb\src\class\cdc\cdc.h */ + +/*********************************************************************** CDC classification*/ +/* Structs + ********************************************************************* */ +typedef struct { + tinyusb_usbdev_t usb_dev; /*!< USB device to set up */ + tusb_class_code_t cdc_class; /*!< CDC device class : Communications or Data device */ + union { + cdc_comm_sublcass_type_t comm_subclass; /*!< Communications device subclasses: AMC, ECM, etc. */ + cdc_data_sublcass_type_t data_subclass; /*!< Data device has only one subclass.*/ + } cdc_subclass; /*!< CDC device subclass according to Class Definitions for Communications Devices the CDC v.1.20 */ +} tinyusb_config_cdc_t; /*!< Main configuration structure of a CDC device */ + +typedef struct { + tinyusb_usbdev_t usb_dev; /*!< USB device used for the instance */ + tusb_class_code_t type; + union { + cdc_comm_sublcass_type_t comm_subclass; /*!< Communications device subclasses: AMC, ECM, etc. */ + cdc_data_sublcass_type_t data_subclass; /*!< Data device has only one subclass.*/ + } cdc_subclass; /*!< CDC device subclass according to Class Definitions for Communications Devices the CDC v.1.20 */ + void *subclass_obj; /*!< Dynamically allocated subclass specific object */ +} esp_tusb_cdc_t; +/*********************************************************************** Structs*/ +/* Functions + ********************************************************************* */ +/** + * @brief Initializing CDC basic object + * @param itf - number of a CDC object + * @param cfg - CDC configuration structure + * + * @return esp_err_t ESP_OK or ESP_FAIL + */ +esp_err_t tinyusb_cdc_init(int itf, const tinyusb_config_cdc_t *cfg); + + +/** + * @brief De-initializing CDC. Clean its objects + * @param itf - number of a CDC object + * @return esp_err_t ESP_OK, ESP_ERR_INVALID_ARG, ESP_ERR_INVALID_STATE + * + */ +esp_err_t tinyusb_cdc_deinit(int itf); + + +/** + * @brief Checks if the CDC initialized and ready to interaction + * + * @return true or false + */ +bool tinyusb_cdc_initialized(int itf); + + +/** + * @brief Return interface of a CDC device + * + * @param itf_num + * @return esp_tusb_cdc_t* pointer to the interface or (NULL) on error + */ +esp_tusb_cdc_t *tinyusb_cdc_get_intf(int itf_num); +/*********************************************************************** Functions*/ + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include_private/descriptors_control.h b/components/tinyusb/additions/include_private/descriptors_control.h new file mode 100644 index 0000000..e77569a --- /dev/null +++ b/components/tinyusb/additions/include_private/descriptors_control.h @@ -0,0 +1,171 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include +#include "usb_descriptors.h" + + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB] + */ + +#ifdef __cplusplus +extern "C" { +#endif + +//------------- EndPoint Descriptor -------------// +enum { + EPNUM_DEFAULT = 0, +# if CFG_TUD_BTH + EPNUM_BT_EVT, + EPNUM_BT_BULK_OUT, +# endif + +# if CFG_TUD_NET + EPNUM_NET_NOTIF, + EPNUM_NET_DATA, +# endif + +# if CFG_TUD_CDC + EPNUM_CDC_NOTIF, + EPNUM_CDC_DATA, +# endif + +# if CFG_TUD_MSC + EPNUM_MSC_DATA, +# endif + +# if CFG_TUD_HID_KBD + EPNUM_HID_DATA, +# endif + +# if CFG_TUD_U2FHID + EPNUM_HID_DATA_2, +# endif +}; + +#if ((CFG_TUD_BTH * 2) + (CFG_TUD_NET * 2) + (CFG_TUD_CDC * 2) + CFG_TUD_MSC + CFG_TUD_HID + CFG_TUD_U2FHID) > 4 +#error "USB endpoint number not be more than 5" +#endif + +//------------- HID Report Descriptor -------------// +#if CFG_TUD_HID +enum { + REPORT_ID_KEYBOARD = 1, + REPORT_ID_MOUSE +}; +#endif + +//------------- Configuration Descriptor -------------// +enum { +# if CFG_TUD_BTH + ITF_NUM_BTH = 0, + ITF_NUM_BTH_DATA, +# endif + +# if CFG_TUD_NET + ITF_NUM_NET, + ITF_NUM_NET_DATA, +# endif + +# if CFG_TUD_CDC + ITF_NUM_CDC, + ITF_NUM_CDC_DATA, +# endif + +# if CFG_TUD_MSC + ITF_NUM_MSC, +# endif + +# if CFG_TUD_HID_KBD + ITF_NUM_HID, +# endif + +# if CFG_TUD_U2FHID + ITF_NUM_HID_2, +# endif + +# if CFG_TUD_DFU + ITF_NUM_DFU, +# endif + ITF_NUM_TOTAL +}; + +//------------- STRID -------------// +enum { + STRID_LANGID = 0, + STRID_MANUFACTURER, + STRID_PRODUCT, + STRID_SERIAL, +#if CFG_TUD_CDC + STRID_CDC_INTERFACE, +#endif +#if CFG_TUD_NET + STRID_NET_INTERFACE, + STRID_MAC, +#endif +#if CFG_TUD_MSC + STRID_MSC_INTERFACE, +#endif +#if CFG_TUD_HID_KBD + STRID_HID_INTERFACE, +#endif +#if CFG_TUD_U2FHID + STRID_HID_INTERFACE_2, +#endif +#if CFG_TUD_BTH + STRID_BTH_INTERFACE, +#endif +#if CFG_TUD_DFU + STRID_DFU_INTERFACE, +#endif +}; + +#define DFU_ALT_COUNT 2 +#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9) + +enum { + TUSB_DESC_TOTAL_LEN = TUD_CONFIG_DESC_LEN + + TUD_CDC_DESC_LEN * CFG_TUD_CDC + + TUD_RNDIS_DESC_LEN * CFG_TUD_NET + + TUD_MSC_DESC_LEN * CFG_TUD_MSC + + TUD_HID_DESC_LEN * CFG_TUD_HID_KBD + + TUD_HID_DESC_LEN * CFG_TUD_U2FHID + + TUD_BTH_DESC_LEN * CFG_TUD_BTH, + + ALT_CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + + TUD_CDC_ECM_DESC_LEN * CFG_TUD_NET + + TUD_CDC_DESC_LEN * CFG_TUD_CDC + + TUD_MSC_DESC_LEN * CFG_TUD_MSC + + TUD_HID_DESC_LEN * CFG_TUD_HID_KBD + + TUD_HID_DESC_LEN * CFG_TUD_U2FHID + + TUD_BTH_DESC_LEN * CFG_TUD_BTH + + TUD_DFU_DESC_LEN(DFU_ALT_COUNT) * CFG_TUD_DFU +}; + +bool tusb_desc_set; +void tusb_set_descriptor(tusb_desc_device_t *desc, const char **str_desc); +void tusb_set_config_descriptor(const uint8_t *config_desc); +tusb_desc_device_t *tusb_get_active_desc(void); +char **tusb_get_active_str_desc(void); +void tusb_clear_descriptor(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/include_private/usb_descriptors.h b/components/tinyusb/additions/include_private/usb_descriptors.h new file mode 100644 index 0000000..76c2b54 --- /dev/null +++ b/components/tinyusb/additions/include_private/usb_descriptors.h @@ -0,0 +1,34 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include "tusb.h" +#include "tinyusb_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n)) + +extern tusb_desc_device_t descriptor_tinyusb; +extern tusb_desc_strarray_device_t descriptor_str_tinyusb; + +extern tusb_desc_device_t descriptor_kconfig; +extern tusb_desc_strarray_device_t descriptor_str_kconfig; + +#ifdef __cplusplus +} +#endif diff --git a/components/tinyusb/additions/src/cdc.c b/components/tinyusb/additions/src/cdc.c new file mode 100644 index 0000000..957ac7b --- /dev/null +++ b/components/tinyusb/additions/src/cdc.c @@ -0,0 +1,162 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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 +#include "esp_check.h" +#include "esp_err.h" +#include "esp_log.h" +#include "tusb.h" +#include "cdc.h" +#include "tusb_cdc_acm.h" +#include "sdkconfig.h" + +static const char *TAG = "tusb_cdc"; + +#define CDC_INTF_NUM CFG_TUD_CDC // number of cdc blocks + +static esp_tusb_cdc_t *cdc_obj[CDC_INTF_NUM] = {}; + +/* Common CDC functions + ********************************************************************* */ +bool tinyusb_cdc_initialized(int itf) +{ + return (cdc_obj[itf] != NULL); +} + +static esp_err_t cdc_interface_check(int itf) +{ + if (tinyusb_cdc_initialized(itf)) { + return ESP_OK; + } else { + ESP_LOGE(TAG, "Interface %d is not initialized. Use `tinyusb_cdc_init` for initialization", itf); + return ESP_ERR_INVALID_STATE; + } +} + +/** + * @brief + * + * @param itf + * @param expected_inited + * @param expected_type use -1 if you don't care + * @return esp_err_t + */ +static esp_err_t cdc_obj_check(int itf, bool expected_inited, tusb_class_code_t expected_type) +{ + bool inited = (cdc_obj[itf] != NULL); + if (expected_inited != inited) { + ESP_LOGE(TAG, "Wrong state of the interface. Expected state: %s", + expected_inited ? "initialized" : "not initialized"); + return ESP_ERR_INVALID_STATE; + } + if (inited && (expected_type != -1) && !(cdc_obj[itf]->type == expected_type)) { + ESP_LOGE(TAG, "Wrong type of the interface. Should be : 0x%x (tusb_class_code_t)", expected_type); + return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + +esp_tusb_cdc_t *tinyusb_cdc_get_intf(int itf_num) +{ + if (cdc_interface_check(itf_num) != ESP_OK) { + return NULL; + } + return cdc_obj[itf_num]; +} + +/*********************************************************************** Common CDC functions*/ +/* CDC class funcs + ********************************************************************* */ +static esp_err_t tusb_cdc_comm_init(int itf) +{ + ESP_RETURN_ON_ERROR(cdc_obj_check(itf, false, -1), TAG, "cdc_obj_check failed"); + cdc_obj[itf] = calloc(1, sizeof(esp_tusb_cdc_t)); + if (cdc_obj[itf] != NULL) { + cdc_obj[itf]->type = TUSB_CLASS_CDC; + ESP_LOGD(TAG, "CDC Comm class initialized"); + return ESP_OK; + } else { + ESP_LOGE(TAG, "CDC Comm initialization error"); + return ESP_FAIL; + } +} + +static esp_err_t tusb_cdc_deinit_comm(int itf) +{ + ESP_RETURN_ON_ERROR(cdc_obj_check(itf, true, TUSB_CLASS_CDC), TAG, "cdc_obj_check failed"); + free(cdc_obj[itf]); + cdc_obj[itf] = NULL; + return ESP_OK; +} + +static esp_err_t tusb_cdc_data_init(int itf) +{ + ESP_RETURN_ON_ERROR(cdc_obj_check(itf, false, TUSB_CLASS_CDC_DATA), TAG, "cdc_obj_check failed"); + cdc_obj[itf] = calloc(1, sizeof(esp_tusb_cdc_t)); + if (cdc_obj[itf] != NULL) { + cdc_obj[itf]->type = TUSB_CLASS_CDC_DATA; + ESP_LOGD(TAG, "CDC Data class initialized"); + return ESP_OK; + } else { + ESP_LOGE(TAG, "CDC Data initialization error"); + return ESP_FAIL; + } +} + +static esp_err_t tusb_cdc_deinit_data(int itf) +{ + ESP_RETURN_ON_ERROR(cdc_obj_check(itf, true, TUSB_CLASS_CDC_DATA), TAG, "cdc_obj_check failed"); + free(cdc_obj[itf]); + cdc_obj[itf] = NULL; + return ESP_OK; +} +/*********************************************************************** CDC class funcs*/ +/* CDC initialization + ********************************************************************* */ +esp_err_t tinyusb_cdc_init(int itf, const tinyusb_config_cdc_t *cfg) +{ + ESP_LOGD(TAG, "CDC initialization..."); + if (itf >= TINYUSB_CDC_TOTAL) { + ESP_LOGE(TAG, "There is not CDC no.%d", itf); + return ESP_ERR_INVALID_ARG; + } + if (cfg->cdc_class == TUSB_CLASS_CDC) { + ESP_RETURN_ON_ERROR(tusb_cdc_comm_init(itf), TAG, "tusb_cdc_comm_init failed"); + cdc_obj[itf]->cdc_subclass.comm_subclass = cfg->cdc_subclass.comm_subclass; + } else { + ESP_RETURN_ON_ERROR(tusb_cdc_data_init(itf), TAG, "tusb_cdc_data_init failed"); + cdc_obj[itf]->cdc_subclass.data_subclass = cfg->cdc_subclass.data_subclass; + } + cdc_obj[itf]->usb_dev = cfg->usb_dev; + return ESP_OK; +} + + +esp_err_t tinyusb_cdc_deinit(int itf) +{ + if (itf >= TINYUSB_CDC_TOTAL) { + ESP_LOGE(TAG, "There is not CDC no.%d", itf); + return ESP_ERR_INVALID_ARG; + } + if (cdc_obj[itf]->type == TUSB_CLASS_CDC) { + ESP_RETURN_ON_ERROR(tusb_cdc_deinit_comm(itf), TAG, "tusb_cdc_deinit_comm failed"); + } else if (cdc_obj[itf]->type == TUSB_CLASS_CDC_DATA) { + ESP_RETURN_ON_ERROR(tusb_cdc_deinit_data(itf), TAG, "tusb_cdc_deinit_data failed"); + } else { + return ESP_ERR_INVALID_ARG; + } + ESP_LOGD(TAG, "De-initialized"); + return ESP_OK; +} +/*********************************************************************** CDC initialization*/ diff --git a/components/tinyusb/additions/src/descriptors_control.c b/components/tinyusb/additions/src/descriptors_control.c new file mode 100644 index 0000000..87fcf02 --- /dev/null +++ b/components/tinyusb/additions/src/descriptors_control.c @@ -0,0 +1,294 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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 "esp_log.h" +#include "descriptors_control.h" +#include "dfu_device.h" +#include "u2f_hid.h" + + +#define TILDA_REPORT_DESC_U2F(...) \ + HID_USAGE_PAGE_N ( FIDO_USAGE_PAGE, 2 ) ,\ + HID_USAGE ( FIDO_USAGE_U2FHID ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ + __VA_ARGS__ \ + HID_USAGE ( FIDO_USAGE_DATA_IN ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ + HID_REPORT_COUNT ( 64 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_USAGE ( FIDO_USAGE_DATA_OUT ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\ + HID_REPORT_COUNT ( 64 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_COLLECTION_END \ + + +static const char *TAG = "tusb_desc"; +static tusb_desc_device_t s_descriptor; +static char *s_str_descriptor[USB_STRING_DESCRIPTOR_ARRAY_SIZE]; +static uint8_t *s_config_descriptor = NULL; +#define MAX_DESC_BUF_SIZE 32 + +#if CFG_TUD_U2FHID //HID Report Descriptor +uint8_t const desc_hid_report_2[] = { + TILDA_REPORT_DESC_U2F() +}; +#endif +#if CFG_TUD_HID //HID Report Descriptor +uint8_t const desc_hid_report[] = { + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)), + TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_MOUSE)) +}; +#endif + +#define FUNC_ATTRS (DFU_ATTR_CAN_UPLOAD | DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) + +uint8_t const desc_configuration[] = { +#if CONFIG_TINYUSB_NET_ECM + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100), +#else + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, 0, 500), +#endif +#if CFG_TUD_BTH + // BT Primary controller descriptor + // Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes + TUD_BTH_DESCRIPTOR(ITF_NUM_BTH, 0 /* STRID_BTH_INTERFACE */, (0x80 | EPNUM_BT_EVT), 16, 1, (0x80 | EPNUM_BT_BULK_OUT), EPNUM_BT_BULK_OUT, 64, 0, 9, 17, 25, 33, 49), +#endif +#if CFG_TUD_NET +#if CONFIG_TINYUSB_NET_ECM + // Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. + TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_NET, STRID_NET_INTERFACE, STRID_MAC, (0x80 | EPNUM_NET_NOTIF), 64, EPNUM_NET_DATA, (0x80 | EPNUM_NET_DATA), CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU), +#elif CONFIG_TINYUSB_NET_RNDIS + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_RNDIS_DESCRIPTOR(ITF_NUM_NET, STRID_NET_INTERFACE, (0x80 | EPNUM_NET_NOTIF), 8, EPNUM_NET_DATA, (0x80 | EPNUM_NET_DATA), CFG_TUD_NET_ENDPOINT_SIZE), +#endif +#endif +#if CFG_TUD_CDC + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, STRID_CDC_INTERFACE, (0x80 | EPNUM_CDC_NOTIF), 8, EPNUM_CDC_DATA, (0x80 | EPNUM_CDC_DATA), 64), +#endif +#if CFG_TUD_MSC + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, STRID_MSC_INTERFACE, EPNUM_MSC_DATA, (0x80 | EPNUM_MSC_DATA), 64), // highspeed 512 +#endif +#if CFG_TUD_HID_KBD + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_HID, STRID_HID_INTERFACE, HID_PROTOCOL_KEYBOARD, sizeof(desc_hid_report), (0x80 | EPNUM_HID_DATA), 8, 10), +#endif +#if CFG_TUD_U2FHID + TUD_HID_DESCRIPTOR(ITF_NUM_HID_2, STRID_HID_INTERFACE_2, HID_PROTOCOL_NONE, sizeof(desc_hid_report_2), (0x80 | EPNUM_HID_DATA_2), 8, 10), +#endif + +#if CFG_TUD_DFU + // Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size + TUD_DFU_DESCRIPTOR(ITF_NUM_DFU, DFU_ALT_COUNT, STRID_DFU_INTERFACE, FUNC_ATTRS, 1000, CFG_TUD_DFU_XFER_BUFSIZE), +#endif + +}; + +// ============================================================================= +// CALLBACKS +// ============================================================================= + +/** + * @brief Invoked when received GET DEVICE DESCRIPTOR. + * Application returns pointer to descriptor + * + * @return uint8_t const* + */ +uint8_t const *tud_descriptor_device_cb(void) +{ + return (uint8_t const *)&s_descriptor; +} + +/** + * @brief Invoked when received GET CONFIGURATION DESCRIPTOR. + * Descriptor contents must exist long enough for transfer to complete + * + * @param index + * @return uint8_t const* Application return pointer to descriptor + */ +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) +{ + (void)index; // for multiple configurations + return s_config_descriptor; +} + +static uint16_t _desc_str[MAX_DESC_BUF_SIZE]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + uint8_t chr_count; + + if ( index == 0) { + memcpy(&_desc_str[1], s_str_descriptor[0], 2); + chr_count = 1; + } +#if CONFIG_TINYUSB_NET_ECM + else if (STRID_MAC == index) + { + // Convert MAC address into UTF-16 + + for (unsigned i=0; i> 4) & 0xf]; + _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf]; + } + } +#endif + else + { + // Convert ASCII string into UTF-16 + + if ( index >= sizeof(s_str_descriptor) / sizeof(s_str_descriptor[0]) ) { + return NULL; + } + + const char *str = s_str_descriptor[index]; + + // Cap at max char + chr_count = strlen(str); + if ( chr_count > MAX_DESC_BUF_SIZE - 1 ) { + chr_count = MAX_DESC_BUF_SIZE - 1; + } + + for (uint8_t i = 0; i < chr_count; i++) { + _desc_str[1 + i] = str[i]; + } + } + + // first byte is length (including header), second byte is string type + _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2 * chr_count + 2); + + return _desc_str; +} + +/** + * @brief Invoked when received GET HID REPORT DESCRIPTOR + * Application returns pointer to descriptor. Descriptor contents must exist + * long enough for transfer to complete + * + * @return uint8_t const* + */ +#if CFG_TUD_HID +uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) +{ + ESP_LOGW(TAG, "Getting descriptor for interface %d", itf); + #if CFG_TUD_HID_KBD + if (itf == 0) { + return desc_hid_report; + } + #endif + #if CFG_TUD_U2FHID + if (itf == 1) { + return desc_hid_report_2; + } + #endif + ESP_LOGE(TAG, "Unknown descriptor %d", itf); + return NULL; +} +#endif + +// ============================================================================= +// Driver functions +// ============================================================================= + +void tusb_set_descriptor(tusb_desc_device_t *dev_desc, const char **str_desc) +{ + ESP_LOGI(TAG, "\n" + "┌─────────────────────────────────┐\n" + "│ USB Device Descriptor Summary │\n" + "├───────────────────┬─────────────┤\n" + "│bDeviceClass │ %-4u │\n" + "├───────────────────┼─────────────┤\n" + "│bDeviceSubClass │ %-4u │\n" + "├───────────────────┼─────────────┤\n" + "│bDeviceProtocol │ %-4u │\n" + "├───────────────────┼─────────────┤\n" + "│bMaxPacketSize0 │ %-4u │\n" + "├───────────────────┼─────────────┤\n" + "│idVendor │ %-#10x │\n" + "├───────────────────┼─────────────┤\n" + "│idProduct │ %-#10x │\n" + "├───────────────────┼─────────────┤\n" + "│bcdDevice │ %-#10x │\n" + "├───────────────────┼─────────────┤\n" + "│iManufacturer │ %-#10x │\n" + "├───────────────────┼─────────────┤\n" + "│iProduct │ %-#10x │\n" + "├───────────────────┼─────────────┤\n" + "│iSerialNumber │ %-#10x │\n" + "├───────────────────┼─────────────┤\n" + "│bNumConfigurations │ %-#10x │\n" + "└───────────────────┴─────────────┘", + dev_desc->bDeviceClass, dev_desc->bDeviceSubClass, + dev_desc->bDeviceProtocol, dev_desc->bMaxPacketSize0, + dev_desc->idVendor, dev_desc->idProduct, dev_desc->bcdDevice, + dev_desc->iManufacturer, dev_desc->iProduct, dev_desc->iSerialNumber, + dev_desc->bNumConfigurations); + s_descriptor = *dev_desc; + + if (str_desc != NULL) { + memcpy(s_str_descriptor, str_desc, + sizeof(s_str_descriptor[0])*USB_STRING_DESCRIPTOR_ARRAY_SIZE); + } + tusb_desc_set = true; +} + +void tusb_set_config_descriptor(const uint8_t *config_desc) +{ + size_t length = 0; + const uint8_t *config_descriptor = NULL; + if (config_desc == NULL) { + config_descriptor = desc_configuration; + ESP_LOGI(TAG, "using default config desc"); + } else { + config_descriptor = config_desc; + ESP_LOGI(TAG, "using custom config desc"); + } + length = (config_descriptor[3]<<8) + config_descriptor[2]; + ESP_LOGI(TAG, "config desc size=%d", length); + s_config_descriptor = realloc(s_config_descriptor, length); + memcpy(s_config_descriptor, config_descriptor, length); +} + +tusb_desc_device_t *tusb_get_active_desc(void) +{ + return &s_descriptor; +} + +char **tusb_get_active_str_desc(void) +{ + return s_str_descriptor; +} + +void tusb_clear_descriptor(void) +{ + memset(&s_descriptor, 0, sizeof(s_descriptor)); + memset(&s_str_descriptor, 0, sizeof(s_str_descriptor)); + free(s_config_descriptor); + s_config_descriptor = NULL; + tusb_desc_set = false; +} diff --git a/components/tinyusb/additions/src/tinyusb.c b/components/tinyusb/additions/src/tinyusb.c new file mode 100644 index 0000000..2363ae3 --- /dev/null +++ b/components/tinyusb/additions/src/tinyusb.c @@ -0,0 +1,85 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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 "sdkconfig.h" +#include "driver/gpio.h" +#include "driver/periph_ctrl.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_rom_gpio.h" +#include "hal/gpio_ll.h" +#include "hal/usb_hal.h" +#include "soc/gpio_periph.h" +#include "soc/usb_periph.h" +#include "tinyusb.h" +#include "descriptors_control.h" +#include "tusb.h" +#include "tusb_tasks.h" + +const static char *TAG = "TinyUSB"; + +static void configure_pins(usb_hal_context_t *usb) +{ + /* usb_periph_iopins currently configures USB_OTG as USB Device. + * Introduce additional parameters in usb_hal_context_t when adding support + * for USB Host. + */ + for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) { + if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) { + esp_rom_gpio_pad_select_gpio(iopin->pin); + if (iopin->is_output) { + esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false); + } else { + esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false); + if ((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) { + gpio_ll_input_enable(&GPIO, iopin->pin); + } + } + esp_rom_gpio_pad_unhold(iopin->pin); + } + } + if (!usb->use_external_phy) { + gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3); + gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3); + } +} + +esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) +{ + tusb_desc_device_t *dev_descriptor; + const char **string_descriptor; + ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + // Enable APB CLK to USB peripheral + periph_module_enable(PERIPH_USB_MODULE); + periph_module_reset(PERIPH_USB_MODULE); + // Initialize HAL layer + usb_hal_context_t hal = { + .use_external_phy = config->external_phy + }; + usb_hal_init(&hal); + configure_pins(&hal); + + dev_descriptor = config->descriptor ? config->descriptor : &descriptor_kconfig; + string_descriptor = config->string_descriptor ? config->string_descriptor : descriptor_str_kconfig; + + tusb_set_config_descriptor(config->config_descriptor); //if NULL, using default descriptor config by menuconfig + tusb_set_descriptor(dev_descriptor, string_descriptor); + + ESP_RETURN_ON_FALSE(tusb_init(), ESP_FAIL, TAG, "Init TinyUSB stack failed"); +#if !CONFIG_TINYUSB_NO_DEFAULT_TASK + ESP_RETURN_ON_ERROR(tusb_run_task(), TAG, "Run TinyUSB task failed"); +#endif + ESP_LOGI(TAG, "TinyUSB Driver installed"); + return ESP_OK; +} diff --git a/components/tinyusb/additions/src/tusb_bth.c b/components/tinyusb/additions/src/tusb_bth.c new file mode 100644 index 0000000..066a144 --- /dev/null +++ b/components/tinyusb/additions/src/tusb_bth.c @@ -0,0 +1,212 @@ +/** + * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * 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 "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "esp_bt.h" + +#include "tinyusb.h" +#include "tusb_bth.h" + +#define BUFFER_SIZE_MAX 256 +#define LE_READ_BUFF_SIZE 0x2002 +#define HCI_H4_CMD_PREAMBLE_SIZE (4) +#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} +#define UINT8_TO_STREAM(p, u8) {*(p)++ = (uint8_t)(u8);} + +static const char *TAG = "tusb_bth"; +static uint16_t acl_buf_size_max = 0; +uint8_t * p_acl_buf = NULL; + +void ble_controller_init(void) { + esp_err_t ret; + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + + if ((ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) { + ESP_LOGI(TAG, "Bluetooth controller release classic bt memory failed: %s", esp_err_to_name(ret)); + return; + } + + if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) { + ESP_LOGI(TAG, "Bluetooth controller initialize failed: %s", esp_err_to_name(ret)); + return; + } + + if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) { + ESP_LOGI(TAG, "Bluetooth controller enable failed: %s", esp_err_to_name(ret)); + return; + } +} + +/* + * @brief: BT controller callback function, used to notify the upper layer that + * controller is ready to receive command + */ +static void controller_rcv_pkt_ready(void) +{ + //TODO +} + +/* + * @brief: BT controller callback function, to transfer data packet to upper + * controller is ready to receive command + */ +static int host_rcv_pkt(uint8_t *data, uint16_t len) +{ + uint16_t act_len = len - 1; + + if(data[0] == HCIT_TYPE_EVENT) { // event data from controller + uint8_t *hci_buf = (uint8_t *)malloc(len); + memcpy(hci_buf, data +1 , act_len); + ESP_LOGI(TAG, "evt_data from controller, evt_data_length: %d :", act_len); + tud_bt_event_send(hci_buf, act_len); + free(hci_buf); + } else if(data[0] == HCIT_TYPE_ACL_DATA) { // acl data from controller + uint8_t *hci_acl_buf_contr = (uint8_t *)malloc(len); + memcpy(hci_acl_buf_contr, data +1 , act_len); + ESP_LOGI(TAG, "acl_data from controller, acl_data_length: %d :", act_len); + tud_bt_acl_data_send(hci_acl_buf_contr, act_len); + free(hci_acl_buf_contr); + } + return 0; +} + +static esp_vhci_host_callback_t vhci_host_cb = { + controller_rcv_pkt_ready, + host_rcv_pkt +}; + +static int host_rcv_pkt_test (uint8_t *data, uint16_t len) { + + ESP_LOGI(TAG, "host_rcv_pkt_test evt_data_length: %d :", len); + if(data[1] == 0x0e && data[2] == 0x07 + && data[4] == 0x02 && data[5] == 0x20) { + // LE Read Buffer size command complete event + uint16_t* size_p = NULL; + uint16_t cmd_value; + size_p = (uint8_t*)(&cmd_value); + *size_p = data[7]; + *(size_p+1) = data[8]; + acl_buf_size_max = *size_p; + ESP_LOGI(TAG, "acl_buf_size_max: %d", acl_buf_size_max); + } + if (!acl_buf_size_max) { + acl_buf_size_max = BUFFER_SIZE_MAX; + } + + p_acl_buf = (uint8_t *)malloc(acl_buf_size_max + 1); + esp_vhci_host_register_callback(&vhci_host_cb); + return 0; +} + +uint16_t make_cmd_le_read_buff_size(uint8_t *buf) +{ + UINT8_TO_STREAM (buf, HCIT_TYPE_COMMAND); + UINT16_TO_STREAM (buf, LE_READ_BUFF_SIZE); + UINT8_TO_STREAM (buf, 0); + return HCI_H4_CMD_PREAMBLE_SIZE; +} + +static esp_vhci_host_callback_t vhci_host_cb_test = { + controller_rcv_pkt_ready, + host_rcv_pkt_test +}; + +void tusb_bth_init(void) +{ + ble_controller_init(); + // register vhci_host_cb_test, test le read buffer size + esp_vhci_host_register_callback(&vhci_host_cb_test); + uint8_t buf[6]; + uint16_t sz = make_cmd_le_read_buff_size(buf); + esp_vhci_host_send_packet(buf, sz); +} + +//--------------------------------------------------------------------+ +// tinyusb callbacks +//--------------------------------------------------------------------+ + +// Invoked when HCI command was received over USB from Bluetooth host. +// Detailed format is described in Bluetooth core specification Vol 2, +// Part E, 5.4.1. +// Length of the command is from 3 bytes (2 bytes for OpCode, +// 1 byte for parameter total length) to 258. +void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) +{ + uint8_t *hci_cmd_buf = (uint8_t *)malloc(cmd_len + 1); + + hci_cmd_buf[0] = HCIT_TYPE_COMMAND; + memcpy(hci_cmd_buf+1, hci_cmd, cmd_len); + esp_vhci_host_send_packet(hci_cmd_buf, cmd_len +1); + + free(hci_cmd_buf); +} + +// Invoked when ACL data was received over USB from Bluetooth host. +// Detailed format is described in Bluetooth core specification Vol 2, +// Part E, 5.4.2. +// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags +// and 16 bits for data total length) to endpoint size. +static bool prepare_write = false; +static uint16_t write_offset = 0; +static uint16_t acl_data_length = 0; +void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) +{ + + // if acl_data is long data + if(!prepare_write) { + // first get acl_data_length + acl_data_length = *(((uint16_t * )acl_data) + 1); + if(acl_data_length > data_len) { + prepare_write = true; + p_acl_buf[0] = HCIT_TYPE_ACL_DATA; + memcpy(p_acl_buf + 1, acl_data, data_len); + write_offset = data_len + 1; + } else { + p_acl_buf[0] = HCIT_TYPE_ACL_DATA; + memcpy(p_acl_buf + 1, acl_data, data_len); + ESP_LOGI(TAG, "short acl_data from host, will send to controller, length: %d", (data_len + 1)); + esp_vhci_host_send_packet(p_acl_buf, data_len + 1); + } + } else { + memcpy(p_acl_buf + write_offset, acl_data, data_len); + write_offset += data_len; + if(acl_data_length > write_offset) { + ESP_LOGI(TAG, "Remaining bytes: %d", (acl_data_length - write_offset)); + return; + } + ESP_LOGI(TAG, "long acl_data from host, will send to controller, length: %d", (data_len + 1)); + prepare_write = false; + esp_vhci_host_send_packet(p_acl_buf, data_len + write_offset); + } + //free(hci_data_buf); +} + +// Called when event sent with tud_bt_event_send() was delivered to BT stack. +// Controller can release/reuse buffer with Event packet at this point. +void tud_bt_event_sent_cb(uint16_t sent_bytes) +{ + //TODO +} + +// Called when ACL data that was sent with tud_bt_acl_data_send() +// was delivered to BT stack. +// Controller can release/reuse buffer with ACL packet at this point. +void tud_bt_acl_data_sent_cb(uint16_t sent_bytes) +{ + //TODO +} \ No newline at end of file diff --git a/components/tinyusb/additions/src/tusb_cdc_acm.c b/components/tinyusb/additions/src/tusb_cdc_acm.c new file mode 100644 index 0000000..f2e536c --- /dev/null +++ b/components/tinyusb/additions/src/tusb_cdc_acm.c @@ -0,0 +1,426 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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 +#include "esp_check.h" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "tusb.h" +#include "tusb_cdc_acm.h" +#include "cdc.h" +#include "sdkconfig.h" + +#define RX_UNREADBUF_SZ_DEFAULT 64 // buffer storing all unread RX data + + +typedef struct { + bool initialized; + size_t rx_unread_buf_sz; + RingbufHandle_t rx_unread_buf; + xSemaphoreHandle ringbuf_read_mux; + uint8_t *rx_tfbuf; + tusb_cdcacm_callback_t callback_rx; + tusb_cdcacm_callback_t callback_rx_wanted_char; + tusb_cdcacm_callback_t callback_line_state_changed; + tusb_cdcacm_callback_t callback_line_coding_changed; +} esp_tusb_cdcacm_t; /*!< CDC_AMC object */ + +static const char *TAG = "tusb_cdc_acm"; + +static inline esp_tusb_cdcacm_t *get_acm(tinyusb_cdcacm_itf_t itf) +{ + esp_tusb_cdc_t *cdc_inst = tinyusb_cdc_get_intf(itf); + if (cdc_inst == NULL) { + return (esp_tusb_cdcacm_t *)NULL; + } + return (esp_tusb_cdcacm_t *)(cdc_inst->subclass_obj); +} + + +/* TinyUSB callbacks + ********************************************************************* */ + +/* Invoked by cdc interface when line state changed e.g connected/disconnected */ +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (dtr && rts) { // connected + if (acm != NULL) { + ESP_LOGV(TAG, "Host connected to CDC no.%d.", itf); + } else { + ESP_LOGW(TAG, "Host is connected to CDC no.%d, but it is not initialized. Initialize it using `tinyusb_cdc_init`.", itf); + return; + } + } else { // disconnected + if (acm != NULL) { + ESP_LOGV(TAG, "Serial device is ready to connect to CDC no.%d", itf); + } else { + return; + } + } + if (acm) { + tusb_cdcacm_callback_t cb = acm->callback_line_state_changed; + if (cb) { + cdcacm_event_t event = { + .type = CDC_EVENT_LINE_STATE_CHANGED, + .line_state_changed_data = { + .dtr = dtr, + .rts = rts + } + }; + cb(itf, &event); + } + } +} + + +/* Invoked when CDC interface received data from host */ +void tud_cdc_rx_cb(uint8_t itf) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (acm) { + if (!acm->rx_unread_buf) { + ESP_LOGE(TAG, "There is no RX buffer created"); + abort(); + } + } else { + tud_cdc_n_read_flush(itf); // we have no place to store data, so just drop it + return; + } + while (tud_cdc_n_available(itf)) { + int read_res = tud_cdc_n_read( itf, + acm->rx_tfbuf, + CONFIG_TINYUSB_CDC_RX_BUFSIZE ); + int res = xRingbufferSend(acm->rx_unread_buf, + acm->rx_tfbuf, + read_res, 0); + if (res != pdTRUE) { + ESP_LOGW(TAG, "The unread buffer is too small, the data has been lost"); + } else { + ESP_LOGV(TAG, "Sent %d bytes to the buffer", read_res); + } + } + if (acm) { + tusb_cdcacm_callback_t cb = acm->callback_rx; + if (cb) { + cdcacm_event_t event = { + .type = CDC_EVENT_RX + }; + cb(itf, &event); + } + } +} + +// Invoked when line coding is change via SET_LINE_CODING +void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const *p_line_coding) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (acm) { + tusb_cdcacm_callback_t cb = acm->callback_line_coding_changed; + if (cb) { + cdcacm_event_t event = { + .type = CDC_EVENT_LINE_CODING_CHANGED, + .line_coding_changed_data = { + .p_line_coding = p_line_coding, + } + }; + cb(itf, &event); + } + } else { + return; + } +} + +// Invoked when received `wanted_char` +void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (acm) { + tusb_cdcacm_callback_t cb = acm->callback_rx_wanted_char; + if (cb) { + cdcacm_event_t event = { + .type = CDC_EVENT_RX_WANTED_CHAR, + .rx_wanted_char_data = { + .wanted_char = wanted_char, + } + }; + cb(itf, &event); + } + } else { + return; + } +} + + + +esp_err_t tinyusb_cdcacm_register_callback(tinyusb_cdcacm_itf_t itf, + cdcacm_event_type_t event_type, + tusb_cdcacm_callback_t callback) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (acm) { + switch (event_type) { + case CDC_EVENT_RX: + acm->callback_rx = callback; + return ESP_OK; + case CDC_EVENT_RX_WANTED_CHAR: + acm->callback_rx_wanted_char = callback; + return ESP_OK; + case CDC_EVENT_LINE_STATE_CHANGED: + acm->callback_line_state_changed = callback; + return ESP_OK; + case CDC_EVENT_LINE_CODING_CHANGED: + acm->callback_line_coding_changed = callback; + return ESP_OK; + default: + ESP_LOGE(TAG, "Wrong event type"); + return ESP_ERR_INVALID_ARG; + } + } else { + ESP_LOGE(TAG, "CDC-ACM is not initialized"); + return ESP_ERR_INVALID_STATE; + } +} + + +esp_err_t tinyusb_cdcacm_unregister_callback(tinyusb_cdcacm_itf_t itf, + cdcacm_event_type_t event_type) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (!acm) { + ESP_LOGE(TAG, "Interface is not initialized. Use `tinyusb_cdc_init` for initialization"); + return ESP_ERR_INVALID_STATE; + } + switch (event_type) { + case CDC_EVENT_RX: + acm->callback_rx = NULL; + return ESP_OK; + case CDC_EVENT_RX_WANTED_CHAR: + acm->callback_rx_wanted_char = NULL; + return ESP_OK; + case CDC_EVENT_LINE_STATE_CHANGED: + acm->callback_line_state_changed = NULL; + return ESP_OK; + case CDC_EVENT_LINE_CODING_CHANGED: + acm->callback_line_coding_changed = NULL; + return ESP_OK; + default: + ESP_LOGE(TAG, "Wrong event type"); + return ESP_ERR_INVALID_ARG; + } +} + +/*********************************************************************** TinyUSB callbacks*/ +/* CDC-ACM + ********************************************************************* */ + +static esp_err_t read_from_rx_unread_to_buffer(esp_tusb_cdcacm_t *acm, uint8_t *out_buf, size_t req_bytes, size_t *read_bytes) +{ + uint8_t *buf = xRingbufferReceiveUpTo(acm->rx_unread_buf, read_bytes, 0, req_bytes); + if (buf) { + memcpy(out_buf, buf, *read_bytes); + vRingbufferReturnItem(acm->rx_unread_buf, (void *)(buf)); + return ESP_OK; + } else { + return ESP_ERR_NO_MEM; + } +} + +static esp_err_t ringbuf_mux_take(esp_tusb_cdcacm_t *acm) +{ + if (xSemaphoreTake(acm->ringbuf_read_mux, 0) != pdTRUE) { + ESP_LOGW(TAG, "Read error: ACM is busy"); + return ESP_ERR_INVALID_STATE; + } + return ESP_OK; +} + +static esp_err_t ringbuf_mux_give(esp_tusb_cdcacm_t *acm) +{ + BaseType_t ret = xSemaphoreGive(acm->ringbuf_read_mux); + assert(ret == pdTRUE); + return ESP_OK; +} + +esp_err_t tinyusb_cdcacm_read(tinyusb_cdcacm_itf_t itf, uint8_t *out_buf, size_t out_buf_sz, size_t *rx_data_size) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + ESP_RETURN_ON_FALSE(acm, ESP_ERR_INVALID_STATE, TAG, "Interface is not initialized. Use `tinyusb_cdc_init` for initialization"); + size_t read_sz; + + /* Take a mutex to proceed two uninterrupted read operations */ + ESP_RETURN_ON_ERROR(ringbuf_mux_take(acm), TAG, "ringbuf_mux_take failed"); + + esp_err_t res = read_from_rx_unread_to_buffer(acm, out_buf, out_buf_sz, &read_sz); + if (res != ESP_OK) { + ESP_RETURN_ON_ERROR(ringbuf_mux_give(acm), TAG, "ringbuf_mux_give failed"); + return res; + } + + *rx_data_size = read_sz; + /* Buffer's data can be wrapped, at that situations we should make another retrievement */ + if (read_from_rx_unread_to_buffer(acm, out_buf + read_sz, out_buf_sz - read_sz, &read_sz) == ESP_OK) { + *rx_data_size += read_sz; + } + + ESP_RETURN_ON_ERROR(ringbuf_mux_give(acm), TAG, "ringbuf_mux_give failed"); + return ESP_OK; +} + + +size_t tinyusb_cdcacm_write_queue_char(tinyusb_cdcacm_itf_t itf, char ch) +{ + if (!get_acm(itf)) { // non-initialized + return 0; + } + return tud_cdc_n_write_char(itf, ch); +} + + +size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, uint8_t *in_buf, size_t in_size) +{ + if (!get_acm(itf)) { // non-initialized + return 0; + } + return tud_cdc_n_write(itf, in_buf, in_size); +} + +static uint32_t tud_cdc_n_write_occupied(tinyusb_cdcacm_itf_t itf) +{ + return CFG_TUD_CDC_TX_BUFSIZE - tud_cdc_n_write_available(itf); +} + +esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_ticks) +{ + if (!get_acm(itf)) { // non-initialized + return ESP_FAIL; + } + + if (!timeout_ticks) { // if no timeout - nonblocking mode + int res = tud_cdc_n_write_flush(itf); + if (!res) { + ESP_LOGW(TAG, "flush failed (res: %d)", res); + return ESP_FAIL; + } else { + if (tud_cdc_n_write_occupied(itf)) { + ESP_LOGW(TAG, "remained data to flush!"); + return ESP_FAIL; + } + } + return ESP_ERR_TIMEOUT; + } else { // trying during the timeout + uint32_t ticks_start = xTaskGetTickCount(); + uint32_t ticks_now = ticks_start; + while (1) { // loop until success or until the time runs out + ticks_now = xTaskGetTickCount(); + if (!tud_cdc_n_write_occupied(itf)) { // if nothing to write - nothing to flush + break; + } + if (tud_cdc_n_write_flush(itf)) { // Success + break; + } + if ( (ticks_now - ticks_start) > timeout_ticks ) { // Time is up + ESP_LOGW(TAG, "Flush failed"); + return ESP_ERR_TIMEOUT; + } + vTaskDelay(1); + } + return ESP_OK; + } +} + +static esp_err_t alloc_obj(tinyusb_cdcacm_itf_t itf) +{ + esp_tusb_cdc_t *cdc_inst = tinyusb_cdc_get_intf(itf); + cdc_inst->subclass_obj = calloc(1, sizeof(esp_tusb_cdcacm_t)); + if (!cdc_inst->subclass_obj) { + return ESP_FAIL; + } else { + return ESP_OK; + } +} + +static void free_obj(tinyusb_cdcacm_itf_t itf) +{ + esp_tusb_cdc_t *cdc_inst = tinyusb_cdc_get_intf(itf); + free(cdc_inst->subclass_obj); + cdc_inst->subclass_obj = NULL; +} + +esp_err_t tusb_cdc_acm_init(const tinyusb_config_cdcacm_t *cfg) +{ + int itf = (int)cfg->cdc_port; + /* Creating a CDC object */ + const tinyusb_config_cdc_t cdc_cfg = { + .usb_dev = cfg->usb_dev, + .cdc_class = TUSB_CLASS_CDC, + .cdc_subclass.comm_subclass = CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL + }; + ESP_RETURN_ON_ERROR(tinyusb_cdc_init(itf, &cdc_cfg), TAG, "tinyusb_cdc_init failed"); + ESP_RETURN_ON_ERROR(alloc_obj(itf), TAG, "alloc_obj failed"); + + esp_tusb_cdcacm_t *acm = get_acm(itf); + /* Callbacks setting up*/ + if (cfg->callback_rx) { + tinyusb_cdcacm_register_callback(itf, CDC_EVENT_RX, cfg->callback_rx); + } + if (cfg->callback_rx_wanted_char) { + tinyusb_cdcacm_register_callback(itf, CDC_EVENT_RX_WANTED_CHAR, cfg->callback_rx_wanted_char); + } + if (cfg->callback_line_state_changed) { + tinyusb_cdcacm_register_callback(itf, CDC_EVENT_LINE_STATE_CHANGED, cfg->callback_line_state_changed); + } + if (cfg->callback_line_coding_changed) { + tinyusb_cdcacm_register_callback( itf, CDC_EVENT_LINE_CODING_CHANGED, cfg->callback_line_coding_changed); + } + + /* Buffers */ + + acm->ringbuf_read_mux = xSemaphoreCreateMutex(); + if (acm->ringbuf_read_mux == NULL) { + ESP_LOGE(TAG, "Creation of a ringbuf mutex failed"); + free_obj(itf); + return ESP_ERR_NO_MEM; + } + + acm->rx_tfbuf = malloc(CONFIG_TINYUSB_CDC_RX_BUFSIZE); + if (!acm->rx_tfbuf) { + ESP_LOGE(TAG, "Creation buffer error"); + free_obj(itf); + return ESP_ERR_NO_MEM; + } + acm->rx_unread_buf_sz = cfg->rx_unread_buf_sz == 0 ? RX_UNREADBUF_SZ_DEFAULT : cfg->rx_unread_buf_sz; + acm->rx_unread_buf = xRingbufferCreate(acm->rx_unread_buf_sz, RINGBUF_TYPE_BYTEBUF); + if (acm->rx_unread_buf == NULL) { + ESP_LOGE(TAG, "Creation buffer error"); + free_obj(itf); + return ESP_ERR_NO_MEM; + } else { + ESP_LOGD(TAG, "Comm Initialized buff:%d bytes", cfg->rx_unread_buf_sz); + return ESP_OK; + } +} + +bool tusb_cdc_acm_initialized(tinyusb_cdcacm_itf_t itf) +{ + esp_tusb_cdcacm_t *acm = get_acm(itf); + if (acm) { + return true; + } else { + return false; + } +} +/*********************************************************************** CDC-ACM*/ diff --git a/components/tinyusb/additions/src/tusb_console.c b/components/tinyusb/additions/src/tusb_console.c new file mode 100644 index 0000000..1942a05 --- /dev/null +++ b/components/tinyusb/additions/src/tusb_console.c @@ -0,0 +1,142 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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 +#include +#include "esp_log.h" +#include "cdc.h" +#include "tusb_console.h" +#include "tinyusb.h" +#include "vfs_tinyusb.h" + +#define STRINGIFY(s) STRINGIFY2(s) +#define STRINGIFY2(s) #s + +static const char *TAG = "tusb_console"; + +typedef struct { + FILE *in; + FILE *out; + FILE *err; +} console_handle_t; + +static console_handle_t con; + + +/** + * @brief Reopen standard streams using a new path + * + * @param f_in - pointer to a pointer holding a file for in or NULL to don't change stdin + * @param f_out - pointer to a pointer holding a file for out or NULL to don't change stdout + * @param f_err - pointer to a pointer holding a file for err or NULL to don't change stderr + * @param path - mount point + * @return esp_err_t ESP_FAIL or ESP_OK + */ +static esp_err_t redirect_std_streams_to(FILE **f_in, FILE **f_out, FILE **f_err, const char *path) +{ + if (f_in) { + *f_in = freopen(path, "r", stdin); + if (*f_in == NULL) { + ESP_LOGE(TAG, "Failed to reopen in!"); + return ESP_FAIL; + } + } + if (f_out) { + *f_out = freopen(path, "w", stdout); + if (*f_out == NULL) { + ESP_LOGE(TAG, "Failed to reopen out!"); + return ESP_FAIL; + } + } + if (f_err) { + *f_err = freopen(path, "w", stderr); + if (*f_err == NULL) { + ESP_LOGE(TAG, "Failed to reopen err!"); + return ESP_FAIL; + } + } + + return ESP_OK; +} + +/** + * @brief Restore output to default + * + * @param f_in - pointer to a pointer of an in file updated with `redirect_std_streams_to` or NULL to don't change stdin + * @param f_out - pointer to a pointer of an out file updated with `redirect_std_streams_to` or NULL to don't change stdout + * @param f_err - pointer to a pointer of an err file updated with `redirect_std_streams_to` or NULL to don't change stderr + * @return esp_err_t ESP_FAIL or ESP_OK + */ +static esp_err_t restore_std_streams(FILE **f_in, FILE **f_out, FILE **f_err) +{ + const char *default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM); + if (f_in) { + stdin = freopen(default_uart_dev, "r", *f_in); + if (stdin == NULL) { + ESP_LOGE(TAG, "Failed to reopen stdin!"); + return ESP_FAIL; + } + } + if (f_out) { + stdout = freopen(default_uart_dev, "w", *f_out); + if (stdout == NULL) { + ESP_LOGE(TAG, "Failed to reopen stdout!"); + return ESP_FAIL; + } + } + if (f_err) { + stderr = freopen(default_uart_dev, "w", *f_err); + if (stderr == NULL) { + ESP_LOGE(TAG, "Failed to reopen stderr!"); + return ESP_FAIL; + } + } + return ESP_OK; +} + +esp_err_t esp_tusb_init_console(int cdc_intf) +{ + if (!tinyusb_cdc_initialized(cdc_intf)) { + ESP_LOGE(TAG, "Can't init the console because TinyUSB's CDC is not initialized!"); + return ESP_ERR_INVALID_STATE; + } + /* Registering TUSB at VFS */ + int res = esp_vfs_tusb_cdc_register(cdc_intf, NULL); + if (res != ESP_OK) { + return res; + } + + res = redirect_std_streams_to(&con.in, &con.out, &con.err, "/dev/tusb_cdc"); + if (res != ESP_OK) { + return res; + } + + return ESP_OK; +} + +esp_err_t esp_tusb_deinit_console(int cdc_intf) +{ + if (!tinyusb_cdc_initialized(cdc_intf)) { + ESP_LOGE(TAG, "Can't deinit the console because TinyUSB's CDC is not initialized!"); + return ESP_ERR_INVALID_STATE; + } + + int res = restore_std_streams(&con.in, &con.out, &con.err); + if (res != ESP_OK) { + return res; + } + esp_vfs_tusb_cdc_unregister(NULL); + return ESP_OK; +} diff --git a/components/tinyusb/additions/src/tusb_dfu.c b/components/tinyusb/additions/src/tusb_dfu.c new file mode 100644 index 0000000..2c5efb5 --- /dev/null +++ b/components/tinyusb/additions/src/tusb_dfu.c @@ -0,0 +1,295 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + /* + * After device is enumerated in dfu mode run the following commands + * + * To transfer firmware from host to device (best to test with text file) + * + * $ dfu-util -d cafe -a 0 -D [filename] + * $ dfu-util -d cafe -a 1 -D [filename] + * + * To transfer firmware from device to host: + * + * $ dfu-util -d cafe -a 0 -U [filename] + * $ dfu-util -d cafe -a 1 -U [filename] + * + */ + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "tusb.h" +#include "tinyusb.h" +#include "nvs_flash.h" +#include "esp_log.h" +#include "esp_err.h" +#include "dfu_device.h" + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "esp_flash_partitions.h" +#include "esp_partition.h" + +static char* TAG = "esp_dfu"; + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ +const char* upload_image[2]= +{ + "Hello world from TinyUSB DFU! - Partition 0", + "Hello world from TinyUSB DFU! - Partition 1" +}; + +#define BUFFSIZE CONFIG_TINYUSB_DFU_BUFSIZE +/*an ota data write buffer ready to write to the flash*/ +static char ota_write_data[BUFFSIZE + 1] = { 0 }; + +static esp_ota_handle_t update_handle = 0; +static const esp_partition_t *update_partition = NULL; +static int binary_file_length = 0; +/*deal with all receive packet*/ +static bool image_header_was_checked = false; + +static esp_err_t ota_start(uint8_t* ota_write_data, uint32_t data_read) +{ + esp_err_t err; + /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */ + + if (image_header_was_checked == false) { + esp_app_desc_t new_app_info; + + ESP_LOGI(TAG, "Starting OTA example"); + + const esp_partition_t *running = esp_ota_get_running_partition(); + + ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)", + running->type, running->subtype, running->address); + + update_partition = esp_ota_get_next_update_partition(NULL); + assert(update_partition != NULL); + ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", + update_partition->subtype, update_partition->address); + if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) { + // check current version with downloading + memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); + ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); + + esp_app_desc_t running_app_info; + if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version); + } + + const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition(); + esp_app_desc_t invalid_app_info; + if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version); + } + + // check current version with last invalid partition + if (last_invalid_app != NULL) { + if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) { + ESP_LOGW(TAG, "New version is the same as invalid version."); + ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version); + ESP_LOGW(TAG, "The firmware has been rolled back to the previous version."); + } + } + + image_header_was_checked = true; + + err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); + esp_ota_abort(update_handle); + return err; + } + ESP_LOGI(TAG, "esp_ota_begin succeeded"); + } else { + ESP_LOGE(TAG, "received package is not fit len"); + esp_ota_abort(update_handle); + return err; + } + } + err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read); + if (err != ESP_OK) { + esp_ota_abort(update_handle); + return err; + } + binary_file_length += data_read; + ESP_LOGD(TAG, "Written image length %d", binary_file_length); + return err; +} + +static esp_err_t ota_complete(void) +{ + esp_err_t err = ESP_OK; + ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length); + + err = esp_ota_end(update_handle); + if (err != ESP_OK) { + if (err == ESP_ERR_OTA_VALIDATE_FAILED) { + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); + } else { + ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err)); + } + return err; + } + + err = esp_ota_set_boot_partition(update_partition); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); + return err; + } + ESP_LOGI(TAG, "OTA done, please restart system!"); + return ESP_OK; +} + +//--------------------------------------------------------------------+ +// Device callbacks +//--------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + ESP_LOGI(TAG, "mounted\n"); +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + ESP_LOGI(TAG, "umounted\n"); +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void) remote_wakeup_en; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + +} + +//--------------------------------------------------------------------+ +// DFU callbacks +// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. +//--------------------------------------------------------------------+ + +// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) +// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. +// During this period, USB host won't try to communicate with us. +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) +{ + if ( state == DFU_DNBUSY ) + { + // For this example + // - Atl0 Flash is fast : 1 ms + // - Alt1 EEPROM is slow: 100 ms + return (alt == 0) ? 1 : 100; + } + else if (state == DFU_MANIFEST) + { + // since we don't buffer entire image and do any flashing in manifest stage + return 0; + } + + return 0; +} + +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +// This callback could be returned before flashing op is complete (async). +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length) +{ + (void) alt; + (void) block_num; + + ESP_LOGI(TAG, "Received Alt %u BlockNum %u of length %u", alt, block_num, length); + + esp_err_t ret = ota_start(data, length); + + if (ret == ESP_OK) { + tud_dfu_finish_flashing(DFU_STATUS_OK); + } else { + tud_dfu_finish_flashing(DFU_STATUS_ERR_WRITE); + } +} + +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) +// Application can do checksum, or actual flashing if buffered entire image previously. +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_manifest_cb(uint8_t alt) +{ + (void) alt; + ESP_LOGI(TAG, "Download completed, enter manifestation\r\n"); + + esp_err_t ret = ota_complete(); + // flashing op for manifest is complete without error + // Application can perform checksum, should it fail, use appropriate status such as errVERIFY. + if (ret == ESP_OK) { + tud_dfu_finish_flashing(DFU_STATUS_OK); + } else { + tud_dfu_finish_flashing(DFU_STATUS_ERR_VERIFY); + } + +} + +// Invoked when received DFU_UPLOAD request +// Application must populate data with up to length bytes and +// Return the number of written bytes +uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length) +{ + (void) block_num; + (void) length; + ESP_LOGI(TAG, "upload data,block_num: %d,length: %d\n", block_num, length); + uint16_t const xfer_len = (uint16_t) strlen(upload_image[alt]); + memcpy(data, upload_image[alt], xfer_len); + + return xfer_len; +} + +// Invoked when the Host has terminated a download or upload transfer +void tud_dfu_abort_cb(uint8_t alt) +{ + (void) alt; + ESP_LOGI(TAG, "Host aborted transfer\r\n"); +} + +// Invoked when a DFU_DETACH request is received +void tud_dfu_detach_cb(void) +{ + ESP_LOGI(TAG, "Host detach, we should probably reboot\r\n"); + esp_restart(); +} \ No newline at end of file diff --git a/components/tinyusb/additions/src/tusb_hid.c b/components/tinyusb/additions/src/tusb_hid.c new file mode 100644 index 0000000..368c8a4 --- /dev/null +++ b/components/tinyusb/additions/src/tusb_hid.c @@ -0,0 +1,143 @@ +// Copyright 2020-2021 Espressif Systems (Shanghai) Co. Ltd. +// +// 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 +#include "esp_err.h" +#include "sdkconfig.h" +#include "esp_log.h" +#include "tusb_hid.h" +#include "descriptors_control.h" + +static const char *TAG = "tusb_hid"; +static bool s_keyboard_pressed = false; + +void tinyusb_hid_mouse_move_report(int8_t x, int8_t y, int8_t vertical, int8_t horizontal) +{ + ESP_LOGD(TAG, "x=%d, y=%d, vertical=%d, horizontal=%d", x, y, vertical, horizontal); + + // Remote wakeup + if (tud_suspended()) { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } else { + // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() + // skip if hid is not ready yet + if (!tud_hid_ready()) { + ESP_LOGW(TAG, "tinyusb not ready %s %d", __func__, __LINE__); + return; + } + + tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, x, y, vertical, horizontal); + + } +} + +void tinyusb_hid_mouse_button_report(uint8_t buttons_map) +{ + ESP_LOGD(TAG, "buttons_map = %u", buttons_map); + + // Remote wakeup + if (tud_suspended()) { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } else { + // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() + // skip if hid is not ready yet + if (!tud_hid_ready()) { + ESP_LOGW(TAG, "tinyusb not ready %s %d", __func__, __LINE__); + return; + } + + tud_hid_mouse_report(REPORT_ID_MOUSE, buttons_map, 0, 0, 0, 0); + + } +} + +void tinyusb_hid_keyboard_report(uint8_t keycode[]) +{ + ESP_LOGD(TAG, "keycode = %u %u %u %u %u %u", keycode[0], keycode[1], keycode[2], keycode[3], keycode[4], keycode[5]); + + // Remote wakeup + if (tud_suspended()) { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + } else { + // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() + // skip if hid is not ready yet + if (!tud_hid_ready()) { + ESP_LOGW(TAG, "tinyusb not ready %s %d", __func__, __LINE__); + return; + } + + uint8_t _keycode[6] = { 0 }; + _keycode[0] = keycode[0]; + _keycode[1] = keycode[1]; + _keycode[2] = keycode[2]; + _keycode[3] = keycode[3]; + _keycode[4] = keycode[4]; + _keycode[5] = keycode[5]; + + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, _keycode); + s_keyboard_pressed = true; + } +} + +/************************************************** TinyUSB callbacks ***********************************************/ +// Invoked when sent REPORT successfully to host +// Application can use this to send the next report +// Note: For composite reports, report[0] is report ID +void tud_hid_report_complete_cb(uint8_t itf, uint8_t const *report, uint8_t len) +{ + (void) itf; + (void) len; + uint8_t report_id = report[0]; + + if (report_id == REPORT_ID_KEYBOARD && s_keyboard_pressed) { + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); + s_keyboard_pressed = false; + } +} + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) itf; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +/* +void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) +{ + // TODO set LED based on CAPLOCK, NUMLOCK etc... + (void) itf; + (void) report_id; + (void) report_type; + (void) buffer; + (void) bufsize; +} +*/ \ No newline at end of file diff --git a/components/tinyusb/additions/src/tusb_msc.c b/components/tinyusb/additions/src/tusb_msc.c new file mode 100644 index 0000000..dfc40a0 --- /dev/null +++ b/components/tinyusb/additions/src/tusb_msc.c @@ -0,0 +1,291 @@ +// Copyright 2020-2021 Espressif Systems (Shanghai) Co. Ltd. +// +// 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 "esp_err.h" +#include "esp_log.h" +#include "ffconf.h" +#include "ff.h" +#include "diskio.h" +#include "tusb_msc.h" + +static uint8_t s_pdrv = 0; +static int s_disk_block_size = 0; + +#define LOGICAL_DISK_NUM 1 +static bool ejected[LOGICAL_DISK_NUM] = {true}; + +esp_err_t tusb_msc_init(const tinyusb_config_msc_t *cfg) +{ + if (cfg == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (cfg->pdrv > 0) { + return ESP_ERR_NOT_SUPPORTED; + } + + s_pdrv = cfg->pdrv; + return ESP_OK; +} + +//--------------------------------------------------------------------+ +// tinyusb callbacks +//--------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + // Reset the ejection tracking every time we're plugged into USB. This allows for us to battery + // power the device, eject, unplug and plug it back in to get the drive. + for (uint8_t i = 0; i < LOGICAL_DISK_NUM; i++) { + ejected[i] = false; + } + + ESP_LOGI(__func__, ""); +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + ESP_LOGW(__func__, ""); +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allows us to perform remote wakeup +// USB Specs: Within 7ms, device must draw an average current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + ESP_LOGW(__func__, ""); +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + ESP_LOGW(__func__, ""); +} + +// Callback invoked when WRITE10 command is completed (status received and accepted by host). +// used to flush any pending cache. +void tud_msc_write10_complete_cb(uint8_t lun) +{ + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return; + } + + // This write is complete, start the autoreload clock. + ESP_LOGD(__func__, ""); +} + +static bool _logical_disk_ejected(void) +{ + bool all_ejected = true; + + for (uint8_t i = 0; i < LOGICAL_DISK_NUM; i++) { + all_ejected &= ejected[i]; + } + + return all_ejected; +} + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + ESP_LOGD(__func__, ""); + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return; + } + + const char vid[] = "Espressif"; + const char pid[] = "Mass Storage"; + const char rev[] = "1.0"; + + memcpy(vendor_id, vid, strlen(vid)); + memcpy(product_id, pid, strlen(pid)); + memcpy(product_rev, rev, strlen(rev)); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + ESP_LOGD(__func__, ""); + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return false; + } + + if (_logical_disk_ejected()) { + // Set 0x3a for media not present. + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); + return false; + } + + return true; +} + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) +{ + ESP_LOGD(__func__, ""); + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return; + } + + disk_ioctl(s_pdrv, GET_SECTOR_COUNT, block_count); + disk_ioctl(s_pdrv, GET_SECTOR_SIZE, block_size); + s_disk_block_size = *block_size; + ESP_LOGD(__func__, "GET_SECTOR_COUNT = %d,GET_SECTOR_SIZE = %d", *block_count, *block_size); +} + +bool tud_msc_is_writable_cb(uint8_t lun) +{ + ESP_LOGD(__func__, ""); + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return false; + } + + return true; +} + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) +{ + ESP_LOGI(__func__, ""); + (void) power_condition; + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return false; + } + + if (load_eject) { + if (!start) { + // Eject but first flush. + if (disk_ioctl(s_pdrv, CTRL_SYNC, NULL) != RES_OK) { + return false; + } else { + ejected[lun] = true; + } + } else { + // We can only load if it hasn't been ejected. + return !ejected[lun]; + } + } else { + if (!start) { + // Stop the unit but don't eject. + if (disk_ioctl(s_pdrv, CTRL_SYNC, NULL) != RES_OK) { + return false; + } + } + + // Always start the unit, even if ejected. Whether media is present is a separate check. + } + + return true; +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) +{ + ESP_LOGD(__func__, ""); + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return 0; + } + + const uint32_t block_count = bufsize / s_disk_block_size; + disk_read(s_pdrv, buffer, lba, block_count); + return block_count * s_disk_block_size; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and return number of written bytes +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) +{ + ESP_LOGD(__func__, ""); + (void) offset; + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return 0; + } + + const uint32_t block_count = bufsize / s_disk_block_size; + disk_write(s_pdrv, buffer, lba, block_count); + return block_count * s_disk_block_size; +} + +// Callback invoked when received an SCSI command not in built-in list below +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ10 and WRITE10 has their own callbacks +int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) +{ + // read10 & write10 has their own callback and MUST not be handled here + ESP_LOGD(__func__, ""); + + if (lun >= LOGICAL_DISK_NUM) { + ESP_LOGE(__func__, "invalid lun number %u", lun); + return 0; + } + + void const *response = NULL; + uint16_t resplen = 0; + + // most scsi handled is input + bool in_xfer = true; + + switch (scsi_cmd[0]) { + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + // Host is about to read/write etc ... better not to disconnect disk + resplen = 0; + break; + + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed status + resplen = -1; + break; + } + + // return resplen must not larger than bufsize + if (resplen > bufsize) { + resplen = bufsize; + } + + if (response && (resplen > 0)) { + if (in_xfer) { + memcpy(buffer, response, resplen); + } else { + // SCSI output + } + } + + return resplen; +} diff --git a/components/tinyusb/additions/src/tusb_net.c b/components/tinyusb/additions/src/tusb_net.c new file mode 100644 index 0000000..9b4a50b --- /dev/null +++ b/components/tinyusb/additions/src/tusb_net.c @@ -0,0 +1,93 @@ +/** + * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd. + * + * 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 "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "lwip/netif.h" +#include "esp_private/wifi.h" + +#include "tusb_net.h" + +extern bool s_wifi_is_connected; +static SemaphoreHandle_t Net_Semphore; + +bool tud_network_wait_xmit(uint32_t ms) +{ + if (xSemaphoreTake(Net_Semphore, ms/portTICK_PERIOD_MS) == pdTRUE) { + xSemaphoreGive(Net_Semphore); + return true; + } + return false; +} + +esp_err_t pkt_wifi2usb(void *buffer, uint16_t len, void *eb) +{ + if (!tud_ready()) { + esp_wifi_internal_free_rx_buffer(eb); + return ERR_USE; + } + + if (tud_network_wait_xmit(100)) { + /* if the network driver can accept another packet, we make it happen */ + if (tud_network_can_xmit()) { + tud_network_xmit(buffer, len); + } + } + + esp_wifi_internal_free_rx_buffer(eb); + return ESP_OK; +} + +void tusb_net_init(void) +{ + vSemaphoreCreateBinary(Net_Semphore); +} + +//--------------------------------------------------------------------+ +// tinyusb callbacks +//--------------------------------------------------------------------+ + +bool tud_network_recv_cb(const uint8_t *src, uint16_t size) +{ + if (s_wifi_is_connected) { + esp_wifi_internal_tx(ESP_IF_WIFI_STA, src, size); + } + tud_network_recv_renew(); + return true; +} + +uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) +{ + uint16_t len = arg; + + /* traverse the "pbuf chain"; see ./lwip/src/core/pbuf.c for more info */ + memcpy(dst, ref, len); + return len; +} + +void tud_network_init_cb(void) +{ + /* TODO */ +} + +void tud_network_idle_status_change_cb(bool enable) +{ + if (enable == true) { + xSemaphoreGive(Net_Semphore); + } else { + xSemaphoreTake(Net_Semphore, 0); + } +} \ No newline at end of file diff --git a/components/tinyusb/additions/src/tusb_tasks.c b/components/tinyusb/additions/src/tusb_tasks.c new file mode 100644 index 0000000..7312473 --- /dev/null +++ b/components/tinyusb/additions/src/tusb_tasks.c @@ -0,0 +1,54 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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 "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_check.h" +#include "tinyusb.h" +#include "tusb_tasks.h" + +const static char *TAG = "tusb_tsk"; +static TaskHandle_t s_tusb_tskh; + +/** + * @brief This top level thread processes all usb events and invokes callbacks + */ +static void tusb_device_task(void *arg) +{ + ESP_LOGD(TAG, "tinyusb task started"); + while (1) { // RTOS forever loop + tud_task(); + } +} + +esp_err_t tusb_run_task(void) +{ + // This function is not garanteed to be thread safe, if invoked multiple times without calling `tusb_stop_task`, will cause memory leak + // doing a sanity check anyway + ESP_RETURN_ON_FALSE(!s_tusb_tskh, ESP_ERR_INVALID_STATE, TAG, "TinyUSB main task already started"); + // Create a task for tinyusb device stack: + xTaskCreate(tusb_device_task, "TinyUSB", CONFIG_TINYUSB_TASK_STACK_SIZE, NULL, CONFIG_TINYUSB_TASK_PRIORITY, &s_tusb_tskh); + ESP_RETURN_ON_FALSE(s_tusb_tskh, ESP_FAIL, TAG, "create TinyUSB main task failed"); + return ESP_OK; +} + +esp_err_t tusb_stop_task(void) +{ + ESP_RETURN_ON_FALSE(s_tusb_tskh, ESP_ERR_INVALID_STATE, TAG, "TinyUSB main task not started yet"); + vTaskDelete(s_tusb_tskh); + s_tusb_tskh = NULL; + return ESP_OK; +} diff --git a/components/tinyusb/additions/src/usb_descriptors.c b/components/tinyusb/additions/src/usb_descriptors.c new file mode 100644 index 0000000..af0de20 --- /dev/null +++ b/components/tinyusb/additions/src/usb_descriptors.c @@ -0,0 +1,153 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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 "usb_descriptors.h" +#include "descriptors_control.h" +#include "sdkconfig.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB] + */ +#define USB_TUSB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(NET, 5) ) + +/**** TinyUSB default ****/ +tusb_desc_device_t descriptor_tinyusb = { + .bLength = sizeof(descriptor_tinyusb), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + +#if CFG_TUD_CDC + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, +#else + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, +#endif + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCafe, + .idProduct = USB_TUSB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +tusb_desc_strarray_device_t descriptor_str_tinyusb = { + // array of pointer to string descriptors + (char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + "123456", // 3: Serials, should use chip ID + "TinyUSB CDC", // 4: CDC Interface + "TinyUSB MSC", // 5: MSC Interface + "TinyUSB HID" // 6: HID +}; +/* End of TinyUSB default */ + +/**** Kconfig driven Descriptor ****/ +tusb_desc_device_t descriptor_kconfig = { + .bLength = sizeof(descriptor_kconfig), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + +#if CFG_TUD_CDC + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, +#elif CFG_TUD_BTH + .bDeviceClass = TUSB_CLASS_WIRELESS_CONTROLLER, + .bDeviceSubClass = TUD_BT_APP_SUBCLASS, + .bDeviceProtocol = TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, +#else + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, +#endif + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + +#if CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID + .idVendor = USB_ESPRESSIF_VID, +#else + .idVendor = CONFIG_TINYUSB_DESC_CUSTOM_VID, +#endif + +#if CONFIG_TINYUSB_DESC_USE_DEFAULT_PID + .idProduct = USB_TUSB_PID, +#else + .idProduct = CONFIG_TINYUSB_DESC_CUSTOM_PID, +#endif + + .bcdDevice = CONFIG_TINYUSB_DESC_BCD_DEVICE, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +tusb_desc_strarray_device_t descriptor_str_kconfig = { + // array of pointer to string descriptors + (char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, // 1: Manufacturer + CONFIG_TINYUSB_DESC_PRODUCT_STRING, // 2: Product + CONFIG_TINYUSB_DESC_SERIAL_STRING, // 3: Serials, should use chip ID + +#if CFG_TUD_CDC + CONFIG_TINYUSB_DESC_CDC_STRING, // CDC Interface +#endif + +#if CFG_TUD_NET + CONFIG_TINYUSB_DESC_NET_STRING, // NET Interface + "", // MAC +#endif + +#if CFG_TUD_MSC + CONFIG_TINYUSB_DESC_MSC_STRING, // MSC Interface +#endif + +#if CFG_TUD_HID_KBD + CONFIG_TINYUSB_DESC_HID_STRING, // HIDs +#endif +#if CFG_TUD_U2FHID + "TiDAL U2F", // U2FHID +#endif + +#if CFG_TUD_BTH + CONFIG_TINYUSB_DESC_BTH_STRING, // BTH +#endif + +#if CFG_TUD_DFU + "FLASH", // 4: DFU Partition 1 + "EEPROM", // 5: DFU Partition 2 +#endif + +}; +/* End of Kconfig driven Descriptor */ diff --git a/components/tinyusb/additions/src/usbd.c b/components/tinyusb/additions/src/usbd.c new file mode 100644 index 0000000..8074ab3 --- /dev/null +++ b/components/tinyusb/additions/src/usbd.c @@ -0,0 +1,1349 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" +#if CFG_TUD_DFU + #include "dfu_device.h" +#endif + +#if TUSB_OPT_DEVICE_ENABLED + +#include "tusb.h" +#include "device/usbd.h" +#include "device/usbd_pvt.h" +#include "device/dcd.h" + + +#ifndef CFG_TUD_TASK_QUEUE_SZ +#define CFG_TUD_TASK_QUEUE_SZ 16 +#endif + +#ifndef CFG_TUD_EP_MAX +#define CFG_TUD_EP_MAX 9 +#endif + +//--------------------------------------------------------------------+ +// Device Data +//--------------------------------------------------------------------+ +typedef struct +{ + struct TU_ATTR_PACKED + { + volatile uint8_t connected : 1; + volatile uint8_t addressed : 1; + volatile uint8_t suspended : 1; + + uint8_t remote_wakeup_en : 1; // enable/disable by host + uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute + uint8_t self_powered : 1; // configuration descriptor's attribute + }; + + volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) + uint8_t speed; + + uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) + uint8_t ep2drv[CFG_TUD_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid ) + + struct TU_ATTR_PACKED + { + volatile bool busy : 1; + volatile bool stalled : 1; + volatile bool claimed : 1; + + // TODO merge ep2drv here, 4-bit should be sufficient + }ep_status[CFG_TUD_EP_MAX][2]; + +}usbd_device_t; + +static usbd_device_t _usbd_dev; + +// Invalid driver ID in itf2drv[] ep2drv[][] mapping +enum { DRVID_INVALID = 0xFFu }; + +//--------------------------------------------------------------------+ +// Class Driver +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + #define DRIVER_NAME(_name) .name = _name, +#else + #define DRIVER_NAME(_name) +#endif + +// Built-in class drivers +static usbd_class_driver_t const _usbd_driver[] = +{ + #if CFG_TUD_CDC + { + DRIVER_NAME("CDC") + .init = cdcd_init, + .reset = cdcd_reset, + .open = cdcd_open, + .control_xfer_cb = cdcd_control_xfer_cb, + .xfer_cb = cdcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MSC + { + DRIVER_NAME("MSC") + .init = mscd_init, + .reset = mscd_reset, + .open = mscd_open, + .control_xfer_cb = mscd_control_xfer_cb, + .xfer_cb = mscd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_HID + { + DRIVER_NAME("HID") + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_AUDIO + { + DRIVER_NAME("AUDIO") + .init = audiod_init, + .reset = audiod_reset, + .open = audiod_open, + .control_xfer_cb = audiod_control_xfer_cb, + .xfer_cb = audiod_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_MIDI + { + DRIVER_NAME("MIDI") + .init = midid_init, + .open = midid_open, + .reset = midid_reset, + .control_xfer_cb = midid_control_xfer_cb, + .xfer_cb = midid_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_VENDOR + { + DRIVER_NAME("VENDOR") + .init = vendord_init, + .reset = vendord_reset, + .open = vendord_open, + .control_xfer_cb = tud_vendor_control_xfer_cb, + .xfer_cb = vendord_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_USBTMC + { + DRIVER_NAME("TMC") + .init = usbtmcd_init_cb, + .reset = usbtmcd_reset_cb, + .open = usbtmcd_open_cb, + .control_xfer_cb = usbtmcd_control_xfer_cb, + .xfer_cb = usbtmcd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU_RUNTIME + { + DRIVER_NAME("DFU-RUNTIME") + .init = dfu_rtd_init, + .reset = dfu_rtd_reset, + .open = dfu_rtd_open, + .control_xfer_cb = dfu_rtd_control_xfer_cb, + .xfer_cb = dfu_rtd_xfer_cb, + .sof = NULL + }, + #endif + + #if CFG_TUD_DFU + { + DRIVER_NAME("DFU") + .init = dfu_moded_init, + .reset = dfu_moded_reset, + .open = dfu_moded_open, + .control_xfer_cb = dfu_moded_control_xfer_cb, + .xfer_cb = NULL, + .sof = NULL + }, + #endif + + #if CFG_TUD_NET + { + DRIVER_NAME("NET") + .init = netd_init, + .reset = netd_reset, + .open = netd_open, + .control_xfer_cb = netd_control_xfer_cb, + .xfer_cb = netd_xfer_cb, + .sof = NULL, + }, + #endif + + #if CFG_TUD_BTH + { + DRIVER_NAME("BTH") + .init = btd_init, + .reset = btd_reset, + .open = btd_open, + .control_xfer_cb = btd_control_xfer_cb, + .xfer_cb = btd_xfer_cb, + .sof = NULL + }, + #endif +}; + +enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) }; + +// Additional class drivers implemented by application +static usbd_class_driver_t const * _app_driver = NULL; +static uint8_t _app_driver_count = 0; + +// virtually joins built-in and application drivers together. +// Application is positioned first to allow overwriting built-in ones. +static inline usbd_class_driver_t const * get_driver(uint8_t drvid) +{ + // Application drivers + if ( usbd_app_driver_get_cb ) + { + if ( drvid < _app_driver_count ) return &_app_driver[drvid]; + drvid -= _app_driver_count; + } + + // Built-in drivers + if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; + + return NULL; +} + +#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) + +//--------------------------------------------------------------------+ +// DCD Event +//--------------------------------------------------------------------+ + +// Event queue +// OPT_MODE_DEVICE is used by OS NONE for mutex (disable usb isr) +OSAL_QUEUE_DEF(OPT_MODE_DEVICE, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); +static osal_queue_t _usbd_q; + +// Mutex for claiming endpoint, only needed when using with preempted RTOS +#if CFG_TUSB_OS != OPT_OS_NONE +static osal_mutex_def_t _ubsd_mutexdef; +static osal_mutex_t _usbd_mutex; +#endif + + +//--------------------------------------------------------------------+ +// Prototypes +//--------------------------------------------------------------------+ +static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id); +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); +static bool process_set_config(uint8_t rhport, uint8_t cfg_num); +static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); + +// from usbd_control.c +void usbd_control_reset(void); +void usbd_control_set_request(tusb_control_request_t const *request); +void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp ); +bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 +static char const* const _usbd_event_str[DCD_EVENT_COUNT] = +{ + "Invalid" , + "Bus Reset" , + "Unplugged" , + "SOF" , + "Suspend" , + "Resume" , + "Setup Received" , + "Xfer Complete" , + "Func Call" +}; + +static char const* const _tusb_std_request_str[] = +{ + "Get Status" , + "Clear Feature" , + "Reserved" , + "Set Feature" , + "Reserved" , + "Set Address" , + "Get Descriptor" , + "Set Descriptor" , + "Get Configuration" , + "Set Configuration" , + "Get Interface" , + "Set Interface" , + "Synch Frame" +}; + +// for usbd_control to print the name of control complete driver +void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) +{ + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + if ( driver->control_xfer_cb == callback ) + { + TU_LOG2(" %s control complete\r\n", driver->name); + return; + } + } +} + +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ +tusb_speed_t tud_speed_get(void) +{ + return (tusb_speed_t) _usbd_dev.speed; +} + +bool tud_connected(void) +{ + return _usbd_dev.connected; +} + +bool tud_mounted(void) +{ + return _usbd_dev.cfg_num ? true : false; +} + +bool tud_suspended(void) +{ + return _usbd_dev.suspended; +} + +bool tud_remote_wakeup(void) +{ + // only wake up host if this feature is supported and enabled and we are suspended + TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en ); + dcd_remote_wakeup(TUD_OPT_RHPORT); + return true; +} + +bool tud_disconnect(void) +{ + TU_VERIFY(dcd_disconnect); + dcd_disconnect(TUD_OPT_RHPORT); + return true; +} + +bool tud_connect(void) +{ + TU_VERIFY(dcd_connect); + dcd_connect(TUD_OPT_RHPORT); + return true; +} + +//--------------------------------------------------------------------+ +// USBD Task +//--------------------------------------------------------------------+ +bool tud_init (void) +{ + TU_LOG2("USBD init\r\n"); + + tu_varclr(&_usbd_dev); + +#if CFG_TUSB_OS != OPT_OS_NONE + // Init device mutex + _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef); + TU_ASSERT(_usbd_mutex); +#endif + + // Init device queue & task + _usbd_q = osal_queue_create(&_usbd_qdef); + TU_ASSERT(_usbd_q); + + // Get application driver if available + if ( usbd_app_driver_get_cb ) + { + _app_driver = usbd_app_driver_get_cb(&_app_driver_count); + } + + // Init class drivers + for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) + { + usbd_class_driver_t const * driver = get_driver(i); + TU_LOG2("%s init\r\n", driver->name); + driver->init(); + } + + // Init device controller driver + dcd_init(TUD_OPT_RHPORT); + dcd_int_enable(TUD_OPT_RHPORT); + + return true; +} + +static void usbd_reset(uint8_t rhport) +{ + tu_varclr(&_usbd_dev); + + memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping + memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping + + usbd_control_reset(); + + for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ ) + { + get_driver(i)->reset(rhport); + } +} + +bool tud_task_event_ready(void) +{ + // Skip if stack is not initialized + if ( !tusb_inited() ) return false; + + return !osal_queue_empty(_usbd_q); +} + +/* USB Device Driver task + * This top level thread manages all device controller event and delegates events to class-specific drivers. + * This should be called periodically within the mainloop or rtos thread. + * + @code + int main(void) + { + application_init(); + tusb_init(); + + while(1) // the mainloop + { + application_code(); + tud_task(); // tinyusb device task + } + } + @endcode + */ +void tud_task (void) +{ + // Skip if stack is not initialized + if ( !tusb_inited() ) return; + + // Loop until there is no more events in the queue + while (1) + { + dcd_event_t event; + + if ( !osal_queue_receive(_usbd_q, &event) ) return; + +#if CFG_TUSB_DEBUG >= 2 + if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG2("\r\n"); // extra line for setup + TU_LOG2("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED"); +#endif + + switch ( event.event_id ) + { + case DCD_EVENT_BUS_RESET: + TU_LOG2("\r\n"); + usbd_reset(event.rhport); + _usbd_dev.speed = event.bus_reset.speed; + break; + + case DCD_EVENT_UNPLUGGED: + TU_LOG2("\r\n"); + usbd_reset(event.rhport); + + // invoke callback + if (tud_umount_cb) tud_umount_cb(); + break; + + case DCD_EVENT_SETUP_RECEIVED: + TU_LOG2_VAR(&event.setup_received); + TU_LOG2("\r\n"); + + // Mark as connected after receiving 1st setup packet. + // But it is easier to set it every time instead of wasting time to check then set + _usbd_dev.connected = 1; + + // mark both in & out control as free + _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0; + _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false; + _usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0; + + // Process control request + if ( !process_control_request(event.rhport, &event.setup_received) ) + { + TU_LOG2(" Stall EP0\r\n"); + // Failed -> stall both control endpoint IN and OUT + dcd_edpt_stall(event.rhport, 0); + dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK); + } + break; + + case DCD_EVENT_XFER_COMPLETE: + { + // Invoke the class callback associated with the endpoint address + uint8_t const ep_addr = event.xfer_complete.ep_addr; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + + _usbd_dev.ep_status[epnum][ep_dir].busy = false; + _usbd_dev.ep_status[epnum][ep_dir].claimed = 0; + + if ( 0 == epnum ) + { + usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + } + else + { + usbd_class_driver_t const * driver = get_driver( _usbd_dev.ep2drv[epnum][ep_dir] ); + TU_ASSERT(driver, ); + + TU_LOG2(" %s xfer callback\r\n", driver->name); + driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len); + } + } + break; + + case DCD_EVENT_SUSPEND: + TU_LOG2("\r\n"); + if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); + break; + + case DCD_EVENT_RESUME: + TU_LOG2("\r\n"); + if (tud_resume_cb) tud_resume_cb(); + break; + + case DCD_EVENT_SOF: + TU_LOG2("\r\n"); + for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ ) + { + usbd_class_driver_t const * driver = get_driver(i); + if ( driver->sof ) driver->sof(event.rhport); + } + break; + + case USBD_EVENT_FUNC_CALL: + TU_LOG2("\r\n"); + if ( event.func_call.func ) event.func_call.func(event.func_call.param); + break; + + default: + TU_BREAKPOINT(); + break; + } + } +} + +//--------------------------------------------------------------------+ +// Control Request Parser & Handling +//--------------------------------------------------------------------+ + +// Helper to invoke class driver control request handler +static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) +{ + usbd_control_set_complete_callback(driver->control_xfer_cb); + TU_LOG2(" %s control request\r\n", driver->name); + return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request); +} + +// This handles the actual request and its response. +// return false will cause its caller to stall control endpoint +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +{ + usbd_control_set_complete_callback(NULL); + + TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID); + + // Vendor request + if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) + { + TU_VERIFY(tud_vendor_control_xfer_cb); + + usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); + return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); + } + +#if CFG_TUSB_DEBUG >= 2 + if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) + { + TU_LOG2(" %s", _tusb_std_request_str[p_request->bRequest]); + if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG2("\r\n"); + } +#endif + + switch ( p_request->bmRequestType_bit.recipient ) + { + //------------- Device Requests e.g in enumeration -------------// + case TUSB_REQ_RCPT_DEVICE: + if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) + { + uint8_t const itf = tu_u16_low(p_request->wIndex); + TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]); + TU_VERIFY(driver); + + // forward to class driver: "non-STD request to Interface" + return invoke_class_control(rhport, driver, p_request); + } + + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Non standard request is not supported + TU_BREAKPOINT(); + return false; + } + + switch ( p_request->bRequest ) + { + case TUSB_REQ_SET_ADDRESS: + // Depending on mcu, status phase could be sent either before or after changing device address, + // or even require stack to not response with status at all + // Therefore DCD must take full responsibility to response and include zlp status packet if needed. + usbd_control_set_request(p_request); // set request since DCD has no access to tud_control_status() API + dcd_set_address(rhport, (uint8_t) p_request->wValue); + // skip tud_control_status() + _usbd_dev.addressed = 1; + break; + + case TUSB_REQ_GET_CONFIGURATION: + { + uint8_t cfg_num = _usbd_dev.cfg_num; + tud_control_xfer(rhport, p_request, &cfg_num, 1); + } + break; + + case TUSB_REQ_SET_CONFIGURATION: + { + uint8_t const cfg_num = (uint8_t) p_request->wValue; + + if ( !_usbd_dev.cfg_num && cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) ); + _usbd_dev.cfg_num = cfg_num; + + tud_control_status(rhport, p_request); + } + break; + + case TUSB_REQ_GET_DESCRIPTOR: + TU_VERIFY( process_get_descriptor(rhport, p_request) ); + break; + + case TUSB_REQ_SET_FEATURE: + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + // Host may enable remote wake up before suspending especially HID device + _usbd_dev.remote_wakeup_en = true; + tud_control_status(rhport, p_request); + break; + + case TUSB_REQ_CLEAR_FEATURE: + // Only support remote wakeup for device feature + TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue); + + // Host may disable remote wake up after resuming + _usbd_dev.remote_wakeup_en = false; + tud_control_status(rhport, p_request); + break; + + case TUSB_REQ_GET_STATUS: + { + // Device status bit mask + // - Bit 0: Self Powered + // - Bit 1: Remote Wakeup enabled + uint16_t status = (_usbd_dev.self_powered ? 1 : 0) | (_usbd_dev.remote_wakeup_en ? 2 : 0); + tud_control_xfer(rhport, p_request, &status, 2); + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + break; + + //------------- Class/Interface Specific Request -------------// + case TUSB_REQ_RCPT_INTERFACE: + { + uint8_t const itf = tu_u16_low(p_request->wIndex); + TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]); + TU_VERIFY(driver); + + // all requests to Interface (STD or Class) is forwarded to class driver. + // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE + if ( !invoke_class_control(rhport, driver, p_request) ) + { + // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class + // driver doesn't use alternate settings or implement this + TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type); + + if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) + { + uint8_t alternate = 0; + tud_control_xfer(rhport, p_request, &alternate, 1); + }else if (TUSB_REQ_SET_INTERFACE == p_request->bRequest) + { + tud_control_status(rhport, p_request); + } else + { + return false; + } + } + } + break; + + //------------- Endpoint Request -------------// + case TUSB_REQ_RCPT_ENDPOINT: + { + uint8_t const ep_addr = tu_u16_low(p_request->wIndex); + uint8_t const ep_num = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) ); + + usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]); + + if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) + { + // Forward class request to its driver + TU_VERIFY(driver); + return invoke_class_control(rhport, driver, p_request); + } + else + { + // Handle STD request to endpoint + switch ( p_request->bRequest ) + { + case TUSB_REQ_GET_STATUS: + { + uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000; + tud_control_xfer(rhport, p_request, &status, 2); + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + case TUSB_REQ_SET_FEATURE: + { + if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) + { + if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) + { + usbd_edpt_clear_stall(rhport, ep_addr); + }else + { + usbd_edpt_stall(rhport, ep_addr); + } + } + + if (driver) + { + // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request + // We will also forward std request targeted endpoint to class drivers as well + + // STD request must always be ACKed regardless of driver returned value + // Also clear complete callback if driver set since it can also stall the request. + (void) invoke_class_control(rhport, driver, p_request); + usbd_control_set_complete_callback(NULL); + + // skip ZLP status if driver already did that + if ( !_usbd_dev.ep_status[0][TUSB_DIR_IN].busy ) tud_control_status(rhport, p_request); + } + } + break; + + // Unknown/Unsupported request + default: TU_BREAKPOINT(); return false; + } + } + } + break; + + // Unknown recipient + default: TU_BREAKPOINT(); return false; + } + + return true; +} + +// Process Set Configure Request +// This function parse configuration descriptor & open drivers accordingly +static bool process_set_config(uint8_t rhport, uint8_t cfg_num) +{ + tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1); // index is cfg_num-1 + TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION); + + // Parse configuration descriptor + _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1 : 0; + _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED) ? 1 : 0; + + // Parse interface descriptor + uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t); + uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + desc_cfg->wTotalLength; + + while( p_desc < desc_end ) + { + tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL; + + // Class will always starts with Interface Association (if any) and then Interface descriptor + if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) + { + desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc; + p_desc = tu_desc_next(p_desc); // next to Interface + } + + TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); + + tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc; + uint16_t const remaining_len = desc_end-p_desc; + + uint8_t drv_id; + for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) + { + usbd_class_driver_t const *driver = get_driver(drv_id); + uint16_t const drv_len = driver->open(rhport, desc_itf, remaining_len); + + if ( drv_len > 0 ) + { + // Open successfully, check if length is correct + TU_ASSERT( sizeof(tusb_desc_interface_t) <= drv_len && drv_len <= remaining_len); + + // Interface number must not be used already + TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber]); + + TU_LOG2(" %s opened\r\n", driver->name); + _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id; + + // If IAD exist, assign all interfaces to the same driver + if (desc_itf_assoc) + { + // IAD's first interface number and class should match with opened interface + TU_ASSERT(desc_itf_assoc->bFirstInterface == desc_itf->bInterfaceNumber && + desc_itf_assoc->bFunctionClass == desc_itf->bInterfaceClass); + + for(uint8_t i=1; ibInterfaceCount; i++) + { + _usbd_dev.itf2drv[desc_itf->bInterfaceNumber+i] = drv_id; + } + } + + mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, drv_len, drv_id); // TODO refactor + + p_desc += drv_len; // next interface + + break; + } + } + + // Failed if cannot find supported driver + TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT); + } + + // invoke callback + if (tud_mount_cb) tud_mount_cb(); + + return true; +} + +// Helper marking endpoint of interface belongs to class driver +static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id) +{ + uint16_t len = 0; + + while( len < desc_len ) + { + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; + + ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; + } + + len = (uint16_t)(len + tu_desc_len(p_desc)); + p_desc = tu_desc_next(p_desc); + } +} + +// return descriptor's buffer and update desc_len +static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) +{ + tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue); + uint8_t const desc_index = tu_u16_low( p_request->wValue ); + + switch(desc_type) + { + case TUSB_DESC_DEVICE: + { + TU_LOG2(" Device\r\n"); + + uint16_t len = sizeof(tusb_desc_device_t); + + // Only send up to EP0 Packet Size if not addressed + // This only happens with the very first get device descriptor and EP0 size = 8 or 16. + if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed) + { + len = CFG_TUD_ENDPOINT0_SIZE; + + // Hack here: we modify the request length to prevent usbd_control response with zlp + ((tusb_control_request_t*) p_request)->wLength = CFG_TUD_ENDPOINT0_SIZE; + } + + return tud_control_xfer(rhport, p_request, (void*) tud_descriptor_device_cb(), len); + } + break; + + case TUSB_DESC_BOS: + { + TU_LOG2(" BOS\r\n"); + + // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) + if (!tud_descriptor_bos_cb) return false; + + tusb_desc_bos_t const* desc_bos = (tusb_desc_bos_t const*) tud_descriptor_bos_cb(); + + uint16_t total_len; + // Use offsetof to avoid pointer to the odd/misaligned address + memcpy(&total_len, (uint8_t*) desc_bos + offsetof(tusb_desc_bos_t, wTotalLength), 2); + + return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len); + } + break; + + case TUSB_DESC_CONFIGURATION: + { + TU_LOG2(" Configuration[%u]\r\n", desc_index); + + tusb_desc_configuration_t const* desc_config = (tusb_desc_configuration_t const*) tud_descriptor_configuration_cb(desc_index); + TU_ASSERT(desc_config); + + uint16_t total_len; + // Use offsetof to avoid pointer to the odd/misaligned address + memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2); + + return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len); + } + break; + + case TUSB_DESC_STRING: + { + TU_LOG2(" String[%u]\r\n", desc_index); + + // String Descriptor always uses the desc set from user + uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex); + TU_VERIFY(desc_str); + + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) desc_str, desc_str[0]); + } + break; + + case TUSB_DESC_DEVICE_QUALIFIER: + TU_LOG2(" Device Qualifier\r\n"); + + // Host sends this request to ask why our device with USB BCD from 2.0 + // but is running at Full/Low Speed. If not highspeed capable stall this request, + // otherwise return the descriptor that could work in highspeed mode + if ( tud_descriptor_device_qualifier_cb ) + { + uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); + TU_ASSERT(desc_qualifier); + + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]); + }else + { + return false; + } + break; + + case TUSB_DESC_OTHER_SPEED_CONFIG: + TU_LOG2(" Other Speed Configuration\r\n"); + + // After Device Qualifier descriptor is received host will ask for this descriptor + return false; // not supported + break; + + default: return false; + } +} + +//--------------------------------------------------------------------+ +// DCD Event Handler +//--------------------------------------------------------------------+ +void dcd_event_handler(dcd_event_t const * event, bool in_isr) +{ + switch (event->event_id) + { + case DCD_EVENT_UNPLUGGED: + // UNPLUGGED event can be bouncing, only processing if we are currently connected + if ( _usbd_dev.connected ) + { + _usbd_dev.connected = 0; + _usbd_dev.addressed = 0; + _usbd_dev.cfg_num = 0; + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + case DCD_EVENT_SOF: + return; // skip SOF event for now + break; + + case DCD_EVENT_SUSPEND: + // NOTE: When plugging/unplugging device, the D+/D- state are unstable and + // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ). + // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish + // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 1; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + case DCD_EVENT_RESUME: + // skip event if not connected (especially required for SAMD) + if ( _usbd_dev.connected ) + { + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); + } + break; + + default: + osal_queue_send(_usbd_q, event, in_isr); + break; + } +} + +void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = eid }; + dcd_event_handler(&event, in_isr); +} + +void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; + event.bus_reset.speed = speed; + dcd_event_handler(&event, in_isr); +} + +void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; + memcpy(&event.setup_received, setup, 8); + + dcd_event_handler(&event, in_isr); +} + +void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) +{ + dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; + + event.xfer_complete.ep_addr = ep_addr; + event.xfer_complete.len = xferred_bytes; + event.xfer_complete.result = result; + + dcd_event_handler(&event, in_isr); +} + +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ + +// Parse consecutive endpoint descriptors (IN & OUT) +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in) +{ + for(int i=0; ibDescriptorType && xfer_type == desc_ep->bmAttributes.xfer); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) + { + (*ep_in) = desc_ep->bEndpointAddress; + }else + { + (*ep_out) = desc_ep->bEndpointAddress; + } + + p_desc = tu_desc_next(p_desc); + } + + return true; +} + +// Helper to defer an isr function +void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) +{ + dcd_event_t event = + { + .rhport = 0, + .event_id = USBD_EVENT_FUNC_CALL, + }; + + event.func_call.func = func; + event.func_call.param = param; + + dcd_event_handler(&event, in_isr); +} + +//--------------------------------------------------------------------+ +// USBD Endpoint API +//--------------------------------------------------------------------+ + +bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) +{ + TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, desc_ep->wMaxPacketSize.size); + + switch (desc_ep->bmAttributes.xfer) + { + case TUSB_XFER_ISOCHRONOUS: + { + uint16_t const max_epsize = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 1023); + TU_ASSERT(desc_ep->wMaxPacketSize.size <= max_epsize); + } + break; + + case TUSB_XFER_BULK: + if (_usbd_dev.speed == TUSB_SPEED_HIGH) + { + // Bulk highspeed must be EXACTLY 512 + TU_ASSERT(desc_ep->wMaxPacketSize.size == 512); + }else + { + // TODO Bulk fullspeed can only be 8, 16, 32, 64 + TU_ASSERT(desc_ep->wMaxPacketSize.size <= 64); + } + break; + + case TUSB_XFER_INTERRUPT: + { + uint16_t const max_epsize = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 64); + TU_ASSERT(desc_ep->wMaxPacketSize.size <= max_epsize); + } + break; + + default: return false; + } + + return dcd_edpt_open(rhport, desc_ep); +} + +bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + +#if CFG_TUSB_OS != OPT_OS_NONE + // pre-check to help reducing mutex lock + TU_VERIFY((_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0)); + + osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER); +#endif + + // can only claim the endpoint if it is not busy and not claimed yet. + bool const ret = (_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0); + if (ret) + { + _usbd_dev.ep_status[epnum][dir].claimed = 1; + } + +#if CFG_TUSB_OS != OPT_OS_NONE + osal_mutex_unlock(_usbd_mutex); +#endif + + return ret; +} + +bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + +#if CFG_TUSB_OS != OPT_OS_NONE + osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER); +#endif + + // can only release the endpoint if it is claimed and not busy + bool const ret = (_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 1); + if (ret) + { + _usbd_dev.ep_status[epnum][dir].claimed = 0; + } + +#if CFG_TUSB_OS != OPT_OS_NONE + osal_mutex_unlock(_usbd_mutex); +#endif + + return ret; +} + +bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return + // and usbd task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) + { + TU_LOG2("OK\r\n"); + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG2("failed\r\n"); + TU_BREAKPOINT(); + return false; + } +} + +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes); + + // Attempt to transfer on a busy endpoint, sound like an race condition ! + TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); + + // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return + // and usbd task can preempt and clear the busy + _usbd_dev.ep_status[epnum][dir].busy = true; + + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) + { + TU_LOG2("OK\r\n"); + return true; + }else + { + // DCD error, mark endpoint as ready to allow next transfer + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = 0; + TU_LOG2("failed\r\n"); + TU_BREAKPOINT(); + return false; + } +} + +bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + return _usbd_dev.ep_status[epnum][dir].busy; +} + +void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = true; + _usbd_dev.ep_status[epnum][dir].busy = true; +} + +void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_clear_stall(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; +} + +bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + return _usbd_dev.ep_status[epnum][dir].stalled; +} + +/** + * usbd_edpt_close will disable an endpoint. + * + * In progress transfers on this EP may be delivered after this call. + * + */ +void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + TU_ASSERT(dcd_edpt_close, /**/); + TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); + + dcd_edpt_close(rhport, ep_addr); + + return; +} + +#endif diff --git a/components/tinyusb/additions/src/vfs_tinyusb.c b/components/tinyusb/additions/src/vfs_tinyusb.c new file mode 100644 index 0000000..0349bb8 --- /dev/null +++ b/components/tinyusb/additions/src/vfs_tinyusb.c @@ -0,0 +1,297 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_vfs.h" +#include "esp_vfs_dev.h" +#include "tinyusb.h" +#include "tusb_cdc_acm.h" +#include "vfs_tinyusb.h" +#include "sdkconfig.h" + +const static char *TAG = "tusb_vfs"; +#define VFS_TUSB_MAX_PATH 16 +#define VFS_TUSB_PATH_DEFAULT "/dev/tusb_cdc" + +// Token signifying that no character is available +#define NONE -1 + +#define FD_CHECK(fd, ret_val) do { \ + if ((fd) != 0) { \ + errno = EBADF; \ + return (ret_val); \ + } \ + } while (0) + + + +#if CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF +# define DEFAULT_TX_MODE ESP_LINE_ENDINGS_CRLF +#elif CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR +# define DEFAULT_TX_MODE ESP_LINE_ENDINGS_CR +#else +# define DEFAULT_TX_MODE ESP_LINE_ENDINGS_LF +#endif + +#if CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF +# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_CRLF +#elif CONFIG_NEWLIB_STDIN_LINE_ENDING_CR +# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_CR +#else +# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_LF +#endif + +typedef struct { + _lock_t write_lock; + _lock_t read_lock; + esp_line_endings_t tx_mode; // Newline conversion mode when transmitting + esp_line_endings_t rx_mode; // Newline conversion mode when receiving + uint32_t flags; + char vfs_path[VFS_TUSB_MAX_PATH]; + int cdc_intf; +} vfs_tinyusb_t; + +static vfs_tinyusb_t s_vfstusb; + + +static esp_err_t apply_path(char const *path) +{ + if (path != NULL) { + size_t path_len = strlen(path) + 1; + if (path_len > VFS_TUSB_MAX_PATH) { + ESP_LOGE(TAG, "The path is too long; maximum is %d characters", VFS_TUSB_MAX_PATH); + return ESP_ERR_INVALID_ARG; + } + strncpy(s_vfstusb.vfs_path, path, (VFS_TUSB_MAX_PATH - 1)); + } else { + strncpy(s_vfstusb.vfs_path, + VFS_TUSB_PATH_DEFAULT, + (VFS_TUSB_MAX_PATH - 1)); + } + ESP_LOGV(TAG, "Path is set to `%s`", s_vfstusb.vfs_path); + return ESP_OK; +} + +/** + * @brief Fill s_vfstusb + * + * @param cdc_intf - interface of tusb for registration + * @param path - a path where the CDC will be registered + * @return esp_err_t ESP_OK or ESP_ERR_INVALID_ARG + */ +static esp_err_t vfstusb_init(int cdc_intf, char const *path) +{ + s_vfstusb.cdc_intf = cdc_intf; + s_vfstusb.tx_mode = DEFAULT_TX_MODE; + s_vfstusb.rx_mode = DEFAULT_RX_MODE; + + return apply_path(path); +} + +/** + * @brief Clear s_vfstusb to default values + */ +static void vfstusb_deinit(void) +{ + memset(&s_vfstusb, 0, sizeof(s_vfstusb)); +} + + +static int tusb_open(const char *path, int flags, int mode) +{ + (void) mode; + (void) path; + s_vfstusb.flags = flags | O_NONBLOCK; // for now only non-blocking mode is implemented + return 0; +} + +static ssize_t tusb_write(int fd, const void *data, size_t size) +{ + FD_CHECK(fd, -1); + size_t written_sz = 0; + const char *data_c = (const char *)data; + _lock_acquire(&(s_vfstusb.write_lock)); + for (size_t i = 0; i < size; i++) { + int c = data_c[i]; + /* handling the EOL */ + if (c == '\n' && s_vfstusb.tx_mode != ESP_LINE_ENDINGS_LF) { + if (tinyusb_cdcacm_write_queue_char(s_vfstusb.cdc_intf, '\r')) { + written_sz++; + } else { + break; // can't write anymore + } + if (s_vfstusb.tx_mode == ESP_LINE_ENDINGS_CR) { + continue; + } + } + /* write a char */ + if (tinyusb_cdcacm_write_queue_char(s_vfstusb.cdc_intf, c)) { + written_sz++; + } else { + break; // can't write anymore + } + + } + tud_cdc_n_write_flush(s_vfstusb.cdc_intf); + _lock_release(&(s_vfstusb.write_lock)); + return written_sz; +} + +static int tusb_close(int fd) +{ + FD_CHECK(fd, -1); + return 0; +} + +static ssize_t tusb_read(int fd, void *data, size_t size) +{ + FD_CHECK(fd, -1); + char *data_c = (char *) data; + size_t received = 0; + _lock_acquire(&(s_vfstusb.read_lock)); + int cm1 = NONE; + int c = NONE; + + while (received < size) { + cm1 = c; // store the old char + int c = tud_cdc_n_read_char(0); // get a new one + if (s_vfstusb.rx_mode == ESP_LINE_ENDINGS_CR) { + if (c == '\r') { + c = '\n'; + } + } else if (s_vfstusb.rx_mode == ESP_LINE_ENDINGS_CR) { + if ((c == '\n') & (cm1 == '\r')) { + --received; // step back + c = '\n'; + } + } + if ( c == NONE) { // if data ends + break; + } + data_c[received] = (char) c; + ++received; + if (c == '\n') { + break; + } + } + _lock_release(&(s_vfstusb.read_lock)); + if (received > 0) { + return received; + } + errno = EWOULDBLOCK; + return -1; +} + + +static int tusb_fstat(int fd, struct stat *st) +{ + FD_CHECK(fd, -1); + memset(st, 0, sizeof(*st)); + st->st_mode = S_IFCHR; + return 0; +} + +static int tusb_fcntl(int fd, int cmd, int arg) +{ + FD_CHECK(fd, -1); + int result = 0; + switch (cmd) { + case F_GETFL: + result = s_vfstusb.flags; + break; + case F_SETFL: + s_vfstusb.flags = arg; + break; + default: + result = -1; + errno = ENOSYS; + break; + } + return result; +} + +esp_err_t esp_vfs_tusb_cdc_unregister(char const *path) +{ + ESP_LOGD(TAG, "Unregistering TinyUSB driver"); + int res; + + if (path == NULL) { // NULL means using the default path for unregistering: VFS_TUSB_PATH_DEFAULT + res = strcmp(s_vfstusb.vfs_path, VFS_TUSB_PATH_DEFAULT); + } else { + res = strcmp(s_vfstusb.vfs_path, path); + } + + if (res) { + res = ESP_ERR_INVALID_ARG; + ESP_LOGE(TAG, "There is no TinyUSB driver registerred to the path '%s' (err: 0x%x)", s_vfstusb.vfs_path, res); + return res; + } + + + + res = esp_vfs_unregister(s_vfstusb.vfs_path); + if (res != ESP_OK) { + ESP_LOGE(TAG, "Can't unregister TinyUSB driver from '%s' (err: 0x%x)", s_vfstusb.vfs_path, res); + } else { + ESP_LOGD(TAG, "Unregistered TinyUSB driver"); + vfstusb_deinit(); + } + return res; +} + + + + +esp_err_t esp_vfs_tusb_cdc_register(int cdc_intf, char const *path) +{ + ESP_LOGD(TAG, "Registering TinyUSB CDC driver"); + int res; + if (!tusb_cdc_acm_initialized(cdc_intf)) { + ESP_LOGE(TAG, "TinyUSB CDC#%d is not initialized", cdc_intf); + return ESP_ERR_INVALID_STATE; + } + + res = vfstusb_init(cdc_intf, path); + if (res != ESP_OK) { + return res; + } + + esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .close = &tusb_close, + .fcntl = &tusb_fcntl, + .fstat = &tusb_fstat, + .open = &tusb_open, + .read = &tusb_read, + .write = &tusb_write, + }; + + res = esp_vfs_register(s_vfstusb.vfs_path, &vfs, NULL); + if (res != ESP_OK) { + ESP_LOGE(TAG, "Can't register TinyUSB driver (err: %x)", res); + } else { + ESP_LOGD(TAG, "TinyUSB CDC registered (%s)", s_vfstusb.vfs_path); + } + return res; +} diff --git a/components/tinyusb/additions/tusb/src/class/dfu/dfu.h b/components/tinyusb/additions/tusb/src/class/dfu/dfu.h new file mode 100644 index 0000000..114c827 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/class/dfu/dfu.h @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_H_ +#define _TUSB_DFU_H_ + +#include "common/tusb_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Common Definitions +//--------------------------------------------------------------------+ + +// DFU Protocol +typedef enum +{ + DFU_PROTOCOL_RT = 0x01, + DFU_PROTOCOL_DFU = 0x02, +} dfu_protocol_type_t; + +// DFU Descriptor Type +typedef enum +{ + DFU_DESC_FUNCTIONAL = 0x21, +} dfu_descriptor_type_t; + +// DFU Requests +typedef enum { + DFU_REQUEST_DETACH = 0, + DFU_REQUEST_DNLOAD = 1, + DFU_REQUEST_UPLOAD = 2, + DFU_REQUEST_GETSTATUS = 3, + DFU_REQUEST_CLRSTATUS = 4, + DFU_REQUEST_GETSTATE = 5, + DFU_REQUEST_ABORT = 6, +} dfu_requests_t; + +// DFU States +typedef enum { + APP_IDLE = 0, + APP_DETACH = 1, + DFU_IDLE = 2, + DFU_DNLOAD_SYNC = 3, + DFU_DNBUSY = 4, + DFU_DNLOAD_IDLE = 5, + DFU_MANIFEST_SYNC = 6, + DFU_MANIFEST = 7, + DFU_MANIFEST_WAIT_RESET = 8, + DFU_UPLOAD_IDLE = 9, + DFU_ERROR = 10, +} dfu_state_t; + +// DFU Status +typedef enum { + DFU_STATUS_OK = 0x00, + DFU_STATUS_ERR_TARGET = 0x01, + DFU_STATUS_ERR_FILE = 0x02, + DFU_STATUS_ERR_WRITE = 0x03, + DFU_STATUS_ERR_ERASE = 0x04, + DFU_STATUS_ERR_CHECK_ERASED = 0x05, + DFU_STATUS_ERR_PROG = 0x06, + DFU_STATUS_ERR_VERIFY = 0x07, + DFU_STATUS_ERR_ADDRESS = 0x08, + DFU_STATUS_ERR_NOTDONE = 0x09, + DFU_STATUS_ERR_FIRMWARE = 0x0A, + DFU_STATUS_ERR_VENDOR = 0x0B, + DFU_STATUS_ERR_USBR = 0x0C, + DFU_STATUS_ERR_POR = 0x0D, + DFU_STATUS_ERR_UNKNOWN = 0x0E, + DFU_STATUS_ERR_STALLEDPKT = 0x0F, +} dfu_status_t; + +#define DFU_ATTR_CAN_DOWNLOAD (1u << 0) +#define DFU_ATTR_CAN_UPLOAD (1u << 1) +#define DFU_ATTR_MANIFESTATION_TOLERANT (1u << 2) +#define DFU_ATTR_WILL_DETACH (1u << 3) + +// DFU Status Request Payload +typedef struct TU_ATTR_PACKED +{ + uint8_t bStatus; + uint8_t bwPollTimeout[3]; + uint8_t bState; + uint8_t iString; +} dfu_status_response_t; + +TU_VERIFY_STATIC( sizeof(dfu_status_response_t) == 6, "size is not correct"); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_H_ */ diff --git a/components/tinyusb/additions/tusb/src/class/dfu/dfu_device.c b/components/tinyusb/additions/tusb/src/class/dfu/dfu_device.c new file mode 100644 index 0000000..14ca9ba --- /dev/null +++ b/components/tinyusb/additions/tusb/src/class/dfu/dfu_device.c @@ -0,0 +1,480 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DFU) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "dfu_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t attrs; + uint8_t alt; + + dfu_state_t state; + dfu_status_t status; + + bool flashing_in_progress; + uint16_t block; + uint16_t length; + + CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; +} dfu_state_ctx_t; + +typedef struct TU_ATTR_PACKED +{ + uint8_t bLength; + uint8_t bDescriptorType; + + union { + struct TU_ATTR_PACKED { + uint8_t bitCanDnload : 1; + uint8_t bitCanUpload : 1; + uint8_t bitManifestationTolerant : 1; + uint8_t bitWillDetach : 1; + uint8_t reserved : 4; + } bmAttributes; + + uint8_t bAttributes; + }; + + uint16_t wDetachTimeOut; + uint16_t wTransferSize; + uint16_t bcdDFUVersion; +} tusb_desc_dfu_functional_t; + +// Only a single dfu state is allowed +CFG_TUSB_MEM_SECTION static dfu_state_ctx_t _dfu_ctx; + +static void reset_state(void) +{ + _dfu_ctx.state = DFU_IDLE; + _dfu_ctx.status = DFU_STATUS_OK; + _dfu_ctx.flashing_in_progress = false; +} + +static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout); +static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= 2 + +static tu_lookup_entry_t const _dfu_request_lookup[] = +{ + { .key = DFU_REQUEST_DETACH , .data = "DETACH" }, + { .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" }, + { .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" }, + { .key = DFU_REQUEST_GETSTATUS , .data = "GETSTATUS" }, + { .key = DFU_REQUEST_CLRSTATUS , .data = "CLRSTATUS" }, + { .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" }, + { .key = DFU_REQUEST_ABORT , .data = "ABORT" }, +}; + +static tu_lookup_table_t const _dfu_request_table = +{ + .count = TU_ARRAY_SIZE(_dfu_request_lookup), + .items = _dfu_request_lookup +}; + +static tu_lookup_entry_t const _dfu_state_lookup[] = +{ + { .key = APP_IDLE , .data = "APP_IDLE" }, + { .key = APP_DETACH , .data = "APP_DETACH" }, + { .key = DFU_IDLE , .data = "IDLE" }, + { .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" }, + { .key = DFU_DNBUSY , .data = "DNBUSY" }, + { .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" }, + { .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" }, + { .key = DFU_MANIFEST , .data = "MANIFEST" }, + { .key = DFU_MANIFEST_WAIT_RESET , .data = "MANIFEST_WAIT_RESET" }, + { .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" }, + { .key = DFU_ERROR , .data = "ERROR" }, +}; + +static tu_lookup_table_t const _dfu_state_table = +{ + .count = TU_ARRAY_SIZE(_dfu_state_lookup), + .items = _dfu_state_lookup +}; + +static tu_lookup_entry_t const _dfu_status_lookup[] = +{ + { .key = DFU_STATUS_OK , .data = "OK" }, + { .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" }, + { .key = DFU_STATUS_ERR_FILE , .data = "errFILE" }, + { .key = DFU_STATUS_ERR_WRITE , .data = "errWRITE" }, + { .key = DFU_STATUS_ERR_ERASE , .data = "errERASE" }, + { .key = DFU_STATUS_ERR_CHECK_ERASED , .data = "errCHECK_ERASED" }, + { .key = DFU_STATUS_ERR_PROG , .data = "errPROG" }, + { .key = DFU_STATUS_ERR_VERIFY , .data = "errVERIFY" }, + { .key = DFU_STATUS_ERR_ADDRESS , .data = "errADDRESS" }, + { .key = DFU_STATUS_ERR_NOTDONE , .data = "errNOTDONE" }, + { .key = DFU_STATUS_ERR_FIRMWARE , .data = "errFIRMWARE" }, + { .key = DFU_STATUS_ERR_VENDOR , .data = "errVENDOR" }, + { .key = DFU_STATUS_ERR_USBR , .data = "errUSBR" }, + { .key = DFU_STATUS_ERR_POR , .data = "errPOR" }, + { .key = DFU_STATUS_ERR_UNKNOWN , .data = "errUNKNOWN" }, + { .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" }, +}; + +static tu_lookup_table_t const _dfu_status_table = +{ + .count = TU_ARRAY_SIZE(_dfu_status_lookup), + .items = _dfu_status_lookup +}; + +#endif + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void dfu_moded_reset(uint8_t rhport) +{ + (void) rhport; + + _dfu_ctx.attrs = 0; + _dfu_ctx.alt = 0; + + reset_state(); +} + +void dfu_moded_init(void) +{ + dfu_moded_reset(0); +} + +uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) rhport; + + //------------- Interface (with Alt) descriptor -------------// + uint8_t const itf_num = itf_desc->bInterfaceNumber; + uint8_t alt_count = 0; + + uint16_t drv_len = 0; + while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU) + { + TU_ASSERT(max_len > drv_len, 0); + + // Alternate must have the same interface number + TU_ASSERT(itf_desc->bInterfaceNumber == itf_num, 0); + + // Alt should increase by one every time + TU_ASSERT(itf_desc->bAlternateSetting == alt_count, 0); + alt_count++; + + drv_len += tu_desc_len(itf_desc); + itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc); + } + + //------------- DFU Functional descriptor -------------// + tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc; + TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0); + drv_len += sizeof(tusb_desc_dfu_functional_t); + + _dfu_ctx.attrs = func_desc->bAttributes; + + // CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR + uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) ); + TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len); + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + TU_LOG2(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status)); + + if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) + { + // Standard request include GET/SET_INTERFACE + switch ( request->bRequest ) + { + case TUSB_REQ_SET_INTERFACE: + if ( stage == CONTROL_STAGE_SETUP ) + { + // Switch Alt interface and reset state machine + _dfu_ctx.alt = (uint8_t) request->wValue; + reset_state(); + return tud_control_status(rhport, request); + } + break; + + case TUSB_REQ_GET_INTERFACE: + if(stage == CONTROL_STAGE_SETUP) + { + return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1); + } + break; + + // unsupported request + default: return false; + } + } + else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS ) + { + TU_LOG2(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest)); + + // Class request + switch ( request->bRequest ) + { + case DFU_REQUEST_DETACH: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( tud_dfu_detach_cb ) tud_dfu_detach_cb(); + } + break; + + case DFU_REQUEST_CLRSTATUS: + if ( stage == CONTROL_STAGE_SETUP ) + { + reset_state(); + tud_control_status(rhport, request); + } + break; + + case DFU_REQUEST_GETSTATE: + if ( stage == CONTROL_STAGE_SETUP ) + { + tud_control_xfer(rhport, request, &_dfu_ctx.state, 1); + } + break; + + case DFU_REQUEST_ABORT: + if ( stage == CONTROL_STAGE_SETUP ) + { + reset_state(); + tud_control_status(rhport, request); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt); + } + break; + + case DFU_REQUEST_UPLOAD: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); + TU_VERIFY(tud_dfu_upload_cb); + TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); + + uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength); + + return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len); + } + break; + + case DFU_REQUEST_DNLOAD: + if ( stage == CONTROL_STAGE_SETUP ) + { + TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD); + TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE); + TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); + + // set to true for both download and manifest + _dfu_ctx.flashing_in_progress = true; + + // save block and length for flashing + _dfu_ctx.block = request->wValue; + _dfu_ctx.length = request->wLength; + + if ( request->wLength ) + { + // Download with payload -> transition to DOWNLOAD SYNC + _dfu_ctx.state = DFU_DNLOAD_SYNC; + return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength); + } + else + { + // Download is complete -> transition to MANIFEST SYNC + _dfu_ctx.state = DFU_MANIFEST_SYNC; + return tud_control_status(rhport, request); + } + } + break; + + case DFU_REQUEST_GETSTATUS: + switch ( _dfu_ctx.state ) + { + case DFU_DNLOAD_SYNC: + return process_download_get_status(rhport, stage, request); + break; + + case DFU_MANIFEST_SYNC: + return process_manifest_get_status(rhport, stage, request); + break; + + default: + if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0); + break; + } + break; + + default: return false; // stall unsupported request + } + }else + { + return false; // unsupported request + } + + return true; +} + +void tud_dfu_finish_flashing(uint8_t status) +{ + _dfu_ctx.flashing_in_progress = false; + + if ( status == DFU_STATUS_OK ) + { + if (_dfu_ctx.state == DFU_DNBUSY) + { + _dfu_ctx.state = DFU_DNLOAD_SYNC; + } + else if (_dfu_ctx.state == DFU_MANIFEST) + { + _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT) + ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET; + } + } + else + { + // failed while flashing, move to dfuError + _dfu_ctx.state = DFU_ERROR; + _dfu_ctx.status = (dfu_status_t)status; + } +} + +static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + // only transition to next state on CONTROL_STAGE_ACK + dfu_state_t next_state; + uint32_t timeout; + + if ( _dfu_ctx.flashing_in_progress ) + { + next_state = DFU_DNBUSY; + timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state); + } + else + { + next_state = DFU_DNLOAD_IDLE; + timeout = 0; + } + + return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( _dfu_ctx.flashing_in_progress ) + { + _dfu_ctx.state = DFU_DNBUSY; + tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length); + }else + { + _dfu_ctx.state = DFU_DNLOAD_IDLE; + } + } + + return true; +} + +static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + // only transition to next state on CONTROL_STAGE_ACK + dfu_state_t next_state; + uint32_t timeout; + + if ( _dfu_ctx.flashing_in_progress ) + { + next_state = DFU_MANIFEST; + timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state); + } + else + { + next_state = DFU_IDLE; + timeout = 0; + } + + return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout); + } + else if ( stage == CONTROL_STAGE_ACK ) + { + if ( _dfu_ctx.flashing_in_progress ) + { + _dfu_ctx.state = DFU_MANIFEST; + tud_dfu_manifest_cb(_dfu_ctx.alt); + } + else + { + _dfu_ctx.state = DFU_IDLE; + } + } + + return true; +} + +static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout) +{ + dfu_status_response_t resp; + resp.bStatus = (uint8_t) status; + resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout); + resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout); + resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout); + resp.bState = (uint8_t) state; + resp.iString = 0; + + return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); +} + +#endif diff --git a/components/tinyusb/additions/tusb/src/class/dfu/dfu_device.h b/components/tinyusb/additions/tusb/src/class/dfu/dfu_device.h new file mode 100644 index 0000000..084bfc3 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/class/dfu/dfu_device.h @@ -0,0 +1,124 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 XMOS LIMITED + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_DEVICE_H_ +#define _TUSB_DFU_DEVICE_H_ + +#include "dfu.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Default Configure & Validation +//--------------------------------------------------------------------+ + +#if !defined(CFG_TUD_DFU_XFER_BUFSIZE) +#define CFG_TUD_DFU_XFER_BUFSIZE 512 +#endif + +#define TU_U32_BYTE3(_u32) ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB +#define TU_U32_BYTE2(_u32) ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff)) +#define TU_U32_BYTE1(_u32) ((uint8_t) ((((uint32_t) _u32) >> 8) & 0x000000ff)) +#define TU_U32_BYTE0(_u32) ((uint8_t) (((uint32_t) _u32) & 0x000000ff)) // LSB + +// Length of template descriptor: 9 bytes + number of alternatives * 9 +#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9) + +// Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size +// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface +#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \ + TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \ + /* Function */ \ + 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101) + +#define _TUD_DFU_ALT(_itfnum, _alt, _stridx) \ + /* Interface */ \ + 9, TUSB_DESC_INTERFACE, _itfnum, _alt, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_DFU, _stridx + +#define _TUD_DFU_ALT_1(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx) + +#define _TUD_DFU_ALT_2(_itfnum, _alt_count, _stridx) \ + _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \ + _TUD_DFU_ALT_1(_itfnum, _alt_count+1, _stridx+1) + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Must be called when the application is done with flashing started by +// tud_dfu_download_cb() and tud_dfu_manifest_cb(). +// status is DFU_STATUS_OK if successful, any other error status will cause state to enter dfuError +void tud_dfu_finish_flashing(uint8_t status); + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. + +// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) +// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. +// During this period, USB host won't try to communicate with us. +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state); + +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +// This callback could be returned before flashing op is complete (async). +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length); + +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) +// Application can do checksum, or actual flashing if buffered entire image previously. +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_manifest_cb(uint8_t alt); + +// Invoked when received DFU_UPLOAD request +// Application must populate data with up to length bytes and +// Return the number of written bytes +TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); + +// Invoked when a DFU_DETACH request is received +TU_ATTR_WEAK void tud_dfu_detach_cb(void); + +// Invoked when the Host has terminated a download or upload transfer +TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void dfu_moded_init(void); +void dfu_moded_reset(uint8_t rhport); +uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_MODE_DEVICE_H_ */ diff --git a/components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.c b/components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.c new file mode 100644 index 0000000..afee2aa --- /dev/null +++ b/components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.c @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Sylvain Munaut + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_DFU_RUNTIME) + +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "dfu_rt_device.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void dfu_rtd_init(void) +{ +} + +void dfu_rtd_reset(uint8_t rhport) +{ + (void) rhport; +} + +uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + (void) rhport; + (void) max_len; + + // Ensure this is DFU Runtime + TU_VERIFY((itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS) && + (itf_desc->bInterfaceProtocol == DFU_PROTOCOL_RT), 0); + + uint8_t const * p_desc = tu_desc_next( itf_desc ); + uint16_t drv_len = sizeof(tusb_desc_interface_t); + + if ( TUSB_DESC_FUNCTIONAL == tu_desc_type(p_desc) ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + return drv_len; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + // nothing to do with DATA or ACK stage + if ( stage != CONTROL_STAGE_SETUP ) return true; + + TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); + + // dfu-util will try to claim the interface with SET_INTERFACE request before sending DFU request + if ( TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && + TUSB_REQ_SET_INTERFACE == request->bRequest ) + { + tud_control_status(rhport, request); + return true; + } + + // Handle class request only from here + TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); + + switch (request->bRequest) + { + case DFU_REQUEST_DETACH: + { + TU_LOG2(" DFU RT Request: DETACH\r\n"); + tud_control_status(rhport, request); + tud_dfu_runtime_reboot_to_dfu_cb(); + } + break; + + case DFU_REQUEST_GETSTATUS: + { + TU_LOG2(" DFU RT Request: GETSTATUS\r\n"); + dfu_status_response_t resp; + // Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0 + memset(&resp, 0x00, sizeof(dfu_status_response_t)); + tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t)); + } + break; + + default: + { + TU_LOG2(" DFU RT Unexpected Request: %d\r\n", request->bRequest); + return false; // stall unsupported request + } + } + + return true; +} + +#endif diff --git a/components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.h b/components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.h new file mode 100644 index 0000000..babaa82 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/class/dfu/dfu_rt_device.h @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Sylvain Munaut + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_DFU_RT_DEVICE_H_ +#define _TUSB_DFU_RT_DEVICE_H_ + +#include "dfu.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ +// Invoked when a DFU_DETACH request is received and bitWillDetach is set +void tud_dfu_runtime_reboot_to_dfu_cb(void); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void dfu_rtd_init(void); +void dfu_rtd_reset(uint8_t rhport); +uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_DFU_RT_DEVICE_H_ */ diff --git a/components/tinyusb/additions/tusb/src/class/net/net_device.c b/components/tinyusb/additions/tusb/src/class/net/net_device.c new file mode 100644 index 0000000..64066d8 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/class/net/net_device.c @@ -0,0 +1,481 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Peter Lawrence + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if ( TUSB_OPT_DEVICE_ENABLED && CFG_TUD_NET ) + +#include "class/net/net_device.h" +#include "device/usbd_pvt.h" +#include "rndis_protocol.h" + +void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */ + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +typedef struct +{ + uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface + uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active + + uint8_t ep_notif; + uint8_t ep_in; + uint8_t ep_out; + + bool ecm_mode; + + // Endpoint descriptor use to open/close when receving SetInterface + // TODO since configuration descriptor may not be long-lived memory, we should + // keep a copy of endpoint attribute instead + uint8_t const * ecm_desc_epdata; + +} netd_interface_t; + +#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t) +#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0 + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN]; + +struct ecm_notify_struct +{ + tusb_control_request_t header; + uint32_t downlink, uplink; +}; + +static const struct ecm_notify_struct ecm_notify_nc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, + .wValue = 1 /* Connected */, + .wLength = 0, + }, +}; + +static const struct ecm_notify_struct ecm_notify_csc = +{ + .header = { + .bmRequestType = 0xA1, + .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, + .wLength = 8, + }, + .downlink = 9728000, + .uplink = 9728000, +}; + +// TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union +{ + uint8_t rndis_buf[120]; + struct ecm_notify_struct ecm_buf; +} notify; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +// TODO remove CFG_TUSB_MEM_SECTION +CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf; + +static bool can_xmit; + +void tud_network_recv_renew(void) +{ + usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_out, received, sizeof(received)); +} + +static void do_in_xfer(uint8_t *buf, uint16_t len) +{ + can_xmit = false; + + if (tud_network_idle_status_change_cb) { + tud_network_idle_status_change_cb(can_xmit); + } + + usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_in, buf, len); +} + +void netd_report(uint8_t *buf, uint16_t len) +{ + usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_notif, buf, len); +} + +//--------------------------------------------------------------------+ +// USBD Driver API +//--------------------------------------------------------------------+ +void netd_init(void) +{ + tu_memclr(&_netd_itf, sizeof(_netd_itf)); +} + +void netd_reset(uint8_t rhport) +{ + (void) rhport; + + netd_init(); +} + +uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) +{ + bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass && + TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); + + bool const is_ecm = (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass && + 0x00 == itf_desc->bInterfaceProtocol); + + TU_VERIFY(is_rndis || is_ecm, 0); + + // confirm interface hasn't already been allocated + TU_ASSERT(0 == _netd_itf.ep_notif, 0); + + // sanity check the descriptor + _netd_itf.ecm_mode = is_ecm; + + //------------- Management Interface -------------// + _netd_itf.itf_num = itf_desc->bInterfaceNumber; + + uint16_t drv_len = sizeof(tusb_desc_interface_t); + uint8_t const * p_desc = tu_desc_next( itf_desc ); + + // Communication Functional Descriptors + while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + { + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + // notification endpoint (if any) + if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + { + TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); + + _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + //------------- Data Interface -------------// + // - RNDIS Data followed immediately by a pair of endpoints + // - CDC-ECM data interface has 2 alternate settings + // - 0 : zero endpoints for inactive (default) + // - 1 : IN & OUT endpoints for active networking + TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); + + do + { + tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; + TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); + + drv_len += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) ); + + // Pair of endpoints + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); + + if ( _netd_itf.ecm_mode ) + { + // ECM by default is in-active, save the endpoint attribute + // to open later when received setInterface + _netd_itf.ecm_desc_epdata = p_desc; + }else + { + // Open endpoint pair for RNDIS + TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 ); + + tud_network_init_cb(); + + // we are ready to transmit a packet + can_xmit = true; + if (tud_network_idle_status_change_cb) { + tud_network_idle_status_change_cb(can_xmit); + } + + // prepare for incoming packets + tud_network_recv_renew(); + } + + drv_len += 2*sizeof(tusb_desc_endpoint_t); + + return drv_len; +} + +void ecm_close(void) +{ + printf("Ecm close\n"); + tusb_control_request_t notify_data = + { + .bmRequestType = 0xA1, + .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, + .wValue = 0 /* Disconnected */, + .wLength = 0, + }; + notify_data.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify_data, sizeof(notify_data)); +} + +void ecm_open(void) +{ + printf("Ecm OPEN\n"); + tusb_control_request_t notify_data = + { + .bmRequestType = 0xA1, + .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, + .wValue = 1 /* Connected */, + .wLength = 0, + }; + notify_data.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify_data, sizeof(notify_data)); +} + +static void ecm_report(bool nc) +{ + notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; + notify.ecm_buf.header.wIndex = _netd_itf.itf_num; + netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if ( stage == CONTROL_STAGE_SETUP ) + { + switch ( request->bmRequestType_bit.type ) + { + case TUSB_REQ_TYPE_STANDARD: + switch ( request->bRequest ) + { + case TUSB_REQ_GET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); + + tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); + } + break; + + case TUSB_REQ_SET_INTERFACE: + { + uint8_t const req_itfnum = (uint8_t) request->wIndex; + uint8_t const req_alt = (uint8_t) request->wValue; + + // Only valid for Data Interface with Alternate is either 0 or 1 + TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); + + // ACM-ECM only: qequest to enable/disable network activities + TU_VERIFY(_netd_itf.ecm_mode); + + _netd_itf.itf_data_alt = req_alt; + + if ( _netd_itf.itf_data_alt ) + { + // TODO since we don't actually close endpoint + // hack here to not re-open it + if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) + { + TU_ASSERT(_netd_itf.ecm_desc_epdata); + TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); + + // TODO should be merge with RNDIS's after endpoint opened + // Also should have opposite callback for application to disable network !! + tud_network_init_cb(); + can_xmit = true; // we are ready to transmit a packet + if (tud_network_idle_status_change_cb) { + tud_network_idle_status_change_cb(can_xmit); + } + tud_network_recv_renew(); // prepare for incoming packets + } + }else + { + // TODO close the endpoint pair + // For now pretend that we did, this should have no harm since host won't try to + // communicate with the endpoints again + // _netd_itf.ep_in = _netd_itf.ep_out = 0 + } + + tud_control_status(rhport, request); + } + break; + + // unsupported request + default: return false; + } + break; + + case TUSB_REQ_TYPE_CLASS: + TU_VERIFY (_netd_itf.itf_num == request->wIndex); + + if (_netd_itf.ecm_mode) + { + /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ + if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) + { + tud_control_xfer(rhport, request, NULL, 0); + ecm_report(true); + } + } + else + { + if (request->bmRequestType_bit.direction == TUSB_DIR_IN) + { + rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf); + uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); + TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); + tud_control_xfer(rhport, request, notify.rndis_buf, msglen); + } + else + { + tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf)); + } + } + break; + + // unsupported request + default: return false; + } + } + else if ( stage == CONTROL_STAGE_DATA ) + { + // Handle RNDIS class control OUT only + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + request->bmRequestType_bit.direction == TUSB_DIR_OUT && + _netd_itf.itf_num == request->wIndex) + { + if ( !_netd_itf.ecm_mode ) + { + rndis_class_set_handler(notify.rndis_buf, request->wLength); + } + } + } + + return true; +} + +static void handle_incoming_packet(uint32_t len) +{ + uint8_t *pnt = received; + uint32_t size = 0; + + if (_netd_itf.ecm_mode) + { + size = len; + } + else + { + rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt); + if (len >= sizeof(rndis_data_packet_t)) + if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) + if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) + { + pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)]; + size = r->DataLength; + } + } + + if (!tud_network_recv_cb(pnt, size)) + { + /* if a buffer was never handled by user code, we must renew on the user's behalf */ + tud_network_recv_renew(); + } +} + +bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void) rhport; + (void) result; + + /* new packet received */ + if ( ep_addr == _netd_itf.ep_out ) + { + handle_incoming_packet(xferred_bytes); + } + + /* data transmission finished */ + if ( ep_addr == _netd_itf.ep_in ) + { + /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */ + + if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) ) + { + do_in_xfer(NULL, 0); /* a ZLP is needed */ + } + else + { + /* we're finally finished */ + can_xmit = true; + if (tud_network_idle_status_change_cb) { + tud_network_idle_status_change_cb(can_xmit); + } + } + } + + if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) + { + if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); + } + + return true; +} + +bool tud_network_can_xmit(void) +{ + return can_xmit; +} + +void tud_network_xmit(void *ref, uint16_t arg) +{ + uint8_t *data; + uint16_t len; + + if (!can_xmit) + return; + + len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; + data = transmitted + len; + + len += tud_network_xmit_cb(data, ref, arg); + + if (!_netd_itf.ecm_mode) + { + rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted); + memset(hdr, 0, sizeof(rndis_data_packet_t)); + hdr->MessageType = REMOTE_NDIS_PACKET_MSG; + hdr->MessageLength = len; + hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset); + hdr->DataLength = len - sizeof(rndis_data_packet_t); + } + + do_in_xfer(transmitted, len); +} + +#endif diff --git a/components/tinyusb/additions/tusb/src/lib/networking/ndis.h b/components/tinyusb/additions/tusb/src/lib/networking/ndis.h new file mode 100644 index 0000000..1c73757 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/lib/networking/ndis.h @@ -0,0 +1,266 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ndis.h *************************************************************** + * + * \brief + * This file contains the possible external configuration of the USB. + * + * \addtogroup usbstick + * + * + ******************************************************************************/ + +/** + \ingroup usbstick + \defgroup RNDIS RNDIS Support + @{ + */ + +/* + * ndis.h + * + * Modified by Colin O'Flynn + * ntddndis.h modified by Benedikt Spranger + * + * Thanks to the cygwin development team, + * espacially to Casper S. Hornstrup + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef _LINUX_NDIS_H +#define _LINUX_NDIS_H + + +#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 +#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A +#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B + +/* from drivers/net/sk98lin/h/skgepnmi.h */ +#define OID_PNP_CAPABILITIES 0xFD010100 +#define OID_PNP_SET_POWER 0xFD010101 +#define OID_PNP_QUERY_POWER 0xFD010102 +#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 +#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 +#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 + +enum NDIS_DEVICE_POWER_STATE { + NdisDeviceStateUnspecified = 0, + NdisDeviceStateD0, + NdisDeviceStateD1, + NdisDeviceStateD2, + NdisDeviceStateD3, + NdisDeviceStateMaximum +}; + +struct NDIS_PM_WAKE_UP_CAPABILITIES { + enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp; + enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp; + enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp; +}; + +/* NDIS_PNP_CAPABILITIES.Flags constants */ +#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001 +#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 +#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 + +/* +struct NDIS_PNP_CAPABILITIES { + __le32 Flags; + struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; +}; + +struct NDIS_PM_PACKET_PATTERN { + __le32 Priority; + __le32 Reserved; + __le32 MaskSize; + __le32 PatternOffset; + __le32 PatternSize; + __le32 PatternFlags; +}; +*/ + +/* Required Object IDs (OIDs) */ +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_SUPPORTED_GUIDS 0x00010117 +#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 +#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 +#define OID_GEN_MACHINE_NAME 0x0001021A +#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B +#define OID_GEN_VLAN_ID 0x0001021C + +/* Optional OIDs */ +#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 +#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 + +/* Required statistics OIDs */ +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +/* Optional statistics OIDs */ +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +#define OID_GEN_NETCARD_LOAD 0x00020211 +#define OID_GEN_DEVICE_PROFILE 0x00020212 +#define OID_GEN_INIT_TIME_MS 0x00020213 +#define OID_GEN_RESET_COUNTS 0x00020214 +#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215 +#define OID_GEN_FRIENDLY_NAME 0x00020216 +#define OID_GEN_MINIPORT_INFO 0x00020217 +#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218 + +/* IEEE 802.3 (Ethernet) OIDs */ +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 + +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 + +/* Wireless LAN OIDs */ +/* Mandatory */ +#define OID_802_11_BSSID 0x0D010101 /* Q S */ +#define OID_802_11_SSID 0x0D010102 /* Q S */ +#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 /* Q S */ +#define OID_802_11_RSSI 0x0D010206 /* Q I */ +#define OID_802_11_BSSID_LIST 0x0D010217 /* Q */ +#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A /* S */ +#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 /* Q S */ +#define OID_802_11_SUPPORTED_RATES 0x0D01020E /* Q */ +#define OID_802_11_CONFIGURATION 0x0D010211 /* Q S */ +#define OID_802_11_ADD_WEP 0x0D010113 /* S */ +#define OID_802_11_WEP_STATUS 0x0D01011B /* Q S */ +#define OID_802_11_REMOVE_WEP 0x0D010114 /* S */ +#define OID_802_11_DISASSOCIATE 0x0D010115 /* S */ +#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 /* Q S */ +#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C /* S */ + + + +/* OID_GEN_MINIPORT_INFO constants */ +#define NDIS_MINIPORT_BUS_MASTER 0x00000001 +#define NDIS_MINIPORT_WDM_DRIVER 0x00000002 +#define NDIS_MINIPORT_SG_LIST 0x00000004 +#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008 +#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010 +#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020 +#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040 +#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080 +#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100 +#define NDIS_MINIPORT_IS_NDIS_5 0x00000200 +#define NDIS_MINIPORT_IS_CO 0x00000400 +#define NDIS_MINIPORT_DESERIALIZE 0x00000800 +#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000 +#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000 +#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000 +#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000 +#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000 +#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000 +#define NDIS_MINIPORT_HIDDEN 0x00040000 +#define NDIS_MINIPORT_SWENUM 0x00080000 +#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000 +#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000 +#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000 +#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000 +#define NDIS_MINIPORT_64BITS_DMA 0x01000000 + +#define NDIS_MEDIUM_802_3 0x00000000 +#define NDIS_MEDIUM_802_5 0x00000001 +#define NDIS_MEDIUM_FDDI 0x00000002 +#define NDIS_MEDIUM_WAN 0x00000003 +#define NDIS_MEDIUM_LOCAL_TALK 0x00000004 +#define NDIS_MEDIUM_DIX 0x00000005 +#define NDIS_MEDIUM_ARCENT_RAW 0x00000006 +#define NDIS_MEDIUM_ARCENT_878_2 0x00000007 +#define NDIS_MEDIUM_ATM 0x00000008 +#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009 +#define NDIS_MEDIUM_IRDA 0x0000000A +#define NDIS_MEDIUM_BPC 0x0000000B +#define NDIS_MEDIUM_CO_WAN 0x0000000C +#define NDIS_MEDIUM_1394 0x0000000D + +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00000100 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 + +#define NDIS_MEDIA_STATE_CONNECTED 0x00000000 +#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001 + +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 + +#endif /* _LINUX_NDIS_H */ + +/** @} */ diff --git a/components/tinyusb/additions/tusb/src/lib/networking/rndis_protocol.h b/components/tinyusb/additions/tusb/src/lib/networking/rndis_protocol.h new file mode 100644 index 0000000..39da296 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/lib/networking/rndis_protocol.h @@ -0,0 +1,313 @@ +/** + * \file rndis_protocol.h + * RNDIS Defines + * + * \author + * Colin O'Flynn + * + * \addtogroup usbstick + */ + +/* Copyright (c) 2008 Colin O'Flynn + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _RNDIS_H +#define _RNDIS_H + +/** + \addtogroup RNDIS + @{ + */ + +#include + +#define RNDIS_MAJOR_VERSION 1 +#define RNDIS_MINOR_VERSION 0 + +#define RNDIS_STATUS_SUCCESS 0X00000000 +#define RNDIS_STATUS_FAILURE 0XC0000001 +#define RNDIS_STATUS_INVALID_DATA 0XC0010015 +#define RNDIS_STATUS_NOT_SUPPORTED 0XC00000BB +#define RNDIS_STATUS_MEDIA_CONNECT 0X4001000B +#define RNDIS_STATUS_MEDIA_DISCONNECT 0X4001000C + + +/* Message set for Connectionless (802.3) Devices */ +#define REMOTE_NDIS_PACKET_MSG 0x00000001 +#define REMOTE_NDIS_INITIALIZE_MSG 0X00000002 +#define REMOTE_NDIS_HALT_MSG 0X00000003 +#define REMOTE_NDIS_QUERY_MSG 0X00000004 +#define REMOTE_NDIS_SET_MSG 0X00000005 +#define REMOTE_NDIS_RESET_MSG 0X00000006 +#define REMOTE_NDIS_INDICATE_STATUS_MSG 0X00000007 +#define REMOTE_NDIS_KEEPALIVE_MSG 0X00000008 +#define REMOTE_NDIS_INITIALIZE_CMPLT 0X80000002 +#define REMOTE_NDIS_QUERY_CMPLT 0X80000004 +#define REMOTE_NDIS_SET_CMPLT 0X80000005 +#define REMOTE_NDIS_RESET_CMPLT 0X80000006 +#define REMOTE_NDIS_KEEPALIVE_CMPLT 0X80000008 + +typedef uint32_t rndis_MessageType_t; +typedef uint32_t rndis_MessageLength_t; +typedef uint32_t rndis_RequestId_t; +typedef uint32_t rndis_MajorVersion_t; +typedef uint32_t rndis_MinorVersion_t; +typedef uint32_t rndis_MaxTransferSize_t; +typedef uint32_t rndis_Status_t; + + +/* Device Flags */ +#define RNDIS_DF_CONNECTIONLESS 0x00000001 +#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002 +typedef uint32_t rndis_DeviceFlags_t; + +/* Mediums */ +#define RNDIS_MEDIUM_802_3 0x00000000 +typedef uint32_t rndis_Medium_t; + + +typedef uint32_t rndis_MaxPacketsPerTransfer_t; +typedef uint32_t rndis_PacketAlignmentFactor_t; +typedef uint32_t rndis_AfListOffset_t; +typedef uint32_t rndis_AfListSize_t; + +/*** Remote NDIS Generic Message type ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + } rndis_generic_msg_t; + + +/*** Remote NDIS Initialize Message ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_MajorVersion_t MajorVersion; + rndis_MinorVersion_t MinorVersion; + rndis_MaxTransferSize_t MaxTransferSize; + } rndis_initialize_msg_t; + +/* Response: */ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_Status_t Status; + rndis_MajorVersion_t MajorVersion; + rndis_MinorVersion_t MinorVersion; + rndis_DeviceFlags_t DeviceFlags; + rndis_Medium_t Medium; + rndis_MaxPacketsPerTransfer_t MaxPacketsPerTransfer; + rndis_MaxTransferSize_t MaxTransferSize; + rndis_PacketAlignmentFactor_t PacketAlignmentFactor; + rndis_AfListOffset_t AfListOffset; + rndis_AfListSize_t AfListSize; + } rndis_initialize_cmplt_t; + + +/*** Remote NDIS Halt Message ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + } rndis_halt_msg_t; + +typedef uint32_t rndis_Oid_t; +typedef uint32_t rndis_InformationBufferLength_t; +typedef uint32_t rndis_InformationBufferOffset_t; +typedef uint32_t rndis_DeviceVcHandle_t; + +/*** Remote NDIS Query Message ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_Oid_t Oid; + rndis_InformationBufferLength_t InformationBufferLength; + rndis_InformationBufferOffset_t InformationBufferOffset; + rndis_DeviceVcHandle_t DeviceVcHandle; + } rndis_query_msg_t; + +/* Response: */ + +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_Status_t Status; + rndis_InformationBufferLength_t InformationBufferLength; + rndis_InformationBufferOffset_t InformationBufferOffset; + } rndis_query_cmplt_t; + +/*** Remote NDIS Set Message ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_Oid_t Oid; + rndis_InformationBufferLength_t InformationBufferLength; + rndis_InformationBufferOffset_t InformationBufferOffset; + rndis_DeviceVcHandle_t DeviceVcHandle; + } rndis_set_msg_t; + +/* Response */ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_Status_t Status; + }rndis_set_cmplt_t; + +/* Information buffer layout for OID_GEN_RNDIS_CONFIG_PARAMETER */ +typedef uint32_t rndis_ParameterNameOffset_t; +typedef uint32_t rndis_ParameterNameLength_t; +typedef uint32_t rndis_ParameterType_t; +typedef uint32_t rndis_ParameterValueOffset_t; +typedef uint32_t rndis_ParameterValueLength_t; + +#define PARAMETER_TYPE_STRING 2 +#define PARAMETER_TYPE_NUMERICAL 0 + +typedef struct{ + rndis_ParameterNameOffset_t ParameterNameOffset; + rndis_ParameterNameLength_t ParameterNameLength; + rndis_ParameterType_t ParameterType; + rndis_ParameterValueOffset_t ParameterValueOffset; + rndis_ParameterValueLength_t ParameterValueLength; + }rndis_config_parameter_t; + +typedef uint32_t rndis_Reserved_t; + +/*** Remote NDIS Soft Reset Message ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_Reserved_t Reserved; + } rndis_reset_msg_t; + +typedef uint32_t rndis_AddressingReset_t; + +/* Response: */ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_Status_t Status; + rndis_AddressingReset_t AddressingReset; + } rndis_reset_cmplt_t; + +/*** Remote NDIS Indicate Status Message ***/ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_Status_t Status; + rndis_Status_t StatusBufferLength; + rndis_Status_t StatusBufferOffset; + } rndis_indicate_status_t; + +typedef uint32_t rndis_DiagStatus_t; +typedef uint32_t rndis_ErrorOffset_t; + +typedef struct { + rndis_DiagStatus_t DiagStatus; + rndis_ErrorOffset_t ErrorOffset; + }rndis_diagnostic_info_t; + +/*** Remote NDIS Keepalive Message */ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + }rndis_keepalive_msg_t; + +/* Response: */ +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_RequestId_t RequestId; + rndis_Status_t Status; + }rndis_keepalive_cmplt_t; + +/*** Remote NDIS Data Packet ***/ + +typedef uint32_t rndis_DataOffset_t; +typedef uint32_t rndis_DataLength_t; +typedef uint32_t rndis_OOBDataOffset_t; +typedef uint32_t rndis_OOBDataLength_t; +typedef uint32_t rndis_NumOOBDataElements_t; +typedef uint32_t rndis_PerPacketInfoOffset_t; +typedef uint32_t rndis_PerPacketInfoLength_t; + +typedef struct{ + rndis_MessageType_t MessageType; + rndis_MessageLength_t MessageLength; + rndis_DataOffset_t DataOffset; + rndis_DataLength_t DataLength; + rndis_OOBDataOffset_t OOBDataOffset; + rndis_OOBDataLength_t OOBDataLength; + rndis_NumOOBDataElements_t NumOOBDataElements; + rndis_PerPacketInfoOffset_t PerPacketInfoOffset; + rndis_PerPacketInfoLength_t PerPacketInfoLength; + rndis_DeviceVcHandle_t DeviceVcHandle; + rndis_Reserved_t Reserved; + }rndis_data_packet_t; + +typedef uint32_t rndis_ClassInformationOffset_t; +typedef uint32_t rndis_Size_t; +typedef uint32_t rndis_Type_t; + +typedef struct{ + rndis_Size_t Size; + rndis_Type_t Type; + rndis_ClassInformationOffset_t ClassInformationType; + }rndis_OOB_packet_t; + +#include "ndis.h" + +typedef enum rnids_state_e { + rndis_uninitialized, + rndis_initialized, + rndis_data_initialized + } rndis_state_t; + +typedef struct { + uint32_t txok; + uint32_t rxok; + uint32_t txbad; + uint32_t rxbad; +} usb_eth_stat_t; + +//void rndis_indicate_status(int status); + +void rndis_disconnect(void); + +void rndis_connect(void); + +#endif /* _RNDIS_H */ + +/** @} */ diff --git a/components/tinyusb/additions/tusb/src/lib/networking/rndis_reports.c b/components/tinyusb/additions/tusb/src/lib/networking/rndis_reports.c new file mode 100644 index 0000000..53c43c4 --- /dev/null +++ b/components/tinyusb/additions/tusb/src/lib/networking/rndis_reports.c @@ -0,0 +1,329 @@ +/* + The original version of this code was lrndis/usbd_rndis_core.c from https://github.com/fetisov/lrndis + It has since been overhauled to suit this application +*/ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 by Sergey Fetisov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "class/net/net_device.h" +#include "rndis_protocol.h" +#include "netif/ethernet.h" +#include "esp_wifi.h" + +#define RNDIS_LINK_SPEED 12000000 /* Link baudrate (12Mbit/s for USB-FS) */ +#define RNDIS_VENDOR CONFIG_TINYUSB_RNDIS_VENDOR /* NIC vendor name */ + +static usb_eth_stat_t usb_eth_stat = { 0, 0, 0, 0 }; +static uint32_t oid_packet_filter = 0x0000000; +static rndis_state_t rndis_state; + +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t ndis_report[8] = { 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + +static const uint32_t OIDSupportedList[] = +{ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_MAC_OPTIONS, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_MAC_OPTIONS +}; + +#define OID_LIST_LENGTH TU_ARRAY_SIZE(OIDSupportedList) +#define ENC_BUF_SIZE (OID_LIST_LENGTH * 4 + 32) + +static void *encapsulated_buffer; + +static void rndis_report(void) +{ + netd_report(ndis_report, sizeof(ndis_report)); +} + +static void rndis_query_cmplt32(int status, uint32_t data) +{ + rndis_query_cmplt_t *c; + c = (rndis_query_cmplt_t *)encapsulated_buffer; + c->MessageType = REMOTE_NDIS_QUERY_CMPLT; + c->MessageLength = sizeof(rndis_query_cmplt_t) + 4; + c->InformationBufferLength = 4; + c->InformationBufferOffset = 16; + c->Status = status; + memcpy(c + 1, &data, sizeof(data)); + rndis_report(); +} + +static void rndis_query_cmplt(int status, const void *data, int size) +{ + rndis_query_cmplt_t *c; + c = (rndis_query_cmplt_t *)encapsulated_buffer; + c->MessageType = REMOTE_NDIS_QUERY_CMPLT; + c->MessageLength = sizeof(rndis_query_cmplt_t) + size; + c->InformationBufferLength = size; + c->InformationBufferOffset = 16; + c->Status = status; + memcpy(c + 1, data, size); + rndis_report(); +} + +#define MAC_OPT NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | \ + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ + NDIS_MAC_OPTION_NO_LOOPBACK + +static const char *rndis_vendor = RNDIS_VENDOR; + +static void rndis_query(void) +{ + uint8_t sta_mac[6] = {0}; + esp_wifi_get_mac(WIFI_IF_STA, sta_mac); + switch (((rndis_query_msg_t *)encapsulated_buffer)->Oid) + { + case OID_GEN_SUPPORTED_LIST: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, OIDSupportedList, 4 * OID_LIST_LENGTH); return; + case OID_GEN_VENDOR_DRIVER_VERSION: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00001000); return; + case OID_802_3_CURRENT_ADDRESS: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, sta_mac, 6); return; + case OID_802_3_PERMANENT_ADDRESS: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, sta_mac, 6); return; + case OID_GEN_MEDIA_SUPPORTED: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; + case OID_GEN_MEDIA_IN_USE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; + case OID_GEN_PHYSICAL_MEDIUM: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return; + case OID_GEN_HARDWARE_STATUS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; + case OID_GEN_LINK_SPEED: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, RNDIS_LINK_SPEED / 100); return; + case OID_GEN_VENDOR_ID: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00FFFFFF); return; + case OID_GEN_VENDOR_DESCRIPTION: rndis_query_cmplt(RNDIS_STATUS_SUCCESS, rndis_vendor, strlen(rndis_vendor) + 1); return; + case OID_GEN_CURRENT_PACKET_FILTER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, oid_packet_filter); return; + case OID_GEN_MAXIMUM_FRAME_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU - SIZEOF_ETH_HDR); return; + case OID_GEN_MAXIMUM_TOTAL_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; + case OID_GEN_TRANSMIT_BLOCK_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; + case OID_GEN_RECEIVE_BLOCK_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return; + case OID_GEN_MEDIA_CONNECT_STATUS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIA_STATE_CONNECTED); return; + case OID_GEN_RNDIS_CONFIG_PARAMETER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; + case OID_802_3_MAXIMUM_LIST_SIZE: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 1); return; + case OID_802_3_MULTICAST_LIST: rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return; + case OID_802_3_MAC_OPTIONS: rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return; + case OID_GEN_MAC_OPTIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, /*MAC_OPT*/ 0); return; + case OID_802_3_RCV_ERROR_ALIGNMENT: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; + case OID_802_3_XMIT_ONE_COLLISION: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; + case OID_802_3_XMIT_MORE_COLLISIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; + case OID_GEN_XMIT_OK: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txok); return; + case OID_GEN_RCV_OK: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxok); return; + case OID_GEN_RCV_ERROR: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxbad); return; + case OID_GEN_XMIT_ERROR: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txbad); return; + case OID_GEN_RCV_NO_BUFFER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return; + default: rndis_query_cmplt(RNDIS_STATUS_FAILURE, NULL, 0); return; + } +} + +#define INFBUF ((uint8_t *)&(m->RequestId) + m->InformationBufferOffset) + +static void rndis_handle_config_parm(const char *data, int keyoffset, int valoffset, int keylen, int vallen) +{ + (void)data; + (void)keyoffset; + (void)valoffset; + (void)keylen; + (void)vallen; +} + +static void rndis_packetFilter(uint32_t newfilter) +{ + (void)newfilter; +} + +static void rndis_handle_set_msg(void) +{ + rndis_set_cmplt_t *c; + rndis_set_msg_t *m; + rndis_Oid_t oid; + + c = (rndis_set_cmplt_t *)encapsulated_buffer; + m = (rndis_set_msg_t *)encapsulated_buffer; + + oid = m->Oid; + c->MessageType = REMOTE_NDIS_SET_CMPLT; + c->MessageLength = sizeof(rndis_set_cmplt_t); + c->Status = RNDIS_STATUS_SUCCESS; + + switch (oid) + { + /* Parameters set up in 'Advanced' tab */ + case OID_GEN_RNDIS_CONFIG_PARAMETER: + { + rndis_config_parameter_t *p; + char *ptr = (char *)m; + ptr += sizeof(rndis_generic_msg_t); + ptr += m->InformationBufferOffset; + p = (rndis_config_parameter_t *) ((void*) ptr); + rndis_handle_config_parm(ptr, p->ParameterNameOffset, p->ParameterValueOffset, p->ParameterNameLength, p->ParameterValueLength); + } + break; + + /* Mandatory general OIDs */ + case OID_GEN_CURRENT_PACKET_FILTER: + memcpy(&oid_packet_filter, INFBUF, 4); + if (oid_packet_filter) + { + rndis_packetFilter(oid_packet_filter); + rndis_state = rndis_data_initialized; + } + else + { + rndis_state = rndis_initialized; + } + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + break; + + case OID_GEN_PROTOCOL_OPTIONS: + break; + + /* Mandatory 802_3 OIDs */ + case OID_802_3_MULTICAST_LIST: + break; + + /* Power Managment: fails for now */ + case OID_PNP_ADD_WAKE_UP_PATTERN: + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + case OID_PNP_ENABLE_WAKE_UP: + default: + c->Status = RNDIS_STATUS_FAILURE; + break; + } + + /* c->MessageID is same as before */ + rndis_report(); + return; +} + +void rndis_indicate_status(int status) +{ + rndis_indicate_status_t *c; + c = (rndis_indicate_status_t *)encapsulated_buffer; + c->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG; + c->MessageLength = sizeof(rndis_indicate_status_t); + c->Status = status; + c->StatusBufferLength = 0; + c->StatusBufferOffset = 0; + rndis_report(); +} + +void rndis_disconnect(void) +{ + int status = RNDIS_STATUS_MEDIA_DISCONNECT; + + rndis_indicate_status(status); +} + +void rndis_connect(void) +{ + int status = RNDIS_STATUS_MEDIA_CONNECT; + + rndis_indicate_status(status); +} + +void rndis_class_set_handler(uint8_t *data, int size) +{ + encapsulated_buffer = data; + (void)size; + + switch (((rndis_generic_msg_t *)encapsulated_buffer)->MessageType) + { + case REMOTE_NDIS_INITIALIZE_MSG: + { + rndis_initialize_cmplt_t *m; + m = ((rndis_initialize_cmplt_t *)encapsulated_buffer); + /* m->MessageID is same as before */ + m->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT; + m->MessageLength = sizeof(rndis_initialize_cmplt_t); + m->MajorVersion = RNDIS_MAJOR_VERSION; + m->MinorVersion = RNDIS_MINOR_VERSION; + m->Status = RNDIS_STATUS_SUCCESS; + m->DeviceFlags = RNDIS_DF_CONNECTIONLESS; + m->Medium = RNDIS_MEDIUM_802_3; + m->MaxPacketsPerTransfer = 1; + m->MaxTransferSize = CFG_TUD_NET_MTU + sizeof(rndis_data_packet_t); + m->PacketAlignmentFactor = 0; + m->AfListOffset = 0; + m->AfListSize = 0; + rndis_state = rndis_initialized; + rndis_report(); + } + break; + + case REMOTE_NDIS_QUERY_MSG: + rndis_query(); + break; + + case REMOTE_NDIS_SET_MSG: + rndis_handle_set_msg(); + break; + + case REMOTE_NDIS_RESET_MSG: + { + rndis_reset_cmplt_t * m; + m = ((rndis_reset_cmplt_t *)encapsulated_buffer); + rndis_state = rndis_uninitialized; + m->MessageType = REMOTE_NDIS_RESET_CMPLT; + m->MessageLength = sizeof(rndis_reset_cmplt_t); + m->Status = RNDIS_STATUS_SUCCESS; + m->AddressingReset = 1; /* Make it look like we did something */ + /* m->AddressingReset = 0; - Windows halts if set to 1 for some reason */ + rndis_report(); + } + break; + + case REMOTE_NDIS_KEEPALIVE_MSG: + { + rndis_keepalive_cmplt_t * m; + m = (rndis_keepalive_cmplt_t *)encapsulated_buffer; + m->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT; + m->MessageLength = sizeof(rndis_keepalive_cmplt_t); + m->Status = RNDIS_STATUS_SUCCESS; + } + /* We have data to send back */ + rndis_report(); + break; + + default: + break; + } +} diff --git a/components/tinyusb/idf_component.yml b/components/tinyusb/idf_component.yml new file mode 100644 index 0000000..628cf7c --- /dev/null +++ b/components/tinyusb/idf_component.yml @@ -0,0 +1,10 @@ +version: "1.1.1" # Component version, required only for components pushed to the service +targets: # List of supported targets (optional, if missing all targets are considered to be supported) + - esp32s2 + - esp32s3 +description: ESP32-S2 TinyUSB Addtions # Description (optional) +url: https://github.com/iot-components/tinyusb # Original repository (optional) +dependencies: + # Required IDF version + idf: + version: "=4.4" diff --git a/drivers/tidal_usb/tidal_usb_console.c b/drivers/tidal_usb/tidal_usb_console.c index 780fe1c..41cb237 100644 --- a/drivers/tidal_usb/tidal_usb_console.c +++ b/drivers/tidal_usb/tidal_usb_console.c @@ -1,10 +1,12 @@ #include "py/runtime.h" #include "py/mphal.h" #include "tinyusb.h" -#include "tusb_cdc_acm.h" #include "tusb_console.h" #include "tidal_usb_console.h" +#if CONFIG_USB_CDC_ENABLED +#include "tusb_cdc_acm.h" + // USB serial read callbacks from mp static uint8_t usb_rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE]; static uint8_t usb_cdc_connected; @@ -35,7 +37,7 @@ void usb_callback_line_state_changed(int itf, cdcacm_event_t *event) { // If dtr && rts are both true, the CDC is connected to a HOST. usb_cdc_connected = dtr && rts; - + // TODO: identify pattern change that esp-idf uses to signal bootloader reset } @@ -63,13 +65,20 @@ void tidal_configure_usb_console() { }; tusb_cdc_acm_init(&amc_cfg); } +#else +void tidal_configure_usb_console() { } +void usb_tx_strn(const char *str, size_t len) { } +#endif + // Expose connected state in Python STATIC mp_obj_t tidal_cdc_connected() { + #if CONFIG_USB_CDC_ENABLED if (usb_cdc_connected) return mp_const_true; else + #endif return mp_const_false; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_cdc_connected_obj, tidal_cdc_connected); diff --git a/scripts/build.sh b/scripts/build.sh index 89076b9..a598953 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -12,5 +12,5 @@ cd ports/esp32/boards ln -sfn /firmware/tildamk6 ./tildamk6 cd .. -make submodules BOARD=tildamk6 USER_C_MODULES=/firmware/drivers/micropython.cmake -make BOARD=tildamk6 USER_C_MODULES=/firmware/drivers/micropython.cmake $@ +make submodules BOARD=tildamk6 USER_COMPONENTS=/firmware/components/tinyusb USER_C_MODULES=/firmware/drivers/micropython.cmake +make BOARD=tildamk6 USER_COMPONENTS=/firmware/components/tinyusb USER_C_MODULES=/firmware/drivers/micropython.cmake $@ diff --git a/tildamk6/sdkconfig.board b/tildamk6/sdkconfig.board index a141a1e..f963518 100644 --- a/tildamk6/sdkconfig.board +++ b/tildamk6/sdkconfig.board @@ -13,21 +13,32 @@ CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=n CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=n CONFIG_APP_PROJECT_VER_FROM_CONFIG=y +# General USB configuration CONFIG_USB_ENABLED=y CONFIG_TINYUSB=y -CONFIG_TINYUSB_HID_ENABLED=y -CONFIG_TINYUSB_CDC_ENABLED=y -CONFIG_TINYUSB_HID_BUFSIZE=128 +CONFIG_TINYUSB_HID_BUFSIZE=256 CONFIG_TINYUSB_DESC_HID_STRING="TiDAL badge" CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Electromagnetic Field" CONFIG_TINYUSB_DESC_PRODUCT_STRING="TiDAL" - CONFIG_TINYUSB_DESC_CUSTOM_VID=0x16D0 CONFIG_TINYUSB_DESC_CUSTOM_PID=0x1114 CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID= CONFIG_TINYUSB_DESC_USE_DEFAULT_PID= -#CONFIG_LOG_DEFAULT_LEVEL_INFO=y -#CONFIG_LOG_DEFAULT_LEVEL_ERROR=n +# USB feature flags +CONFIG_TINYUSB_CDC_ENABLED=y +CONFIG_TINYUSB_HID_ENABLED=y +CONFIG_TINYUSB_HIDKEYBOARD_ENABLED=y +CONFIG_TINYUSB_U2FHID_ENABLED=n +CONFIG_TINYUSB_MSC_ENABLED=n +CONFIG_TINYUSB_MIDI_ENABLED=n +CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED=n +CONFIG_TINYUSB_NET_ENABLED=n +CONFIG_TINYUSB_BTH_ENABLED=n +CONFIG_TINYUSB_DFU_ENABLED=n + +# Development experimental flags +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +CONFIG_LOG_DEFAULT_LEVEL_ERROR=n #CONFIG_FREERTOS_USE_TICKLESS_IDLE=y #CONFIG_PM_DFS_INIT_AUTO=y From f50f336799cf654be2d09ddbffcccd325e7c69e8 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sat, 28 May 2022 11:06:18 +0100 Subject: [PATCH 02/32] Reduce patching of micropython to support USB --- micropython.diff | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/micropython.diff b/micropython.diff index 6c48db4..eb08bdf 100644 --- a/micropython.diff +++ b/micropython.diff @@ -1,18 +1,19 @@ -diff --git a/ports/esp32/CMakeLists.txt b/ports/esp32/CMakeLists.txt -index 8b2f09a72..bc4af823a 100644 ---- a/ports/esp32/CMakeLists.txt -+++ b/ports/esp32/CMakeLists.txt -@@ -18,6 +18,10 @@ if(NOT EXISTS ${MICROPY_BOARD_DIR}/mpconfigboard.cmake) - message(FATAL_ERROR "Invalid MICROPY_BOARD specified: ${MICROPY_BOARD}") - endif() +diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile +index c8ca9262c..e6224a2a3 100644 +--- a/ports/esp32/Makefile ++++ b/ports/esp32/Makefile +@@ -30,6 +30,11 @@ ifdef FROZEN_MANIFEST + IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST) + endif ++ifdef USER_COMPONENTS ++ IDFPY_FLAGS += -DEXTRA_COMPONENT_DIRS=${USER_COMPONENTS} ++endif + -+set(IDF_TARGET esp32s3) -+include($ENV{IOT_SOLUTION_PATH}/component.cmake) + - # Include main IDF cmake file. - include($ENV{IDF_PATH}/tools/cmake/project.cmake) - + all: + idf.py $(IDFPY_FLAGS) build + @$(PYTHON) makeimg.py \ diff --git a/ports/esp32/main.c b/ports/esp32/main.c index a1c27c0a2..56b145478 100644 --- a/ports/esp32/main.c From e4b1cd21282a18ae81336bd8c1da00d457f64034 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 29 May 2022 18:23:19 +0100 Subject: [PATCH 03/32] Progress on internal U2F protocol This implements enough of the CTAP1 protocol to complete transactions, albeit with hard-coded responses that don't pass cryptographic muster. --- .../additions/src/descriptors_control.c | 2 +- drivers/tidal_usb/tidal_usb_hid.c | 8 +- drivers/tidal_usb/tidal_usb_u2f.c | 256 ++++++++++++++++-- drivers/tidal_usb/tidal_usb_u2f.h | 54 +++- 4 files changed, 290 insertions(+), 30 deletions(-) diff --git a/components/tinyusb/additions/src/descriptors_control.c b/components/tinyusb/additions/src/descriptors_control.c index 87fcf02..a9f9a12 100644 --- a/components/tinyusb/additions/src/descriptors_control.c +++ b/components/tinyusb/additions/src/descriptors_control.c @@ -202,7 +202,7 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) } #endif #if CFG_TUD_U2FHID - if (itf == 1) { + if (itf == 0+(CFG_TUD_HID_KBD)) { return desc_hid_report_2; } #endif diff --git a/drivers/tidal_usb/tidal_usb_hid.c b/drivers/tidal_usb/tidal_usb_hid.c index c50a060..3108827 100644 --- a/drivers/tidal_usb/tidal_usb_hid.c +++ b/drivers/tidal_usb/tidal_usb_hid.c @@ -1,4 +1,5 @@ #include "py/runtime.h" +#include "esp_log.h" #include "tinyusb.h" #include "tusb_hid.h" #include "usb.h" @@ -8,10 +9,12 @@ #include "tidal_usb_u2f.h" #endif +static const char *TAG = "tidalHID"; + void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { printf("REPORT: %d %d %d\n", itf, report_id, report_type); #if CFG_TUD_U2FHID - if (itf == 1) { + if (itf == 0+(CFG_TUD_HID_KBD)) { // This is the U2F device handle_report_u2f(itf, report_id, report_type, buffer, bufsize); } @@ -22,7 +25,8 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep // report, so buttons are considered held until they're explicitly released void tud_hid_report_complete_cb(uint8_t itf, uint8_t const *report, uint8_t len) { - // no-op + ESP_LOGW(TAG, "HID report complete"); + pop_and_send_report(); } // Send up to 6 keyboard scancodes diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index cd84f56..b25361f 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -1,7 +1,9 @@ #include "descriptors_control.h" #include "tidal_usb_u2f.h" #include "u2f_hid.h" +#include "u2f.h" #include "esp_log.h" +#include #if CFG_TUD_U2FHID static const char *TAG = "tidalU2F"; @@ -9,11 +11,43 @@ static const char *TAG = "tidalU2F"; uint8_t *in_progress_packet = NULL; bool packet_needs_free = false; -uint16_t expected_size = NULL; -uint16_t current_index = NULL; +uint16_t expected_size = 0; +uint16_t current_index = 0; +bool had_user_interaction = false; + +u2f_hid_msg upcoming_report_ring[REPORT_RING_SIZE] = { NULL }; +bool upcoming_report_ring_waiting[REPORT_RING_SIZE] = { false }; +uint8_t write_head = 0; +uint8_t read_head = 0; + +void push_report(u2f_hid_msg *msg) { + if (upcoming_report_ring_waiting[write_head]) { + // There's already a report waiting to be picked up. This is a fatal error. + ESP_LOGE(TAG, "U2F outbound report buffer full"); + } + ESP_LOGI(TAG, "Writing into buffer at position %d", write_head); + memcpy(&upcoming_report_ring[write_head], msg, sizeof(u2f_hid_msg)); + upcoming_report_ring_waiting[write_head] = true; + write_head = (write_head + 1) % REPORT_RING_SIZE; + return; +} + +void pop_and_send_report() { + if (!upcoming_report_ring_waiting[read_head]) { + // There's already a report waiting to be picked up. This is a fatal error. + ESP_LOGW(TAG, "U2F outbound report buffer empty"); + return; + } + ESP_LOGI(TAG, "Sending pending report from position %d", read_head); + u2f_report(&upcoming_report_ring[read_head]); + upcoming_report_ring_waiting[read_head] = false; + memset(&upcoming_report_ring[read_head], 0, sizeof(u2f_hid_msg)); + read_head = (read_head + 1) % REPORT_RING_SIZE; +} + bool handle_message_fragment(uint8_t *buffer) { - const u2f_hid_msg *msg = buffer; + const u2f_hid_msg *msg = (u2f_hid_msg *) buffer; if (in_progress_packet != NULL) { // This is a continuation packet uint16_t bytes_to_copy = min(sizeof(msg->cont.data), expected_size-current_index); @@ -31,12 +65,12 @@ bool handle_message_fragment(uint8_t *buffer) { // This is a command packet, check if we need to set // up a continuation uint16_t msg_size = (msg->init.BCNTH << 8) + msg->init.BCNTL; - ESP_LOGI(TAG, "Got message of size %d", msg_size); + ESP_LOGI(TAG, "Got initial packet of size %d for message %x", msg_size, msg->init.CMD); if (msg_size <= HID_RPT_SIZE) { // No, it's small enough ESP_LOGI(TAG, "Using existing buffer"); - in_progress_packet = msg; + in_progress_packet = buffer; expected_size = msg_size; packet_needs_free = false; return true; @@ -64,7 +98,7 @@ void handle_report_u2f(uint8_t itf, uint8_t report_id, hid_report_type_t report_ const u2f_hid_msg *msg = in_progress_packet; uint16_t msg_size = (msg->init.BCNTH << 8) + msg->init.BCNTL; - ESP_LOGI(TAG, "Handling command %02x (%d)", msg->init.CMD, msg->init.CMD); + ESP_LOGI(TAG, "Handling command %02x", msg->init.CMD); if (msg->init.CMD == U2FHID_INIT) { // INIT command handle_u2f_init((const u2fhid_init_request *) msg->init.data); @@ -73,15 +107,25 @@ void handle_report_u2f(uint8_t itf, uint8_t report_id, hid_report_type_t report_ } else if (msg->init.CMD == U2FHID_WINK) { handle_u2f_wink(); } else { + ESP_LOGE(TAG, "Unknown U2FHID transport command %02x", msg->init.CMD); // Unknown report type, log it. - printf("REPORT: %d %d %d\n", itf, report_id, report_type); + /*printf("REPORT: %d %d %d\n", itf, report_id, report_type); for (int i=0;iCID, + .init.CMD = U2FHID_ERROR, + .init.BCNTH = 0, + .init.BCNTL = 1, + .init.data = { ERR_INVALID_CMD } + }; + u2f_report(&response); + } if (packet_needs_free) { @@ -118,39 +162,186 @@ void handle_u2f_init(u2fhid_init_request const* init_request) { }; memcpy(response.init.data, &response_data, 17); - // Cast this to a char array so we can debug print it - uint8_t *as_buf = (uint8_t *) &response; - for (int i=0;i> 8; + response_data.data[198] = U2F_SW_NO_ERROR & 0xFF; + ESP_LOGI(TAG, "Done"); + + /*printf("RAW data:"); + for (int i=0;i> 8; + response_data.data[1] = U2F_SW_CONDITIONS_NOT_SATISFIED & 0xFF; + return response_data; + } + + ESP_LOGI(TAG, "Allocating container"); + arbitrary_size_container response_data = { + .size=79, + .data=malloc(79) + }; + // Set reserved byte + ESP_LOGI(TAG, "Setting presence bit"); + response_data.data[0] = 0x01; + // The next 4 bytes are a counter + response_data.data[0] = 0x00; + response_data.data[0] = 0x00; + response_data.data[0] = 0x00; + response_data.data[0] = 0x01; + // Now we send the signature + ESP_LOGI(TAG, "Setting signature"); + memset(response_data.data + 5, 0xE1, 71); + + // Set the status epilogue + response_data.data[77] = U2F_SW_NO_ERROR >> 8; + response_data.data[78] = U2F_SW_NO_ERROR & 0xFF; + ESP_LOGI(TAG, "Done"); + /*printf("RAW data:"); + for (int i=0;isize); + uint16_t place = 0; + uint8_t seq = 0; u2f_hid_msg response = { .CID = TIDAL_CHANNEL, .init.CMD = U2FHID_MSG, - .init.BCNTH = 0, - .init.BCNTL = 0, - .init.data = "" + .init.BCNTH = (response_data->size >> 8), + .init.BCNTL = (response_data->size & 0xFF), + .init.data = { 0 } }; + memcpy(response.init.data, response_data->data + place, sizeof(response.init.data)); + ESP_LOGI(TAG, "Sending initial packet %d/%d", place, response_data->size); + place += sizeof(response.init.data); + while (place < response_data->size) { + u2f_hid_msg next_report = { + .CID = TIDAL_CHANNEL, + .cont.SEQ = seq++, + .cont.data = { 0 } + }; + memcpy(next_report.cont.data, response_data->data + place, sizeof(next_report.cont.data)); + ESP_LOGI(TAG, "Sending continuation packet %d/%d", place, response_data->size); + place += sizeof(next_report.cont.data); + push_report(&next_report); + } u2f_report(&response); } +void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { + + /*printf("U2FMSG:"); + for (int i=0;iINS == U2F_REGISTER) { + ESP_LOGI(TAG, "Will process U2F_REGISTER raw message (Instruction %x)", raw_message->INS); + u2f_raw_register_request_body *register_params = (u2f_raw_register_request_body *) raw_message->extended_form.data; + + if (!had_user_interaction) { + // The user needs to allow this, send back the conditions + // not satisfied status as the only body + + ESP_LOGI(TAG, "Awaiting user interaction, reporting conditions not satisfied"); + u2f_hid_msg response = { + .CID = TIDAL_CHANNEL, + .init.CMD = U2FHID_MSG, + .init.BCNTH = 0, + .init.BCNTL = 0x02, + .init.data = { + (U2F_SW_CONDITIONS_NOT_SATISFIED >> 8), + (U2F_SW_CONDITIONS_NOT_SATISFIED & 0xff) + } + }; + had_user_interaction = true; + u2f_report(&response); + } else { + // Reset the interaction flag + had_user_interaction = false; + arbitrary_size_container response_data = process_register_command(register_params); + send_multipart_response(&response_data); + free(response_data.data); + } + } else if (raw_message->INS == U2F_AUTHENTICATE) { + ESP_LOGI(TAG, "Will process U2F_AUTHENTICATE raw message (Instruction %x)", raw_message->INS); + u2f_raw_authenticate_request_body *authenticate_params = (u2f_raw_authenticate_request_body *) raw_message->extended_form.data; + + arbitrary_size_container response_data = process_authenticate_command(raw_message->P1, authenticate_params); + send_multipart_response(&response_data); + free(response_data.data); + } else { + ESP_LOGE(TAG, "Got U2F raw message, but instruction %x is not known", raw_message->INS); + } +} + void handle_u2f_wink() { ESP_LOGW(TAG, "WINKING!"); @@ -163,10 +354,23 @@ void handle_u2f_wink() { }; u2f_report(&response); } + + void u2f_report(u2f_hid_msg *cmd) { - // This is wrong, but I'm just trying to make it match - // what a real one is doing for now, to help debug. + // For some reason, sending with a report ID of 0 is causing + // timeout then -ENOENT, so as long as the 0th byte of the + // buffer isn't a 0 we can do a really filthy hack and put that + // in the report id field. + // Sit Deus propitius huic potatori + uint8_t *as_buf = (uint8_t *) cmd; - //tud_hid_n_report(ITF_NUM_HID_2, 0, as_buf, HID_RPT_SIZE-1); + /*printf("Sending response packet"); + for (int i=0;i Date: Sun, 29 May 2022 22:56:25 +0100 Subject: [PATCH 04/32] Update U2F implementation to be ready for crypto drop-in This changes the u2f implementation around somewhat, so it no longer hard-codes lengths of some variable length fields. It moves the crypto functions out to their own file, ahead of implementation. --- drivers/tidal_usb/micropython.cmake | 1 + drivers/tidal_usb/tidal_usb_u2f.c | 100 +++++++++++++++++-------- drivers/tidal_usb/tidal_usb_u2f.h | 7 -- drivers/tidal_usb/u2f.h | 111 ++++++++++++++++++++++++++++ drivers/tidal_usb/u2f_crypto.c | 46 ++++++++++++ drivers/tidal_usb/u2f_crypto.h | 12 +++ 6 files changed, 238 insertions(+), 39 deletions(-) create mode 100644 drivers/tidal_usb/u2f.h create mode 100644 drivers/tidal_usb/u2f_crypto.c create mode 100644 drivers/tidal_usb/u2f_crypto.h diff --git a/drivers/tidal_usb/micropython.cmake b/drivers/tidal_usb/micropython.cmake index 83e539d..78afd80 100644 --- a/drivers/tidal_usb/micropython.cmake +++ b/drivers/tidal_usb/micropython.cmake @@ -7,6 +7,7 @@ target_sources(usermod_tidal_usb INTERFACE ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_hid.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_console.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_u2f.c + ${CMAKE_CURRENT_LIST_DIR}/u2f_crypto.c ) # Add the current directory as an include directory. diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index b25361f..8955116 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -3,6 +3,7 @@ #include "u2f_hid.h" #include "u2f.h" #include "esp_log.h" +#include "u2f_crypto.h" #include #if CFG_TUD_U2FHID @@ -169,36 +170,57 @@ void handle_u2f_init(u2fhid_init_request const* init_request) { arbitrary_size_container process_register_command(u2f_raw_register_request_body *register_params) { ESP_LOGI(TAG, "Allocating container"); arbitrary_size_container response_data = { - .size=199, - .data=malloc(199) + .size=0, + .data=malloc(512) }; + size_t write_head = 0; + uint8_t handle = allocate_handle(); + // Set reserved byte ESP_LOGI(TAG, "Setting header"); - response_data.data[0] = 0x05; + response_data.data[write_head++] = 0x05; + // The next 65 bytes are the pubkey ESP_LOGI(TAG, "Setting pubkey"); - memset(response_data.data + 1, 0xC0, 65); + set_pubkey(handle, response_data.data + write_head); + write_head += 65; + // Then handle length followed by handle ESP_LOGI(TAG, "Setting handle"); - response_data.data[65] = 0x02; - response_data.data[66] = 'H'; - response_data.data[67] = 'H'; + response_data.data[write_head++] = 0x01; + response_data.data[write_head++] = handle; + // Attestation certificate ESP_LOGI(TAG, "Setting cert"); - char cert[] = "-----BEGIN CERTIFICATE-----\ -BLAH\ ------END CERTIFICATE-----"; - memcpy(response_data.data + 68, cert, strlen(cert)); - // Now we send the signature + // Get the certificate from the secure elefment + arbitrary_size_container cert = get_der_certificate(1); + // Copy it into the current data stream + memcpy(response_data.data + write_head, cert.data, cert.size); + write_head += cert.size; + // Free the intermediate copy + free(cert.data); + + // Create the signature out of 0x00, the register request, key handle and pubkey ESP_LOGI(TAG, "Setting signature"); - memset(response_data.data + 126, 0xE1, 71); - + uint8_t signature_input[131] = { 0 }; + signature_input[0] = 0x00; + memcpy(signature_input + 1, register_params, 65); + signature_input[66] = handle; + memcpy(signature_input + 67, response_data.data + 1, 64); + arbitrary_size_container signature = get_signature(signature_input); + memcpy(response_data.data + write_head, signature.data, signature.size); + write_head += signature.size; + // Free the intermediate copy + free(signature.data); + // Set the status epilogue - response_data.data[197] = U2F_SW_NO_ERROR >> 8; - response_data.data[198] = U2F_SW_NO_ERROR & 0xFF; - ESP_LOGI(TAG, "Done"); + response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; + response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; + ESP_LOGI(TAG, "Built %d byte register response", write_head); + response_data.size = write_head; + realloc(response_data.data, write_head); - /*printf("RAW data:"); + printf("RAW data:"); for (int i=0;iapplication_param, 32); + memcpy(signature_input + 32, response_data.data, 5); + memcpy(signature_input + 37, authenticate_params->challenge_param, 32); + arbitrary_size_container signature = get_signature(signature_input); + memcpy(response_data.data + write_head, signature.data, signature.size); + write_head += signature.size; + // Free the intermediate copy + free(signature.data); + // Set the status epilogue - response_data.data[77] = U2F_SW_NO_ERROR >> 8; - response_data.data[78] = U2F_SW_NO_ERROR & 0xFF; - ESP_LOGI(TAG, "Done"); + response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; + response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; + ESP_LOGI(TAG, "Built %d byte authenticate response", write_head); + response_data.size = write_head; + realloc(response_data.data, write_head); + /*printf("RAW data:"); for (int i=0;i +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// General constants + +#define U2F_EC_KEY_SIZE 32 // EC key size in bytes +#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point +#define U2F_MAX_KH_SIZE 128 // Max size of key handle +#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate +#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature +#define U2F_CTR_SIZE 4 // Size of counter field +#define U2F_APPID_SIZE 32 // Size of application id +#define U2F_CHAL_SIZE 32 // Size of challenge + +#define ENC_SIZE(x) ((x + 7) & 0xfff8) + +// EC (uncompressed) point + +#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format + +typedef struct __attribute__((packed)) { + uint8_t pointFormat; // Point type + uint8_t x[U2F_EC_KEY_SIZE]; // X-value + uint8_t y[U2F_EC_KEY_SIZE]; // Y-value +} U2F_EC_POINT; + +// U2F native commands + +#define U2F_REGISTER 0x01 // Registration command +#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command +#define U2F_VERSION 0x03 // Read version string command + +#define U2F_VENDOR_FIRST 0x40 // First vendor defined command +#define U2F_VENDOR_LAST 0xbf // Last vendor defined command + +// U2F_CMD_REGISTER command defines + +#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier +#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier + +typedef struct __attribute__((packed)) { + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id +} U2F_REGISTER_REQ; + +typedef struct __attribute__((packed)) { + uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) + U2F_EC_POINT pubKey; // Generated public key + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandleCertSig[ + U2F_MAX_KH_SIZE + // Key handle + U2F_MAX_ATT_CERT_SIZE + // Attestation certificate + U2F_MAX_EC_SIG_SIZE]; // Registration signature +} U2F_REGISTER_RESP; + +// U2F_CMD_AUTHENTICATE command defines + +// Authentication control byte + +#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign +#define U2F_AUTH_CHECK_ONLY 0x07 // Check only +#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set + +typedef struct __attribute__((packed)) { + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle +} U2F_AUTHENTICATE_REQ; + +typedef struct __attribute__((packed)) { + uint8_t flags; // U2F_AUTH_FLAG_ values + uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) + uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature +} U2F_AUTHENTICATE_RESP; + +// Command status responses + +#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR +#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA +#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED +#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED +#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED + +#ifdef __cplusplus +} +#endif + +#endif // __U2F_H_INCLUDED__ \ No newline at end of file diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c new file mode 100644 index 0000000..4f91ceb --- /dev/null +++ b/drivers/tidal_usb/u2f_crypto.c @@ -0,0 +1,46 @@ +#include "u2f_crypto.h" +#include "esp_log.h" +#include +#include +#include + +static const char *TAG = "tidalU2F"; + +arbitrary_size_container get_der_certificate(uint8_t handle) { + uint8_t cert[] = { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x56, 0xfc, 0xfd, 0xe4, 0x9c, 0x47, 0x59, 0xce, 0xd2, + 0x0e, 0xb3, 0xbf, 0xd4, 0x42, 0x75, 0x0b, 0x8d, 0x97, 0x15, 0xc6, 0x50, 0xfd, 0xb9, 0xd1, 0xd8, + 0x6a, 0xb0, 0x71, 0xa2, 0x90, 0xe0, 0xeb, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x6f, 0x76, 0x9d, 0x62, 0xb7, 0x00, 0xbc, + 0x0c, 0x58, 0x99, 0x76, 0x82, 0x95, 0x80, 0xdd, 0xc6, 0xb1, 0x2e, 0x26, 0x02, 0x43, 0xdf, 0xe1, + 0xe6, 0x72, 0x7b, 0xa1, 0xe9, 0xdc, 0xe1, 0xae, 0x26, 0x8a, 0x23, 0x45, 0xb0, 0xbb, 0x0f, 0x4f, + 0x3e, 0x73, 0xa1, 0x01, 0x09, 0xfb, 0xbe, 0x04, 0xf0, 0x91, 0xd5, 0xa7, 0xd9, 0xe6, 0x77, 0x26, + 0x01, 0xaf, 0xfb, 0xbc, 0x21, 0x20, 0x79, 0x7b, 0xcc + }; + ESP_LOGI(TAG, "Allocating %d bytes", sizeof(cert)); + arbitrary_size_container response_data = { + .size=sizeof(cert), + .data=malloc(sizeof(cert)), + }; + memcpy(response_data.data, cert, sizeof(cert)); + return response_data; +} + +arbitrary_size_container get_signature(uint8_t signature_input[]) { + ESP_LOGI(TAG, "Allocating %d bytes", 73); + arbitrary_size_container response_data = { + .size=73, + .data=malloc(73), + }; + memset(response_data.data, 0xF0, 73); + return response_data; +} + +void *set_pubkey(uint8_t handle, uint8_t *target) { + memset(target, 0xC0, 65); + return; +} + +uint8_t allocate_handle() { + return 1; +} \ No newline at end of file diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h new file mode 100644 index 0000000..5d0ab83 --- /dev/null +++ b/drivers/tidal_usb/u2f_crypto.h @@ -0,0 +1,12 @@ +#include +#include + +typedef struct arbitrary_size_container { + size_t size; + uint8_t *data; +} arbitrary_size_container; + +arbitrary_size_container get_der_certificate(uint8_t handle); +arbitrary_size_container get_signature(uint8_t signature_input[]); +void *set_pubkey(uint8_t handle, uint8_t *target); +uint8_t allocate_handle(); \ No newline at end of file From 02ff0f7c8713f7de5a546e212c4da5f09d628243 Mon Sep 17 00:00:00 2001 From: Mark Steward Date: Mon, 13 Jun 2022 00:47:43 +0100 Subject: [PATCH 05/32] Add cryptoauthlib and partial SoftI2C HAL --- drivers/ecc108a/cryptoauthlib/README.md | 3 + drivers/ecc108a/cryptoauthlib/atca_basic.c | 4142 +++++++++++++++++ drivers/ecc108a/cryptoauthlib/atca_basic.h | 647 +++ drivers/ecc108a/cryptoauthlib/atca_bool.h | 43 + drivers/ecc108a/cryptoauthlib/atca_cfgs.c | 226 + drivers/ecc108a/cryptoauthlib/atca_cfgs.h | 78 + drivers/ecc108a/cryptoauthlib/atca_compiler.h | 222 + drivers/ecc108a/cryptoauthlib/atca_config.h | 14 + drivers/ecc108a/cryptoauthlib/atca_debug.c | 49 + drivers/ecc108a/cryptoauthlib/atca_debug.h | 11 + drivers/ecc108a/cryptoauthlib/atca_device.c | 134 + drivers/ecc108a/cryptoauthlib/atca_device.h | 312 ++ drivers/ecc108a/cryptoauthlib/atca_devtypes.h | 59 + drivers/ecc108a/cryptoauthlib/atca_helpers.c | 881 ++++ drivers/ecc108a/cryptoauthlib/atca_helpers.h | 83 + drivers/ecc108a/cryptoauthlib/atca_iface.c | 438 ++ drivers/ecc108a/cryptoauthlib/atca_iface.h | 215 + drivers/ecc108a/cryptoauthlib/atca_status.h | 91 + .../ecc108a/cryptoauthlib/atca_utils_sizes.c | 109 + drivers/ecc108a/cryptoauthlib/atca_version.h | 38 + drivers/ecc108a/cryptoauthlib/calib/README.md | 17 + .../cryptoauthlib/calib/calib_aes_gcm.h | 76 + .../ecc108a/cryptoauthlib/calib/calib_basic.c | 373 ++ .../ecc108a/cryptoauthlib/calib/calib_basic.h | 236 + .../cryptoauthlib/calib/calib_command.c | 766 +++ .../cryptoauthlib/calib/calib_command.h | 744 +++ .../cryptoauthlib/calib/calib_derivekey.c | 86 + .../cryptoauthlib/calib/calib_execution.c | 563 +++ .../cryptoauthlib/calib/calib_execution.h | 78 + .../cryptoauthlib/calib/calib_gendig.c | 92 + .../cryptoauthlib/calib/calib_genkey.c | 199 + .../cryptoauthlib/calib/calib_helpers.c | 264 ++ .../ecc108a/cryptoauthlib/calib/calib_info.c | 204 + .../ecc108a/cryptoauthlib/calib/calib_lock.c | 258 + .../cryptoauthlib/calib/calib_privwrite.c | 193 + .../cryptoauthlib/calib/calib_random.c | 88 + .../ecc108a/cryptoauthlib/calib/calib_read.c | 923 ++++ .../ecc108a/cryptoauthlib/calib/calib_sign.c | 252 + .../ecc108a/cryptoauthlib/calib/calib_write.c | 885 ++++ drivers/ecc108a/cryptoauthlib/cryptoauthlib.h | 130 + drivers/ecc108a/cryptoauthlib/hal/atca_hal.c | 548 +++ drivers/ecc108a/cryptoauthlib/hal/atca_hal.h | 238 + .../cryptoauthlib/hal/hal_esp32_mp_softi2c.c | 132 + .../ecc108a/cryptoauthlib/host/atca_host.h | 465 ++ drivers/ecc108a/ecc108a.c | 51 + drivers/ecc108a/micropython.cmake | 58 + drivers/micropython.cmake | 2 + modules/ecc108a_tools/dump_config.py | 57 + 48 files changed, 15773 insertions(+) create mode 100644 drivers/ecc108a/cryptoauthlib/README.md create mode 100644 drivers/ecc108a/cryptoauthlib/atca_basic.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_basic.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_bool.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_cfgs.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_cfgs.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_compiler.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_config.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_debug.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_debug.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_device.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_device.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_devtypes.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_helpers.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_helpers.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_iface.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_iface.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_status.h create mode 100644 drivers/ecc108a/cryptoauthlib/atca_utils_sizes.c create mode 100644 drivers/ecc108a/cryptoauthlib/atca_version.h create mode 100644 drivers/ecc108a/cryptoauthlib/calib/README.md create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_aes_gcm.h create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_basic.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_basic.h create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_command.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_command.h create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_derivekey.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_execution.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_execution.h create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_gendig.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_genkey.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_helpers.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_info.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_lock.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_privwrite.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_random.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_read.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_sign.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_write.c create mode 100644 drivers/ecc108a/cryptoauthlib/cryptoauthlib.h create mode 100644 drivers/ecc108a/cryptoauthlib/hal/atca_hal.c create mode 100644 drivers/ecc108a/cryptoauthlib/hal/atca_hal.h create mode 100644 drivers/ecc108a/cryptoauthlib/hal/hal_esp32_mp_softi2c.c create mode 100644 drivers/ecc108a/cryptoauthlib/host/atca_host.h create mode 100644 drivers/ecc108a/ecc108a.c create mode 100644 drivers/ecc108a/micropython.cmake create mode 100644 modules/ecc108a_tools/dump_config.py diff --git a/drivers/ecc108a/cryptoauthlib/README.md b/drivers/ecc108a/cryptoauthlib/README.md new file mode 100644 index 0000000..7145a0e --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/README.md @@ -0,0 +1,3 @@ +Copied from https://github.com/MicrochipTech/cryptoauthlib (9a37b8d) +Any changes are guarded with #if(n)def ATCA_TIDAL + diff --git a/drivers/ecc108a/cryptoauthlib/atca_basic.c b/drivers/ecc108a/cryptoauthlib/atca_basic.c new file mode 100644 index 0000000..b533d6d --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_basic.c @@ -0,0 +1,4142 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods. These methods provide a simpler way + * to access the core crypto methods. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "atca_basic.h" +#include "atca_version.h" + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +#if defined(_MSC_VER) +#pragma message("Warning : Using a constant host nonce with atcab_read_enc, atcab_write_enc, etcc., can allow spoofing of a device by replaying previously recorded messages") +#else +#warning "Using a constant host nonce with atcab_read_enc, atcab_write_enc, etcc., can allow spoofing of a device by replaying previously recorded messages" +#endif +#endif + +const char atca_version[] = ATCA_LIBRARY_VERSION_DATE; +ATCADevice _gDevice = NULL; +#ifdef ATCA_NO_HEAP +SHARED_LIB_EXPORT struct atca_iface g_atcab_iface; +SHARED_LIB_EXPORT struct atca_device g_atcab_device; +#endif + +/** \brief basic API methods are all prefixed with atcab_ (CryptoAuthLib Basic) + * the fundamental premise of the basic API is it is based on a single interface + * instance and that instance is global, so all basic API commands assume that + * one global device is the one to operate on. + */ + +/** \brief returns a version string for the CryptoAuthLib release. + * The format of the version string returned is "yyyymmdd" + * \param[out] ver_str ptr to space to receive version string + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_version(char *ver_str) +{ + strcpy(ver_str, atca_version); + return ATCA_SUCCESS; +} + + +/** \brief Creates and initializes a ATCADevice context + * \param[out] device Pointer to the device context pointer + * \param[in] cfg Logical interface configuration. Some predefined + * configurations can be found in atca_cfgs.h + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_init_ext(ATCADevice* device, ATCAIfaceCfg *cfg) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + if (device) + { + // If a device has already been initialized, release it + if (*device) + { + atcab_release_ext(device); + } + +#ifdef ATCA_NO_HEAP + g_atcab_device.mIface = g_atcab_iface; + status = initATCADevice(cfg, &g_atcab_device); + if (status != ATCA_SUCCESS) + { + return status; + } + *device = &g_atcab_device; +#else + *device = newATCADevice(cfg); + if (*device == NULL) + { + return ATCA_GEN_FAIL; + } +#endif + +#ifdef ATCA_ATECC608_SUPPORT + if (cfg->devtype == ATECC608) + { + if ((status = calib_read_bytes_zone(*device, ATCA_ZONE_CONFIG, 0, ATCA_CHIPMODE_OFFSET, &(*device)->clock_divider, 1)) != ATCA_SUCCESS) + { + return status; + } + (*device)->clock_divider &= ATCA_CHIPMODE_CLOCK_DIV_MASK; + } +#endif + +#ifdef ATCA_ECC204_SUPPORT + /* To compatible with kitprotocol firmware on otherside */ + /* On kitprotocol firmware, during discovery time itself ECC204 would have woke up */ + if ((ECC204 == cfg->devtype) && (atca_iface_is_kit(atGetIFace(*device)))) + { + (*device)->device_state = ATCA_DEVICE_STATE_ACTIVE; + } +#endif + + } + + return ATCA_SUCCESS; +} + +/** \brief Creates a global ATCADevice object used by Basic API. + * \param[in] cfg Logical interface configuration. Some predefined + * configurations can be found in atca_cfgs.h + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_init(ATCAIfaceCfg* cfg) +{ + return atcab_init_ext(&_gDevice, cfg); +} + +/** \brief Initialize the global ATCADevice object to point to one of your + * choosing for use with all the atcab_ basic API. + * + * \deprecated This function is not recommended for use generally. Use of _ext + * is recommended instead. You can use atcab_init_ext to obtain an initialized + * instance and associated it with the global structure - but this shouldn't be + * a required process except in extremely unusual circumstances. + * + * \param[in] ca_device ATCADevice instance to use as the global Basic API + * crypto device instance + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_init_device(ATCADevice ca_device) +{ + if (ca_device == NULL) + { + return ATCA_BAD_PARAM; + } + + // if there's already a device created, release it + if (_gDevice) + { + atcab_release(); + } + + _gDevice = ca_device; + + return ATCA_SUCCESS; +} + +/** \brief release (free) the an ATCADevice instance. + * \param[in] device Pointer to the device context pointer + * \return Returns ATCA_SUCCESS . + */ +ATCA_STATUS atcab_release_ext(ATCADevice* device) +{ +#ifdef ATCA_NO_HEAP + ATCA_STATUS status = releaseATCADevice(*device); + if (status != ATCA_SUCCESS) + { + return status; + } + *device = NULL; +#else + deleteATCADevice(device); +#endif + return ATCA_SUCCESS; +} + +/** \brief release (free) the global ATCADevice instance. + * This must be called in order to release or free up the interface. + * \return Returns ATCA_SUCCESS . + */ +ATCA_STATUS atcab_release(void) +{ + return atcab_release_ext(&_gDevice); +} + +/** \brief Get the global device object. + * \return instance of global ATCADevice + */ +ATCADevice atcab_get_device(void) +{ + return _gDevice; +} + +/** \brief Get the selected device type of rthe device context + * + * \param[in] device Device context pointer + * \return Device type if basic api is initialized or ATCA_DEV_UNKNOWN. + */ +ATCADeviceType atcab_get_device_type_ext(ATCADevice device) +{ + ATCADeviceType ret = ATCA_DEV_UNKNOWN; + + if (device && device->mIface.mIfaceCFG) + { + ret = device->mIface.mIfaceCFG->devtype; + } + return ret; +} + +/** \brief Get the current device type configured for the global ATCADevice + * \return Device type if basic api is initialized or ATCA_DEV_UNKNOWN. + */ +ATCADeviceType atcab_get_device_type(void) +{ + return atcab_get_device_type_ext(_gDevice); +} + +/** \brief Get the current device address based on the configured device + * and interface + * \return the device address if applicable else 0xFF + */ +uint8_t atcab_get_device_address(ATCADevice device) +{ + if (device && device->mIface.mIfaceCFG) + { + switch (device->mIface.mIfaceCFG->iface_type) + { + case ATCA_I2C_IFACE: +#ifdef ATCA_ENABLE_DEPRECATED + return device->mIface.mIfaceCFG->atcai2c.slave_address; +#else + return device->mIface.mIfaceCFG->atcai2c.address; +#endif + default: + break; + } + } + return 0xFF; +} + + +/** \brief Check whether the device is cryptoauth device + * \return True if device is cryptoauth device or False. + */ +bool atcab_is_ca_device(ATCADeviceType dev_type) +{ + return (dev_type < TA100) ? true : false; +} + +/** \brief Check whether the device is Trust Anchor device + * \return True if device is Trust Anchor device or False. + */ +bool atcab_is_ta_device(ATCADeviceType dev_type) +{ + return (dev_type == TA100) ? true : false; +} + +#if (ATCA_CA_SUPPORT && ATCA_TA_SUPPORT) || defined(ATCA_USE_ATCAB_FUNCTIONS) || defined(ATCA_ECC204_SUPPORT) + +/** \brief wakeup the CryptoAuth device + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_wakeup(void) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_wakeup(_gDevice); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = ATCA_SUCCESS; +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief idle the CryptoAuth device + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_idle(void) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_idle(_gDevice); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = ATCA_SUCCESS; +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief invoke sleep on the CryptoAuth device + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sleep(void) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sleep(_gDevice); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = ATCA_SUCCESS; +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + + return status; +} + +/** \brief Gets the size of the specified zone in bytes. + * + * \param[in] zone Zone to get size information from. Config(0), OTP(1), or + * Data(2) which requires a slot. + * \param[in] slot If zone is Data(2), the slot to query for size. + * \param[out] size Zone size is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_get_zone_size(uint8_t zone, uint16_t slot, size_t* size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_get_zone_size(_gDevice, zone, slot, size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_get_zone_size(_gDevice, zone, slot, size); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* AES commands */ +/** \brief Compute the AES-128 encrypt, decrypt, or GFM calculation. + * \param[in] mode The mode for the AES command. + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] aes_in Input data to the AES command (16 bytes). + * \param[out] aes_out Output data from the AES command is returned here (16 + * bytes). + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes(uint8_t mode, uint16_t key_id, const uint8_t* aes_in, uint8_t* aes_out) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if defined(ATCA_ATECC608_SUPPORT) + status = calib_aes(_gDevice, mode, key_id, aes_in, aes_out); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Perform an AES-128 encrypt operation with a key in the device. + * + * \param[in] device Device context pointer + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] key_block Index of the 16-byte block to use within the key + * location for the actual key. + * \param[in] plaintext Input plaintext to be encrypted (16 bytes). + * \param[out] ciphertext Output ciphertext is returned here (16 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_encrypt_ext(ATCADevice device, uint16_t key_id, uint8_t key_block, const uint8_t* plaintext, uint8_t* ciphertext) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if defined(ATCA_ATECC608_SUPPORT) + status = calib_aes_encrypt(device, key_id, key_block, plaintext, ciphertext); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_aes_encrypt(device, key_id, key_block, plaintext, ciphertext); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Perform an AES-128 encrypt operation with a key in the device. + * + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] key_block Index of the 16-byte block to use within the key + * location for the actual key. + * \param[in] plaintext Input plaintext to be encrypted (16 bytes). + * \param[out] ciphertext Output ciphertext is returned here (16 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_encrypt(uint16_t key_id, uint8_t key_block, const uint8_t* plaintext, uint8_t* ciphertext) +{ + return atcab_aes_encrypt_ext(_gDevice, key_id, key_block, plaintext, ciphertext); +} + +/** \brief Perform an AES-128 decrypt operation with a key in the device. + * + * \param[in] device Device context pointer + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] key_block Index of the 16-byte block to use within the key + * location for the actual key. + * \param[in] ciphertext Input ciphertext to be decrypted (16 bytes). + * \param[out] plaintext Output plaintext is returned here (16 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_decrypt_ext(ATCADevice device, uint16_t key_id, uint8_t key_block, const uint8_t* ciphertext, uint8_t* plaintext) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if defined(ATCA_ATECC608_SUPPORT) + status = calib_aes_decrypt(device, key_id, key_block, ciphertext, plaintext); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_aes_decrypt(device, key_id, key_block, ciphertext, plaintext); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Perform an AES-128 decrypt operation with a key in the device. + * + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] key_block Index of the 16-byte block to use within the key + * location for the actual key. + * \param[in] ciphertext Input ciphertext to be decrypted (16 bytes). + * \param[out] plaintext Output plaintext is returned here (16 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_decrypt(uint16_t key_id, uint8_t key_block, const uint8_t* ciphertext, uint8_t* plaintext) +{ + return atcab_aes_decrypt_ext(_gDevice, key_id, key_block, ciphertext, plaintext); +} + +/** \brief Perform a Galois Field Multiply (GFM) operation. + * + * \param[in] h First input value (16 bytes). + * \param[in] input Second input value (16 bytes). + * \param[out] output GFM result is returned here (16 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gfm(const uint8_t* h, const uint8_t* input, uint8_t* output) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if defined(ATCA_ATECC608_SUPPORT) + status = calib_aes_gfm(_gDevice, h, input, output); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Initialize context for AES GCM operation with an existing IV, which + * is common when starting a decrypt operation. + * + * \param[in] ctx AES GCM context to be initialized. + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] key_block Index of the 16-byte block to use within the key + * location for the actual key. + * \param[in] iv Initialization vector. + * \param[in] iv_size Size of IV in bytes. Standard is 12 bytes. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_init(atca_aes_gcm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, const uint8_t* iv, size_t iv_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_init(_gDevice, ctx, key_id, key_block, iv, iv_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Initialize context for AES GCM operation with a IV composed of a + * random and optional fixed(free) field, which is common when + * starting an encrypt operation. + * + * \param[in] ctx AES CTR context to be initialized. + * \param[in] key_id Key location. Can either be a slot number or + * ATCA_TEMPKEY_KEYID for TempKey. + * \param[in] key_block Index of the 16-byte block to use within the + * key location for the actual key. + * \param[in] rand_size Size of the random field in bytes. Minimum and + * recommended size is 12 bytes. Max is 32 bytes. + * \param[in] free_field Fixed data to include in the IV after the + * random field. Can be NULL if not used. + * \param[in] free_field_size Size of the free field in bytes. + * \param[out] iv Initialization vector is returned here. Its + * size will be rand_size and free_field_size + * combined. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_init_rand(atca_aes_gcm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, size_t rand_size, + const uint8_t* free_field, size_t free_field_size, uint8_t* iv) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_init_rand(_gDevice, ctx, key_id, key_block, rand_size, free_field, free_field_size, iv); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Process Additional Authenticated Data (AAD) using GCM mode and a + * key within the ATECC608 device. + * + * This can be called multiple times. atcab_aes_gcm_init() or + * atcab_aes_gcm_init_rand() should be called before the first use of this + * function. When there is AAD to include, this should be called before + * atcab_aes_gcm_encrypt_update() or atcab_aes_gcm_decrypt_update(). + * + * \param[in] ctx AES GCM context + * \param[in] aad Additional authenticated data to be added + * \param[in] aad_size Size of aad in bytes + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_aad_update(atca_aes_gcm_ctx_t* ctx, const uint8_t* aad, uint32_t aad_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_aad_update(_gDevice, ctx, aad, aad_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Encrypt data using GCM mode and a key within the ATECC608 device. + * atcab_aes_gcm_init() or atcab_aes_gcm_init_rand() should be called + * before the first use of this function. + * + * \param[in] ctx AES GCM context structure. + * \param[in] plaintext Plaintext to be encrypted (16 bytes). + * \param[in] plaintext_size Size of plaintext in bytes. + * \param[out] ciphertext Encrypted data is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_encrypt_update(atca_aes_gcm_ctx_t* ctx, const uint8_t* plaintext, uint32_t plaintext_size, uint8_t* ciphertext) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_encrypt_update(_gDevice, ctx, plaintext, plaintext_size, ciphertext); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Complete a GCM encrypt operation returning the authentication tag. + * + * \param[in] ctx AES GCM context structure. + * \param[out] tag Authentication tag is returned here. + * \param[in] tag_size Tag size in bytes (12 to 16 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_encrypt_finish(atca_aes_gcm_ctx_t* ctx, uint8_t* tag, size_t tag_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_encrypt_finish(_gDevice, ctx, tag, tag_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Decrypt data using GCM mode and a key within the ATECC608 device. + * atcab_aes_gcm_init() or atcab_aes_gcm_init_rand() should be called + * before the first use of this function. + * + * \param[in] ctx AES GCM context structure. + * \param[in] ciphertext Ciphertext to be decrypted. + * \param[in] ciphertext_size Size of ciphertext in bytes. + * \param[out] plaintext Decrypted data is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_decrypt_update(atca_aes_gcm_ctx_t* ctx, const uint8_t* ciphertext, uint32_t ciphertext_size, uint8_t* plaintext) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_decrypt_update(_gDevice, ctx, ciphertext, ciphertext_size, plaintext); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Complete a GCM decrypt operation verifying the authentication tag. + * + * \param[in] ctx AES GCM context structure. + * \param[in] tag Expected authentication tag. + * \param[in] tag_size Size of tag in bytes (12 to 16 bytes). + * \param[out] is_verified Returns whether or not the tag verified. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_aes_gcm_decrypt_finish(atca_aes_gcm_ctx_t* ctx, const uint8_t* tag, size_t tag_size, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_aes_gcm_decrypt_finish(_gDevice, ctx, tag, tag_size, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* CheckMAC command */ + +/** \brief Compares a MAC response with input values + * \param[in] mode Controls which fields within the device are used in + * the message + * \param[in] key_id Key location in the CryptoAuth device to use for the + * MAC + * \param[in] challenge Challenge data (32 bytes) + * \param[in] response MAC response data (32 bytes) + * \param[in] other_data OtherData parameter (13 bytes) + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_checkmac(uint8_t mode, uint16_t key_id, const uint8_t* challenge, const uint8_t* response, const uint8_t* other_data) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_checkmac(_gDevice, mode, key_id, challenge, response, other_data); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* Counter command */ + +/** \brief Compute the Counter functions + * \param[in] mode the mode used for the counter + * \param[in] counter_id The counter to be used + * \param[out] counter_value pointer to the counter value returned from device + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_counter(uint8_t mode, uint16_t counter_id, uint32_t* counter_value) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_counter(_gDevice, mode, counter_id, counter_value); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_counter(_gDevice, mode, counter_id, counter_value); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Increments one of the device's monotonic counters + * \param[in] counter_id Counter to be incremented + * \param[out] counter_value New value of the counter is returned here. Can be + * NULL if not needed. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_counter_increment(uint16_t counter_id, uint32_t* counter_value) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_counter_increment(_gDevice, counter_id, counter_value); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_counter_increment(_gDevice, counter_id, counter_value); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Read one of the device's monotonic counters + * \param[in] counter_id Counter to be read + * \param[out] counter_value Counter value is returned here. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_counter_read(uint16_t counter_id, uint32_t* counter_value) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_counter_read(_gDevice, counter_id, counter_value); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_counter_read(_gDevice, counter_id, counter_value); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* DeriveKey command */ + +/** \brief Executes the DeviveKey command for deriving a new key from a + * nonce (TempKey) and an existing key. + * + * \param[in] mode Bit 2 must match the value in TempKey.SourceFlag + * \param[in] key_id Key slot to be written + * \param[in] mac Optional 32 byte MAC used to validate operation. NULL + * if not required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_derivekey(uint8_t mode, uint16_t key_id, const uint8_t* mac) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_derivekey(_gDevice, mode, key_id, mac); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* ECDH command */ + +/** \brief Base function for generating premaster secret key using ECDH. + * \param[in] mode Mode to be used for ECDH computation + * \param[in] key_id Slot of key for ECDH computation + * \param[in] public_key Public key input to ECDH calculation. X and Y + * integers in big-endian format. 64 bytes for P256 + * key. + * \param[out] pms Computed ECDH pre-master secret is returned here (32 + * bytes) if returned directly. Otherwise NULL. + * \param[out] out_nonce Nonce used to encrypt pre-master secret. NULL if + * output encryption not used. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_ecdh_base(uint8_t mode, uint16_t key_id, const uint8_t* public_key, uint8_t* pms, uint8_t* out_nonce) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_ecdh_base(_gDevice, mode, key_id, public_key, pms, out_nonce); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief ECDH command with a private key in a slot and the premaster secret + * is returned in the clear. + * + * \param[in] key_id Slot of private key for ECDH computation + * \param[in] public_key Public key input to ECDH calculation. X and Y + * integers in big-endian format. 64 bytes for P256 + * key. + * \param[out] pms Computed ECDH premaster secret is returned here. + * 32 bytes. + * + * \return ATCA_SUCCESS on success + */ +ATCA_STATUS atcab_ecdh(uint16_t key_id, const uint8_t* public_key, uint8_t* pms) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_ecdh(_gDevice, key_id, public_key, pms); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_ecdh_compat(_gDevice, key_id, public_key, pms); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief ECDH command with a private key in a slot and the premaster secret + * is read from the next slot. + * + * This function only works for even numbered slots with the proper + * configuration. + * + * \param[in] key_id Slot of key for ECDH computation + * \param[in] public_key Public key input to ECDH calculation. X and Y + * integers in big-endian format. 64 bytes for P256 + * key. + * \param[out] pms Computed ECDH premaster secret is returned here + * (32 bytes). + * \param[in] read_key Read key for the premaster secret slot (key_id|1). + * \param[in] read_key_id Read key slot for read_key. + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_ecdh_enc(uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* read_key, uint16_t read_key_id) +#else +ATCA_STATUS atcab_ecdh_enc(uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* read_key, uint16_t read_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]) +#endif +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT +#ifdef ATCA_USE_CONSTANT_HOST_NONCE + status = calib_ecdh_enc(_gDevice, key_id, public_key, pms, read_key, read_key_id); +#else + status = calib_ecdh_enc(_gDevice, key_id, public_key, pms, read_key, read_key_id, num_in); +#endif +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief ECDH command with a private key in a slot and the premaster secret + * is returned encrypted using the IO protection key. + * + * \param[in] key_id Slot of key for ECDH computation + * \param[in] public_key Public key input to ECDH calculation. X and Y + * integers in big-endian format. 64 bytes for P256 + * key. + * \param[out] pms Computed ECDH premaster secret is returned here + * (32 bytes). + * \param[in] io_key IO protection key. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_ecdh_ioenc(uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* io_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ATECC608_SUPPORT + status = calib_ecdh_ioenc(_gDevice, key_id, public_key, pms, io_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief ECDH command with a private key in TempKey and the premaster secret + * is returned in the clear. + * + * \param[in] public_key Public key input to ECDH calculation. X and Y + * integers in big-endian format. 64 bytes for P256 + * key. + * \param[out] pms Computed ECDH premaster secret is returned here + * (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_ecdh_tempkey(const uint8_t* public_key, uint8_t* pms) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ATECC608_SUPPORT + status = calib_ecdh_tempkey(_gDevice, public_key, pms); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief ECDH command with a private key in TempKey and the premaster secret + * is returned encrypted using the IO protection key. + * + * \param[in] public_key Public key input to ECDH calculation. X and Y + * integers in big-endian format. 64 bytes for P256 + * key. + * \param[out] pms Computed ECDH premaster secret is returned here + * (32 bytes). + * \param[in] io_key IO protection key. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_ecdh_tempkey_ioenc(const uint8_t* public_key, uint8_t* pms, const uint8_t* io_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ATECC608_SUPPORT + status = calib_ecdh_tempkey_ioenc(_gDevice, public_key, pms, io_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* GenDig command */ + +/** \brief Issues a GenDig command, which performs a SHA256 hash on the source data indicated by zone with the + * contents of TempKey. See the CryptoAuth datasheet for your chip to see what the values of zone + * correspond to. + * \param[in] zone Designates the source of the data to hash with TempKey. + * \param[in] key_id Indicates the key, OTP block, or message order for shared nonce mode. + * \param[in] other_data Four bytes of data for SHA calculation when using a NoMac key, 32 bytes for + * "Shared Nonce" mode, otherwise ignored (can be NULL). + * \param[in] other_data_size Size of other_data in bytes. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_gendig(uint8_t zone, uint16_t key_id, const uint8_t* other_data, uint8_t other_data_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_gendig(_gDevice, zone, key_id, other_data, other_data_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* GenKey command */ + +/** \brief Issues GenKey command, which can generate a private key, compute a + * public key, nd/or compute a digest of a public key. + * + * \param[in] mode Mode determines what operations the GenKey + * command performs. + * \param[in] key_id Slot to perform the GenKey command on. + * \param[in] other_data OtherData for PubKey digest calculation. Can be set + * to NULL otherwise. + * \param[out] public_key If the mode indicates a public key will be + * calculated, it will be returned here. Format will + * be the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_genkey_base(uint8_t mode, uint16_t key_id, const uint8_t* other_data, uint8_t* public_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_genkey_base(_gDevice, mode, key_id, other_data, public_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Issues GenKey command, which generates a new random private key in + * slot/handle and returns the public key. + * + * \param[in] key_id Slot number where an ECC private key is configured. + * Can also be ATCA_TEMPKEY_KEYID to generate a private + * key in TempKey. + * \param[out] public_key Public key will be returned here. Format will be + * the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_genkey(uint16_t key_id, uint8_t* public_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_genkey(_gDevice, key_id, public_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_genkey_compat(_gDevice, key_id, public_key); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Uses GenKey command to calculate the public key from an existing + * private key in a slot. + * + * \param[in] key_id Slot number of the private key. + * \param[out] public_key Public key will be returned here. Format will be + * the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_get_pubkey_ext(ATCADevice device, uint16_t key_id, uint8_t* public_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_get_pubkey(device, key_id, public_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_get_pubkey_compat(device, key_id, public_key); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Uses GenKey command to calculate the public key from an existing + * private key in a slot. + * + * \param[in] key_id Slot number of the private key. + * \param[out] public_key Public key will be returned here. Format will be + * the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_get_pubkey(uint16_t key_id, uint8_t* public_key) +{ + return atcab_get_pubkey_ext(_gDevice, key_id, public_key); +} + +// HMAC command functions + +/** \brief Issues a HMAC command, which computes an HMAC/SHA-256 digest of a + * key stored in the device, a challenge, and other information on the + * device. + * + * \param[in] mode Controls which fields within the device are used in the + * message. + * \param[in] key_id Which key is to be used to generate the response. + * Bits 0:3 only are used to select a slot but all 16 bits + * are used in the HMAC message. + * \param[out] digest HMAC digest is returned in this buffer (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_hmac(uint8_t mode, uint16_t key_id, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if defined(ATCA_ATSHA204A_SUPPORT) || defined(ATCA_ATECC508A_SUPPORT) + status = calib_hmac(_gDevice, mode, key_id, digest); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// Info command functions + +/** \brief Issues an Info command, which return internal device information and + * can control GPIO and the persistent latch. + * + * \param[in] mode Selects which mode to be used for info command. + * \param[in] param2 Selects the particular fields for the mode. + * \param[out] out_data Response from info command (4 bytes). Can be set to + * NULL if not required. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_info_base(uint8_t mode, uint16_t param2, uint8_t* out_data) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_info_base(_gDevice, mode, param2, out_data); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Use the Info command to get the device revision (DevRev). + * \param[out] revision Device revision is returned here (4 bytes). + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_info(uint8_t* revision) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_info(_gDevice, revision); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_info_compat(_gDevice, revision); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Use the Info command to set the persistent latch state for an + * ATECC608 device. + * + * \param[out] state Persistent latch state. Set (true) or clear (false). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_info_set_latch(bool state) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_info_set_latch(_gDevice, state); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Use the Info command to get the persistent latch current state for + * an ATECC608 device. + * + * \param[out] state The state is returned here. Set (true) or Cler (false). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_info_get_latch(bool* state) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_info_get_latch(_gDevice, state); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// KDF command functions + +/** \brief Executes the KDF command, which derives a new key in PRF, AES, or + * HKDF modes. + * + * Generally this function combines a source key with an input string and + * creates a result key/digest/array. + * + * \param[in] mode Mode determines KDF algorithm (PRF,AES,HKDF), source + * key location, and target key locations. + * \param[in] key_id Source and target key slots if locations are in the + * EEPROM. Source key slot is the LSB and target key + * slot is the MSB. + * \param[in] details Further information about the computation, depending + * on the algorithm (4 bytes). + * \param[in] message Input value from system (up to 128 bytes). Actual size + * of message is 16 bytes for AES algorithm or is encoded + * in the MSB of the details parameter for other + * algorithms. + * \param[out] out_data Output of the KDF function is returned here. If the + * result remains in the device, this can be NULL. + * \param[out] out_nonce If the output is encrypted, a 32 byte random nonce + * generated by the device is returned here. If output + * encryption is not used, this can be NULL. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_kdf(uint8_t mode, uint16_t key_id, const uint32_t details, const uint8_t* message, uint8_t* out_data, uint8_t* out_nonce) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_kdf(_gDevice, mode, key_id, details, message, out_data, out_nonce); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* Lock commands */ + +/** \brief The Lock command prevents future modifications of the Configuration + * and/or Data and OTP zones. If the device is so configured, then + * this command can be used to lock individual data slots. This + * command fails if the designated area is already locked. + * + * \param[in] mode Zone, and/or slot, and summary check (bit 7). + * \param[in] summary_crc CRC of the config or data zones. Ignored for + * slot locks or when mode bit 7 is set. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_lock(uint8_t mode, uint16_t summary_crc) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_lock(_gDevice, mode, summary_crc); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Unconditionally (no CRC required) lock the config zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_lock_config_zone(void) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_lock_config_zone(_gDevice); +#endif + } + else + { + status = calib_lock_config_zone(_gDevice); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_lock_config(_gDevice); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Lock the config zone with summary CRC. + * + * The CRC is calculated over the entire config zone contents. 48 bytes for TA100, + * 88 bytes for ATSHA devices, 128 bytes for ATECC devices. Lock will fail if the provided + * CRC doesn't match the internally calculated one. + * + * \param[in] summary_crc Expected CRC over the config zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_lock_config_zone_crc(uint16_t summary_crc) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = ATCA_UNIMPLEMENTED; +#endif + } + else + { + status = calib_lock_config_zone_crc(_gDevice, summary_crc); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_lock_config_with_crc(_gDevice, summary_crc); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Unconditionally (no CRC required) lock the data zone (slots and OTP). + * for CryptoAuth devices and lock the setup for Trust Anchor device. + * + * ConfigZone must be locked and DataZone must be unlocked for the zone to be successfully locked. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_lock_data_zone(void) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_lock_data_zone(_gDevice); +#endif + } + else + { + status = calib_lock_data_zone(_gDevice); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_lock_setup(_gDevice); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Lock the data zone (slots and OTP) with summary CRC. + * + * The CRC is calculated over the concatenated contents of all the slots and + * OTP at the end. Private keys (KeyConfig.Private=1) are skipped. Lock will + * fail if the provided CRC doesn't match the internally calculated one. + * + * \param[in] summary_crc Expected CRC over the data zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_lock_data_zone_crc(uint16_t summary_crc) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = ATCA_UNIMPLEMENTED; +#endif + } + else + { + status = calib_lock_data_zone_crc(_gDevice, summary_crc); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Lock an individual slot in the data zone on an ATECC device. Not + * available for ATSHA devices. Slot must be configured to be slot + * lockable (KeyConfig.Lockable=1) (for cryptoauth devices) or Lock + * an individual handle in shared data element on an Trust Anchor device + * (for Trust Anchor devices). + * + * \param[in] slot Slot to be locked in data zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_lock_data_slot(uint16_t slot) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_lock_data_slot(_gDevice, slot); +#endif + } + else + { + status = calib_lock_data_slot(_gDevice, slot); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_lock_handle(_gDevice, slot); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// MAC command functions + +/** \brief Executes MAC command, which computes a SHA-256 digest of a key + * stored in the device, a challenge, and other information on the + * device. + * + * \param[in] mode Controls which fields within the device are used in + * the message + * \param[in] key_id Key in the CryptoAuth device to use for the MAC + * \param[in] challenge Challenge message (32 bytes). May be NULL if mode + * indicates a challenge isn't required. + * \param[out] digest MAC response is returned here (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_mac(uint8_t mode, uint16_t key_id, const uint8_t* challenge, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_mac(_gDevice, mode, key_id, challenge, digest); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// Nonce command functions + +/** \brief Executes Nonce command, which loads a random or fixed nonce/data + * into the device for use by subsequent commands. + * + * \param[in] mode Controls the mechanism of the internal RNG or fixed + * write. + * \param[in] zero Param2, normally 0, but can be used to indicate a + * nonce calculation mode (bit 15). + * \param[in] num_in Input value to either be included in the nonce + * calculation in random modes (20 bytes) or to be + * written directly (32 bytes or 64 bytes(ATECC608)) + * in pass-through mode. + * \param[out] rand_out If using a random mode, the internally generated + * 32-byte random number that was used in the nonce + * calculation is returned here. Can be NULL if not + * needed. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_nonce_base(uint8_t mode, uint16_t zero, const uint8_t* num_in, uint8_t* rand_out) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_nonce_base(_gDevice, mode, zero, num_in, rand_out); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Execute a Nonce command in pass-through mode to initialize TempKey + * to a specified value. + * + * \param[in] num_in Data to be loaded into TempKey (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_nonce(const uint8_t* num_in) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_nonce(_gDevice, num_in); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Execute a Nonce command in pass-through mode to load one of the + * device's internal buffers with a fixed value. + * + * For the ATECC608, available targets are TempKey (32 or 64 bytes), Message + * Digest Buffer (32 or 64 bytes), or the Alternate Key Buffer (32 bytes). For + * all other devices, only TempKey (32 bytes) is available. + * + * \param[in] target Target device buffer to load. Can be + * NONCE_MODE_TARGET_TEMPKEY, + * NONCE_MODE_TARGET_MSGDIGBUF, or + * NONCE_MODE_TARGET_ALTKEYBUF. + * \param[in] num_in Data to load into the buffer. + * \param[in] num_in_size Size of num_in in bytes. Can be 32 or 64 bytes + * depending on device and target. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_nonce_load(uint8_t target, const uint8_t* num_in, uint16_t num_in_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_nonce_load(_gDevice, target, num_in, num_in_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Execute a Nonce command to generate a random nonce combining a host + * nonce (num_in) and a device random number. + * + * \param[in] num_in Host nonce to be combined with the device random + * number (20 bytes). + * \param[out] rand_out Internally generated 32-byte random number that was + * used in the nonce/challenge calculation is returned + * here. Can be NULL if not needed. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_nonce_rand(const uint8_t* num_in, uint8_t* rand_out) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_nonce_rand(_gDevice, num_in, rand_out); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Execute a Nonce command in pass-through mode to initialize TempKey + * to a specified value. + * + * \param[in] num_in Data to be loaded into TempKey (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_challenge(const uint8_t* num_in) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_challenge(_gDevice, num_in); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Execute a Nonce command to generate a random challenge combining + * a host nonce (num_in) and a device random number. + * + * \param[in] num_in Host nonce to be combined with the device random + * number (20 bytes). + * \param[out] rand_out Internally generated 32-byte random number that was + * used in the nonce/challenge calculation is returned + * here. Can be NULL if not needed. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_challenge_seed_update(const uint8_t* num_in, uint8_t* rand_out) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_challenge_seed_update(_gDevice, num_in, rand_out); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// PrivWrite command functions + +/** \brief Executes PrivWrite command, to write externally generated ECC + * private keys into the device. + * + * \param[in] key_id Slot to write the external private key into. + * \param[in] priv_key External private key (36 bytes) to be written. + * The first 4 bytes should be zero for P256 curve. + * \param[in] write_key_id Write key slot. Ignored if write_key is NULL. + * \param[in] write_key Write key (32 bytes). If NULL, perform an + * unencrypted PrivWrite, which is only available when + * the data zone is unlocked. + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_priv_write(uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32]) +#else +ATCA_STATUS atcab_priv_write(uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32], const uint8_t num_in[NONCE_NUMIN_SIZE]) +#endif +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT +#ifdef ATCA_USE_CONSTANT_HOST_NONCE + status = calib_priv_write(_gDevice, key_id, priv_key, write_key_id, write_key); +#else + status = calib_priv_write(_gDevice, key_id, priv_key, write_key_id, write_key, num_in); +#endif /* ATCA_USE_CONSTANT_HOST_NONCE */ +#endif /* ATCA_ECC_SUPPORT */ + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// Random command functions + +/** \brief Executes Random command, which generates a 32 byte random number + * from the device. + * + * \param[in] device Device context pointer + * \param[out] rand_out 32 bytes of random data is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_random_ext(ATCADevice device, uint8_t* rand_out) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_random(device, rand_out); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_random_compat(device, rand_out); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + + +/** \brief Executes Random command, which generates a 32 byte random number + * from the device. + * + * \param[out] rand_out 32 bytes of random data is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_random(uint8_t* rand_out) +{ + return atcab_random_ext(_gDevice, rand_out); +} + +// Read command functions + +/** \brief Executes Read command, which reads either 4 or 32 bytes of data from + * a given slot, configuration zone, or the OTP zone. + * + * When reading a slot or OTP, data zone must be locked and the slot + * configuration must not be secret for a slot to be successfully read. + * + * \param[in] zone Zone to be read from device. Options are + * ATCA_ZONE_CONFIG, ATCA_ZONE_OTP, or ATCA_ZONE_DATA. + * \param[in] slot Slot number for data zone and ignored for other zones. + * \param[in] block 32 byte block index within the zone. + * \param[in] offset 4 byte work index within the block. Ignored for 32 byte + * reads. + * \param[out] data Read data is returned here. + * \param[in] len Length of the data to be read. Must be either 4 or 32. + * + * returns ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_zone(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint8_t* data, uint8_t len) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_read_zone(_gDevice, zone, slot, block, offset, data, len); +#endif + } + else + { + status = calib_read_zone(_gDevice, zone, slot, block, offset, data, len); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Read command, which reads the configuration zone to see if + * the specified zone is locked. + * + * \param[in] zone The zone to query for locked (use LOCK_ZONE_CONFIG or + * LOCK_ZONE_DATA). + * \param[out] is_locked Lock state returned here. True if locked. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_is_locked(uint8_t zone, bool* is_locked) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_is_locked(_gDevice, zone, is_locked); +#endif + } + else + { + status = calib_is_locked(_gDevice, zone, is_locked); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + if (LOCK_ZONE_CONFIG == zone) + { + status = talib_is_config_locked(_gDevice, is_locked); + } + else if (LOCK_ZONE_DATA == zone) + { + status = talib_is_setup_locked(_gDevice, is_locked); + } + else + { + status = ATCA_TRACE(ATCA_BAD_PARAM, ""); + } +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief This function check whether configuration zone is locked or not + * + * \param[out] is_locked Lock state returned here. True if locked. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_is_config_locked(bool* is_locked) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_is_locked(_gDevice, ATCA_ZONE_CONFIG, is_locked); +#endif + } + else + { + status = calib_is_locked(_gDevice, LOCK_ZONE_CONFIG, is_locked); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_is_config_locked(_gDevice, is_locked); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief This function check whether data/setup zone is locked or not + * + * \param[out] is_locked Lock state returned here. True if locked. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_is_data_locked(bool* is_locked) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_is_locked(_gDevice, ATCA_ZONE_DATA, is_locked); +#endif + } + else + { + status = calib_is_locked(_gDevice, LOCK_ZONE_DATA, is_locked); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_is_setup_locked(_gDevice, is_locked); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief This function check whether slot/handle is locked or not + * + * \param[in] slot Slot to query for locked + * \param[out] is_locked Lock state returned here. True if locked. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_is_slot_locked(uint16_t slot, bool* is_locked) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_is_slot_locked(_gDevice, slot, is_locked); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_is_handle_locked(_gDevice, slot, is_locked); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + + +/** \brief Check to see if the key is a private key or not + * + * This function will issue the Read command as many times as is required to + * read the requested data. + * + * \param[in] slot Slot number to read from if zone is ATCA_ZONE_DATA(2). + * Ignored for all other zones. + * \param[out] is_private Returned valud if successful. True if key is private. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_is_private_ext(ATCADevice device, uint16_t slot, bool* is_private) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_is_private(_gDevice, slot, is_private); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_is_private(_gDevice, slot, is_private); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +ATCA_STATUS atcab_is_private(uint16_t slot, bool* is_private) +{ + return atcab_is_private_ext(_gDevice, slot, is_private); +} + +/** \brief Used to read an arbitrary number of bytes from any zone configured + * for clear reads. + * + * This function will issue the Read command as many times as is required to + * read the requested data. + * + * \param[in] zone Zone to read data from. Option are ATCA_ZONE_CONFIG(0), + * ATCA_ZONE_OTP(1), or ATCA_ZONE_DATA(2). + * \param[in] slot Slot number to read from if zone is ATCA_ZONE_DATA(2). + * Ignored for all other zones. + * \param[in] offset Byte offset within the zone to read from. + * \param[out] data Read data is returned here. + * \param[in] length Number of bytes to read starting from the offset. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_bytes_zone(uint8_t zone, uint16_t slot, size_t offset, uint8_t* data, size_t length) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_read_bytes_zone(_gDevice, zone, slot, offset, data, length); +#endif + } + else + { + status = calib_read_bytes_zone(_gDevice, zone, slot, offset, data, length); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_read_bytes_zone(_gDevice, zone, slot, offset, data, length); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief This function returns serial number of the device. + * + * \param[out] serial_number 9 byte serial number is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_serial_number(uint8_t* serial_number) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_read_serial_number(_gDevice, serial_number); +#endif + } + else + { + status = calib_read_serial_number(_gDevice, serial_number); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_info_serial_number_compat(_gDevice, serial_number); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Read command to read an ECC P256 public key from a slot + * configured for clear reads. + * + * This function assumes the public key is stored using the ECC public key + * format specified in the datasheet. + * + * \param[in] device Device context pointer + * \param[in] slot Slot number to read from. Only slots 8 to 15 are + * large enough for a public key. + * \param[out] public_key Public key is returned here (64 bytes). Format will + * be the 32 byte X and Y big-endian integers + * concatenated. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_pubkey_ext(ATCADevice device, uint16_t slot, uint8_t* public_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_read_pubkey(_gDevice, slot, public_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_read_pubkey_compat(_gDevice, slot, public_key); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Read command to read an ECC P256 public key from a slot + * configured for clear reads. + * + * This function assumes the public key is stored using the ECC public key + * format specified in the datasheet. + * + * \param[in] slot Slot number to read from. Only slots 8 to 15 are + * large enough for a public key. + * \param[out] public_key Public key is returned here (64 bytes). Format will + * be the 32 byte X and Y big-endian integers + * concatenated. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_pubkey(uint16_t slot, uint8_t* public_key) +{ + return atcab_read_pubkey_ext(_gDevice, slot, public_key); +} + +/** \brief Executes Read command to read a 64 byte ECDSA P256 signature from a + * slot configured for clear reads. + * + * \param[in] slot Slot number to read from. Only slots 8 to 15 are large + * enough for a signature. + * \param[out] sig Signature will be returned here (64 bytes). Format will be + * the 32 byte R and S big-endian integers concatenated. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_sig(uint16_t slot, uint8_t* sig) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_read_sig(_gDevice, slot, sig); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_read_sig_compat(_gDevice, slot, sig); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Read command to read the complete device configuration + * zone. + * + * \param[out] config_data Configuration zone data is returned here. 88 bytes + * for ATSHA devices, 128 bytes for ATECC devices and + * 48 bytes for Trust Anchor devices. + * + * \returns ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_read_config_zone(uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_read_config_zone(_gDevice, config_data); +#endif + } + else + { + status = calib_read_config_zone(_gDevice, config_data); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_read_config_zone(_gDevice, config_data); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Compares a specified configuration zone with the configuration zone + * currently on the device. + * + * This only compares the static portions of the configuration zone and skips + * those that are unique per device (first 16 bytes) and areas that can change + * after the configuration zone has been locked (e.g. LastKeyUse). + * + * \param[in] config_data Full configuration data to compare the device + * against. + * \param[out] same_config Result is returned here. True if the static portions + * on the configuration zones are the same. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_cmp_config_zone(uint8_t* config_data, bool* same_config) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_cmp_config_zone(_gDevice, config_data, same_config); +#endif + } + else + { + status = calib_cmp_config_zone(_gDevice, config_data, same_config); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_cmp_config_zone(_gDevice, config_data, same_config); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Read command on a slot configured for encrypted reads and + * decrypts the data to return it as plaintext. + * + * Data zone must be locked for this command to succeed. Can only read 32 byte + * blocks. + * + * \param[in] key_id The slot ID to read from. + * \param[in] block Index of the 32 byte block within the slot to read. + * \param[out] data Decrypted (plaintext) data from the read is returned + * here (32 bytes). + * \param[in] enc_key 32 byte ReadKey for the slot being read. + * \param[in] enc_key_id KeyID of the ReadKey being used. + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * returns ATCA_SUCCESS on success, otherwise an error code. + */ +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_read_enc(uint16_t key_id, uint8_t block, uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id) +#else +ATCA_STATUS atcab_read_enc(uint16_t key_id, uint8_t block, uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]) +#endif +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) + status = calib_read_enc(_gDevice, key_id, block, data, enc_key, enc_key_id); +#else + status = calib_read_enc(_gDevice, key_id, block, data, enc_key, enc_key_id, num_in); +#endif +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +// SecureBoot command functions + +/** \brief Executes Secure Boot command, which provides support for secure + * boot of an external MCU or MPU. + * + * \param[in] mode Mode determines what operations the SecureBoot + * command performs. + * \param[in] param2 Not used, must be 0. + * \param[in] digest Digest of the code to be verified (32 bytes). + * \param[in] signature Signature of the code to be verified (64 bytes). Can + * be NULL when using the FullStore mode. + * \param[out] mac Validating MAC will be returned here (32 bytes). Can + * be NULL if not required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_secureboot(uint8_t mode, uint16_t param2, const uint8_t* digest, const uint8_t* signature, uint8_t* mac) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ATECC608_SUPPORT + status = calib_secureboot(_gDevice, mode, param2, digest, signature, mac); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Secure Boot command with encrypted digest and validated + * MAC response using the IO protection key. + * + * \param[in] mode Mode determines what operations the SecureBoot + * command performs. + * \param[in] digest Digest of the code to be verified (32 bytes). + * This is the plaintext digest (not encrypted). + * \param[in] signature Signature of the code to be verified (64 bytes). Can + * be NULL when using the FullStore mode. + * \param[in] num_in Host nonce (20 bytes). + * \param[in] io_key IO protection key (32 bytes). + * \param[out] is_verified Verify result is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_secureboot_mac(uint8_t mode, const uint8_t* digest, const uint8_t* signature, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ATECC608_SUPPORT + status = calib_secureboot_mac(_gDevice, mode, digest, signature, num_in, io_key, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* SelfTest Command */ + +/** \brief Executes the SelfTest command, which performs a test of one or more + * of the cryptographic engines within the ATECC608 chip. + * + * \param[in] mode Functions to test. Can be a bit field combining any + * of the following: SELFTEST_MODE_RNG, + * SELFTEST_MODE_ECDSA_VERIFY, SELFTEST_MODE_ECDSA_SIGN, + * SELFTEST_MODE_ECDH, SELFTEST_MODE_AES, + * SELFTEST_MODE_SHA, SELFTEST_MODE_ALL. + * \param[in] param2 Currently unused, should be 0. + * \param[out] result Results are returned here as a bit field. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_selftest(uint8_t mode, uint16_t param2, uint8_t* result) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ATECC608_SUPPORT + status = calib_selftest(_gDevice, mode, param2, result); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* SHA Command */ + +/** \brief Executes SHA command, which computes a SHA-256 or HMAC/SHA-256 + * digest for general purpose use by the host system. + * + * Only the Start(0) and Compute(1) modes are available for ATSHA devices. + * + * \param[in] mode SHA command mode Start(0), Update/Compute(1), + * End(2), Public(3), HMACstart(4), HMACend(5), + * Read_Context(6), or Write_Context(7). Also + * message digest target location for the + * ATECC608. + * \param[in] length Number of bytes in the message parameter or + * KeySlot for the HMAC key if Mode is + * HMACstart(4) or Public(3). + * \param[in] data_in Message bytes to be hashed or Write_Context if + * restoring a context on the ATECC608. Can be + * NULL if not required by the mode. + * \param[out] data_out Data returned by the command (digest or + * context). + * \param[in,out] data_out_size As input, the size of the data_out buffer. As + * output, the number of bytes returned in + * data_out. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_base(uint8_t mode, uint16_t length, const uint8_t* data_in, uint8_t* data_out, uint16_t* data_out_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_base(_gDevice, mode, length, data_in, data_out, data_out_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha_base_compat(_gDevice, mode, length, data_in, data_out, data_out_size); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to initialize SHA-256 calculation engine + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_start(void) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_start(_gDevice); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha_start(_gDevice); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to add 64 bytes of message data to the current + * context. + * + * \param[in] message 64 bytes of message data to add to add to operation. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_update(const uint8_t* message) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_update(_gDevice, message); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha_update_compat(_gDevice, message); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to complete SHA-256 or HMAC/SHA-256 operation. + * + * \param[out] digest Digest from SHA-256 or HMAC/SHA-256 will be returned + * here (32 bytes). + * \param[in] length Length of any remaining data to include in hash. Max 64 + * bytes. + * \param[in] message Remaining data to include in hash. NULL if length is 0. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_end(uint8_t* digest, uint16_t length, const uint8_t* message) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_end(_gDevice, digest, length, message); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha_end_compat(_gDevice, digest, length, message); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to read the SHA-256 context back. Only for + * ATECC608 with SHA-256 contexts. HMAC not supported. + * + * \param[out] context Context data is returned here. + * \param[in,out] context_size As input, the size of the context buffer in + * bytes. As output, the size of the returned + * context data. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_read_context(uint8_t* context, uint16_t* context_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_read_context(_gDevice, context, context_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha_read_context(_gDevice, context, context_size); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to write (restore) a SHA-256 context into the + * the device. Only supported for ATECC608 with SHA-256 contexts. + * + * \param[in] context Context data to be restored. + * \param[in] context_size Size of the context data in bytes. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_write_context(const uint8_t* context, uint16_t context_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_write_context(_gDevice, context, context_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha_write_context(_gDevice, context, context_size); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Use the SHA command to compute a SHA-256 digest. + * + * \param[in] length Size of message parameter in bytes. + * \param[in] message Message data to be hashed. + * \param[out] digest Digest is returned here (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha(uint16_t length, const uint8_t* message, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha(_gDevice, length, message, digest); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha(_gDevice, length, message, digest); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Use the SHA command to compute a SHA-256 digest. + * + * \param[in] data Message data to be hashed. + * \param[in] data_size Size of data in bytes. + * \param[out] digest Digest is returned here (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_hw_sha2_256(const uint8_t* data, size_t data_size, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_hw_sha2_256(_gDevice, data, data_size, digest); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sha(_gDevice, (uint16_t)data_size, data, digest); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Initialize a SHA context for performing a hardware SHA-256 operation + * on a device. Note that only one SHA operation can be run at a time. + * + * \param[in] ctx SHA256 context + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_hw_sha2_256_init(atca_sha256_ctx_t* ctx) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_hw_sha2_256_init(_gDevice, ctx); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Add message data to a SHA context for performing a hardware SHA-256 + * operation on a device. + * + * \param[in] ctx SHA256 context + * \param[in] data Message data to be added to hash. + * \param[in] data_size Size of data in bytes. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_hw_sha2_256_update(atca_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_hw_sha2_256_update(_gDevice, ctx, data, data_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Finish SHA-256 digest for a SHA context for performing a hardware + * SHA-256 operation on a device. + * + * \param[in] ctx SHA256 context + * \param[out] digest SHA256 digest is returned here (32 bytes) + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_hw_sha2_256_finish(atca_sha256_ctx_t* ctx, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_hw_sha2_256_finish(_gDevice, ctx, digest); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to start an HMAC/SHA-256 operation + * + * \param[in] ctx HMAC/SHA-256 context + * \param[in] key_slot Slot key id to use for the HMAC calculation + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_hmac_init(atca_hmac_sha256_ctx_t* ctx, uint16_t key_slot) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_hmac_init(_gDevice, ctx, key_slot); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to add an arbitrary amount of message data to + * a HMAC/SHA-256 operation. + * + * \param[in] ctx HMAC/SHA-256 context + * \param[in] data Message data to add + * \param[in] data_size Size of message data in bytes + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_hmac_update(atca_hmac_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_hmac_update(_gDevice, ctx, data, data_size); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes SHA command to complete a HMAC/SHA-256 operation. + * + * \param[in] ctx HMAC/SHA-256 context + * \param[out] digest HMAC/SHA-256 result is returned here (32 bytes). + * \param[in] target Where to save the digest internal to the device. + * For ATECC608, can be SHA_MODE_TARGET_TEMPKEY, + * SHA_MODE_TARGET_MSGDIGBUF, or SHA_MODE_TARGET_OUT_ONLY. + * For all other devices, SHA_MODE_TARGET_TEMPKEY is the + * only option. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_hmac_finish(atca_hmac_sha256_ctx_t* ctx, uint8_t* digest, uint8_t target) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_hmac_finish(_gDevice, ctx, digest, target); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + + + +/** \brief Use the SHA command to compute an HMAC/SHA-256 operation. + * + * \param[in] device Device context pointer + * \param[in] data Message data to be hashed. + * \param[in] data_size Size of data in bytes. + * \param[in] key_slot Slot key id to use for the HMAC calculation + * \param[out] digest Digest is returned here (32 bytes). + * \param[in] target Where to save the digest internal to the device. + * For ATECC608, can be SHA_MODE_TARGET_TEMPKEY, + * SHA_MODE_TARGET_MSGDIGBUF, or + * SHA_MODE_TARGET_OUT_ONLY. For all other devices, + * SHA_MODE_TARGET_TEMPKEY is the only option. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_hmac_ext(ATCADevice device, const uint8_t* data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_sha_hmac(device, data, data_size, key_slot, digest, target); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_hmac_compat(device, data, data_size, key_slot, digest, target); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Use the SHA command to compute an HMAC/SHA-256 operation. + * + * \param[in] data Message data to be hashed. + * \param[in] data_size Size of data in bytes. + * \param[in] key_slot Slot key id to use for the HMAC calculation + * \param[out] digest Digest is returned here (32 bytes). + * \param[in] target Where to save the digest internal to the device. + * For ATECC608, can be SHA_MODE_TARGET_TEMPKEY, + * SHA_MODE_TARGET_MSGDIGBUF, or + * SHA_MODE_TARGET_OUT_ONLY. For all other devices, + * SHA_MODE_TARGET_TEMPKEY is the only option. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sha_hmac(const uint8_t* data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target) +{ + return atcab_sha_hmac_ext(_gDevice, data, data_size, key_slot, digest, target); +} + + +/* Sign command */ + +/** \brief Executes the Sign command, which generates a signature using the + * ECDSA algorithm. + * + * \param[in] mode Mode determines what the source of the message to be + * signed. + * \param[in] key_id Private key slot used to sign the message. + * \param[out] signature Signature is returned here. Format is R and S + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sign_base(uint8_t mode, uint16_t key_id, uint8_t* signature) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_sign_base(_gDevice, mode, key_id, signature); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Sign command, to sign a 32-byte external message using the + * private key in the specified slot. The message to be signed + * will be loaded into the Message Digest Buffer to the + * ATECC608 device or TempKey for other devices. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot of the private key to be used to sign the + * message. + * \param[in] msg 32-byte message to be signed. Typically the SHA256 + * hash of the full message. + * \param[out] signature Signature will be returned here. Format is R and S + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sign_ext(ATCADevice device, uint16_t key_id, const uint8_t* msg, uint8_t* signature) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_sign(device, key_id, msg, signature); +#endif + } + else + { + status = calib_sign(device, key_id, msg, signature); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_sign_compat(device, key_id, msg, signature); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes Sign command, to sign a 32-byte external message using the + * private key in the specified slot. The message to be signed + * will be loaded into the Message Digest Buffer to the + * ATECC608 device or TempKey for other devices. + * + * \param[in] key_id Slot of the private key to be used to sign the + * message. + * \param[in] msg 32-byte message to be signed. Typically the SHA256 + * hash of the full message. + * \param[out] signature Signature will be returned here. Format is R and S + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sign(uint16_t key_id, const uint8_t* msg, uint8_t* signature) +{ + return atcab_sign_ext(_gDevice, key_id, msg, signature); +} + +/** \brief Executes Sign command to sign an internally generated message. + * + * \param[in] key_id Slot of the private key to be used to sign the + * message. + * \param[in] is_invalidate Set to true if the signature will be used with + * the Verify(Invalidate) command. false for all + * other cases. + * \param[in] is_full_sn Set to true if the message should incorporate + * the device's full serial number. + * \param[out] signature Signature is returned here. Format is R and S + * integers in big-endian format. 64 bytes for + * P256 curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_sign_internal(uint16_t key_id, bool is_invalidate, bool is_full_sn, uint8_t* signature) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_sign_internal(_gDevice, key_id, is_invalidate, is_full_sn, signature); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* UpdateExtra command */ + +/** \brief Executes UpdateExtra command to update the values of the two + * extra bytes within the Configuration zone (bytes 84 and 85). + * + * Can also be used to decrement the limited use counter associated with the + * key in slot NewValue. + * + * \param[in] mode Mode determines what operations the UpdateExtra + * command performs. + * \param[in] new_value Value to be written. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_updateextra(uint8_t mode, uint16_t new_value) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_updateextra(_gDevice, mode, new_value); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* Verify command */ + +/** \brief Executes the Verify command, which takes an ECDSA [R,S] signature + * and verifies that it is correctly generated from a given message and + * public key. In all cases, the signature is an input to the command. + * + * For the Stored, External, and ValidateExternal Modes, the contents of + * TempKey (or Message Digest Buffer in some cases for the ATECC608) should + * contain the 32 byte message. + * + * \param[in] mode Verify command mode and options + * \param[in] key_id Stored mode, the slot containing the public key to + * be used for the verification. + * ValidateExternal mode, the slot containing the + * public key to be validated. + * External mode, KeyID contains the curve type to be + * used to Verify the signature. + * Validate or Invalidate mode, the slot containing + * the public key to be (in)validated. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key If mode is External, the public key to be used for + * verification. X and Y integers in big-endian format. + * 64 bytes for P256 curve. NULL for all other modes. + * \param[in] other_data If mode is Validate, the bytes used to generate the + * message for the validation (19 bytes). NULL for all + * other modes. + * \param[out] mac If mode indicates a validating MAC, then the MAC will + * will be returned here. Can be NULL otherwise. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_verify(uint8_t mode, uint16_t key_id, const uint8_t* signature, const uint8_t* public_key, const uint8_t* other_data, uint8_t* mac) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify(_gDevice, mode, key_id, signature, public_key, other_data, mac); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Verify command, which verifies a signature (ECDSA + * verify operation) with all components (message, signature, and + * public key) supplied. The message to be signed will be loaded into + * the Message Digest Buffer to the ATECC608 device or TempKey for + * other devices. + * + * \param[in] device Device context pointer + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key The public key to be used for verification. X and + * Y integers in big-endian format. 64 bytes for + * P256 curve. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_extern_ext(ATCADevice device, const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify_extern(device, message, signature, public_key, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_verify_extern_compat(device, message, signature, public_key, is_verified); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Verify command, which verifies a signature (ECDSA + * verify operation) with all components (message, signature, and + * public key) supplied. The message to be signed will be loaded into + * the Message Digest Buffer to the ATECC608 device or TempKey for + * other devices. + * + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key The public key to be used for verification. X and + * Y integers in big-endian format. 64 bytes for + * P256 curve. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_extern(const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, bool* is_verified) +{ + return atcab_verify_extern_ext(_gDevice, message, signature, public_key, is_verified); +} + +/** \brief Executes the Verify command with verification MAC, which verifies a + * signature (ECDSA verify operation) with all components (message, + * signature, and public key) supplied. This function is only available + * on the ATECC608. + * + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key The public key to be used for verification. X and + * Y integers in big-endian format. 64 bytes for + * P256 curve. + * \param[in] num_in System nonce (32 byte) used for the verification + * MAC. + * \param[in] io_key IO protection key for verifying the validation MAC. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_extern_mac(const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify_extern_mac(_gDevice, message, signature, public_key, num_in, io_key, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Verify command, which verifies a signature (ECDSA + * verify operation) with a public key stored in the device. The + * message to be signed will be loaded into the Message Digest Buffer + * to the ATECC608 device or TempKey for other devices. + * + * \param[in] device Device context pointer + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] key_id Slot containing the public key to be used in the + * verification. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_stored_ext(ATCADevice device, const uint8_t* message, const uint8_t* signature, uint16_t key_id, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify_stored(device, message, signature, key_id, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_verify_stored_compat(device, message, signature, key_id, is_verified); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Verify command, which verifies a signature (ECDSA + * verify operation) with a public key stored in the device. The + * message to be signed will be loaded into the Message Digest Buffer + * to the ATECC608 device or TempKey for other devices. + * + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] key_id Slot containing the public key to be used in the + * verification. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_stored(const uint8_t* message, const uint8_t* signature, uint16_t key_id, bool* is_verified) +{ + return atcab_verify_stored_ext(_gDevice, message, signature, key_id, is_verified); +} + +/** \brief Executes the Verify command with verification MAC, which verifies a + * signature (ECDSA verify operation) with a public key stored in the + * device. This function is only available on the ATECC608. + * + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] key_id Slot containing the public key to be used in the + * verification. + * \param[in] num_in System nonce (32 byte) used for the verification + * MAC. + * \param[in] io_key IO protection key for verifying the validation MAC. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_stored_mac(const uint8_t* message, const uint8_t* signature, uint16_t key_id, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify_stored_mac(_gDevice, message, signature, key_id, num_in, io_key, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Verify command in Validate mode to validate a public + * key stored in a slot. + * + * This command can only be run after GenKey has been used to create a PubKey + * digest of the public key to be validated in TempKey (mode=0x10). + * + * \param[in] key_id Slot containing the public key to be validated. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] other_data 19 bytes of data used to build the verification + * message. + * \param[out] is_verified Boolean whether or not the message, signature, + * validation public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_validate(uint16_t key_id, const uint8_t* signature, const uint8_t* other_data, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify_validate(_gDevice, key_id, signature, other_data, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Verify command in Invalidate mode which invalidates a + * previously validated public key stored in a slot. + * + * This command can only be run after GenKey has been used to create a PubKey + * digest of the public key to be invalidated in TempKey (mode=0x10). + * + * \param[in] key_id Slot containing the public key to be invalidated. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] other_data 19 bytes of data used to build the verification + * message. + * \param[out] is_verified Boolean whether or not the message, signature, + * validation public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS atcab_verify_invalidate(uint16_t key_id, const uint8_t* signature, const uint8_t* other_data, bool* is_verified) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#ifdef ATCA_ECC_SUPPORT + status = calib_verify_invalidate(_gDevice, key_id, signature, other_data, is_verified); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/* Write command functions */ + +/** + * \brief Executes the Write command, which writes either one four byte word or + * a 32-byte block to one of the EEPROM zones on the device. Depending + * upon the value of the WriteConfig byte for this slot, the data may be + * required to be encrypted by the system prior to being sent to the + * device. This command cannot be used to write slots configured as ECC + * private keys. + * + * \param[in] zone Zone/Param1 for the write command. + * \param[in] address Address/Param2 for the write command. + * \param[in] value Plain-text data to be written or cipher-text for + * encrypted writes. 32 or 4 bytes depending on bit 7 in the + * zone. + * \param[in] mac MAC required for encrypted writes (32 bytes). Set to NULL + * if not required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_write(uint8_t zone, uint16_t address, const uint8_t* value, const uint8_t* mac) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_write(_gDevice, zone, address, value, mac); +#endif + } + else + { + status = calib_write(_gDevice, zone, address, value, mac); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Write command, which writes either 4 or 32 bytes of + * data into a device zone. + * + * \param[in] zone Device zone to write to (0=config, 1=OTP, 2=data). + * \param[in] slot If writing to the data zone, it is the slot to write to, + * otherwise it should be 0. + * \param[in] block 32-byte block to write to. + * \param[in] offset 4-byte word within the specified block to write to. If + * performing a 32-byte write, this should be 0. + * \param[in] data Data to be written. + * \param[in] len Number of bytes to be written. Must be either 4 or 32. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_write_zone(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, const uint8_t* data, uint8_t len) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_write_zone(_gDevice, zone, slot, block, offset, data, len); +#endif + } + else + { + status = calib_write_zone(_gDevice, zone, slot, block, offset, data, len); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_write_zone(_gDevice, zone, slot, block, offset, data, len); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Write command, which writes data into the + * configuration, otp, or data zones with a given byte offset and + * length. Offset and length must be multiples of a word (4 bytes). + * + * Config zone must be unlocked for writes to that zone. If data zone is + * unlocked, only 32-byte writes are allowed to slots and OTP and the offset + * and length must be multiples of 32 or the write will fail. + * + * \param[in] zone Zone to write data to: ATCA_ZONE_CONFIG(0), + * ATCA_ZONE_OTP(1), or ATCA_ZONE_DATA(2). + * \param[in] slot If zone is ATCA_ZONE_DATA(2), the slot number to + * write to. Ignored for all other zones. + * \param[in] offset_bytes Byte offset within the zone to write to. Must be + * a multiple of a word (4 bytes). + * \param[in] data Data to be written. + * \param[in] length Number of bytes to be written. Must be a multiple + * of a word (4 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_write_bytes_zone(uint8_t zone, uint16_t slot, size_t offset_bytes, const uint8_t* data, size_t length) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_write_bytes_zone(_gDevice, zone, slot, offset_bytes, data, length); +#endif + } + else + { + status = calib_write_bytes_zone(_gDevice, zone, slot, offset_bytes, data, length); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_write_bytes_zone(_gDevice, zone, slot, offset_bytes, data, length); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Uses the write command to write a public key to a slot in the + * proper format. + * + * \param[in] slot Slot number to write. Only slots 8 to 15 are large + * enough to store a public key. + * \param[in] public_key Public key to write into the slot specified. X and Y + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_write_pubkey(uint16_t slot, const uint8_t* public_key) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_write_pubkey(_gDevice, slot, public_key); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_write_pubkey_compat(_gDevice, slot, public_key); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Write command, which writes the configuration zone. + * + * First 16 bytes are skipped as they are not writable. LockValue and + * LockConfig are also skipped and can only be changed via the Lock + * command. + * + * This command may fail if UserExtra and/or Selector bytes have + * already been set to non-zero values. + * + * \param[in] config_data Data to the config zone data. This should be 88 + * bytes for SHA devices and 128 bytes for ECC + * devices. + * + * \returns ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_write_config_zone(const uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + if (ECC204 == dev_type) + { +#if defined(ATCA_ECC204_SUPPORT) + status = calib_ecc204_write_config_zone(_gDevice, config_data); +#endif + } + else + { + status = calib_write_config_zone(_gDevice, config_data); + } +#endif + } + else if (atcab_is_ta_device(dev_type)) + { +#if ATCA_TA_SUPPORT + status = talib_write_config_zone(_gDevice, config_data); +#endif + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Executes the Write command, which performs an encrypted write of + * a 32 byte block into given slot. + * + * The function takes clear text bytes and encrypts them for writing over the + * wire. Data zone must be locked and the slot configuration must be set to + * encrypted write for the block to be successfully written. + * + * \param[in] key_id Slot ID to write to. + * \param[in] block Index of the 32 byte block to write in the slot. + * \param[in] data 32 bytes of clear text data to be written to the slot + * \param[in] enc_key WriteKey to encrypt with for writing + * \param[in] enc_key_id The KeyID of the WriteKey + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * returns ATCA_SUCCESS on success, otherwise an error code. + */ +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_write_enc(uint16_t key_id, uint8_t block, const uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id) +#else +ATCA_STATUS atcab_write_enc(uint16_t key_id, uint8_t block, const uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]) +#endif +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) + status = calib_write_enc(_gDevice, key_id, block, data, enc_key, enc_key_id); +#else + status = calib_write_enc(_gDevice, key_id, block, data, enc_key, enc_key_id, num_in); +#endif +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +/** \brief Initialize one of the monotonic counters in device with a specific + * value. + * + * The monotonic counters are stored in the configuration zone using a special + * format. This encodes a binary count value into the 8 byte encoded value + * required. Can only be set while the configuration zone is unlocked. + * + * \param[in] counter_id Counter to be written. + * \param[in] counter_value Counter value to set. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_write_config_counter(uint16_t counter_id, uint32_t counter_value) +{ + ATCA_STATUS status = ATCA_UNIMPLEMENTED; + ATCADeviceType dev_type = atcab_get_device_type(); + + if (atcab_is_ca_device(dev_type)) + { +#if ATCA_CA_SUPPORT + status = calib_write_config_counter(_gDevice, counter_id, counter_value); +#endif + } + else if (atcab_is_ta_device(dev_type)) + { + status = ATCA_UNIMPLEMENTED; + } + else + { + status = ATCA_NOT_INITIALIZED; + } + return status; +} + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/atca_basic.h b/drivers/ecc108a/cryptoauthlib/atca_basic.h new file mode 100644 index 0000000..ae12eb4 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_basic.h @@ -0,0 +1,647 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods - a simple crypto authentication API. + * These methods manage a global ATCADevice object behind the scenes. They also + * manage the wake/idle state transitions so callers don't need to. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef ATCA_BASIC_H_ +#define ATCA_BASIC_H_ +/*lint +flb */ + +#include "cryptoauthlib.h" +#ifndef ATCA_TIDAL +#include "crypto/atca_crypto_sw_sha2.h" +#endif // ifndef ATCA_TIDAL + +/** \defgroup atcab_ Basic Crypto API methods (atcab_) + * + * \brief + * These methods provide the most convenient, simple API to CryptoAuth chips + * + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +ATCA_DLL ATCADevice _gDevice; + +// Basic global methods +ATCA_STATUS atcab_version(char *ver_str); +ATCA_STATUS atcab_init_ext(ATCADevice* device, ATCAIfaceCfg* cfg); +ATCA_STATUS atcab_init(ATCAIfaceCfg *cfg); +ATCA_STATUS atcab_init_device(ATCADevice ca_device); +ATCA_STATUS atcab_release_ext(ATCADevice* device); +ATCA_STATUS atcab_release(void); +ATCADevice atcab_get_device(void); +ATCADeviceType atcab_get_device_type_ext(ATCADevice device); +ATCADeviceType atcab_get_device_type(void); +uint8_t atcab_get_device_address(ATCADevice device); + +bool atcab_is_ca_device(ATCADeviceType dev_type); +bool atcab_is_ta_device(ATCADeviceType dev_type); + +#define atcab_get_addr(...) calib_get_addr(__VA_ARGS__) +#define atca_execute_command(...) calib_execute_command(__VA_ARGS__) + + +#ifndef ATCA_TIDAL +// AES Mode functions +#include "crypto/atca_crypto_hw_aes.h" +ATCA_STATUS atcab_aes_cbc_init_ext(ATCADevice device, atca_aes_cbc_ctx_t* ctx, uint16_t key_id, uint8_t key_block, const uint8_t* iv); +ATCA_STATUS atcab_aes_cbc_init(atca_aes_cbc_ctx_t* ctx, uint16_t key_id, uint8_t key_block, const uint8_t* iv); +ATCA_STATUS atcab_aes_cbc_encrypt_block(atca_aes_cbc_ctx_t* ctx, const uint8_t* plaintext, uint8_t* ciphertext); +ATCA_STATUS atcab_aes_cbc_decrypt_block(atca_aes_cbc_ctx_t* ctx, const uint8_t* ciphertext, uint8_t* plaintext); + +ATCA_STATUS atcab_aes_cbcmac_init_ext(ATCADevice device, atca_aes_cbcmac_ctx_t* ctx, uint16_t key_id, uint8_t key_block); +ATCA_STATUS atcab_aes_cbcmac_init(atca_aes_cbcmac_ctx_t* ctx, uint16_t key_id, uint8_t key_block); +ATCA_STATUS atcab_aes_cbcmac_update(atca_aes_cbcmac_ctx_t* ctx, const uint8_t* data, uint32_t data_size); +ATCA_STATUS atcab_aes_cbcmac_finish(atca_aes_cbcmac_ctx_t* ctx, uint8_t* mac, uint32_t mac_size); + +ATCA_STATUS atcab_aes_cmac_init_ext(ATCADevice device, atca_aes_cmac_ctx_t* ctx, uint16_t key_id, uint8_t key_block); +ATCA_STATUS atcab_aes_cmac_init(atca_aes_cmac_ctx_t* ctx, uint16_t key_id, uint8_t key_block); +ATCA_STATUS atcab_aes_cmac_update(atca_aes_cmac_ctx_t* ctx, const uint8_t* data, uint32_t data_size); +ATCA_STATUS atcab_aes_cmac_finish(atca_aes_cmac_ctx_t* ctx, uint8_t* cmac, uint32_t cmac_size); + +ATCA_STATUS atcab_aes_ctr_init_ext(ATCADevice device, atca_aes_ctr_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t counter_size, const uint8_t* iv); +ATCA_STATUS atcab_aes_ctr_init(atca_aes_ctr_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t counter_size, const uint8_t* iv); +ATCA_STATUS atcab_aes_ctr_init_rand_ext(ATCADevice device, atca_aes_ctr_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t counter_size, uint8_t* iv); +ATCA_STATUS atcab_aes_ctr_init_rand(atca_aes_ctr_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t counter_size, uint8_t* iv); +ATCA_STATUS atcab_aes_ctr_block(atca_aes_ctr_ctx_t* ctx, const uint8_t* input, uint8_t* output); +ATCA_STATUS atcab_aes_ctr_encrypt_block(atca_aes_ctr_ctx_t* ctx, const uint8_t* plaintext, uint8_t* ciphertext); +ATCA_STATUS atcab_aes_ctr_decrypt_block(atca_aes_ctr_ctx_t* ctx, const uint8_t* ciphertext, uint8_t* plaintext); +ATCA_STATUS atcab_aes_ctr_increment(atca_aes_ctr_ctx_t* ctx); + +ATCA_STATUS atcab_aes_ccm_init_ext(ATCADevice device, atca_aes_ccm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t* iv, size_t iv_size, size_t aad_size, size_t text_size, size_t tag_size); +ATCA_STATUS atcab_aes_ccm_init(atca_aes_ccm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t* iv, size_t iv_size, size_t aad_size, size_t text_size, size_t tag_size); +ATCA_STATUS atcab_aes_ccm_init_rand_ext(ATCADevice device, atca_aes_ccm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t* iv, size_t iv_size, size_t aad_size, size_t text_size, size_t tag_size); +ATCA_STATUS atcab_aes_ccm_init_rand(atca_aes_ccm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, uint8_t* iv, size_t iv_size, size_t aad_size, size_t text_size, size_t tag_size); +ATCA_STATUS atcab_aes_ccm_aad_update(atca_aes_ccm_ctx_t* ctx, const uint8_t* aad, size_t aad_size); +ATCA_STATUS atcab_aes_ccm_aad_finish(atca_aes_ccm_ctx_t* ctx); +ATCA_STATUS atcab_aes_ccm_encrypt_update(atca_aes_ccm_ctx_t* ctx, const uint8_t* plaintext, uint32_t plaintext_size, uint8_t* ciphertext); +ATCA_STATUS atcab_aes_ccm_decrypt_update(atca_aes_ccm_ctx_t* ctx, const uint8_t* ciphertext, uint32_t ciphertext_size, uint8_t* plaintext); +ATCA_STATUS atcab_aes_ccm_encrypt_finish(atca_aes_ccm_ctx_t* ctx, uint8_t* tag, uint8_t* tag_size); +ATCA_STATUS atcab_aes_ccm_decrypt_finish(atca_aes_ccm_ctx_t* ctx, const uint8_t* tag, bool* is_verified); + +// Hardware Accelerated algorithms +ATCA_STATUS atcab_pbkdf2_sha256_ext(ATCADevice device, const uint32_t iter, const uint16_t slot, const uint8_t* salt, const size_t salt_len, uint8_t* result, size_t result_len); +ATCA_STATUS atcab_pbkdf2_sha256(const uint32_t iter, const uint16_t slot, const uint8_t* salt, const size_t salt_len, uint8_t* result, size_t result_len); +#endif // ifndef ATCA_TIDAL + + +#if ATCA_CA_SUPPORT && !ATCA_TA_SUPPORT && !defined(ATCA_USE_ATCAB_FUNCTIONS) && !defined(ATCA_ECC204_SUPPORT) + +#define atcab_wakeup() calib_wakeup(_gDevice) +#define atcab_idle() calib_idle(_gDevice) +#define atcab_sleep() calib_sleep(_gDevice) +#define _atcab_exit(...) _calib_exit(_gDevice, __VA_ARGS__) +#define atcab_get_zone_size(...) calib_get_zone_size(_gDevice, __VA_ARGS__) + + +// AES command functions +#define atcab_aes(...) calib_aes(_gDevice, __VA_ARGS__) +#define atcab_aes_encrypt(...) calib_aes_encrypt(_gDevice, __VA_ARGS__) +#define atcab_aes_encrypt_ext calib_aes_encrypt +#define atcab_aes_decrypt(...) calib_aes_decrypt(_gDevice, __VA_ARGS__) +#define atcab_aes_decrypt_ext calib_aes_decrypt +#define atcab_aes_gfm(...) calib_aes_gfm(_gDevice, __VA_ARGS__) + +#define atcab_aes_gcm_init(...) calib_aes_gcm_init(_gDevice, __VA_ARGS__) +#define atcab_aes_gcm_init_rand(...) calib_aes_gcm_init_rand(_gDevice, __VA_ARGS__) +#define atcab_aes_gcm_aad_update(...) calib_aes_gcm_aad_update(_gDevice, __VA_ARGS__) +#define atcab_aes_gcm_encrypt_update(...) calib_aes_gcm_encrypt_update(_gDevice, __VA_ARGS__) +#define atcab_aes_gcm_encrypt_finish(...) calib_aes_gcm_encrypt_finish(_gDevice, __VA_ARGS__) +#define atcab_aes_gcm_decrypt_update(...) calib_aes_gcm_decrypt_update(_gDevice, __VA_ARGS__) +#define atcab_aes_gcm_decrypt_finish(...) calib_aes_gcm_decrypt_finish(_gDevice, __VA_ARGS__) + +// CheckMAC command functions +#define atcab_checkmac(...) calib_checkmac(_gDevice, __VA_ARGS__) + +// Counter command functions +#define atcab_counter(...) calib_counter(_gDevice, __VA_ARGS__) +#define atcab_counter_increment(...) calib_counter_increment(_gDevice, __VA_ARGS__) +#define atcab_counter_read(...) calib_counter_read(_gDevice, __VA_ARGS__) + +// DeriveKey command functions +#define atcab_derivekey(...) calib_derivekey(_gDevice, __VA_ARGS__) + +// ECDH command functions +#define atcab_ecdh_base(...) calib_ecdh_base(_gDevice, __VA_ARGS__) +#define atcab_ecdh(...) calib_ecdh(_gDevice, __VA_ARGS__) +#define atcab_ecdh_enc(...) calib_ecdh_enc(_gDevice, __VA_ARGS__) +#define atcab_ecdh_ioenc(...) calib_ecdh_ioenc(_gDevice, __VA_ARGS__) +#define atcab_ecdh_tempkey(...) calib_ecdh_tempkey(_gDevice, __VA_ARGS__) +#define atcab_ecdh_tempkey_ioenc(...) calib_ecdh_tempkey_ioenc(_gDevice, __VA_ARGS__) + +// GenDig command functions +#define atcab_gendig(...) calib_gendig(_gDevice, __VA_ARGS__) + +// GenKey command functions +#define atcab_genkey_base(...) calib_genkey_base(_gDevice, __VA_ARGS__) +#define atcab_genkey(...) calib_genkey(_gDevice, __VA_ARGS__) +#define atcab_get_pubkey(...) calib_get_pubkey(_gDevice, __VA_ARGS__) +#define atcab_get_pubkey_ext calib_get_pubkey + +// HMAC command functions +#define atcab_hmac(...) calib_hmac(_gDevice, __VA_ARGS__) + +// Info command functions +#define atcab_info_base(...) calib_info_base(_gDevice, __VA_ARGS__) +#define atcab_info(...) calib_info(_gDevice, __VA_ARGS__) +#define atcab_info_get_latch(...) calib_info_get_latch(_gDevice, __VA_ARGS__) +#define atcab_info_set_latch(...) calib_info_set_latch(_gDevice, __VA_ARGS__) + +// KDF command functions +#define atcab_kdf(...) calib_kdf(_gDevice, __VA_ARGS__) + +// Lock command functions +#define atcab_lock(...) calib_lock(_gDevice, __VA_ARGS__) +#define atcab_lock_config_zone() calib_lock_config_zone(_gDevice) +#define atcab_lock_config_zone_crc(...) calib_lock_config_zone_crc(_gDevice, __VA_ARGS__) +#define atcab_lock_data_zone() calib_lock_data_zone(_gDevice) +#define atcab_lock_data_zone_crc(...) calib_lock_data_zone_crc(_gDevice, __VA_ARGS__) +#define atcab_lock_data_slot(...) calib_lock_data_slot(_gDevice, __VA_ARGS__) + +// MAC command functions +#define atcab_mac(...) calib_mac(_gDevice, __VA_ARGS__) + +// Nonce command functions +#define atcab_nonce_base(...) calib_nonce_base(_gDevice, __VA_ARGS__) +#define atcab_nonce(...) calib_nonce(_gDevice, __VA_ARGS__) +#define atcab_nonce_load(...) calib_nonce_load(_gDevice, __VA_ARGS__) +#define atcab_nonce_rand(...) calib_nonce_rand(_gDevice, __VA_ARGS__) +#define atcab_challenge(...) calib_challenge(_gDevice, __VA_ARGS__) +#define atcab_challenge_seed_update(...) calib_challenge_seed_update(_gDevice, __VA_ARGS__) + +// PrivWrite command functions +#define atcab_priv_write(...) calib_priv_write(_gDevice, __VA_ARGS__) + + +// Random command functions +#define atcab_random(...) calib_random(_gDevice, __VA_ARGS__) +#define atcab_random_ext calib_random + +// Read command functions +#define atcab_read_zone(...) calib_read_zone(_gDevice, __VA_ARGS__) +#define atcab_is_locked(...) calib_is_locked(_gDevice, __VA_ARGS__) +#define atcab_is_config_locked(...) calib_is_locked(_gDevice, LOCK_ZONE_CONFIG, __VA_ARGS__) +#define atcab_is_data_locked(...) calib_is_locked(_gDevice, LOCK_ZONE_DATA, __VA_ARGS__) +#define atcab_is_slot_locked(...) calib_is_slot_locked(_gDevice, __VA_ARGS__) +#define atcab_is_private(...) calib_is_private(_gDevice, __VA_ARGS__) +#define atcab_is_private_ext calib_is_private +#define atcab_read_bytes_zone(...) calib_read_bytes_zone(_gDevice, __VA_ARGS__) +#define atcab_read_serial_number(...) calib_read_serial_number(_gDevice, __VA_ARGS__) +#define atcab_read_pubkey(...) calib_read_pubkey(_gDevice, __VA_ARGS__) +#define atcab_read_pubkey_ext calib_read_pubkey +#define atcab_read_sig(...) calib_read_sig(_gDevice, __VA_ARGS__) +#define atcab_read_config_zone(...) calib_read_config_zone(_gDevice, __VA_ARGS__) +#define atcab_cmp_config_zone(...) calib_cmp_config_zone(_gDevice, __VA_ARGS__) +#define atcab_read_enc(...) calib_read_enc(_gDevice, __VA_ARGS__) + + +// SecureBoot command functions +#define atcab_secureboot(...) calib_secureboot(_gDevice, __VA_ARGS__) +#define atcab_secureboot_mac(...) calib_secureboot_mac(_gDevice, __VA_ARGS__) + +// SelfTest command functions +#define atcab_selftest(...) calib_selftest(_gDevice, __VA_ARGS__) + +// SHA command functions +#define atcab_sha_base(...) calib_sha_base(_gDevice, __VA_ARGS__) +#define atcab_sha_start() calib_sha_start(_gDevice) +#define atcab_sha_update(...) calib_sha_update(_gDevice, __VA_ARGS__) +#define atcab_sha_end(...) calib_sha_end(_gDevice, __VA_ARGS__) +#define atcab_sha_read_context(...) calib_sha_read_context(_gDevice, __VA_ARGS__) +#define atcab_sha_write_context(...) calib_sha_write_context(_gDevice, __VA_ARGS__) +#define atcab_sha(...) calib_sha(_gDevice, __VA_ARGS__) +#define atcab_hw_sha2_256(...) calib_hw_sha2_256(_gDevice, __VA_ARGS__) +#define atcab_hw_sha2_256_init(...) calib_hw_sha2_256_init(_gDevice, __VA_ARGS__) +#define atcab_hw_sha2_256_update(...) calib_hw_sha2_256_update(_gDevice, __VA_ARGS__) +#define atcab_hw_sha2_256_finish(...) calib_hw_sha2_256_finish(_gDevice, __VA_ARGS__) +#define atcab_sha_hmac_init(...) calib_sha_hmac_init(_gDevice, __VA_ARGS__) +#define atcab_sha_hmac_update(...) calib_sha_hmac_update(_gDevice, __VA_ARGS__) +#define atcab_sha_hmac_finish(...) calib_sha_hmac_finish(_gDevice, __VA_ARGS__) +#define atcab_sha_hmac(...) calib_sha_hmac(_gDevice, __VA_ARGS__) +#define atcab_sha_hmac_ext calib_sha_hmac +#define SHA_CONTEXT_MAX_SIZE (99) + +// Sign command functions +#define atcab_sign_base(...) calib_sign_base(_gDevice, __VA_ARGS__) +#define atcab_sign(...) calib_sign(_gDevice, __VA_ARGS__) +#define atcab_sign_ext calib_sign +#define atcab_sign_internal(...) calib_sign_internal(_gDevice, __VA_ARGS__) + +// UpdateExtra command functions +#define atcab_updateextra(...) calib_updateextra(_gDevice, __VA_ARGS__) + +// Verify command functions +#define atcab_verify(...) calib_verify(_gDevice, __VA_ARGS__) +#define atcab_verify_extern(...) calib_verify_extern(_gDevice, __VA_ARGS__) +#define atcab_verify_extern_ext calib_verify_extern +#define atcab_verify_extern_mac(...) calib_verify_extern_mac(_gDevice, __VA_ARGS__) +#define atcab_verify_stored(...) calib_verify_stored(_gDevice, __VA_ARGS__) +#define atcab_verify_stored_ext calib_verify_stored +#define atcab_verify_stored_mac(...) calib_verify_stored_mac(_gDevice, __VA_ARGS__) +#define atcab_verify_validate(...) calib_verify_validate(_gDevice, __VA_ARGS__) +#define atcab_verify_invalidate(...) calib_verify_invalidate(_gDevice, __VA_ARGS__) + +// Write command functions +#define atcab_write(...) calib_write(_gDevice, __VA_ARGS__) +#define atcab_write_zone(...) calib_write_zone(_gDevice, __VA_ARGS__) +#define atcab_write_bytes_zone(...) calib_write_bytes_zone(_gDevice, __VA_ARGS__) +#define atcab_write_pubkey(...) calib_write_pubkey(_gDevice, __VA_ARGS__) +#define atcab_write_config_zone(...) calib_write_config_zone(_gDevice, __VA_ARGS__) +#define atcab_write_enc(...) calib_write_enc(_gDevice, __VA_ARGS__) +#define atcab_write_config_counter(...) calib_write_config_counter(_gDevice, __VA_ARGS__) + +#elif ATCA_TA_SUPPORT && !ATCA_CA_SUPPORT && !defined(ATCA_USE_ATCAB_FUNCTIONS) + +#define atcab_wakeup(...) (0) +#define atcab_idle(...) (0) +#define atcab_sleep(...) (0) +#define _atcab_exit(...) (1) +#define atcab_get_zone_size(...) talib_get_zone_size(_gDevice, __VA_ARGS__) +//#define atcab_get_addr(...) (1) + +// AES command functions +#define atcab_aes(...) (1) +#define atcab_aes_encrypt(...) talib_aes_encrypt(_gDevice, __VA_ARGS__) +#define atcab_aes_encrypt_ext talib_aes_encrypt +#define atcab_aes_decrypt(...) talib_aes_decrypt(_gDevice, __VA_ARGS__) +#define atcab_aes_decrypt_ext talib_aes_decrypt +#define atcab_aes_gfm(...) (1) + +#define atcab_aes_gcm_init(...) (1) +#define atcab_aes_gcm_init_rand(...) (1) +#define atcab_aes_gcm_aad_update(...) (1) +#define atcab_aes_gcm_encrypt_update(...) (1) +#define atcab_aes_gcm_encrypt_finish(...) (1) +#define atcab_aes_gcm_decrypt_update(...) (1) +#define atcab_aes_gcm_decrypt_finish(...) (1) + +// CheckMAC command functions +#define atcab_checkmac(...) (1) + +// Counter command functions +#define atcab_counter(...) talib_counter(_gDevice, __VA_ARGS__) +#define atcab_counter_increment(...) talib_counter_increment(_gDevice, __VA_ARGS__) +#define atcab_counter_read(...) talib_counter_read(_gDevice, __VA_ARGS__) + +// DeriveKey command functions +#define atcab_derivekey(...) (1) + +// ECDH command functions +#define atcab_ecdh_base(...) (1) +#define atcab_ecdh(...) talib_ecdh_compat(_gDevice, __VA_ARGS__) +#define atcab_ecdh_enc(...) (ATCA_UNIMPLEMENTED) +#define atcab_ecdh_ioenc(...) (ATCA_UNIMPLEMENTED) +#define atcab_ecdh_tempkey(...) (1) +#define atcab_ecdh_tempkey_ioenc(...) (ATCA_UNIMPLEMENTED) + +// GenDig command functions +#define atcab_gendig(...) (1) + +// GenKey command functions +#define atcab_genkey_base(...) (ATCA_UNIMPLEMENTED) +#define atcab_genkey(...) talib_genkey_compat(_gDevice, __VA_ARGS__) +#define atcab_get_pubkey(...) talib_get_pubkey_compat(_gDevice, __VA_ARGS__) +#define atcab_get_pubkey_ext talib_get_pubkey_compat + +// HMAC command functions +#define atcab_hmac(...) (ATCA_UNIMPLEMENTED) + +// Info command functions +#define atcab_info_base(...) talib_info_base(_gDevice, __VA_ARGS__) +#define atcab_info(...) talib_info_compat(_gDevice, __VA_ARGS__) +#define atcab_info_get_latch(...) (1) +#define atcab_info_set_latch(...) (1) +//#define atcab_info_get_latch(...) talib_info_get_latch(_gDevice, __VA_ARGS__) +//#define atcab_info_set_latch(...) talib_info_set_latch(_gDevice, __VA_ARGS__) + +// KDF command functions +#define atcab_kdf(...) (1) + +// Lock command functions +#define atcab_lock(...) (1) +#define atcab_lock_config_zone() talib_lock_config(_gDevice) +#define atcab_lock_config_zone_crc(...) talib_lock_config_with_crc(_gDevice, __VA_ARGS__) +#define atcab_lock_data_zone() talib_lock_setup(_gDevice) +#define atcab_lock_data_zone_crc(...) (1) +#define atcab_lock_data_slot(...) talib_lock_handle(_gDevice, __VA_ARGS__) + +// MAC command functions +#define atcab_mac(...) (ATCA_UNIMPLEMENTED) + +// Nonce command functions +#define atcab_nonce_base(...) (1) +#define atcab_nonce(...) (1) +#define atcab_nonce_load(...) (1) +#define atcab_nonce_rand(...) (1) +#define atcab_challenge(...) (1) +#define atcab_challenge_seed_update(...) (1) + +// PrivWrite command functionsoc +#define atcab_priv_write(...) (1) + +// Random command functions +#define atcab_random(...) talib_random_compat(_gDevice, __VA_ARGS__) +#define atcab_random_ext talib_random_compat + +// Read command functions +#define atcab_read_zone(...) (ATCA_UNIMPLEMENTED) +#define atcab_is_locked(...) talib_is_locked_compat(_gDevice, __VA_ARGS__) +#define atcab_is_config_locked(...) talib_is_config_locked(_gDevice, __VA_ARGS__) +#define atcab_is_data_locked(...) talib_is_setup_locked(_gDevice, __VA_ARGS__) +#define atcab_is_slot_locked(...) talib_is_handle_locked(_gDevice, __VA_ARGS__) +#define atcab_is_private(...) talib_is_private(_gDevice, __VA_ARGS__) +#define atcab_is_private_ext talib_is_private +#define atcab_read_bytes_zone(...) talib_read_bytes_zone(_gDevice, __VA_ARGS__) +#define atcab_read_serial_number(...) talib_info_serial_number_compat(_gDevice, __VA_ARGS__) +#define atcab_read_pubkey(...) talib_read_pubkey_compat(_gDevice, __VA_ARGS__) +#define atcab_read_pubkey_ext talib_read_pubkey_compat +#define atcab_read_sig(...) talib_read_sig_compat(_gDevice, __VA_ARGS__) +#define atcab_read_config_zone(...) talib_read_config_zone(_gDevice, __VA_ARGS__) +#define atcab_cmp_config_zone(...) talib_cmp_config_zone(_gDevice, __VA_ARGS__) +#define atcab_read_enc(...) (ATCA_UNIMPLEMENTED) + + +// SecureBoot command functions +#define atcab_secureboot(...) (ATCA_UNIMPLEMENTED) +#define atcab_secureboot_mac(...) (ATCA_UNIMPLEMENTED) + +// SelfTest command functions +#define atcab_selftest(...) (1) + +// SHA command functions +#define atcab_sha_base(...) talib_sha_base_compat(_gDevice, __VA_ARGS__) +#define atcab_sha_start() talib_sha_start(_gDevice) +#define atcab_sha_update(...) talib_sha_update_compat(_gDevice, __VA_ARGS__) +#define atcab_sha_end(...) talib_sha_end_compat(_gDevice, __VA_ARGS__) +#define atcab_sha_read_context(...) talib_sha_read_context(_gDevice, __VA_ARGS__) +#define atcab_sha_write_context(...) talib_sha_write_context(_gDevice, __VA_ARGS__) +#define atcab_sha(...) talib_sha(_gDevice, __VA_ARGS__) +#define atcab_hw_sha2_256(...) (1) +#define atcab_hw_sha2_256_init(...) (1) +#define atcab_hw_sha2_256_update(...) (1) +#define atcab_hw_sha2_256_finish(...) (1) +#define atcab_sha_hmac_init(...) (ATCA_UNIMPLEMENTED) +#define atcab_sha_hmac_update(...) (ATCA_UNIMPLEMENTED) +#define atcab_sha_hmac_finish(...) (ATCA_UNIMPLEMENTED) +#define atcab_sha_hmac(...) talib_hmac_compat(_gDevice, __VA_ARGS__) +#define atcab_sha_hmac_ext talib_hmac_compat +#define SHA_CONTEXT_MAX_SIZE (109) + +// Sign command functions +#define atcab_sign_base(...) (1) +#define atcab_sign(...) talib_sign_compat(_gDevice, __VA_ARGS__) +#define atcab_sign_ext talib_sign_compat +#define atcab_sign_internal(...) (1) + +// UpdateExtra command functions +#define atcab_updateextra(...) (1) + +// Verify command functions +#define atcab_verify(...) (1) +#define atcab_verify_extern(...) talib_verify_extern_compat(_gDevice, __VA_ARGS__) +#define atcab_verify_extern_ext talib_verify_extern_compat +#define atcab_verify_extern_mac(...) (ATCA_UNIMPLEMENTED) +#define atcab_verify_stored(...) talib_verify_stored_compat(_gDevice, __VA_ARGS__) +#define atcab_verify_stored_ext talib_verify_stored_compat +#define atcab_verify_stored_mac(...) (ATCA_UNIMPLEMENTED) +#define atcab_verify_validate(...) (ATCA_UNIMPLEMENTED) +#define atcab_verify_invalidate(...) (ATCA_UNIMPLEMENTED) + +// Write command functions +#define atcab_write(...) (ATCA_UNIMPLEMENTED) +#define atcab_write_zone(...) talib_write_zone(_gDevice, __VA_ARGS__) +#define atcab_write_bytes_zone(...) talib_write_bytes_zone(_gDevice, __VA_ARGS__) +#define atcab_write_pubkey(...) talib_write_pubkey_compat(_gDevice, __VA_ARGS__) +#define atcab_write_config_zone(...) talib_write_config_zone(_gDevice, __VA_ARGS__) +#define atcab_write_enc(...) (ATCA_UNIMPLEMENTED) +#define atcab_write_config_counter(...) (ATCA_UNIMPLEMENTED) + +#endif + +#if (ATCA_TA_SUPPORT && ATCA_CA_SUPPORT) || defined(ATCA_USE_ATCAB_FUNCTIONS) || defined(ATCA_ECC204_SUPPORT) + +/* Basic global methods */ +ATCA_STATUS _atcab_exit(void); +ATCA_STATUS atcab_wakeup(void); +ATCA_STATUS atcab_idle(void); +ATCA_STATUS atcab_sleep(void); +//ATCA_STATUS atcab_get_addr(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint16_t* addr); +ATCA_STATUS atcab_get_zone_size(uint8_t zone, uint16_t slot, size_t* size); + +// AES command functions +ATCA_STATUS atcab_aes(uint8_t mode, uint16_t key_id, const uint8_t* aes_in, uint8_t* aes_out); +ATCA_STATUS atcab_aes_encrypt(uint16_t key_id, uint8_t key_block, const uint8_t* plaintext, uint8_t* ciphertext); +ATCA_STATUS atcab_aes_encrypt_ext(ATCADevice device, uint16_t key_id, uint8_t key_block, const uint8_t* plaintext, uint8_t* ciphertext); +ATCA_STATUS atcab_aes_decrypt(uint16_t key_id, uint8_t key_block, const uint8_t* ciphertext, uint8_t* plaintext); +ATCA_STATUS atcab_aes_decrypt_ext(ATCADevice device, uint16_t key_id, uint8_t key_block, const uint8_t* ciphertext, uint8_t* plaintext); +ATCA_STATUS atcab_aes_gfm(const uint8_t* h, const uint8_t* input, uint8_t* output); + +/* AES GCM */ +ATCA_STATUS atcab_aes_gcm_init(atca_aes_gcm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, const uint8_t* iv, size_t iv_size); +ATCA_STATUS atcab_aes_gcm_init_rand(atca_aes_gcm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, size_t rand_size, + const uint8_t* free_field, size_t free_field_size, uint8_t* iv); +ATCA_STATUS atcab_aes_gcm_aad_update(atca_aes_gcm_ctx_t* ctx, const uint8_t* aad, uint32_t aad_size); +ATCA_STATUS atcab_aes_gcm_encrypt_update(atca_aes_gcm_ctx_t* ctx, const uint8_t* plaintext, uint32_t plaintext_size, uint8_t* ciphertext); +ATCA_STATUS atcab_aes_gcm_encrypt_finish(atca_aes_gcm_ctx_t* ctx, uint8_t* tag, size_t tag_size); +ATCA_STATUS atcab_aes_gcm_decrypt_update(atca_aes_gcm_ctx_t* ctx, const uint8_t* ciphertext, uint32_t ciphertext_size, uint8_t* plaintext); +ATCA_STATUS atcab_aes_gcm_decrypt_finish(atca_aes_gcm_ctx_t* ctx, const uint8_t* tag, size_t tag_size, bool* is_verified); + +/* CheckMAC command */ +ATCA_STATUS atcab_checkmac(uint8_t mode, uint16_t key_id, const uint8_t* challenge, const uint8_t* response, const uint8_t* other_data); + +/* Counter command */ +ATCA_STATUS atcab_counter(uint8_t mode, uint16_t counter_id, uint32_t* counter_value); +ATCA_STATUS atcab_counter_increment(uint16_t counter_id, uint32_t* counter_value); +ATCA_STATUS atcab_counter_read(uint16_t counter_id, uint32_t* counter_value); + +/* DeriveKey command */ +ATCA_STATUS atcab_derivekey(uint8_t mode, uint16_t key_id, const uint8_t* mac); + +/* ECDH command */ +ATCA_STATUS atcab_ecdh_base(uint8_t mode, uint16_t key_id, const uint8_t* public_key, uint8_t* pms, uint8_t* out_nonce); +ATCA_STATUS atcab_ecdh(uint16_t key_id, const uint8_t* public_key, uint8_t* pms); + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_ecdh_enc(uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* read_key, uint16_t read_key_id); +#else +ATCA_STATUS atcab_ecdh_enc(uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* read_key, uint16_t read_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +ATCA_STATUS atcab_ecdh_ioenc(uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* io_key); +ATCA_STATUS atcab_ecdh_tempkey(const uint8_t* public_key, uint8_t* pms); +ATCA_STATUS atcab_ecdh_tempkey_ioenc(const uint8_t* public_key, uint8_t* pms, const uint8_t* io_key); + +// GenDig command functions +ATCA_STATUS atcab_gendig(uint8_t zone, uint16_t key_id, const uint8_t* other_data, uint8_t other_data_size); + +// GenKey command functions +ATCA_STATUS atcab_genkey_base(uint8_t mode, uint16_t key_id, const uint8_t* other_data, uint8_t* public_key); +ATCA_STATUS atcab_genkey(uint16_t key_id, uint8_t* public_key); +ATCA_STATUS atcab_get_pubkey(uint16_t key_id, uint8_t* public_key); +ATCA_STATUS atcab_get_pubkey_ext(ATCADevice device, uint16_t key_id, uint8_t* public_key); + +// HMAC command functions +ATCA_STATUS atcab_hmac(uint8_t mode, uint16_t key_id, uint8_t* digest); + +// Info command functions +ATCA_STATUS atcab_info_base(uint8_t mode, uint16_t param2, uint8_t* out_data); +ATCA_STATUS atcab_info(uint8_t* revision); +ATCA_STATUS atcab_info_set_latch(bool state); +ATCA_STATUS atcab_info_get_latch(bool* state); + +// KDF command functions +ATCA_STATUS atcab_kdf(uint8_t mode, uint16_t key_id, const uint32_t details, const uint8_t* message, uint8_t* out_data, uint8_t* out_nonce); + +// Lock command functions +ATCA_STATUS atcab_lock(uint8_t mode, uint16_t summary_crc); +ATCA_STATUS atcab_lock_config_zone(void); +ATCA_STATUS atcab_lock_config_zone_crc(uint16_t summary_crc); +ATCA_STATUS atcab_lock_data_zone(void); +ATCA_STATUS atcab_lock_data_zone_crc(uint16_t summary_crc); +ATCA_STATUS atcab_lock_data_slot(uint16_t slot); + +// MAC command functions +ATCA_STATUS atcab_mac(uint8_t mode, uint16_t key_id, const uint8_t* challenge, uint8_t* digest); + +// Nonce command functions +ATCA_STATUS atcab_nonce_base(uint8_t mode, uint16_t zero, const uint8_t* num_in, uint8_t* rand_out); +ATCA_STATUS atcab_nonce(const uint8_t* num_in); +ATCA_STATUS atcab_nonce_load(uint8_t target, const uint8_t* num_in, uint16_t num_in_size); +ATCA_STATUS atcab_nonce_rand(const uint8_t* num_in, uint8_t* rand_out); +ATCA_STATUS atcab_challenge(const uint8_t* num_in); +ATCA_STATUS atcab_challenge_seed_update(const uint8_t* num_in, uint8_t* rand_out); + +// PrivWrite command functions +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_priv_write(uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32]); +#else +ATCA_STATUS atcab_priv_write(uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32], const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +// Random command functions +ATCA_STATUS atcab_random(uint8_t* rand_out); +ATCA_STATUS atcab_random_ext(ATCADevice device, uint8_t* rand_out); + +// Read command functions +ATCA_STATUS atcab_read_zone(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint8_t* data, uint8_t len); +ATCA_STATUS atcab_is_locked(uint8_t zone, bool* is_locked); +ATCA_STATUS atcab_is_config_locked(bool* is_locked); +ATCA_STATUS atcab_is_data_locked(bool* is_locked); +ATCA_STATUS atcab_is_slot_locked(uint16_t slot, bool* is_locked); +ATCA_STATUS atcab_is_private_ext(ATCADevice device, uint16_t slot, bool* is_private); +ATCA_STATUS atcab_is_private(uint16_t slot, bool* is_private); +ATCA_STATUS atcab_read_bytes_zone(uint8_t zone, uint16_t slot, size_t offset, uint8_t* data, size_t length); +ATCA_STATUS atcab_read_serial_number(uint8_t* serial_number); +ATCA_STATUS atcab_read_pubkey(uint16_t slot, uint8_t* public_key); +ATCA_STATUS atcab_read_pubkey_ext(ATCADevice device, uint16_t slot, uint8_t* public_key); +ATCA_STATUS atcab_read_sig(uint16_t slot, uint8_t* sig); +ATCA_STATUS atcab_read_config_zone(uint8_t* config_data); +ATCA_STATUS atcab_cmp_config_zone(uint8_t* config_data, bool* same_config); + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_read_enc(uint16_t key_id, uint8_t block, uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id); +#else +ATCA_STATUS atcab_read_enc(uint16_t key_id, uint8_t block, uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +// SecureBoot command functions +ATCA_STATUS atcab_secureboot(uint8_t mode, uint16_t param2, const uint8_t* digest, const uint8_t* signature, uint8_t* mac); +ATCA_STATUS atcab_secureboot_mac(uint8_t mode, const uint8_t* digest, const uint8_t* signature, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified); + +/* SelfTest Command */ +ATCA_STATUS atcab_selftest(uint8_t mode, uint16_t param2, uint8_t* result); + +/* SHA Command */ +#define SHA_CONTEXT_MAX_SIZE (109) +ATCA_STATUS atcab_sha_base(uint8_t mode, uint16_t length, const uint8_t* data_in, uint8_t* data_out, uint16_t* data_out_size); +ATCA_STATUS atcab_sha_start(void); +ATCA_STATUS atcab_sha_update(const uint8_t* message); +ATCA_STATUS atcab_sha_end(uint8_t* digest, uint16_t length, const uint8_t* message); +ATCA_STATUS atcab_sha_read_context(uint8_t* context, uint16_t* context_size); +ATCA_STATUS atcab_sha_write_context(const uint8_t* context, uint16_t context_size); +ATCA_STATUS atcab_sha(uint16_t length, const uint8_t* message, uint8_t* digest); +ATCA_STATUS atcab_hw_sha2_256(const uint8_t* data, size_t data_size, uint8_t* digest); + +ATCA_STATUS atcab_hw_sha2_256_init(atca_sha256_ctx_t* ctx); +ATCA_STATUS atcab_hw_sha2_256_update(atca_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size); +ATCA_STATUS atcab_hw_sha2_256_finish(atca_sha256_ctx_t* ctx, uint8_t* digest); +ATCA_STATUS atcab_sha_hmac_init(atca_hmac_sha256_ctx_t* ctx, uint16_t key_slot); +ATCA_STATUS atcab_sha_hmac_update(atca_hmac_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size); +ATCA_STATUS atcab_sha_hmac_finish(atca_hmac_sha256_ctx_t* ctx, uint8_t* digest, uint8_t target); + +ATCA_STATUS atcab_sha_hmac(const uint8_t* data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target); +ATCA_STATUS atcab_sha_hmac_ext(ATCADevice device, const uint8_t* data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target); + +/* Sign command */ +ATCA_STATUS atcab_sign_base(uint8_t mode, uint16_t key_id, uint8_t* signature); +ATCA_STATUS atcab_sign(uint16_t key_id, const uint8_t* msg, uint8_t* signature); +ATCA_STATUS atcab_sign_ext(ATCADevice device, uint16_t key_id, const uint8_t* msg, uint8_t* signature); +ATCA_STATUS atcab_sign_internal(uint16_t key_id, bool is_invalidate, bool is_full_sn, uint8_t* signature); + +/* UpdateExtra command */ +ATCA_STATUS atcab_updateextra(uint8_t mode, uint16_t new_value); + +/* Verify command */ +ATCA_STATUS atcab_verify(uint8_t mode, uint16_t key_id, const uint8_t* signature, const uint8_t* public_key, const uint8_t* other_data, uint8_t* mac); +ATCA_STATUS atcab_verify_extern(const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, bool* is_verified); +ATCA_STATUS atcab_verify_extern_ext(ATCADevice device, const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, bool* is_verified); +ATCA_STATUS atcab_verify_extern_mac(const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified); +ATCA_STATUS atcab_verify_stored(const uint8_t* message, const uint8_t* signature, uint16_t key_id, bool* is_verified); +ATCA_STATUS atcab_verify_stored_ext(ATCADevice device, const uint8_t* message, const uint8_t* signature, uint16_t key_id, bool* is_verified); +ATCA_STATUS atcab_verify_stored_mac(const uint8_t* message, const uint8_t* signature, uint16_t key_id, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified); + +ATCA_STATUS atcab_verify_validate(uint16_t key_id, const uint8_t* signature, const uint8_t* other_data, bool* is_verified); +ATCA_STATUS atcab_verify_invalidate(uint16_t key_id, const uint8_t* signature, const uint8_t* other_data, bool* is_verified); + +/* Write command functions */ +ATCA_STATUS atcab_write(uint8_t zone, uint16_t address, const uint8_t* value, const uint8_t* mac); +ATCA_STATUS atcab_write_zone(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, const uint8_t* data, uint8_t len); +ATCA_STATUS atcab_write_bytes_zone(uint8_t zone, uint16_t slot, size_t offset_bytes, const uint8_t* data, size_t length); +ATCA_STATUS atcab_write_pubkey(uint16_t slot, const uint8_t* public_key); +ATCA_STATUS atcab_write_config_zone(const uint8_t* config_data); + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS atcab_write_enc(uint16_t key_id, uint8_t block, const uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id); +#else +ATCA_STATUS atcab_write_enc(uint16_t key_id, uint8_t block, const uint8_t* data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +ATCA_STATUS atcab_write_config_counter(uint16_t counter_id, uint32_t counter_value); + + +#endif /* ATCA_TA_SUPPORT && ATCA_CA_SUPPORT */ + +#ifdef __cplusplus +} +#endif + +/** @} */ +/*lint -flb*/ +#endif /* ATCA_BASIC_H_ */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_bool.h b/drivers/ecc108a/cryptoauthlib/atca_bool.h new file mode 100644 index 0000000..5707b71 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_bool.h @@ -0,0 +1,43 @@ +/** + * \file + * + * \brief bool define for systems that don't have it + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef _ATCA_BOOL_H +#define _ATCA_BOOL_H + +#if defined(_MSC_VER) && (_MSC_VER <= 1700) +// VS2012 and earlier don't support stdbool.h + #ifndef __cplusplus + #define bool unsigned char + #define false 0 + #define true 1 + #endif +#else + #include +#endif + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/atca_cfgs.c b/drivers/ecc108a/cryptoauthlib/atca_cfgs.c new file mode 100644 index 0000000..f04f1be --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_cfgs.c @@ -0,0 +1,226 @@ +/** + * \file + * \brief a set of default configurations for various ATCA devices and interfaces + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include +#include "cryptoauthlib.h" +#include "atca_cfgs.h" +#include "atca_iface.h" +#include "atca_device.h" + +/** \defgroup config Configuration (cfg_) + * \brief Logical device configurations describe the CryptoAuth device type and logical interface. + @{ */ + +/* if the number of these configurations grows large, we can #ifdef them based on required device support */ + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_I2C) +/** \brief default configuration for an ECCx08A device */ +ATCAIfaceCfg cfg_ateccx08a_i2c_default = { + .iface_type = ATCA_I2C_IFACE, + .devtype = ATECC608, + { +#ifdef ATCA_ENABLE_DEPRECATED + .atcai2c.slave_address = 0xC0, +#else + .atcai2c.address = 0xC0, +#endif + .atcai2c.bus = 2, +#ifdef __linux__ + .atcai2c.baud = 100000, +#else + .atcai2c.baud = 400000, +#endif + }, + .wake_delay = 1500, + .rx_retries = 20 +}; +#endif + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_SWI) +/** \brief default configuration for an ECCx08A device on the logical SWI bus over UART*/ +ATCAIfaceCfg cfg_ateccx08a_swi_default = { + .iface_type = ATCA_SWI_IFACE, + .devtype = ATECC608, + { + .atcaswi.bus = 4, + }, + .wake_delay = 1500, + .rx_retries = 10 +}; +#endif + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_KIT_UART) +/** \brief default configuration for Kit protocol over the device's async interface */ +ATCAIfaceCfg cfg_ateccx08_kituart_default = { + .iface_type = ATCA_UART_IFACE, + .devtype = ATECC608, + { + .atcauart.port = 0, + .atcauart.baud = 115200, + .atcauart.wordsize = 8, + .atcauart.parity = 2, + .atcauart.stopbits = 1, + }, + .rx_retries = 1, +}; +#endif + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_KIT_HID) +/** \brief default configuration for Kit protocol over the device's async interface */ +ATCAIfaceCfg cfg_ateccx08a_kithid_default = { + .iface_type = ATCA_HID_IFACE, + .devtype = ATECC608, + { + .atcahid.dev_interface = ATCA_KIT_AUTO_IFACE, + .atcahid.dev_identity = 0, + .atcahid.idx = 0, + .atcahid.vid = 0x03EB, + .atcahid.pid = 0x2312, + .atcahid.packetsize = 64, + } +}; +#endif + +#if defined(ATCA_SHA_SUPPORT) && defined(ATCA_HAL_I2C) +/** \brief default configuration for a SHA204A device on the first logical I2C bus */ +ATCAIfaceCfg cfg_atsha20xa_i2c_default = { + .iface_type = ATCA_I2C_IFACE, + .devtype = ATSHA204A, + { +#ifdef ATCA_ENABLE_DEPRECATED + .atcai2c.slave_address = 0xC8, +#else + .atcai2c.address = 0xC8, +#endif + .atcai2c.bus = 2, +#ifdef __linux__ + .atcai2c.baud = 100000, +#else + .atcai2c.baud = 400000, +#endif + }, + .wake_delay = 2560, + .rx_retries = 20 +}; +#endif + +#if defined(ATCA_SHA_SUPPORT) && defined(ATCA_HAL_SWI) +/** \brief default configuration for an SHA20xA device on the logical SWI bus over UART*/ +ATCAIfaceCfg cfg_atsha20xa_swi_default = { + .iface_type = ATCA_SWI_IFACE, + .devtype = ATSHA204A, + { + .atcaswi.bus = 4, + }, + .wake_delay = 2560, + .rx_retries = 10 +}; +#endif + +#if defined(ATCA_SHA_SUPPORT) && defined(ATCA_HAL_KIT_UART) +/** \brief default configuration for Kit protocol over the device's async interface */ +ATCAIfaceCfg cfg_atsha20xa_kituart_default = { + .iface_type = ATCA_UART_IFACE, + .devtype = ATSHA204A, + { + .atcauart.port = 0, + .atcauart.baud = 115200, + .atcauart.wordsize = 8, + .atcauart.parity = 2, + .atcauart.stopbits = 1, + }, + .rx_retries = 1, +}; +#endif + +#if defined(ATCA_SHA_SUPPORT) && defined(ATCA_HAL_KIT_HID) +/** \brief default configuration for Kit protocol over the device's async interface */ +ATCAIfaceCfg cfg_atsha20xa_kithid_default = { + .iface_type = ATCA_HID_IFACE, + .devtype = ATSHA204A, + .atcahid.dev_interface = ATCA_KIT_AUTO_IFACE, + .atcahid.dev_identity = 0, + .atcahid.idx = 0, + .atcahid.vid = 0x03EB, + .atcahid.pid = 0x2312, + .atcahid.packetsize = 64, +}; +#endif + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_I2C) +/** \brief default configuration for an ECC204 device on the first logical I2C bus */ +ATCAIfaceCfg cfg_ecc204_i2c_default = { + .iface_type = ATCA_I2C_IFACE, + .devtype = ECC204, + { +#ifdef ATCA_ENABLE_DEPRECATED + .atcai2c.slave_address = 0x33, +#else + .atcai2c.address = 0x33, +#endif + .atcai2c.bus = 2, +#ifdef __linux__ + .atcai2c.baud = 100000, +#else + .atcai2c.baud = 400000, +#endif + }, + .wake_delay = 1500, + .rx_retries = 20 +}; +#endif + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_SWI) +/** \brief default configuration for an ECC204 device on the logical SWI over GPIO*/ +ATCAIfaceCfg cfg_ecc204_swi_default = { + .iface_type = ATCA_SWI_IFACE, + .devtype = ECC204, + { + .atcaswi.bus = 4, + }, + .wake_delay = 1500, + .rx_retries = 10 +}; +#endif + +#if defined(ATCA_ECC_SUPPORT) && defined(ATCA_HAL_KIT_HID) +/** \brief default configuration for Kit protocol over the device's async interface */ +ATCAIfaceCfg cfg_ecc204_kithid_default = { + .iface_type = ATCA_HID_IFACE, + .devtype = ECC204, + { + .atcahid.dev_interface = ATCA_KIT_AUTO_IFACE, + .atcahid.dev_identity = 0, + .atcahid.idx = 0, + .atcahid.vid = 0x03EB, + .atcahid.pid = 0x2312, + .atcahid.packetsize = 64, + } +}; +#endif + +/** @} */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_cfgs.h b/drivers/ecc108a/cryptoauthlib/atca_cfgs.h new file mode 100644 index 0000000..72f0f4a --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_cfgs.h @@ -0,0 +1,78 @@ +/** + * \file + * \brief a set of default configurations for various ATCA devices and interfaces + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +#ifndef ATCA_CFGS_H_ +#define ATCA_CFGS_H_ + +#include "atca_iface.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \brief default configuration for an ECCx08A device on the first logical I2C bus */ +extern ATCAIfaceCfg cfg_ateccx08a_i2c_default; + +/** \brief default configuration for an ECCx08A device on the logical SWI bus over UART*/ +extern ATCAIfaceCfg cfg_ateccx08a_swi_default; + +/** \brief default configuration for Kit protocol over a CDC interface */ +extern ATCAIfaceCfg cfg_ateccx08a_kitcdc_default; + +/** \brief default configuration for Kit protocol over a HID interface */ +extern ATCAIfaceCfg cfg_ateccx08a_kithid_default; + + +/** \brief default configuration for a SHA204A device on the first logical I2C bus */ +extern ATCAIfaceCfg cfg_atsha20xa_i2c_default; + +/** \brief default configuration for an SHA20xA device on the logical SWI bus over UART*/ +extern ATCAIfaceCfg cfg_atsha20xa_swi_default; + +/** \brief default configuration for Kit protocol over a CDC interface */ +extern ATCAIfaceCfg cfg_atsha20xa_kitcdc_default; + +/** \brief default configuration for Kit protocol over a HID interface for SHA204 */ +extern ATCAIfaceCfg cfg_atsha20xa_kithid_default; + + +/** \brief default configuration for an ECC204 device on the first logical I2C bus */ +extern ATCAIfaceCfg cfg_ecc204_i2c_default; + +/** \brief default configuration for an ECC204 device on the logical SWI over GPIO*/ +extern ATCAIfaceCfg cfg_ecc204_swi_default; + +/** \brief default configuration for Kit protocol over the device's async interface */ +extern ATCAIfaceCfg cfg_ecc204_kithid_default; + + +#ifdef __cplusplus +} +#endif +#endif /* ATCA_CFGS_H_ */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_compiler.h b/drivers/ecc108a/cryptoauthlib/atca_compiler.h new file mode 100644 index 0000000..c746ccb --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_compiler.h @@ -0,0 +1,222 @@ +/** + * \file + * \brief CryptoAuthLiub is meant to be portable across architectures, even + * non-Microchip architectures and compiler environments. This file is + * for isolating compiler specific macros. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +#ifndef ATCA_COMPILER_H_ +#define ATCA_COMPILER_H_ + +#if defined(__clang__) +/* Clang/LLVM. ---------------------------------------------- */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define ATCA_UINT16_HOST_TO_LE(x) __builtin_bswap16(x) +#define ATCA_UINT16_LE_TO_HOST(x) __builtin_bswap16(x) +#define ATCA_UINT32_HOST_TO_LE(x) __builtin_bswap32(x) +#define ATCA_UINT16_HOST_TO_BE(x) (x) +#define ATCA_UINT16_BE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_BE(x) (x) +#define ATCA_UINT32_BE_TO_HOST(x) (x) +#define ATCA_UINT64_HOST_TO_BE(x) (x) +#define ATCA_UINT64_BE_TO_HOST(x) (x) +#else +#define ATCA_UINT16_HOST_TO_LE(x) (x) +#define ATCA_UINT16_LE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) (x) +#define ATCA_UINT16_HOST_TO_BE(x) __builtin_bswap16(x) +#define ATCA_UINT16_BE_TO_HOST(x) __builtin_bswap16(x) +#define ATCA_UINT32_HOST_TO_BE(x) __builtin_bswap32(x) +#define ATCA_UINT32_BE_TO_HOST(x) __builtin_bswap32(x) +#define ATCA_UINT64_HOST_TO_BE(x) __builtin_bswap64(x) +#define ATCA_UINT64_BE_TO_HOST(x) __builtin_bswap64(x) +#endif + +#ifdef WIN32 +#define SHARED_LIB_EXPORT __declspec(dllexport) +#define SHARED_LIB_IMPORT __declspec(dllimport) +#else +#define SHARED_LIB_EXPORT +#define SHARED_LIB_IMPORT extern +#endif + +#elif defined(__XC8) || defined(__XC16) +/* Microchip XC8 and XC16 Compilers ------------------------- */ +#ifndef SIZE_MAX +#define SIZE_MAX 65535 +#endif + +#define ATCA_UINT16_HOST_TO_LE(x) (x) +#define ATCA_UINT16_LE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) (x) +#define ATCA_UINT16_HOST_TO_BE(x) ((((x) & 0x00FF) << 8) | (((x) & 0xFF00) >> 8)) +#define ATCA_UINT16_BE_TO_HOST(x) ((((x) & 0x00FF) << 8) | (((x) & 0xFF00) >> 8)) +#define ATCA_UINT32_HOST_TO_BE(x) ((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8) | (((x) & 0xFF000000) >> 24)) +#define ATCA_UINT32_BE_TO_HOST(x) ((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8) | (((x) & 0xFF000000) >> 24)) +#define ATCA_UINT64_HOST_TO_BE(x) ((uint64_t)ATCA_UINT32_HOST_TO_BE((uint32_t)(x)) << 32 + (uint64_t)ATCA_UINT32_HOST_TO_BE((uint32_t)((x) >> 32))) +#define ATCA_UINT64_BE_TO_HOST(x) ((uint64_t)ATCA_UINT32_BE_TO_HOST((uint32_t)(x)) << 32 + (uint64_t)ATCA_UINT32_BE_TO_HOST((uint32_t)((x) >> 32))) +#define SHARED_LIB_EXPORT +#define SHARED_LIB_IMPORT extern + +//#elif defined(__ICC) || defined(__INTEL_COMPILER) +/* Intel ICC/ICPC. ------------------------------------------ */ + +#elif defined(__GNUC__) || defined(__GNUG__) +/* GNU GCC/G++. --------------------------------------------- */ +#if defined(__AVR32__) +#define ATCA_UINT16_HOST_TO_LE(x) __builtin_bswap_16(x) +#define ATCA_UINT16_LE_TO_HOST(x) __builtin_bswap_16(x) +#define ATCA_UINT32_HOST_TO_LE(x) __builtin_bswap_32(x) +#define ATCA_UINT16_HOST_TO_BE(x) (x) +#define ATCA_UINT16_BE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_BE(x) (x) +#define ATCA_UINT32_BE_TO_HOST(x) (x) +#define ATCA_UINT64_HOST_TO_BE(x) (x) +#define ATCA_UINT64_BE_TO_HOST(x) (x) +#define ATCA_NO_PRAGMA_PACK +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define ATCA_UINT16_HOST_TO_LE(x) __builtin_bswap16(x) +#define ATCA_UINT16_LE_TO_HOST(x) __builtin_bswap16(x) +#define ATCA_UINT16_HOST_TO_BE(x) (x) +#define ATCA_UINT16_BE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) __builtin_bswap32(x) +#define ATCA_UINT32_HOST_TO_BE(x) (x) +#define ATCA_UINT32_BE_TO_HOST(x) (x) +#define ATCA_UINT64_HOST_TO_BE(x) (x) +#define ATCA_UINT64_BE_TO_HOST(x) (x) +#else +#define ATCA_UINT16_HOST_TO_BE(x) __builtin_bswap16(x) +#define ATCA_UINT16_BE_TO_HOST(x) __builtin_bswap16(x) +#define ATCA_UINT16_HOST_TO_LE(x) (x) +#define ATCA_UINT16_LE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) (x) +#define ATCA_UINT32_HOST_TO_BE(x) __builtin_bswap32(x) +#define ATCA_UINT32_BE_TO_HOST(x) __builtin_bswap32(x) +#define ATCA_UINT64_HOST_TO_BE(x) __builtin_bswap64(x) +#define ATCA_UINT64_BE_TO_HOST(x) __builtin_bswap64(x) +#endif + +#ifdef WIN32 +#define SHARED_LIB_EXPORT __declspec(dllexport) +#define SHARED_LIB_IMPORT __declspec(dllimport) +#else +#define SHARED_LIB_EXPORT +#define SHARED_LIB_IMPORT extern +#endif + + +//#elif defined(__HP_cc) || defined(__HP_aCC) +/* Hewlett-Packard C/aC++. ---------------------------------- */ + +//#elif defined(__IBMC__) || defined(__IBMCPP__) +/* IBM XL C/C++. -------------------------------------------- */ + +#elif defined(_MSC_VER) +/* Microsoft Visual Studio. --------------------------------- */ +// MSVC is usually always little-endian architecture +#include +#define ATCA_UINT16_HOST_TO_BE(x) _byteswap_ushort(x) +#define ATCA_UINT16_BE_TO_HOST(x) _byteswap_ushort(x) +#define ATCA_UINT16_HOST_TO_LE(x) (x) +#define ATCA_UINT16_LE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) (x) +#define ATCA_UINT32_HOST_TO_BE(x) _byteswap_ulong(x) +#define ATCA_UINT32_BE_TO_HOST(x) _byteswap_ulong(x) +#define ATCA_UINT64_HOST_TO_BE(x) _byteswap_uint64(x) +#define ATCA_UINT64_BE_TO_HOST(x) _byteswap_uint64(x) +#define strtok_r strtok_s + +#define SHARED_LIB_EXPORT __declspec(dllexport) +#define SHARED_LIB_IMPORT __declspec(dllimport) + +//#elif defined(__PGI) +/* Portland Group PGCC/PGCPP. ------------------------------- */ + +//#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +/* Oracle Solaris Studio. ----------------------------------- */ + +#elif defined __CC_ARM +/* ARMCC/RealView ------------------------------------------- */ +#ifdef __BIG_ENDIAN +#define ATCA_UINT16_HOST_TO_LE(x) ((x >> 8) | ((x & 0xFF) << 8)) +#define ATCA_UINT16_LE_TO_HOST(x) ((x >> 8) | ((x & 0xFF) << 8)) +#define ATCA_UINT32_HOST_TO_LE(x) __rev(x) +#define ATCA_UINT32_HOST_TO_BE(x) (x) +#define ATCA_UINT32_BE_TO_HOST(x) (x) +#define ATCA_UINT64_HOST_TO_BE(x) (x) +#define ATCA_UINT64_BE_TO_HOST(x) (x) +#else +#define ATCA_UINT16_HOST_TO_LE(x) (x) +#define ATCA_UINT16_LE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) (x) +#define ATCA_UINT32_HOST_TO_BE(x) __rev(x) +#define ATCA_UINT32_BE_TO_HOST(x) __rev(x) +#define ATCA_UINT64_HOST_TO_BE(x) (((uint64_t)__rev((uint32_t)x) << 32) | (uint64_t)__rev((uint32_t)(x >> 32))) +#define ATCA_UINT64_BE_TO_HOST(x) (((uint64_t)__rev((uint32_t)x) << 32) | (uint64_t)__rev((uint32_t)(x >> 32))) +#endif + +#define SHARED_LIB_EXPORT +#define SHARED_LIB_IMPORT extern + +#elif defined __ICCARM__ +/* IAR ARM ------------------------------------------- */ +#include +#if __LITTLE_ENDIAN__ == 0 +#define ATCA_UINT16_HOST_TO_LE(x) __REV16(x) +#define ATCA_UINT16_LE_TO_HOST(x) __REV16(x) +#define ATCA_UINT32_HOST_TO_LE(x) __REV(x) +#define ATCA_UINT32_HOST_TO_BE(x) (x) +#define ATCA_UINT32_BE_TO_HOST(x) (x) +#define ATCA_UINT64_HOST_TO_BE(x) (x) +#define ATCA_UINT64_BE_TO_HOST(x) (x) +#else +#define ATCA_UINT16_HOST_TO_LE(x) (x) +#define ATCA_UINT16_LE_TO_HOST(x) (x) +#define ATCA_UINT32_HOST_TO_LE(x) (x) +#define ATCA_UINT32_HOST_TO_BE(x) __REV(x) +#define ATCA_UINT32_BE_TO_HOST(x) __REV(x) +#define ATCA_UINT64_HOST_TO_BE(x) (((uint64_t)__REV((uint32_t)x) << 32) | (uint64_t)__REV((uint32_t)(x >> 32))) +#define ATCA_UINT64_BE_TO_HOST(x) (((uint64_t)__REV((uint32_t)x) << 32) | (uint64_t)__REV((uint32_t)(x >> 32))) +#endif + +#define SHARED_LIB_EXPORT +#define SHARED_LIB_IMPORT extern + +#endif + +#ifdef ATCA_BUILD_SHARED_LIBS +#if defined(cryptoauth_EXPORTS) && defined(_WIN32) +#define ATCA_DLL SHARED_LIB_EXPORT +#else +#define ATCA_DLL SHARED_LIB_IMPORT +#endif +#else +#undef SHARED_LIB_EXPORT +#define SHARED_LIB_EXPORT +#define ATCA_DLL extern +#endif + +#endif /* ATCA_COMPILER_H_ */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_config.h b/drivers/ecc108a/cryptoauthlib/atca_config.h new file mode 100644 index 0000000..6787ecc --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_config.h @@ -0,0 +1,14 @@ +#include "py/mphal.h" + +#define ATCA_ATECC108A_SUPPORT +#define ATCA_POST_DELAY_MSEC 25 +#define ATCA_HAL_I2C + +#define ATCA_PLATFORM_MALLOC malloc +#define ATCA_PLATFORM_FREE free + +#define ATCA_TIDAL + +#define atca_delay_ms mp_hal_delay_ms +#define atca_delay_us mp_hal_delay_us + diff --git a/drivers/ecc108a/cryptoauthlib/atca_debug.c b/drivers/ecc108a/cryptoauthlib/atca_debug.c new file mode 100644 index 0000000..f1cf6d9 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_debug.c @@ -0,0 +1,49 @@ +/** + * \file + * \brief Debug/Trace for CryptoAuthLib calls + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include + +FILE * g_trace_fp; + +void atca_trace_config(FILE* fp) +{ + g_trace_fp = fp; +} + +ATCA_STATUS atca_trace(ATCA_STATUS status) +{ + return status; +} + +ATCA_STATUS atca_trace_msg(ATCA_STATUS status, const char * msg) +{ + if (ATCA_SUCCESS != status) + { + fprintf(g_trace_fp ? g_trace_fp : stderr, msg, status); + } + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/atca_debug.h b/drivers/ecc108a/cryptoauthlib/atca_debug.h new file mode 100644 index 0000000..fbe6847 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_debug.h @@ -0,0 +1,11 @@ +#ifndef _ATCA_DEBUG_H +#define _ATCA_DEBUG_H + +#include "atca_status.h" + +void atca_trace_config(FILE* fp); + +ATCA_STATUS atca_trace(ATCA_STATUS status); +ATCA_STATUS atca_trace_msg(ATCA_STATUS status, const char * msg); + +#endif /* _ATCA_DEBUG_H */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_device.c b/drivers/ecc108a/cryptoauthlib/atca_device.c new file mode 100644 index 0000000..855e638 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_device.c @@ -0,0 +1,134 @@ +/** + * \file + * \brief Microchip CryptoAuth device object + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include + +/** \defgroup device ATCADevice (atca_) + * \brief ATCADevice object - composite of command and interface objects + @{ */ + + +#ifndef ATCA_NO_HEAP +/** \brief constructor for a Microchip CryptoAuth device + * \param[in] cfg Interface configuration object + * \return Reference to a new ATCADevice on success. NULL on failure. + */ +ATCADevice newATCADevice(ATCAIfaceCfg *cfg) +{ + ATCADevice ca_dev = NULL; + ATCA_STATUS status; + + if (cfg == NULL) + { + return NULL; + } + + ca_dev = (ATCADevice)hal_malloc(sizeof(*ca_dev)); + if (ca_dev == NULL) + { + return NULL; + } + + memset(ca_dev, 0, sizeof(struct atca_device)); + + status = initATCADevice(cfg, ca_dev); + if (status != ATCA_SUCCESS) + { + hal_free(ca_dev); + ca_dev = NULL; + return NULL; + } + + return ca_dev; +} + +/** \brief destructor for a device NULLs reference after object is freed + * \param[in] ca_dev pointer to a reference to a device + */ +void deleteATCADevice(ATCADevice *ca_dev) +{ + if (ca_dev == NULL) + { + return; + } + + releaseATCADevice(*ca_dev); + + hal_free(*ca_dev); + *ca_dev = NULL; +} +#endif + +/** \brief Initializer for an Microchip CryptoAuth device + * \param[in] cfg pointer to an interface configuration object + * \param[in,out] ca_dev As input, pre-allocated structure to be initialized. + * mCommands and mIface members should point to existing + * structures to be initialized. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS initATCADevice(ATCAIfaceCfg *cfg, ATCADevice ca_dev) +{ + ATCA_STATUS status; + + if (cfg == NULL || ca_dev == NULL) + { + return ATCA_BAD_PARAM; + } + + status = initATCAIface(cfg, &ca_dev->mIface); + if (status != ATCA_SUCCESS) + { + return status; + } + + return ATCA_SUCCESS; +} + +/** \brief returns a reference to the ATCAIface interface object for the device + * \param[in] dev reference to a device + * \return reference to the ATCAIface object for the device + */ +ATCAIface atGetIFace(ATCADevice dev) +{ + return &dev->mIface; +} + +/** \brief Release any resources associated with the device. + * \param[in] ca_dev Device to release + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS releaseATCADevice(ATCADevice ca_dev) +{ + if (ca_dev == NULL) + { + return ATCA_BAD_PARAM; + } + + return releaseATCAIface(&ca_dev->mIface); +} + +/** @} */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_device.h b/drivers/ecc108a/cryptoauthlib/atca_device.h new file mode 100644 index 0000000..a9ac7f2 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_device.h @@ -0,0 +1,312 @@ +/** + * \file + * + * \brief Microchip Crypto Auth device object + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef ATCA_DEVICE_H +#define ATCA_DEVICE_H +/*lint +flb */ + +#include "atca_iface.h" +/** \defgroup device ATCADevice (atca_) + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ATCA_NO_PRAGMA_PACK +#pragma pack(push, 1) +#define ATCA_PACKED +#else +#define ATCA_PACKED __attribute__ ((packed)) +#endif + +typedef struct ATCA_PACKED _atsha204a_config +{ + uint32_t SN03; + uint32_t RevNum; + uint32_t SN47; + uint8_t SN8; + uint8_t Reserved0; + uint8_t I2C_Enable; + uint8_t Reserved1; + uint8_t I2C_Address; + uint8_t Reserved2; + uint8_t OTPmode; + uint8_t ChipMode; + uint16_t SlotConfig[16]; + uint16_t Counter[8]; + uint8_t LastKeyUse[16]; + uint8_t UserExtra; + uint8_t Selector; + uint8_t LockValue; + uint8_t LockConfig; +} atsha204a_config_t; + +typedef struct ATCA_PACKED _atecc508a_config +{ + uint32_t SN03; + uint32_t RevNum; + uint32_t SN47; + uint8_t SN8; + uint8_t Reserved0; + uint8_t I2C_Enable; + uint8_t Reserved1; + uint8_t I2C_Address; + uint8_t Reserved2; + uint8_t OTPmode; + uint8_t ChipMode; + uint16_t SlotConfig[16]; + uint8_t Counter0[8]; + uint8_t Counter1[8]; + uint8_t LastKeyUse[16]; + uint8_t UserExtra; + uint8_t Selector; + uint8_t LockValue; + uint8_t LockConfig; + uint16_t SlotLocked; + uint16_t RFU; + uint32_t X509format; + uint16_t KeyConfig[16]; +} atecc508a_config_t; + +typedef struct ATCA_PACKED _atecc608_config +{ + uint32_t SN03; + uint32_t RevNum; + uint32_t SN47; + uint8_t SN8; + uint8_t AES_Enable; + uint8_t I2C_Enable; + uint8_t Reserved1; + uint8_t I2C_Address; + uint8_t Reserved2; + uint8_t CountMatch; + uint8_t ChipMode; + uint16_t SlotConfig[16]; + uint8_t Counter0[8]; + uint8_t Counter1[8]; + uint8_t UseLock; + uint8_t VolatileKeyPermission; + uint16_t SecureBoot; + uint8_t KdflvLoc; + uint16_t KdflvStr; + uint8_t Reserved3[9]; + uint8_t UserExtra; + uint8_t UserExtraAdd; + uint8_t LockValue; + uint8_t LockConfig; + uint16_t SlotLocked; + uint16_t ChipOptions; + uint32_t X509format; + uint16_t KeyConfig[16]; +} atecc608_config_t; + +#ifndef ATCA_NO_PRAGMA_PACK +#pragma pack(pop) +#endif + +/** \brief ATCADeviceState says about device state + */ +typedef enum +{ + ATCA_DEVICE_STATE_UNKNOWN = 0, + ATCA_DEVICE_STATE_SLEEP, + ATCA_DEVICE_STATE_IDLE, + ATCA_DEVICE_STATE_ACTIVE +} ATCADeviceState; + + +/** \brief atca_device is the C object backing ATCADevice. See the atca_device.h file for + * details on the ATCADevice methods + */ +struct atca_device +{ + atca_iface_t mIface; /**< Physical interface */ + uint8_t device_state; /**< Device Power State */ + + uint8_t clock_divider; + uint16_t execution_time_msec; + + uint8_t session_state; /**< Secure Session State */ + uint16_t session_counter; /**< Secure Session Message Count */ + uint16_t session_key_id; /**< Key ID used for a secure sesison */ + uint8_t* session_key; /**< Session Key */ + uint8_t session_key_len; /**< Length of key used for the session in bytes */ + + uint16_t options; /**< Nested command details parameter */ + +}; + +typedef struct atca_device * ATCADevice; + +ATCA_STATUS initATCADevice(ATCAIfaceCfg* cfg, ATCADevice cadev); +ATCADevice newATCADevice(ATCAIfaceCfg *cfg); +ATCA_STATUS releaseATCADevice(ATCADevice ca_dev); +void deleteATCADevice(ATCADevice *ca_dev); + +ATCAIface atGetIFace(ATCADevice dev); + + + +#ifdef __cplusplus +} +#endif +#define ATCA_AES_ENABLE_EN_SHIFT (0) +#define ATCA_AES_ENABLE_EN_MASK (0x01u << ATCA_AES_ENABLE_EN_SHIFT) + +/* I2C */ +#define ATCA_I2C_ENABLE_EN_SHIFT (0) +#define ATCA_I2C_ENABLE_EN_MASK (0x01u << ATCA_I2C_ENABLE_EN_SHIFT) + +/* Counter Match Feature */ +#define ATCA_COUNTER_MATCH_EN_SHIFT (0) +#define ATCA_COUNTER_MATCH_EN_MASK (0x01u << ATCA_COUNTER_MATCH_EN_SHIFT) +#define ATCA_COUNTER_MATCH_KEY_SHIFT (4) +#define ATCA_COUNTER_MATCH_KEY_MASK (0x0Fu << ATCA_COUNTER_MATCH_KEY_SHIFT) +#define ATCA_COUNTER_MATCH_KEY(v) (ATCA_COUNTER_MATCH_KEY_MASK & (v << ATCA_COUNTER_MATCH_KEY_SHIFT)) + +/* ChipMode */ +#define ATCA_CHIP_MODE_I2C_EXTRA_SHIFT (0) +#define ATCA_CHIP_MODE_I2C_EXTRA_MASK (0x01u << ATCA_CHIP_MODE_I2C_EXTRA_SHIFT) +#define ATCA_CHIP_MODE_TTL_EN_SHIFT (1) +#define ATCA_CHIP_MODE_TTL_EN_MASK (0x01u << ATCA_CHIP_MODE_TTL_EN_SHIFT) +#define ATCA_CHIP_MODE_WDG_LONG_SHIFT (2) +#define ATCA_CHIP_MODE_WDG_LONG_MASK (0x01u << ATCA_CHIP_MODE_WDG_LONG_SHIFT) +#define ATCA_CHIP_MODE_CLK_DIV_SHIFT (3) +#define ATCA_CHIP_MODE_CLK_DIV_MASK (0x1Fu << ATCA_CHIP_MODE_CLK_DIV_SHIFT) +#define ATCA_CHIP_MODE_CLK_DIV(v) (ATCA_CHIP_MODE_CLK_DIV_MASK & (v << ATCA_CHIP_MODE_CLK_DIV_SHIFT)) + +/* General Purpose Slot Config (Not ECC Private Keys) */ +#define ATCA_SLOT_CONFIG_READKEY_SHIFT (0) +#define ATCA_SLOT_CONFIG_READKEY_MASK (0x0Fu << ATCA_SLOT_CONFIG_READKEY_SHIFT) +#define ATCA_SLOT_CONFIG_READKEY(v) (ATCA_SLOT_CONFIG_READKEY_MASK & (v << ATCA_SLOT_CONFIG_READKEY_SHIFT)) +#define ATCA_SLOT_CONFIG_NOMAC_SHIFT (4) +#define ATCA_SLOT_CONFIG_NOMAC_MASK (0x01u << ATCA_SLOT_CONFIG_NOMAC_SHIFT) +#define ATCA_SLOT_CONFIG_LIMITED_USE_SHIFT (5) +#define ATCA_SLOT_CONFIG_LIMITED_USE_MASK (0x01u << ATCA_SLOT_CONFIG_LIMITED_USE_SHIFT) +#define ATCA_SLOT_CONFIG_ENCRYPTED_READ_SHIFT (6) +#define ATCA_SLOT_CONFIG_ENCRYPTED_READ_MASK (0x01u << ATCA_SLOT_CONFIG_ENCRYPTED_READ_SHIFT) +#define ATCA_SLOT_CONFIG_IS_SECRET_SHIFT (7) +#define ATCA_SLOT_CONFIG_IS_SECRET_MASK (0x01u << ATCA_SLOT_CONFIG_IS_SECRET_SHIFT) +#define ATCA_SLOT_CONFIG_WRITE_KEY_SHIFT (8) +#define ATCA_SLOT_CONFIG_WRITE_KEY_MASK (0x0Fu << ATCA_SLOT_CONFIG_WRITE_KEY_SHIFT) +#define ATCA_SLOT_CONFIG_WRITE_KEY(v) (ATCA_SLOT_CONFIG_WRITE_KEY_MASK & (v << ATCA_SLOT_CONFIG_WRITE_KEY_SHIFT)) +#define ATCA_SLOT_CONFIG_WRITE_CONFIG_SHIFT (12) +#define ATCA_SLOT_CONFIG_WRITE_CONFIG_MASK (0x0Fu << ATCA_SLOT_CONFIG_WRITE_CONFIG_SHIFT) +#define ATCA_SLOT_CONFIG_WRITE_CONFIG(v) (ATCA_SLOT_CONFIG_WRITE_CONFIG_MASK & (v << ATCA_SLOT_CONFIG_WRITE_CONFIG_SHIFT)) + +/* Slot Config for ECC Private Keys */ +#define ATCA_SLOT_CONFIG_EXT_SIG_SHIFT (0) +#define ATCA_SLOT_CONFIG_EXT_SIG_MASK (0x01u << ATCA_SLOT_CONFIG_EXT_SIG_SHIFT) +#define ATCA_SLOT_CONFIG_INT_SIG_SHIFT (1) +#define ATCA_SLOT_CONFIG_INT_SIG_MASK (0x01u << ATCA_SLOT_CONFIG_INT_SIG_SHIFT) +#define ATCA_SLOT_CONFIG_ECDH_SHIFT (2) +#define ATCA_SLOT_CONFIG_ECDH_MASK (0x01u << ATCA_SLOT_CONFIG_ECDH_SHIFT) +#define ATCA_SLOT_CONFIG_WRITE_ECDH_SHIFT (3) +#define ATCA_SLOT_CONFIG_WRITE_ECDH_MASK (0x01u << ATCA_SLOT_CONFIG_WRITE_ECDH_SHIFT) +#define ATCA_SLOT_CONFIG_GEN_KEY_SHIFT (8) +#define ATCA_SLOT_CONFIG_GEN_KEY_MASK (0x01u << ATCA_SLOT_CONFIG_GEN_KEY_SHIFT) +#define ATCA_SLOT_CONFIG_PRIV_WRITE_SHIFT (9) +#define ATCA_SLOT_CONFIG_PRIV_WRITE_MASK (0x01u << ATCA_SLOT_CONFIG_PRIV_WRITE_SHIFT) + +/* Use Lock */ +#define ATCA_USE_LOCK_ENABLE_SHIFT (0) +#define ATCA_USE_LOCK_ENABLE_MASK (0x0Fu << ATCA_USE_LOCK_ENABLE_SHIFT) +#define ATCA_USE_LOCK_KEY_SHIFT (4) +#define ATCA_USE_LOCK_KEY_MASK (0x0Fu << ATCA_USE_LOCK_KEY_SHIFT) + +/* Voltatile Key Permission */ +#define ATCA_VOL_KEY_PERM_SLOT_SHIFT (0) +#define ATCA_VOL_KEY_PERM_SLOT_MASK (0x0Fu << ATCA_VOL_KEY_PERM_SLOT_SHIFT) +#define ATCA_VOL_KEY_PERM_SLOT(v) (ATCA_VOL_KEY_PERM_SLOT_MASK & (v << ATCA_VOL_KEY_PERM_SLOT_SHIFT)) +#define ATCA_VOL_KEY_PERM_EN_SHIFT (7) +#define ATCA_VOL_KEY_PERM_EN_MASK (0x01u << ATCA_VOL_KEY_PERM_EN_SHIFT) + +/* Secure Boot */ +#define ATCA_SECURE_BOOT_MODE_SHIFT (0) +#define ATCA_SECURE_BOOT_MODE_MASK (0x03u << ATCA_SECURE_BOOT_MODE_SHIFT) +#define ATCA_SECURE_BOOT_MODE(v) (ATCA_SECURE_BOOT_MODE_MASK & (v << ATCA_SECURE_BOOT_MODE_SHIFT)) +#define ATCA_SECURE_BOOT_PERSIST_EN_SHIFT (3) +#define ATCA_SECURE_BOOT_PERSIST_EN_MASK (0x01u << ATCA_SECURE_BOOT_PERSIST_EN_SHIFT) +#define ATCA_SECURE_BOOT_RAND_NONCE_SHIFT (4) +#define ATCA_SECURE_BOOT_RAND_NONCE_MASK (0x01u << ATCA_SECURE_BOOT_RAND_NONCE_SHIFT) +#define ATCA_SECURE_BOOT_DIGEST_SHIFT (8) +#define ATCA_SECURE_BOOT_DIGEST_MASK (0x0Fu << ATCA_SECURE_BOOT_DIGEST_SHIFT) +#define ATCA_SECURE_BOOT_DIGEST(v) (ATCA_SECURE_BOOT_DIGEST_MASK & (v << ATCA_SECURE_BOOT_DIGEST_SHIFT)) +#define ATCA_SECURE_BOOT_PUB_KEY_SHIFT (12) +#define ATCA_SECURE_BOOT_PUB_KEY_MASK (0x0Fu << ATCA_SECURE_BOOT_PUB_KEY_SHIFT) +#define ATCA_SECURE_BOOT_PUB_KEY(v) (ATCA_SECURE_BOOT_PUB_KEY_MASK & (v << ATCA_SECURE_BOOT_PUB_KEY_SHIFT)) + +/* Slot Locked */ +#define ATCA_SLOT_LOCKED(v) ((0x01 << v) & 0xFFFFu) + +/* Chip Options */ +#define ATCA_CHIP_OPT_POST_EN_SHIFT (0) +#define ATCA_CHIP_OPT_POST_EN_MASK (0x01u << ATCA_CHIP_OPT_POST_EN_SHIFT) +#define ATCA_CHIP_OPT_IO_PROT_EN_SHIFT (1) +#define ATCA_CHIP_OPT_IO_PROT_EN_MASK (0x01u << ATCA_CHIP_OPT_IO_PROT_EN_SHIFT) +#define ATCA_CHIP_OPT_KDF_AES_EN_SHIFT (2) +#define ATCA_CHIP_OPT_KDF_AES_EN_MASK (0x01u << ATCA_CHIP_OPT_KDF_AES_EN_SHIFT) +#define ATCA_CHIP_OPT_ECDH_PROT_SHIFT (8) +#define ATCA_CHIP_OPT_ECDH_PROT_MASK (0x03u << ATCA_CHIP_OPT_ECDH_PROT_SHIFT) +#define ATCA_CHIP_OPT_ECDH_PROT(v) (ATCA_CHIP_OPT_ECDH_PROT_MASK & (v << ATCA_CHIP_OPT_ECDH_PROT_SHIFT)) +#define ATCA_CHIP_OPT_KDF_PROT_SHIFT (10) +#define ATCA_CHIP_OPT_KDF_PROT_MASK (0x03u << ATCA_CHIP_OPT_KDF_PROT_SHIFT) +#define ATCA_CHIP_OPT_KDF_PROT(v) (ATCA_CHIP_OPT_KDF_PROT_MASK & (v << ATCA_CHIP_OPT_KDF_PROT_SHIFT)) +#define ATCA_CHIP_OPT_IO_PROT_KEY_SHIFT (12) +#define ATCA_CHIP_OPT_IO_PROT_KEY_MASK (0x0Fu << ATCA_CHIP_OPT_IO_PROT_KEY_SHIFT) +#define ATCA_CHIP_OPT_IO_PROT_KEY(v) (ATCA_CHIP_OPT_IO_PROT_KEY_MASK & (v << ATCA_CHIP_OPT_IO_PROT_KEY_SHIFT)) + +/* Key Config */ +#define ATCA_KEY_CONFIG_OFFSET(x) (96UL + (x) * 2) +#define ATCA_KEY_CONFIG_PRIVATE_SHIFT (0) +#define ATCA_KEY_CONFIG_PRIVATE_MASK (0x01u << ATCA_KEY_CONFIG_PRIVATE_SHIFT) +#define ATCA_KEY_CONFIG_PUB_INFO_SHIFT (1) +#define ATCA_KEY_CONFIG_PUB_INFO_MASK (0x01u << ATCA_KEY_CONFIG_PUB_INFO_SHIFT) +#define ATCA_KEY_CONFIG_KEY_TYPE_SHIFT (2) +#define ATCA_KEY_CONFIG_KEY_TYPE_MASK (0x07u << ATCA_KEY_CONFIG_KEY_TYPE_SHIFT) +#define ATCA_KEY_CONFIG_KEY_TYPE(v) (ATCA_KEY_CONFIG_KEY_TYPE_MASK & (v << ATCA_KEY_CONFIG_KEY_TYPE_SHIFT)) +#define ATCA_KEY_CONFIG_LOCKABLE_SHIFT (5) +#define ATCA_KEY_CONFIG_LOCKABLE_MASK (0x01u << ATCA_KEY_CONFIG_LOCKABLE_SHIFT) +#define ATCA_KEY_CONFIG_REQ_RANDOM_SHIFT (6) +#define ATCA_KEY_CONFIG_REQ_RANDOM_MASK (0x01u << ATCA_KEY_CONFIG_REQ_RANDOM_SHIFT) +#define ATCA_KEY_CONFIG_REQ_AUTH_SHIFT (7) +#define ATCA_KEY_CONFIG_REQ_AUTH_MASK (0x01u << ATCA_KEY_CONFIG_REQ_AUTH_SHIFT) +#define ATCA_KEY_CONFIG_AUTH_KEY_SHIFT (8) +#define ATCA_KEY_CONFIG_AUTH_KEY_MASK (0x0Fu << ATCA_KEY_CONFIG_AUTH_KEY_SHIFT) +#define ATCA_KEY_CONFIG_AUTH_KEY(v) (ATCA_KEY_CONFIG_AUTH_KEY_MASK & (v << ATCA_KEY_CONFIG_AUTH_KEY_SHIFT)) +#define ATCA_KEY_CONFIG_PERSIST_DISABLE_SHIFT (12) +#define ATCA_KEY_CONFIG_PERSIST_DISABLE_MASK (0x01u << ATCA_KEY_CONFIG_PERSIST_DISABLE_SHIFT) +#define ATCA_KEY_CONFIG_RFU_SHIFT (13) +#define ATCA_KEY_CONFIG_RFU_MASK (0x01u << ATCA_KEY_CONFIG_RFU_SHIFT) +#define ATCA_KEY_CONFIG_X509_ID_SHIFT (14) +#define ATCA_KEY_CONFIG_X509_ID_MASK (0x03u << ATCA_KEY_CONFIG_X509_ID_SHIFT) +#define ATCA_KEY_CONFIG_X509_ID(v) (ATCA_KEY_CONFIG_X509_ID_MASK & (v << ATCA_KEY_CONFIG_X509_ID_SHIFT)) +/** @} */ +/*lint -flb*/ +#endif diff --git a/drivers/ecc108a/cryptoauthlib/atca_devtypes.h b/drivers/ecc108a/cryptoauthlib/atca_devtypes.h new file mode 100644 index 0000000..ba8f82d --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_devtypes.h @@ -0,0 +1,59 @@ +/** + * \file + * \brief Microchip Crypto Auth + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +#ifndef ATCA_DEVTYPES_H_ +#define ATCA_DEVTYPES_H_ + +/** \defgroup device ATCADevice (atca_) + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \brief The supported Device type in Cryptoauthlib library */ +typedef enum +{ + ATSHA204A = 0, + ATECC108A = 1, + ATECC508A = 2, + ATECC608A = 3, + ATECC608B = 3, + ATECC608 = 3, + ATSHA206A = 4, + ECC204 = 5, + TA100 = 0x10, + ATCA_DEV_UNKNOWN = 0x20 +} ATCADeviceType; + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* ATCA_DEVTYPES_H_ */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_helpers.c b/drivers/ecc108a/cryptoauthlib/atca_helpers.c new file mode 100644 index 0000000..6086f34 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_helpers.c @@ -0,0 +1,881 @@ +/** + * \file + * \brief Helpers to support the CryptoAuthLib Basic API methods + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include +#include +#include +#include "cryptoauthlib.h" +#include "atca_helpers.h" + + + +/* Ruleset: + Index - Meaning + 0 - 62 Character + 1 - 63 Character + 2 - Pad Character (none if 0) + 3 - Maximum line length (no limit if 0) */ +uint8_t atcab_b64rules_default[4] = { '+', '/', '=', 64 }; +uint8_t atcab_b64rules_mime[4] = { '+', '/', '=', 76 }; +uint8_t atcab_b64rules_urlsafe[4] = { '-', '_', 0, 0 }; + + +/** \brief Convert a binary buffer to a hex string for easy reading. + * \param[in] bin Input data to convert. + * \param[in] bin_size Size of data to convert. + * \param[out] hex Buffer that receives hex string. + * \param[in,out] hex_size As input, the size of the hex buffer. + * As output, the size of the output hex. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_bin2hex(const uint8_t* bin, size_t bin_size, char* hex, size_t* hex_size) +{ + return atcab_bin2hex_(bin, bin_size, hex, hex_size, true, true, true); +} + +static void uint8_to_hex(uint8_t num, char* hex_str) +{ + uint8_t nibble = (num >> 4) & 0x0F; + + if (nibble < 10) + { + *(hex_str++) = '0' + nibble; + } + else + { + *(hex_str++) = 'A' + (nibble - 10); + } + nibble = num & 0x0F; + if (nibble < 10) + { + *(hex_str++) = '0' + nibble; + } + else + { + *(hex_str++) = 'A' + (nibble - 10); + } +} + +static void hex_to_lowercase(char *buffer, size_t length) +{ + size_t index; + + if ((buffer != NULL) && (length > 0)) + { + for (index = 0; index < length; index++) + { + buffer[index] = (uint8_t)(tolower(buffer[index])); + } + } +} + + +static void hex_to_uppercase(char *buffer, size_t length) +{ + size_t index; + + if ((buffer != NULL) && (length > 0)) + { + for (index = 0; index < length; index++) + { + buffer[index] = (uint8_t)(toupper(buffer[index])); + } + } +} + +/** \brief To reverse the input data. + * \param[in] bin Input data to reverse. + * \param[in] bin_size Size of data to reverse. + * \param[out] dest Buffer to store reversed binary data. + * \param[in] dest_size The size of the dest buffer. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_reversal(const uint8_t* bin, size_t bin_size, uint8_t* dest, size_t* dest_size) +{ + size_t last, i; + + // Verify the inputs + if ((bin == NULL) || (dest == NULL)) + { + return ATCA_BAD_PARAM; + } + + if (*dest_size < bin_size) + { + return ATCA_SMALL_BUFFER; + } + + last = bin_size - 1; + + for (i = 0; i < bin_size; i++) + { + dest[i] = bin[last]; + last--; + } + *dest_size = bin_size; + return ATCA_SUCCESS; +} + + +/** \brief Function that converts a binary buffer to a hex string suitable for + * easy reading. + * \param[in] bin Input data to convert. + * \param[in] bin_size Size of data to convert. + * \param[out] hex Buffer that receives hex string. + * \param[in,out] hex_size As input, the size of the hex buffer. + * As output, the size of the output hex. + * \param[in] is_pretty Indicates whether new lines should be + * added for pretty printing. + * \param[in] is_space Convert the output hex with space between it. + * \param[in] is_upper Convert the output hex to upper case. + + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_bin2hex_(const uint8_t* bin, size_t bin_size, char* hex, size_t* hex_size, bool is_pretty, bool is_space, bool is_upper) +{ + size_t i; + size_t cur_hex_size = 0; + size_t max_hex_size; + + // Verify the inputs + if (bin == NULL || hex == NULL || hex_size == NULL) + { + return ATCA_BAD_PARAM; + } + + max_hex_size = *hex_size; + *hex_size = 0; + + // Convert one byte at a time + for (i = 0; i < bin_size; i++) + { + if (cur_hex_size > max_hex_size) + { + break; + } + if (i != 0) + { + if (is_pretty && (i % 16 == 0)) + { + if (cur_hex_size + 2 > max_hex_size) + { + return ATCA_SMALL_BUFFER; + } + memcpy(&hex[cur_hex_size], "\r\n", 2); + cur_hex_size += 2; + } + else + { + if (is_space) + { + if (cur_hex_size + 1 > max_hex_size) + { + return ATCA_SMALL_BUFFER; + } + hex[cur_hex_size] = ' '; + cur_hex_size += 1; + } + } + } + + if (cur_hex_size + 2 > max_hex_size) + { + return ATCA_SMALL_BUFFER; + } + uint8_to_hex(bin[i], &hex[cur_hex_size]); + cur_hex_size += 2; + } + + if (is_upper) + { + hex_to_uppercase(hex, cur_hex_size); + } + else + { + hex_to_lowercase(hex, cur_hex_size); + } + + *hex_size = cur_hex_size; + if (cur_hex_size < max_hex_size) + { + // Since we have room add NULL as a convenience, but don't add to the + // output size. + hex[cur_hex_size] = 0; + } + + return ATCA_SUCCESS; +} + +inline static uint8_t hex_digit_to_num(char c) +{ + if (c >= '0' && c <= '9') + { + return (uint8_t)(c - '0'); + } + if (c >= 'a' && c <= 'f') + { + return (uint8_t)(c - 'a') + 10; + } + if (c >= 'A' && c <= 'F') + { + return (uint8_t)(c - 'A') + 10; + } + return 16; +} + + +ATCA_STATUS atcab_hex2bin_(const char* hex, size_t hex_size, uint8_t* bin, size_t* bin_size, bool is_space) +{ + size_t hex_index; + size_t bin_index = 0; + bool is_upper_nibble = true; + + for (hex_index = 0; hex_index < hex_size; hex_index++) + { + if (!isHexDigit(hex[hex_index])) + { + if (((hex_index + 1) % 3 == 0) && is_space) + { + if (hex[hex_index] != ' ') + { + return ATCA_BAD_PARAM; + } + } + + continue; // Skip any non-hex character + } + if (bin_index >= *bin_size) + { + return ATCA_SMALL_BUFFER; + } + + if (is_upper_nibble) + { + // Upper nibble + bin[bin_index] = (uint8_t)(hex_digit_to_num(hex[hex_index]) << 4); + } + else + { + // Lower nibble + bin[bin_index] += hex_digit_to_num(hex[hex_index]); + bin_index++; + } + is_upper_nibble = !is_upper_nibble; + } + if (!is_upper_nibble) + { + // Didn't end with an even number of hex digits. Assume it was malformed. + return ATCA_BAD_PARAM; + } + *bin_size = bin_index; + + return ATCA_SUCCESS; +} + +/** \brief Function that converts a hex string to binary buffer + * \param[in] hex Input buffer to convert + * \param[in] hex_size Length of buffer to convert + * \param[out] bin Buffer that receives binary + * \param[in,out] bin_size As input, the size of the bin buffer. + * As output, the size of the bin data. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_hex2bin(const char* hex, size_t hex_size, uint8_t* bin, size_t* bin_size) +{ + return atcab_hex2bin_(hex, hex_size, bin, bin_size, false); +} + +/** + * \brief Checks to see if a character is an ASCII representation of a digit ((c ge '0') and (c le '9')) + * \param[in] c character to check + * \return True if the character is a digit + */ +bool isDigit(char c) +{ + return (c >= '0') && (c <= '9'); +} + +/** + * \brief Checks to see if a character is blank space + * \param[in] c character to check + * \return True if the character is blankspace + */ +bool isBlankSpace(char c) +{ + return (c == '\n') || (c == '\r') || (c == '\t') || (c == ' '); +} + +/** + * \brief Checks to see if a character is an ASCII representation of hex ((c >= 'A') and (c <= 'F')) || ((c >= 'a') and (c <= 'f')) + * \param[in] c character to check + * \return True if the character is a hex + */ +bool isAlpha(char c) +{ + return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')); +} + +/** + * \brief Checks to see if a character is an ASCII representation of hex ((c >= 'A') and (c <= 'F')) || ((c >= 'a') and (c <= 'f')) + * \param[in] c character to check + * \return True if the character is a hex + */ +bool isHexAlpha(char c) +{ + return ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')); +} + +/** + * \brief Returns true if this character is a valid hex character or if this is blankspace (The character can be + * included in a valid hexstring). + * \param[in] c character to check + * \return True if the character can be included in a valid hexstring + */ +bool isHex(char c) +{ + return isHexDigit(c) || isBlankSpace(c); +} + +/** + * \brief Returns true if this character is a valid hex character. + * \param[in] c character to check + * \return True if the character can be included in a valid hexstring + */ +bool isHexDigit(char c) +{ + return isDigit(c) || isHexAlpha(c); +} + +/** + * \brief Remove spaces from a ASCII hex string. + * \param[in] ascii_hex Initial hex string to remove blankspace from + * \param[in] ascii_hex_len Length of the initial hex string + * \param[in] packed_hex Resulting hex string without blankspace + * \param[in,out] packed_len In: Size to packed_hex buffer + * Out: Number of bytes in the packed hex string + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS packHex(const char* ascii_hex, size_t ascii_hex_len, char* packed_hex, size_t* packed_len) +{ + size_t i = 0; + size_t j = 0; + + // Verify the inputs + if ((ascii_hex == NULL) || (packed_hex == NULL) || (packed_len == NULL)) + { + return ATCA_BAD_PARAM; + } + // Loop through each character and only add the hex characters + for (i = 0; i < ascii_hex_len; i++) + { + if (isHexDigit(ascii_hex[i])) + { + if (j > *packed_len) + { + break; + } + packed_hex[j++] = ascii_hex[i]; + } + } + *packed_len = j; + + return ATCA_SUCCESS; +} + +#ifdef ATCA_PRINTF +/** \brief Print each hex character in the binary buffer with spaces between bytes + * \param[in] label label to print + * \param[in] binary input buffer to print + * \param[in] bin_len length of buffer to print + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_printbin_label(const char* label, uint8_t* binary, size_t bin_len) +{ + printf("%s", label); + return atcab_printbin(binary, bin_len, true); +} + +/** \brief Print each hex character in the binary buffer with spaces between bytes + * \param[in] binary input buffer to print + * \param[in] bin_len length of buffer to print + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_printbin_sp(uint8_t* binary, size_t bin_len) +{ + return atcab_printbin(binary, bin_len, true); +} + +/** \brief Print each hex character in the binary buffer + * \param[in] binary input buffer to print + * \param[in] bin_len length of buffer to print + * \param[in] add_space indicates whether spaces and returns should be added for pretty printing + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_printbin(uint8_t* binary, size_t bin_len, bool add_space) +{ + size_t i = 0; + size_t line_len = 16; + + // Verify the inputs + if (binary == NULL) + { + return ATCA_BAD_PARAM; + } + + // Set the line length + line_len = add_space ? 16 : 32; + + // Print the bytes + for (i = 0; i < bin_len; i++) + { + // Print the byte + if (add_space) + { + printf("%02X ", binary[i]); + } + else + { + printf("%02X", binary[i]); + } + + // Break at the line_len + if ((i + 1) % line_len == 0) + { + printf("\r\n"); + } + } + // Print the last carriage return + printf("\r\n"); + + return ATCA_SUCCESS; +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Base 64 Encode/Decode + +#define B64_IS_EQUAL (uint8_t)64 +#define B64_IS_INVALID (uint8_t)0xFF + +/** + * \brief Returns true if this character is a valid base 64 character or if this is space (A character can be + * included in a valid base 64 string). + * \param[in] c character to check + * \param[in] rules base64 ruleset to use + * \return True if the character can be included in a valid base 64 string + */ +bool isBase64(char c, const uint8_t * rules) +{ + return isBase64Digit(c, rules) || isBlankSpace(c); +} + +/** + * \brief Returns true if this character is a valid base 64 character. + * \param[in] c character to check + * \param[in] rules base64 ruleset to use + * \return True if the character can be included in a valid base 64 string + */ +bool isBase64Digit(char c, const uint8_t * rules) +{ + return isDigit(c) || isAlpha(c) || c == rules[0] || c == rules[1] || c == rules[2]; +} + +/** + * \brief Returns the base 64 index of the given character. + * \param[in] c character to check + * \param[in] rules base64 ruleset to use + * \return the base 64 index of the given character + */ +uint8_t base64Index(char c, const uint8_t * rules) +{ + if ((c >= 'A') && (c <= 'Z')) + { + return (uint8_t)(c - 'A'); + } + if ((c >= 'a') && (c <= 'z')) + { + return (uint8_t)(26 + c - 'a'); + } + if ((c >= '0') && (c <= '9')) + { + return (uint8_t)(52 + c - '0'); + } + if (c == rules[0]) + { + return (uint8_t)62; + } + if (c == rules[1]) + { + return (uint8_t)63; + } + if (c == rules[2]) + { + return B64_IS_EQUAL; + } + return B64_IS_INVALID; +} + +/** + * \brief Returns the base 64 character of the given index. + * \param[in] id index to check + * \param[in] rules base64 ruleset to use + * \return the base 64 character of the given index + */ +char base64Char(uint8_t id, const uint8_t * rules) +{ + if (id < 26) + { + return (char)('A' + id); + } + if ((id >= 26) && (id < 52)) + { + return (char)('a' + id - 26); + } + if ((id >= 52) && (id < 62)) + { + return (char)('0' + id - 52); + } + if (id == 62) + { + return rules[0]; + } + if (id == 63) + { + return rules[1]; + } + + if (id == B64_IS_EQUAL) + { + return rules[2]; + } + return B64_IS_INVALID; +} + +static ATCA_STATUS atcab_base64decode_block(const uint8_t id[4], uint8_t* data, size_t* data_size, size_t data_max_size) +{ + ATCA_STATUS status = ATCA_SUCCESS; + size_t new_bytes = 0; + + do + { + // Make sure padding characters can only be the last two + if ((id[0] == B64_IS_EQUAL) || + (id[1] == B64_IS_EQUAL) || + (id[2] == B64_IS_EQUAL && id[3] != B64_IS_EQUAL)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Base64 chars after end padding"); + break; + } + + // Make sure output buffer has enough space + if (id[2] == B64_IS_EQUAL) + { + new_bytes = 1; + } + else if (id[3] == B64_IS_EQUAL) + { + new_bytes = 2; + } + else + { + new_bytes = 3; + } + if ((*data_size) + new_bytes > data_max_size) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "decoded buffer too small"); + break; + } + + // Decode into output buffer + data[(*data_size)++] = (uint8_t)((id[0] << 2) | (id[1] >> 4)); + if (id[2] == B64_IS_EQUAL) + { + break; + } + data[(*data_size)++] = (uint8_t)((id[1] << 4) | (id[2] >> 2)); + if (id[3] == B64_IS_EQUAL) + { + break; + } + data[(*data_size)++] = (uint8_t)((id[2] << 6) | id[3]); + } + while (false); + + return status; +} + +/** + * \brief Decode base64 string to data with ruleset option. + * + * \param[in] encoded Base64 string to be decoded. + * \param[in] encoded_size Size of the base64 string in bytes. + * \param[out] data Decoded data will be returned here. + * \param[in,out] data_size As input, the size of the byte_array buffer. + * As output, the length of the decoded data. + * \param[in] rules base64 ruleset to use + */ +ATCA_STATUS atcab_base64decode_(const char* encoded, size_t encoded_size, uint8_t* data, size_t* data_size, const uint8_t * rules) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t id[4]; + int id_index = 0; + size_t enc_index = 0; + size_t data_max_size; + bool is_done = false; + + do + { + // Check the input parameters + if (encoded == NULL || data == NULL || data_size == NULL || rules == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Null input parameter"); + break; + } + data_max_size = *data_size; + *data_size = 0; + + // Start decoding the input data + for (enc_index = 0; enc_index < encoded_size; enc_index++) + { + if (isBlankSpace(encoded[enc_index])) + { + continue; // Skip any empty characters + } + if (!isBase64Digit(encoded[enc_index], rules)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid base64 character"); + break; + } + if (is_done) + { + // We found valid base64 characters after end padding (equals) + // characters + status = ATCA_TRACE(ATCA_BAD_PARAM, "Base64 chars after end padding"); + break; + } + id[id_index++] = base64Index(encoded[enc_index], rules); + // Process data 4 characters at a time + if (id_index >= 4) + { + id_index = 0; + status = atcab_base64decode_block(id, data, data_size, data_max_size); + if (status != ATCA_SUCCESS) + { + break; + } + + is_done = (id[3] == B64_IS_EQUAL); + } + } + if (status != ATCA_SUCCESS) + { + break; + } + if (id_index) + { + if (id_index < 2) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid number of base64 chars"); + break; + } + // End of base64 string, but no padding characters + for (; id_index < 4; id_index++) + { + id[id_index] = B64_IS_EQUAL; + } + status = atcab_base64decode_block(id, data, data_size, data_max_size); + } + } + while (false); + + return status; +} + +/** \brief Encode data as base64 string with ruleset option. */ +ATCA_STATUS atcab_base64encode_( + const uint8_t* data, /**< [in] The input byte array that will be converted to base 64 encoded characters */ + size_t data_size, /**< [in] The length of the byte array */ + char* encoded, /**< [in] The output converted to base 64 encoded characters. */ + size_t* encoded_size, /**< [inout] Input: The size of the encoded buffer, Output: The length of the encoded base 64 character string */ + const uint8_t * rules /**< [in] ruleset to use during encoding */ + ) +{ + ATCA_STATUS status = ATCA_SUCCESS; + size_t data_idx = 0; + size_t b64_idx = 0; + size_t offset = 0; + uint8_t id = 0; + size_t b64_len; + + do + { + // Check the input parameters + if (encoded == NULL || data == NULL || encoded_size == NULL || !rules) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Null input parameter"); + break; + } + + // Calculate output length for buffer size check + b64_len = (data_size / 3 + (data_size % 3 != 0)) * 4; // ceil(size/3)*4 + if (rules[3]) + { + // We add newlines to the output + if (rules[3] % 4 != 0) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "newline rules[3] must be multiple of 4"); + break; + } + b64_len += (b64_len / rules[3]) * 2; + } + b64_len += 1; // terminating null + if (*encoded_size < b64_len) + { + status = ATCA_TRACE(ATCA_SMALL_BUFFER, "Length of encoded buffer too small"); + break; + } + // Initialize the return length to 0 + *encoded_size = 0; + + // Loop through the byte array by 3 then map to 4 base 64 encoded characters + for (data_idx = 0; data_idx < data_size; data_idx += 3) + { + // Add \r\n every n bytes if specified + if (rules[3] && data_idx > 0 && (b64_idx - offset) % rules[3] == 0) + { + // as soon as we do this, we introduce an offset + encoded[b64_idx++] = '\r'; + encoded[b64_idx++] = '\n'; + offset += 2; + } + + id = (data[data_idx] & 0xFC) >> 2; + encoded[b64_idx++] = base64Char(id, rules); + id = (uint8_t)((data[data_idx] & 0x03) << 4); + if (data_idx + 1 < data_size) + { + id |= (data[data_idx + 1] & 0xF0) >> 4; + encoded[b64_idx++] = base64Char(id, rules); + id = (uint8_t)((data[data_idx + 1] & 0x0F) << 2); + if (data_idx + 2 < data_size) + { + id |= (data[data_idx + 2] & 0xC0) >> 6; + encoded[b64_idx++] = base64Char(id, rules); + id = data[data_idx + 2] & 0x3F; + encoded[b64_idx++] = base64Char(id, rules); + } + else + { + encoded[b64_idx++] = base64Char(id, rules); + encoded[b64_idx++] = base64Char(B64_IS_EQUAL, rules); + } + } + else + { + encoded[b64_idx++] = base64Char(id, rules); + encoded[b64_idx++] = base64Char(B64_IS_EQUAL, rules); + encoded[b64_idx++] = base64Char(B64_IS_EQUAL, rules); + } + } + + // Strip any trailing nulls + while (b64_idx > 1 && encoded[b64_idx - 1] == 0) + { + b64_idx--; + } + + // Null terminate end + encoded[b64_idx++] = 0; + + // Set the final encoded length (excluding terminating null) + *encoded_size = b64_idx - 1; + } + while (false); + return status; +} + + +/** + * \brief Encode data as base64 string + * + * \param[in] byte_array Data to be encode in base64. + * \param[in] array_len Size of byte_array in bytes. + * \param[in] encoded Base64 output is returned here. + * \param[in,out] encoded_len As input, the size of the encoded buffer. + * As output, the length of the encoded base64 + * character string. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_base64encode(const uint8_t* byte_array, size_t array_len, char* encoded, size_t* encoded_len) +{ + return atcab_base64encode_(byte_array, array_len, encoded, encoded_len, atcab_b64rules_default); +} + +/** + * \brief Decode base64 string to data + * + * \param[in] encoded Base64 string to be decoded. + * \param[in] encoded_len Size of the base64 string in bytes. + * \param[out] byte_array Decoded data will be returned here. + * \param[in,out] array_len As input, the size of the byte_array buffer. + * As output, the length of the decoded data. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcab_base64decode(const char* encoded, size_t encoded_len, uint8_t* byte_array, size_t* array_len) +{ + return atcab_base64decode_(encoded, encoded_len, byte_array, array_len, atcab_b64rules_default); +} + +/** + * \brief Guaranteed to perform memory writes regardless of optimization level. Matches memset_s signature + */ +int atcab_memset_s(void* dest, size_t destsz, int ch, size_t count) +{ + if (dest == NULL) + { + return -1; + } + if (destsz > SIZE_MAX) + { + return -1; + } + if (count > destsz) + { + return -1; + } + + volatile unsigned char* p = dest; + while (destsz-- && count--) + { + *p++ = (uint8_t)ch; + } + + return 0; +} diff --git a/drivers/ecc108a/cryptoauthlib/atca_helpers.h b/drivers/ecc108a/cryptoauthlib/atca_helpers.h new file mode 100644 index 0000000..447f847 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_helpers.h @@ -0,0 +1,83 @@ +/** + * \file + * \brief Helpers to support the CryptoAuthLib Basic API methods + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef ATCA_HELPERS_H_ +#define ATCA_HELPERS_H_ + +#include "cryptoauthlib.h" + +/** \ingroup atcab_ + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +ATCA_STATUS atcab_printbin(uint8_t* binary, size_t bin_len, bool add_space); +ATCA_STATUS atcab_bin2hex(const uint8_t* bin, size_t bin_size, char* hex, size_t* hex_size); +ATCA_STATUS atcab_bin2hex_(const uint8_t* bin, size_t bin_size, char* hex, size_t* hex_size, bool is_pretty, bool is_space, bool is_upper); +ATCA_STATUS atcab_hex2bin(const char* ascii_hex, size_t ascii_hex_len, uint8_t* binary, size_t* bin_len); +ATCA_STATUS atcab_hex2bin_(const char* hex, size_t hex_size, uint8_t* bin, size_t* bin_size, bool is_space); +ATCA_STATUS atcab_printbin_sp(uint8_t* binary, size_t bin_len); +ATCA_STATUS atcab_printbin_label(const char* label, uint8_t* binary, size_t bin_len); + + +ATCA_STATUS packHex(const char* ascii_hex, size_t ascii_hex_len, char* packed_hex, size_t* packed_len); +bool isDigit(char c); +bool isBlankSpace(char c); +bool isAlpha(char c); +bool isHexAlpha(char c); +bool isHex(char c); +bool isHexDigit(char c); + +bool isBase64(char c, const uint8_t * rules); +bool isBase64Digit(char c, const uint8_t * rules); +uint8_t base64Index(char c, const uint8_t * rules); +char base64Char(uint8_t id, const uint8_t * rules); + +ATCA_DLL uint8_t atcab_b64rules_default[4]; +ATCA_DLL uint8_t atcab_b64rules_mime[4]; +ATCA_DLL uint8_t atcab_b64rules_urlsafe[4]; + +ATCA_STATUS atcab_base64decode_(const char* encoded, size_t encoded_size, uint8_t* data, size_t* data_size, const uint8_t * rules); +ATCA_STATUS atcab_base64decode(const char* encoded, size_t encoded_size, uint8_t* data, size_t* data_size); + +ATCA_STATUS atcab_base64encode_(const uint8_t* data, size_t data_size, char* encoded, size_t* encoded_size, const uint8_t * rules); +ATCA_STATUS atcab_base64encode(const uint8_t* data, size_t data_size, char* encoded, size_t* encoded_size); + + +ATCA_STATUS atcab_reversal(const uint8_t* bin, size_t bin_size, uint8_t* dest, size_t* dest_size); + +int atcab_memset_s(void* dest, size_t destsz, int ch, size_t count); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* ATCA_HELPERS_H_ */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_iface.c b/drivers/ecc108a/cryptoauthlib/atca_iface.c new file mode 100644 index 0000000..ab8aeac --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_iface.c @@ -0,0 +1,438 @@ +/** + * \file + * + * \brief Microchip CryptoAuthLib hardware interface object + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \defgroup interface ATCAIface (atca_) + * \brief Abstract interface to all CryptoAuth device types. This interface + * connects to the HAL implementation and abstracts the physical details of the + * device communication from all the upper layers of CryptoAuthLib + @{ */ + + +/** \brief Initializer for ATCAIface objects + * \param[in] cfg Logical configuration for the interface + * \param[in] ca_iface Interface structure to initialize. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS initATCAIface(ATCAIfaceCfg *cfg, ATCAIface ca_iface) +{ + ATCA_STATUS status; + + if (cfg == NULL || ca_iface == NULL) + { + return ATCA_BAD_PARAM; + } + + ca_iface->mIfaceCFG = cfg; + + status = ATCA_TRACE(atinit(ca_iface), "atinit"); + if (status != ATCA_SUCCESS) + { + return status; + } + + return ATCA_SUCCESS; +} + +#ifndef ATCA_NO_HEAP +/** \brief Constructor for ATCAIface objects + * \param[in] cfg Logical configuration for the interface + * \return New interface instance on success. NULL on failure. + */ +ATCAIface newATCAIface(ATCAIfaceCfg *cfg) +{ + ATCAIface ca_iface; + ATCA_STATUS status; + + ca_iface = (ATCAIface)hal_malloc(sizeof(struct atca_iface)); + status = initATCAIface(cfg, ca_iface); + if (status != ATCA_SUCCESS) + { + hal_free(ca_iface); + ca_iface = NULL; + return NULL; + } + + return ca_iface; +} +#endif + +/** \brief Performs the HAL initialization by calling intermediate HAL wrapper + * function. If using the basic API, the atcab_init() function should + * be called instead. + * \param[in] ca_iface Device to interact with. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atinit(ATCAIface ca_iface) +{ + ATCA_STATUS status = ATCA_COMM_FAIL; + + if (ca_iface) + { + status = ATCA_TRACE(hal_iface_init(ca_iface->mIfaceCFG, &ca_iface->hal, &ca_iface->phy), "Failed to configure HAL"); + + /* Initialize the physical interface if one is required for the hal */ + if (ATCA_SUCCESS == status && ca_iface->phy) + { + if (ca_iface->phy->halinit && ca_iface->phy->halpostinit) + { + if (ATCA_SUCCESS == (status = ATCA_TRACE(ca_iface->phy->halinit(ca_iface, ca_iface->mIfaceCFG), "phyinit"))) + { + status = ATCA_TRACE(ca_iface->phy->halpostinit(ca_iface), "phypostinit"); + } + } + else + { + status = ATCA_TRACE(ATCA_ASSERT_FAILURE, "phy is invalid"); + } + } + + /* Initialize the hal itself */ + if (ATCA_SUCCESS == status) + { + if (ca_iface->hal->halinit && ca_iface->hal->halpostinit) + { + if (ATCA_SUCCESS == (status = ATCA_TRACE(ca_iface->hal->halinit(ca_iface, ca_iface->mIfaceCFG), "halinit"))) + { + status = ATCA_TRACE(ca_iface->hal->halpostinit(ca_iface), "halpostinit"); + } + } + else + { + status = ATCA_TRACE(ATCA_ASSERT_FAILURE, "hal is invalid"); + } + } + } + + return status; +} + +/** \brief Sends the data to the device by calling intermediate HAL wrapper + * function. + * \param[in] ca_iface Device to interact with. + * \param[in] word_address device transaction type + * \param[in] txdata Data to be transmitted to the device. + * \param[in] txlength Number of bytes to be transmitted to the device. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atsend(ATCAIface ca_iface, uint8_t address, uint8_t *txdata, int txlength) +{ + if (!ca_iface) + { + return ATCA_BAD_PARAM; + } + + if (ca_iface->hal && ca_iface->hal->halsend) + { +#ifdef ATCA_HAL_I2C + if (ATCA_I2C_IFACE == ca_iface->mIfaceCFG->iface_type && 0xFF == address) + { +#ifdef ATCA_ENABLE_DEPRECATED + address = ca_iface->mIfaceCFG->atcai2c.slave_address; +#else + address = ca_iface->mIfaceCFG->atcai2c.address; +#endif + } +#endif + + return ca_iface->hal->halsend(ca_iface, address, txdata, txlength); + } + else + { + return ATCA_NOT_INITIALIZED; + } +} + +/** \brief Receives data from the device by calling intermediate HAL wrapper + * function. + * \param[in] ca_iface Device to interact with. + * \param[in] word_address device transaction type + * \param[out] rxdata Data received will be returned here. + * \param[in,out] rxlength As input, the size of the rxdata buffer. + * As output, the number of bytes received. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atreceive(ATCAIface ca_iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength) +{ + if (!ca_iface) + { + return ATCA_BAD_PARAM; + } + + if (ca_iface->hal && ca_iface->hal->halreceive) + { + return ca_iface->hal->halreceive(ca_iface, word_address, rxdata, rxlength); + } + else + { + return ATCA_NOT_INITIALIZED; + } +} + + +/** \brief Perform control operations with the underlying hal driver + * \param[in] ca_iface Device to interact with. + * \param[in] option Control parameter identifier + * \param[in] param Optional pointer to parameter value + * \param[in] paramlen Length of the parameter + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atcontrol(ATCAIface ca_iface, uint8_t option, void* param, size_t paramlen) +{ + if (!ca_iface) + { + return ATCA_BAD_PARAM; + } + + + if (ca_iface->hal && ca_iface->hal->halcontrol) + { + return ca_iface->hal->halcontrol(ca_iface, option, param, paramlen); + } + else + { + return ATCA_NOT_INITIALIZED; + } +} + +/** \brief Wakes up the device by calling intermediate HAL wrapper function. The + * atcab_wakeup() function should be used instead. + * \deprecated This function does not have defined behavior when ATCA_HAL_LEGACY_API + * is undefined. + * + * \param[in] ca_iface Device to interact with. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atwake(ATCAIface ca_iface) +{ + if (!ca_iface) + { + return ATCA_BAD_PARAM; + } + + + if (ca_iface->hal && ca_iface->hal->halcontrol) + { + ATCA_STATUS status = ca_iface->hal->halcontrol(ca_iface, ATCA_HAL_CONTROL_WAKE, NULL, 0); + + if (ATCA_WAKE_FAILED == status) + { + // The device might be performing a POST. Wait for it to complete + // and try again. + atca_delay_ms(ATCA_POST_DELAY_MSEC); + + status = ca_iface->hal->halcontrol(ca_iface, ATCA_HAL_CONTROL_WAKE, NULL, 0); + } + return status; + } + else + { + return ATCA_NOT_INITIALIZED; + } +} + + +/** \brief Puts the device into idle state by calling intermediate HAL wrapper + * function. The atcab_idle() function should be used instead. + * \deprecated This function does not have defined behavior when ATCA_HAL_LEGACY_API + * is undefined. + * \param[in] ca_iface Device to interact with. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atidle(ATCAIface ca_iface) +{ + if (!ca_iface) + { + return ATCA_BAD_PARAM; + } + + if (ca_iface->hal && ca_iface->hal->halcontrol) + { + ATCA_STATUS status = ca_iface->hal->halcontrol(ca_iface, ATCA_HAL_CONTROL_IDLE, NULL, 0); + atca_delay_ms(1); + return status; + } + else + { + return ATCA_NOT_INITIALIZED; + } +} + +/** \brief Puts the device into sleep state by calling intermediate HAL wrapper + * function. The atcab_sleep() function should be used instead. + * \deprecated This function does not have defined behavior when ATCA_HAL_LEGACY_API + * is undefined. + * \param[in] ca_iface Device to interact with. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atsleep(ATCAIface ca_iface) +{ + if (!ca_iface) + { + return ATCA_BAD_PARAM; + } + + if (ca_iface->hal && ca_iface->hal->halcontrol) + { + ATCA_STATUS status = ca_iface->hal->halcontrol(ca_iface, ATCA_HAL_CONTROL_SLEEP, NULL, 0); + atca_delay_ms(1); + return status; + } + else + { + return ATCA_NOT_INITIALIZED; + } +} + + +/** \brief Returns the logical interface configuration for the device. + * \param[in] ca_iface Device interface. + * \return Logical interface configuration. + */ +ATCAIfaceCfg * atgetifacecfg(ATCAIface ca_iface) +{ + return ca_iface ? ca_iface->mIfaceCFG : NULL; +} + + +/** \brief Returns the HAL data pointer for the device. + * \param[in] ca_iface Device interface. + * \return HAL data pointer. + */ +void* atgetifacehaldat(ATCAIface ca_iface) +{ + return ca_iface ? ca_iface->hal_data : NULL; +} + +/** \brief Check if the given interface is configured as a "kit protocol" one where + * transactions are atomic + * \return true if the interface is considered a kit + */ +bool atca_iface_is_kit(ATCAIface ca_iface) +{ + bool ret = false; + + if (ca_iface && ca_iface->mIfaceCFG) + { + if (ATCA_HID_IFACE == ca_iface->mIfaceCFG->iface_type || ATCA_KIT_IFACE == ca_iface->mIfaceCFG->iface_type + || ATCA_UART_IFACE == ca_iface->mIfaceCFG->iface_type) + { + ret = true; + } + } + return ret; +} + +/** \brief Check if the given interface is configured as a SWI + * \return true if the interface is considered a kit + */ +bool atca_iface_is_swi(ATCAIface ca_iface) +{ + bool ret = false; + + if (ca_iface && ca_iface->mIfaceCFG) + { + if (ATCA_SWI_IFACE == ca_iface->mIfaceCFG->iface_type || ATCA_SWI_GPIO_IFACE == ca_iface->mIfaceCFG->iface_type) + { + ret = true; + } + } + return ret; +} + +/** \brief Retrive the number of retries for a configured interface */ +int atca_iface_get_retries(ATCAIface ca_iface) +{ + if (ca_iface && ca_iface->mIfaceCFG) + { + return ca_iface->mIfaceCFG->rx_retries; + } + else + { + return 0; + } +} + +/** \brief Retrive the wake/retry delay for a configured interface/device */ +uint16_t atca_iface_get_wake_delay(ATCAIface ca_iface) +{ + if (ca_iface && ca_iface->mIfaceCFG) + { + return ca_iface->mIfaceCFG->wake_delay; + } + else + { + return 1500; + } +} + + +/** \brief Instruct the HAL driver to release any resources associated with + * this interface. + * \param[in] ca_iface Device interface. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS releaseATCAIface(ATCAIface ca_iface) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + + if (ca_iface && ca_iface->mIfaceCFG) + { + if (ATCA_SUCCESS == (status = hal_iface_release(ca_iface->mIfaceCFG->iface_type, ca_iface->hal_data))) + { + ca_iface->hal_data = NULL; + } + if (ATCA_CUSTOM_IFACE == ca_iface->mIfaceCFG->iface_type) + { +#ifndef ATCA_NO_HEAP + hal_free(ca_iface->hal); +#endif + ca_iface->hal = NULL; + } + } + return status; +} + +#ifndef ATCA_NO_HEAP +/** \brief Instruct the HAL driver to release any resources associated with + * this interface, then delete the object. + * \param[in] ca_iface Device interface. + */ +void deleteATCAIface(ATCAIface *ca_iface) +{ + if (ca_iface) + { + releaseATCAIface(*ca_iface); + hal_free(*ca_iface); + *ca_iface = NULL; + } +} +#endif + +/** @} */ diff --git a/drivers/ecc108a/cryptoauthlib/atca_iface.h b/drivers/ecc108a/cryptoauthlib/atca_iface.h new file mode 100644 index 0000000..1cb80ea --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_iface.h @@ -0,0 +1,215 @@ +/** + * \file + * + * \brief Microchip Crypto Auth hardware interface object + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef ATCA_IFACE_H +#define ATCA_IFACE_H +/*lint +flb */ + +/** \defgroup interface ATCAIface (atca_) + * \brief Abstract interface to all CryptoAuth device types. This interface + * connects to the HAL implementation and abstracts the physical details of the + * device communication from all the upper layers of CryptoAuthLib + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "atca_config.h" +#include "atca_devtypes.h" +#include "atca_status.h" + + +typedef enum +{ + ATCA_I2C_IFACE = 0, /**< Native I2C Driver */ + ATCA_SWI_IFACE = 1, /**< SWI or 1-Wire over UART/USART */ + ATCA_UART_IFACE = 2, /**< Kit v1 over UART/USART */ + ATCA_SPI_IFACE = 3, /**< Native SPI Driver */ + ATCA_HID_IFACE = 4, /**< Kit v1 over HID */ + ATCA_KIT_IFACE = 5, /**< Kit v2 (Binary/Bridging) */ + ATCA_CUSTOM_IFACE = 6, /**< Custom HAL functions provided during interface init */ + ATCA_I2C_GPIO_IFACE = 7, /**< I2C "Bitbang" Driver */ + ATCA_SWI_GPIO_IFACE = 8, /**< SWI or 1-Wire using a GPIO */ + ATCA_SPI_GPIO_IFACE = 9, /**< SWI or 1-Wire using a GPIO */ + + // additional physical interface types here + ATCA_UNKNOWN_IFACE = 0xFE +} ATCAIfaceType; + + +/*The types are used within the kit protocol to identify the correct interface*/ +typedef enum +{ ATCA_KIT_AUTO_IFACE, //Selects the first device if the Kit interface is not defined + ATCA_KIT_I2C_IFACE, + ATCA_KIT_SWI_IFACE, + ATCA_KIT_SPI_IFACE, + ATCA_KIT_UNKNOWN_IFACE } ATCAKitType; + + +/* ATCAIfaceCfg is the configuration object for a device + */ + +typedef struct +{ + + ATCAIfaceType iface_type; // active iface - how to interpret the union below + ATCADeviceType devtype; // explicit device type + + union // each instance of an iface cfg defines a single type of interface + { + struct + { +#ifdef ATCA_ENABLE_DEPRECATED + uint8_t slave_address; // 8-bit slave address +#else + uint8_t address; /**< Device address - the upper 7 bits are the I2c address bits */ +#endif + uint8_t bus; // logical i2c bus number, 0-based - HAL will map this to a pin pair for SDA SCL + uint32_t baud; // typically 400000 + } atcai2c; + + struct + { + uint8_t address; // 7-bit device address + uint8_t bus; // logical SWI bus - HAL will map this to a pin or uart port + } atcaswi; + + struct + { + uint8_t bus; // logical i2c bus number, 0-based - HAL will map this to a spi pheripheral + uint8_t select_pin; // CS pin line typically 0 + uint32_t baud; // typically 16000000 + } atcaspi; + + struct + { + ATCAKitType dev_interface; // Kit interface type + uint8_t dev_identity; // I2C address for the I2C interface device or the bus number for the SWI interface device. + uint8_t port; // Port numbers where supported - otherwise accept the device through config data + uint32_t baud; // typically 115200 + uint8_t wordsize; // usually 8 + uint8_t parity; // 0 == even, 1 == odd, 2 == none + uint8_t stopbits; // 0,1,2 + } atcauart; + + struct + { + int idx; // HID enumeration index + ATCAKitType dev_interface; // Kit interface type + uint8_t dev_identity; // I2C address for the I2C interface device or the bus number for the SWI interface device. + uint32_t vid; // Vendor ID of kit (0x03EB for CK101) + uint32_t pid; // Product ID of kit (0x2312 for CK101) + uint32_t packetsize; // Size of the USB packet + } atcahid; + + struct + { + ATCAKitType dev_interface; // Target Bus Type + uint8_t dev_identity; // Target device identity + uint32_t flags; + } atcakit; + + struct + { + ATCA_STATUS (*halinit)(void *hal, void *cfg); + ATCA_STATUS (*halpostinit)(void *iface); + ATCA_STATUS (*halsend)(void *iface, uint8_t word_address, uint8_t *txdata, int txlength); + ATCA_STATUS (*halreceive)(void *iface, uint8_t word_address, uint8_t* rxdata, uint16_t* rxlength); + ATCA_STATUS (*halwake)(void *iface); + ATCA_STATUS (*halidle)(void *iface); + ATCA_STATUS (*halsleep)(void *iface); + ATCA_STATUS (*halrelease)(void* hal_data); + } atcacustom; + + }; + + uint16_t wake_delay; // microseconds of tWHI + tWLO which varies based on chip type + int rx_retries; // the number of retries to attempt for receiving bytes + void * cfg_data; // opaque data used by HAL in device discovery +} ATCAIfaceCfg; + + + +typedef struct atca_iface * ATCAIface; + +/** \brief HAL Driver Structure + */ +typedef struct +{ + ATCA_STATUS (*halinit)(ATCAIface iface, ATCAIfaceCfg* cfg); + ATCA_STATUS (*halpostinit)(ATCAIface iface); + ATCA_STATUS (*halsend)(ATCAIface iface, uint8_t word_address, uint8_t* txdata, int txlength); + ATCA_STATUS (*halreceive)(ATCAIface iface, uint8_t word_address, uint8_t* rxdata, uint16_t* rxlength); + ATCA_STATUS (*halcontrol)(ATCAIface iface, uint8_t option, void* param, size_t paramlen); + ATCA_STATUS (*halrelease)(void* hal_data); +} ATCAHAL_t; + +/** \brief atca_iface is the context structure for a configured interface + */ +typedef struct atca_iface +{ + ATCAIfaceCfg* mIfaceCFG; /**< Points to previous defined/given Cfg object, the caller manages this */ + ATCAHAL_t* hal; /**< The configured HAL for the interface */ + ATCAHAL_t* phy; /**< When a HAL is not a "native" hal it needs a physical layer to be associated with it */ + void* hal_data; /**< Pointer to HAL specific context/data */ +} atca_iface_t; + +ATCA_STATUS initATCAIface(ATCAIfaceCfg *cfg, ATCAIface ca_iface); +ATCAIface newATCAIface(ATCAIfaceCfg *cfg); +ATCA_STATUS releaseATCAIface(ATCAIface ca_iface); +void deleteATCAIface(ATCAIface *ca_iface); + +// IFace methods +ATCA_STATUS atinit(ATCAIface ca_iface); +ATCA_STATUS atsend(ATCAIface ca_iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS atreceive(ATCAIface ca_iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS atcontrol(ATCAIface ca_iface, uint8_t option, void* param, size_t paramlen); +ATCA_STATUS atwake(ATCAIface ca_iface); +ATCA_STATUS atidle(ATCAIface ca_iface); +ATCA_STATUS atsleep(ATCAIface ca_iface); + +// accessors +ATCAIfaceCfg * atgetifacecfg(ATCAIface ca_iface); +void* atgetifacehaldat(ATCAIface ca_iface); + +/* Utilities */ +bool atca_iface_is_kit(ATCAIface ca_iface); +bool atca_iface_is_swi(ATCAIface ca_iface); +int atca_iface_get_retries(ATCAIface ca_iface); +uint16_t atca_iface_get_wake_delay(ATCAIface ca_iface); + +#ifdef __cplusplus +} +#endif +/*lint -flb*/ +/** @} */ +#endif diff --git a/drivers/ecc108a/cryptoauthlib/atca_status.h b/drivers/ecc108a/cryptoauthlib/atca_status.h new file mode 100644 index 0000000..b3ee1cb --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_status.h @@ -0,0 +1,91 @@ +/** + * \file + * + * \brief Microchip Crypto Auth status codes + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef _ATCA_STATUS_H +#define _ATCA_STATUS_H + +#include +#include "atca_bool.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* all status codes for the ATCA lib are defined here */ + +typedef enum +{ + ATCA_SUCCESS = 0x00, //!< Function succeeded. + ATCA_CONFIG_ZONE_LOCKED = 0x01, + ATCA_DATA_ZONE_LOCKED = 0x02, + ATCA_INVALID_POINTER, + ATCA_INVALID_LENGTH, + ATCA_WAKE_FAILED = 0xD0, //!< response status byte indicates CheckMac failure (status byte = 0x01) + ATCA_CHECKMAC_VERIFY_FAILED = 0xD1, //!< response status byte indicates CheckMac failure (status byte = 0x01) + ATCA_PARSE_ERROR = 0xD2, //!< response status byte indicates parsing error (status byte = 0x03) + ATCA_STATUS_CRC = 0xD4, //!< response status byte indicates DEVICE did not receive data properly (status byte = 0xFF) + ATCA_STATUS_UNKNOWN = 0xD5, //!< response status byte is unknown + ATCA_STATUS_ECC = 0xD6, //!< response status byte is ECC fault (status byte = 0x05) + ATCA_STATUS_SELFTEST_ERROR = 0xD7, //!< response status byte is Self Test Error, chip in failure mode (status byte = 0x07) + ATCA_FUNC_FAIL = 0xE0, //!< Function could not execute due to incorrect condition / state. + ATCA_GEN_FAIL = 0xE1, //!< unspecified error + ATCA_BAD_PARAM = 0xE2, //!< bad argument (out of range, null pointer, etc.) + ATCA_INVALID_ID = 0xE3, //!< invalid device id, id not set + ATCA_INVALID_SIZE = 0xE4, //!< Count value is out of range or greater than buffer size. + ATCA_RX_CRC_ERROR = 0xE5, //!< CRC error in data received from device + ATCA_RX_FAIL = 0xE6, //!< Timed out while waiting for response. Number of bytes received is > 0. + ATCA_RX_NO_RESPONSE = 0xE7, //!< Not an error while the Command layer is polling for a command response. + ATCA_RESYNC_WITH_WAKEUP = 0xE8, //!< Re-synchronization succeeded, but only after generating a Wake-up + ATCA_PARITY_ERROR = 0xE9, //!< for protocols needing parity + ATCA_TX_TIMEOUT = 0xEA, //!< for Microchip PHY protocol, timeout on transmission waiting for master + ATCA_RX_TIMEOUT = 0xEB, //!< for Microchip PHY protocol, timeout on receipt waiting for master + ATCA_TOO_MANY_COMM_RETRIES = 0xEC, //!< Device did not respond too many times during a transmission. Could indicate no device present. + ATCA_SMALL_BUFFER = 0xED, //!< Supplied buffer is too small for data required + ATCA_COMM_FAIL = 0xF0, //!< Communication with device failed. Same as in hardware dependent modules. + ATCA_TIMEOUT = 0xF1, //!< Timed out while waiting for response. Number of bytes received is 0. + ATCA_BAD_OPCODE = 0xF2, //!< opcode is not supported by the device + ATCA_WAKE_SUCCESS = 0xF3, //!< received proper wake token + ATCA_EXECUTION_ERROR = 0xF4, //!< chip was in a state where it could not execute the command, response status byte indicates command execution error (status byte = 0x0F) + ATCA_UNIMPLEMENTED = 0xF5, //!< Function or some element of it hasn't been implemented yet + ATCA_ASSERT_FAILURE = 0xF6, //!< Code failed run-time consistency check + ATCA_TX_FAIL = 0xF7, //!< Failed to write + ATCA_NOT_LOCKED = 0xF8, //!< required zone was not locked + ATCA_NO_DEVICES = 0xF9, //!< For protocols that support device discovery (kit protocol), no devices were found + ATCA_HEALTH_TEST_ERROR = 0xFA, //!< random number generator health test error + ATCA_ALLOC_FAILURE = 0xFB, //!< Couldn't allocate required memory + ATCA_USE_FLAGS_CONSUMED = 0xFC, //!< Use flags on the device indicates its consumed fully + ATCA_NOT_INITIALIZED = 0xFD, //!< The library has not been initialized so the command could not be executed +} ATCA_STATUS; + +#define ATCA_STATUS_AUTH_BIT 0x40 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/ecc108a/cryptoauthlib/atca_utils_sizes.c b/drivers/ecc108a/cryptoauthlib/atca_utils_sizes.c new file mode 100644 index 0000000..7bf9686 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_utils_sizes.c @@ -0,0 +1,109 @@ +/** + * \file + * \brief API to Return structure sizes of cryptoauthlib structures + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +#define SIZE_OF_API_T(x) size_t x ## _size(void); size_t x ## _size(void) { return sizeof( x ); } +#define SIZE_OF_API_S(x) size_t x ## _size(void); size_t x ## _size(void) { return sizeof(struct x ); } + +#ifndef ATCA_TIDAL +#if ATCA_CA_SUPPORT +#include "atcacert/atcacert_date.h" +#include "atcacert/atcacert_def.h" +/* atcacert_date.h */ +SIZE_OF_API_T(atcacert_tm_utc_t) +SIZE_OF_API_T(atcacert_date_format_t) + +/* atcacert_def.h */ +SIZE_OF_API_T(atcacert_cert_type_t) +SIZE_OF_API_T(atcacert_cert_sn_src_t) +SIZE_OF_API_T(atcacert_device_zone_t) +SIZE_OF_API_T(atcacert_std_cert_element_t) +SIZE_OF_API_T(atcacert_device_loc_t) +SIZE_OF_API_T(atcacert_cert_loc_t) +SIZE_OF_API_T(atcacert_cert_element_t) +SIZE_OF_API_T(atcacert_def_t) +SIZE_OF_API_T(atcacert_build_state_t) +#endif + +/* atcab.h */ +SIZE_OF_API_T(atca_aes_cbc_ctx_t) +SIZE_OF_API_T(atca_aes_cmac_ctx_t) +SIZE_OF_API_T(atca_aes_ctr_ctx_t) +#endif // ifndef ATCA_TIDAL + +#if ATCA_CA_SUPPORT +#include "host/atca_host.h" + +/* atca_host.h */ +SIZE_OF_API_T(atca_temp_key_t) +SIZE_OF_API_S(atca_include_data_in_out) +SIZE_OF_API_T(atca_nonce_in_out_t) +SIZE_OF_API_T(atca_io_decrypt_in_out_t) +SIZE_OF_API_T(atca_verify_mac_in_out_t) +SIZE_OF_API_T(atca_secureboot_enc_in_out_t) +SIZE_OF_API_T(atca_secureboot_mac_in_out_t) +SIZE_OF_API_T(atca_mac_in_out_t) +SIZE_OF_API_S(atca_hmac_in_out) +SIZE_OF_API_T(atca_gen_dig_in_out_t) +SIZE_OF_API_T(atca_write_mac_in_out_t) +SIZE_OF_API_S(atca_derive_key_in_out) +SIZE_OF_API_S(atca_derive_key_mac_in_out) +SIZE_OF_API_S(atca_decrypt_in_out) +SIZE_OF_API_T(atca_check_mac_in_out_t) +SIZE_OF_API_T(atca_verify_in_out_t) +SIZE_OF_API_T(atca_gen_key_in_out_t) +SIZE_OF_API_T(atca_sign_internal_in_out_t) +#endif + +/* atca_bool.h */ +SIZE_OF_API_T(bool) + +/* atca_command.h */ +#if ATCA_CA_SUPPORT +SIZE_OF_API_T(ATCAPacket) +#endif + +/* atca_device.h */ +SIZE_OF_API_S(atca_device) + +/* atca_devtypes.h */ +SIZE_OF_API_T(ATCADeviceType) + +/* calib_execution.h */ +#ifdef ATCA_NO_POLL +#include "calib/calib_execution.h" +SIZE_OF_API_T(device_execution_time_t) +#endif + +/* atca_iface.h */ +SIZE_OF_API_T(ATCAIfaceType) +SIZE_OF_API_T(ATCAIfaceCfg) +SIZE_OF_API_S(atca_iface) + +/* atca_status.h */ +SIZE_OF_API_T(ATCA_STATUS) diff --git a/drivers/ecc108a/cryptoauthlib/atca_version.h b/drivers/ecc108a/cryptoauthlib/atca_version.h new file mode 100644 index 0000000..0a8d8bc --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/atca_version.h @@ -0,0 +1,38 @@ +/** + * \file + * + * \brief Microchip CryptoAuth Library Version + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef _ATCA_VERSION_H +#define _ATCA_VERSION_H + +// Version format yyyymmdd +#define ATCA_LIBRARY_VERSION_DATE "20211006" +#define ATCA_LIBRARY_VERSION_MAJOR 3 +#define ATCA_LIBRARY_VERSION_MINOR 3 +#define ATCA_LIBRARY_VERSION_BUILD 3 + +#endif /* _ATCA_VERSION_H */ diff --git a/drivers/ecc108a/cryptoauthlib/calib/README.md b/drivers/ecc108a/cryptoauthlib/calib/README.md new file mode 100644 index 0000000..0c4bdef --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/README.md @@ -0,0 +1,17 @@ +calib directory - Purpose +========================= +The purpose of this directory is to contain the files implementing the APIs for +a basic interface to the core CryptoAuthLib library. + +High-level functions like these make it very convenient to use the library when +standard configurations and defaults are in play. They are the easiest to use +when developing examples or trying to understand the "flow" of an +authentication operation without getting overwhelmed by the details. + +This makes simple jobs easy and if you need more sophistication and power, you +can employ the full power of the CryptoAuthLib object model. + +See the Doxygen documentation in cryptoauthlib/docs for details on the API of +the calib commands. + +@ingroup calib_ diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_aes_gcm.h b/drivers/ecc108a/cryptoauthlib/calib/calib_aes_gcm.h new file mode 100644 index 0000000..c242f59 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_aes_gcm.h @@ -0,0 +1,76 @@ +/** + * \file + * \brief Unity tests for the cryptoauthlib AES GCM functions. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ +#ifndef CALIB_BASIC_AES_GCM_H_ +#define CALIB_BASIC_AES_GCM_H_ + +/** \ingroup atcab_ + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATCA_AES_GCM_IV_STD_LENGTH 12 + +extern const char* atca_basic_aes_gcm_version; + +/** Context structure for AES GCM operations. + */ + +typedef struct atca_aes_gcm_ctx +{ + uint16_t key_id; //!< Key location. Can either be a slot number or ATCA_TEMPKEY_KEYID for TempKey. + uint8_t key_block; //!< Index of the 16-byte block to use within the key location for the actual key. + uint8_t cb[AES_DATA_SIZE]; //!< Counter block, comprises of nonce + count value (16 bytes). + uint32_t data_size; //!< Size of the data being encrypted/decrypted in bytes. + uint32_t aad_size; //!< Size of the additional authenticated data in bytes. + uint8_t h[AES_DATA_SIZE]; //!< Subkey for ghash functions in GCM. + uint8_t j0[AES_DATA_SIZE]; //!< Precounter block generated from IV. + uint8_t y[AES_DATA_SIZE]; //!< Current GHASH output + uint8_t partial_aad[AES_DATA_SIZE]; //!< Partial blocks of data waiting to be processed + uint32_t partial_aad_size; //!< Amount of data in the partial block buffer + uint8_t enc_cb[AES_DATA_SIZE]; //!< Last encrypted counter block + uint8_t ciphertext_block[AES_DATA_SIZE]; //!< Last ciphertext block +} atca_aes_gcm_ctx_t; + +ATCA_STATUS calib_aes_gcm_init(ATCADevice device, atca_aes_gcm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, const uint8_t* iv, size_t iv_size); +ATCA_STATUS calib_aes_gcm_init_rand(ATCADevice device, atca_aes_gcm_ctx_t* ctx, uint16_t key_id, uint8_t key_block, size_t rand_size, + const uint8_t* free_field, size_t free_field_size, uint8_t* iv); +ATCA_STATUS calib_aes_gcm_aad_update(ATCADevice device, atca_aes_gcm_ctx_t* ctx, const uint8_t* aad, uint32_t aad_size); +ATCA_STATUS calib_aes_gcm_encrypt_update(ATCADevice device, atca_aes_gcm_ctx_t* ctx, const uint8_t* plaintext, uint32_t plaintext_size, uint8_t* ciphertext); +ATCA_STATUS calib_aes_gcm_encrypt_finish(ATCADevice device, atca_aes_gcm_ctx_t* ctx, uint8_t* tag, size_t tag_size); +ATCA_STATUS calib_aes_gcm_decrypt_update(ATCADevice device, atca_aes_gcm_ctx_t* ctx, const uint8_t* ciphertext, uint32_t ciphertext_size, uint8_t* plaintext); +ATCA_STATUS calib_aes_gcm_decrypt_finish(ATCADevice device, atca_aes_gcm_ctx_t* ctx, const uint8_t* tag, size_t tag_size, bool* is_verified); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_basic.c b/drivers/ecc108a/cryptoauthlib/calib/calib_basic.c new file mode 100644 index 0000000..cf37063 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_basic.c @@ -0,0 +1,373 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods. These methods provide a simpler way + * to access the core crypto methods. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief basic API methods are all prefixed with atcab_ (CryptoAuthLib Basic) + * the fundamental premise of the basic API is it is based on a single interface + * instance and that instance is global, so all basic API commands assume that + * one global device is the one to operate on. + */ + +ATCA_STATUS calib_wakeup_i2c(ATCADevice device) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + uint8_t second_byte = 0x01; // I2C general call should not interpreted as an addr write + ATCAIface iface = atGetIFace(device); + + if (iface) + { + int retries = atca_iface_get_retries(iface); + uint8_t address = atcab_get_device_address(device); + uint32_t temp; + uint32_t wake; + uint16_t rxlen; + + do + { + if (100000UL < iface->mIfaceCFG->atcai2c.baud) + { + temp = 100000UL; + status = atcontrol(iface, ATCA_HAL_CHANGE_BAUD, &temp, sizeof(temp)); + if (ATCA_UNIMPLEMENTED == status) + { + status = atcontrol(iface, ATCA_HAL_CONTROL_WAKE, NULL, 0); + break; + } + } + else + { + status = ATCA_SUCCESS; + } + + #ifdef ATCA_ECC204_SUPPORT + if (ECC204 == atcab_get_device_type_ext(device)) + { + (void)atsend(iface, address, NULL, 0); + } + else + { + + (void)atsend(iface, 0x00, &second_byte, sizeof(second_byte)); + } + #else + (void)atsend(iface, 0x00, &second_byte, sizeof(second_byte)); + #endif + atca_delay_us(atca_iface_get_wake_delay(iface)); + + rxlen = sizeof(wake); + if (ATCA_SUCCESS == status) + { + status = atreceive(iface, address, (uint8_t*)&wake, &rxlen); + } + + if ((ATCA_SUCCESS == status) && (100000UL < iface->mIfaceCFG->atcai2c.baud)) + { + temp = iface->mIfaceCFG->atcai2c.baud; + status = atcontrol(iface, ATCA_HAL_CHANGE_BAUD, &temp, sizeof(temp)); + } + + if (ATCA_SUCCESS == status) + { + status = hal_check_wake((uint8_t*)&wake, rxlen); + } + } + while (0 < retries-- && ATCA_SUCCESS != status); + } + return status; +} + +/** \brief wakeup the CryptoAuth device + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_wakeup(ATCADevice device) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + ATCAIface iface = atGetIFace(device); + + if (iface && iface->mIfaceCFG) + { +#ifdef ATCA_HAL_LEGACY_API + status = atwake(iface); +#else + if (atca_iface_is_kit(iface) || atca_iface_is_swi(&device->mIface)) + { + status = atwake(iface); + } + else if (ATCA_I2C_IFACE == iface->mIfaceCFG->iface_type) + { + status = calib_wakeup_i2c(device); + } + else + { + status = ATCA_SUCCESS; + } +#endif + } + + return status; +} + +/** \brief idle the CryptoAuth device + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_idle(ATCADevice device) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + +#ifdef ATCA_HAL_LEGACY_API + status = atidle(&device->mIface); +#else + if (atca_iface_is_kit(&device->mIface) || atca_iface_is_swi(&device->mIface)) + { + status = atidle(&device->mIface); + } + else + { + if (ECC204 != atcab_get_device_type_ext(device)) + { + uint8_t command = 0x02; + status = atsend(&device->mIface, atcab_get_device_address(device), &command, 1); + } + else + { + status = ATCA_SUCCESS; + } + } +#endif + return status; +} + +/** \brief invoke sleep on the CryptoAuth device + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sleep(ATCADevice device) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + +#ifdef ATCA_HAL_LEGACY_API + status = atsleep(&device->mIface); +#else + if (atca_iface_is_kit(&device->mIface) || atca_iface_is_swi(&device->mIface)) + { + status = atsleep(&device->mIface); + } + else + { + uint8_t command = 0x01; + status = atsend(&device->mIface, atcab_get_device_address(device), &command, 1); + } +#endif + return status; +} + +/** \brief common cleanup code which idles the device after any operation + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS _calib_exit(ATCADevice device) +{ + return calib_idle(device); +} + + +/** \brief Compute the address given the zone, slot, block, and offset + * \param[in] zone Zone to get address from. Config(0), OTP(1), or + * Data(2) which requires a slot. + * \param[in] slot Slot Id number for data zone and zero for other zones. + * \param[in] block Block number within the data or configuration or OTP zone . + * \param[in] offset Offset Number within the block of data or configuration or OTP zone. + * \param[out] addr Pointer to the address of data or configuration or OTP zone. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_get_addr(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint16_t* addr) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t mem_zone = zone & 0x03; + + if (addr == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + if ((mem_zone != ATCA_ZONE_CONFIG) && (mem_zone != ATCA_ZONE_DATA) && (mem_zone != ATCA_ZONE_OTP)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); + } + do + { + // Initialize the addr to 00 + *addr = 0; + // Mask the offset + offset = offset & (uint8_t)0x07; + if ((mem_zone == ATCA_ZONE_CONFIG) || (mem_zone == ATCA_ZONE_OTP)) + { + *addr = ((uint16_t)block) << 3; + *addr |= offset; + } + else // ATCA_ZONE_DATA + { + *addr = slot << 3; + *addr |= offset; + *addr |= ((uint16_t)block) << 8; + } + } + while (0); + + return status; +} + +/** \brief Compute the address given the zone, slot, block, and offset for ECC204 device + * \param[in] zone Zone to get address from. Config(1) or + * Data(0) which requires a slot. + * \param[in] slot Slot Id number for data zone and zero for other zones. + * \param[in] block Block number within the data zone . + * \param[in] offset Aalways zero. + * \param[out] addr Pointer to the address of data or configuration zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_ecc204_get_addr(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint16_t* addr) +{ + ATCA_STATUS status = ATCA_SUCCESS; + + ((void)zone); + ((void)offset); + + if (addr == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + // Initialize the addr to 00 + *addr = 0; + *addr = slot << 3; + *addr |= ((uint16_t)block) << 8; + + return status; +} + +/** \brief Gets the size of the specified zone in bytes. + * + * \param[in] device Device context pointer + * \param[in] zone Zone to get size information from. Config(0), OTP(1), or + * Data(2) which requires a slot. + * \param[in] slot If zone is Data(2), the slot to query for size. + * \param[out] size Zone size is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_get_zone_size(ATCADevice device, uint8_t zone, uint16_t slot, size_t* size) +{ + ATCA_STATUS status = ATCA_SUCCESS; + + if ((device == NULL) || (size == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + if (device->mIface.mIfaceCFG->devtype == ATSHA204A) + { + switch (zone) + { + case ATCA_ZONE_CONFIG: *size = 88; break; + case ATCA_ZONE_OTP: *size = 64; break; + case ATCA_ZONE_DATA: *size = 32; break; + default: status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); break; + } + } + else if (device->mIface.mIfaceCFG->devtype == ATSHA206A) + { + switch (zone) + { + case ATCA_ZONE_CONFIG: *size = 88; break; + case ATCA_ZONE_OTP: *size = 0; break; + case ATCA_ZONE_DATA: *size = 32; break; + default: status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); break; + } + } +#ifdef ATCA_ECC204_SUPPORT + else if (ECC204 == device->mIface.mIfaceCFG->devtype) + { + switch (zone) + { + case ATCA_ZONE_CONFIG: *size = 64; break; + case ATCA_ZONE_DATA: + if ((0 == slot) || (3 == slot)) + { + *size = 32; + } + else if (1 == slot) + { + *size = 320; + } + else if (2 == slot) + { + *size = 64; + } + else + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot received"); + } + break; + default: status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); break; + } + } +#endif + else + { + switch (zone) + { + case ATCA_ZONE_CONFIG: *size = 128; break; + case ATCA_ZONE_OTP: *size = 64; break; + case ATCA_ZONE_DATA: + if (slot < 8) + { + *size = 36; + } + else if (slot == 8) + { + *size = 416; + } + else if (slot < 16) + { + *size = 72; + } + else + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot received"); + } + break; + default: status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); break; + } + } + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_basic.h b/drivers/ecc108a/cryptoauthlib/calib/calib_basic.h new file mode 100644 index 0000000..f5d3c35 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_basic.h @@ -0,0 +1,236 @@ +#ifndef _CALIB_H +#define _CALIB_H + +#include "calib_command.h" +#include "calib_execution.h" + +/** \defgroup calib_ Basic Crypto API methods for CryptoAuth Devices (calib_) + * + * \brief + * These methods provide a simple API to CryptoAuth chips + * + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +ATCA_STATUS calib_wakeup(ATCADevice device); +ATCA_STATUS calib_idle(ATCADevice device); +ATCA_STATUS calib_sleep(ATCADevice device); +ATCA_STATUS _calib_exit(ATCADevice device); +ATCA_STATUS calib_get_addr(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint16_t* addr); +ATCA_STATUS calib_get_zone_size(ATCADevice device, uint8_t zone, uint16_t slot, size_t* size); +ATCA_STATUS calib_ecc204_get_addr(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint16_t* addr); + +/* Helper Functions */ +ATCA_STATUS calib_is_locked(ATCADevice device, uint8_t zone, bool* is_locked); +ATCA_STATUS calib_is_slot_locked(ATCADevice device, uint16_t slot, bool* is_locked); +ATCA_STATUS calib_is_private(ATCADevice device, uint16_t slot, bool* is_private); +ATCA_STATUS calib_ecc204_is_locked(ATCADevice device, uint8_t zone, bool* is_locked); +ATCA_STATUS calib_ecc204_is_data_locked(ATCADevice device, bool* is_locked); +ATCA_STATUS calib_ecc204_is_config_locked(ATCADevice device, bool* is_locked); + +//AES command functions +ATCA_STATUS calib_aes(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* aes_in, uint8_t* aes_out); +ATCA_STATUS calib_aes_encrypt(ATCADevice device, uint16_t key_id, uint8_t key_block, const uint8_t* plaintext, uint8_t* ciphertext); +ATCA_STATUS calib_aes_decrypt(ATCADevice device, uint16_t key_id, uint8_t key_block, const uint8_t* ciphertext, uint8_t* plaintext); +ATCA_STATUS calib_aes_gfm(ATCADevice device, const uint8_t* h, const uint8_t* input, uint8_t* output); + +//CheckMAC command functions +ATCA_STATUS calib_checkmac(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t *challenge, const uint8_t *response, const uint8_t *other_data); + +// Counter command functions +ATCA_STATUS calib_counter(ATCADevice device, uint8_t mode, uint16_t counter_id, uint32_t* counter_value); +ATCA_STATUS calib_counter_increment(ATCADevice device, uint16_t counter_id, uint32_t* counter_value); +ATCA_STATUS calib_counter_read(ATCADevice device, uint16_t counter_id, uint32_t* counter_value); + +// DeriveKey command functions +ATCA_STATUS calib_derivekey(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* mac); + +// ECDH command functions +ATCA_STATUS calib_ecdh_base(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* public_key, uint8_t* pms, uint8_t* out_nonce); +ATCA_STATUS calib_ecdh(ATCADevice device, uint16_t key_id, const uint8_t* public_key, uint8_t* pms); + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_ecdh_enc(ATCADevice device, uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* read_key, uint16_t read_key_id); +#else +ATCA_STATUS calib_ecdh_enc(ATCADevice device, uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* read_key, uint16_t read_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +ATCA_STATUS calib_ecdh_ioenc(ATCADevice device, uint16_t key_id, const uint8_t* public_key, uint8_t* pms, const uint8_t* io_key); +ATCA_STATUS calib_ecdh_tempkey(ATCADevice device, const uint8_t* public_key, uint8_t* pms); +ATCA_STATUS calib_ecdh_tempkey_ioenc(ATCADevice device, const uint8_t* public_key, uint8_t* pms, const uint8_t* io_key); + +// GenDig command functions +ATCA_STATUS calib_gendig(ATCADevice device, uint8_t zone, uint16_t key_id, const uint8_t *other_data, uint8_t other_data_size); + +// GenKey command functions +ATCA_STATUS calib_genkey_base(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* other_data, uint8_t* public_key); +ATCA_STATUS calib_genkey(ATCADevice device, uint16_t key_id, uint8_t* public_key); +ATCA_STATUS calib_get_pubkey(ATCADevice device, uint16_t key_id, uint8_t* public_key); +ATCA_STATUS calib_genkey_mac(ATCADevice device, uint8_t* public_key, uint8_t* mac); + +// HMAC command functions +ATCA_STATUS calib_hmac(ATCADevice device, uint8_t mode, uint16_t key_id, uint8_t* digest); + +// Info command functions +ATCA_STATUS calib_info_base(ATCADevice device, uint8_t mode, uint16_t param2, uint8_t* out_data); +ATCA_STATUS calib_info(ATCADevice device, uint8_t* revision); +ATCA_STATUS calib_info_set_latch(ATCADevice device, bool state); +ATCA_STATUS calib_info_get_latch(ATCADevice device, bool* state); +ATCA_STATUS calib_info_privkey_valid(ATCADevice device, uint16_t key_id, uint8_t* is_valid); +ATCA_STATUS calib_info_lock_status(ATCADevice device, uint16_t param2, uint8_t* is_locked); + +// KDF command functions +ATCA_STATUS calib_kdf(ATCADevice device, uint8_t mode, uint16_t key_id, const uint32_t details, const uint8_t* message, uint8_t* out_data, uint8_t* out_nonce); + +// Lock command functions +ATCA_STATUS calib_lock(ATCADevice device, uint8_t mode, uint16_t summary_crc); +ATCA_STATUS calib_lock_config_zone(ATCADevice device); +ATCA_STATUS calib_lock_config_zone_crc(ATCADevice device, uint16_t summary_crc); +ATCA_STATUS calib_lock_data_zone(ATCADevice device); +ATCA_STATUS calib_lock_data_zone_crc(ATCADevice device, uint16_t summary_crc); +ATCA_STATUS calib_lock_data_slot(ATCADevice device, uint16_t slot); +// Lock ECC204 command functions +ATCA_STATUS calib_ecc204_lock_config_slot(ATCADevice device, uint16_t slot, uint16_t summary_crc); +ATCA_STATUS calib_ecc204_lock_config_zone(ATCADevice device); +ATCA_STATUS calib_ecc204_lock_data_slot(ATCADevice device, uint16_t slot); +ATCA_STATUS calib_ecc204_lock_data_zone(ATCADevice device); + +// MAC command functions +ATCA_STATUS calib_mac(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* challenge, uint8_t* digest); + +// Nonce command functions +ATCA_STATUS calib_nonce_base(ATCADevice device, uint8_t mode, uint16_t zero, const uint8_t *num_in, uint8_t* rand_out); +ATCA_STATUS calib_nonce(ATCADevice device, const uint8_t *num_in); +ATCA_STATUS calib_nonce_load(ATCADevice device, uint8_t target, const uint8_t *num_in, uint16_t num_in_size); +ATCA_STATUS calib_nonce_rand(ATCADevice device, const uint8_t *num_in, uint8_t* rand_out); +ATCA_STATUS calib_challenge(ATCADevice device, const uint8_t *num_in); +ATCA_STATUS calib_challenge_seed_update(ATCADevice device, const uint8_t *num_in, uint8_t* rand_out); +ATCA_STATUS calib_nonce_gen_session_key(ATCADevice device, uint16_t param2, uint8_t* num_in, + uint8_t* rand_out); + +// PrivWrite command functions + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_priv_write(ATCADevice device, uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32]); +#else +ATCA_STATUS calib_priv_write(ATCADevice device, uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32], const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif +// Random command functions +ATCA_STATUS calib_random(ATCADevice device, uint8_t* rand_out); + +// Read command functions +ATCA_STATUS calib_read_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint8_t *data, uint8_t len); +ATCA_STATUS calib_read_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, size_t offset, uint8_t *data, size_t length); +ATCA_STATUS calib_read_serial_number(ATCADevice device, uint8_t* serial_number); +ATCA_STATUS calib_read_pubkey(ATCADevice device, uint16_t slot, uint8_t *public_key); +ATCA_STATUS calib_read_sig(ATCADevice device, uint16_t slot, uint8_t *sig); +ATCA_STATUS calib_read_config_zone(ATCADevice device, uint8_t* config_data); +ATCA_STATUS calib_cmp_config_zone(ATCADevice device, uint8_t* config_data, bool* same_config); +// ECC204 Read command functions +ATCA_STATUS calib_ecc204_read_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, size_t offset, + uint8_t* data, uint8_t len); +ATCA_STATUS calib_ecc204_read_config_zone(ATCADevice device, uint8_t* config_data); +ATCA_STATUS calib_ecc204_read_serial_number(ATCADevice device, uint8_t* serial_number); +ATCA_STATUS calib_ecc204_read_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, + size_t block, uint8_t* data, size_t length); +ATCA_STATUS calib_ecc204_cmp_config_zone(ATCADevice device, uint8_t* config_data, bool* same_config); + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_read_enc(ATCADevice device, uint16_t key_id, uint8_t block, uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id); +#else +ATCA_STATUS calib_read_enc(ATCADevice device, uint16_t key_id, uint8_t block, uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +// SecureBoot command functions +ATCA_STATUS calib_secureboot(ATCADevice device, uint8_t mode, uint16_t param2, const uint8_t* digest, const uint8_t* signature, uint8_t* mac); +ATCA_STATUS calib_secureboot_mac(ATCADevice device, uint8_t mode, const uint8_t* digest, const uint8_t* signature, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified); + +// SelfTest command functions +ATCA_STATUS calib_selftest(ATCADevice device, uint8_t mode, uint16_t param2, uint8_t* result); + +// SHA command functions +typedef struct atca_sha256_ctx +{ + uint32_t total_msg_size; //!< Total number of message bytes processed + uint32_t block_size; //!< Number of bytes in current block + uint8_t block[ATCA_SHA256_BLOCK_SIZE * 2]; //!< Unprocessed message storage +} atca_sha256_ctx_t; + +typedef atca_sha256_ctx_t atca_hmac_sha256_ctx_t; + +ATCA_STATUS calib_sha_base(ATCADevice device, uint8_t mode, uint16_t length, const uint8_t* data_in, uint8_t* data_out, uint16_t* data_out_size); +ATCA_STATUS calib_sha_start(ATCADevice device); +ATCA_STATUS calib_sha_update(ATCADevice device, const uint8_t* message); +ATCA_STATUS calib_sha_end(ATCADevice device, uint8_t *digest, uint16_t length, const uint8_t *message); +ATCA_STATUS calib_sha_read_context(ATCADevice device, uint8_t* context, uint16_t* context_size); +ATCA_STATUS calib_sha_write_context(ATCADevice device, const uint8_t* context, uint16_t context_size); +ATCA_STATUS calib_sha(ATCADevice device, uint16_t length, const uint8_t *message, uint8_t *digest); +ATCA_STATUS calib_hw_sha2_256(ATCADevice device, const uint8_t * data, size_t data_size, uint8_t* digest); +ATCA_STATUS calib_hw_sha2_256_init(ATCADevice device, atca_sha256_ctx_t* ctx); +ATCA_STATUS calib_hw_sha2_256_update(ATCADevice device, atca_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size); +ATCA_STATUS calib_hw_sha2_256_finish(ATCADevice device, atca_sha256_ctx_t* ctx, uint8_t* digest); +ATCA_STATUS calib_sha_hmac_init(ATCADevice device, atca_hmac_sha256_ctx_t* ctx, uint16_t key_slot); +ATCA_STATUS calib_sha_hmac_update(ATCADevice device, atca_hmac_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size); +ATCA_STATUS calib_sha_hmac_finish(ATCADevice device, atca_hmac_sha256_ctx_t* ctx, uint8_t* digest, uint8_t target); +ATCA_STATUS calib_sha_hmac(ATCADevice device, const uint8_t * data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target); + +// Sign command functions +ATCA_STATUS calib_sign_base(ATCADevice device, uint8_t mode, uint16_t key_id, uint8_t *signature); +ATCA_STATUS calib_sign(ATCADevice device, uint16_t key_id, const uint8_t *msg, uint8_t *signature); +ATCA_STATUS calib_sign_internal(ATCADevice device, uint16_t key_id, bool is_invalidate, bool is_full_sn, uint8_t *signature); +// ECC204 Sign command functions +ATCA_STATUS calib_ecc204_sign(ATCADevice device, uint16_t key_id, const uint8_t* msg, uint8_t* signature); + +// UpdateExtra command functions +ATCA_STATUS calib_updateextra(ATCADevice device, uint8_t mode, uint16_t new_value); + +// Verify command functions +ATCA_STATUS calib_verify(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* signature, const uint8_t* public_key, const uint8_t* other_data, uint8_t* mac); +ATCA_STATUS calib_verify_extern(ATCADevice device, const uint8_t *message, const uint8_t *signature, const uint8_t *public_key, bool *is_verified); +ATCA_STATUS calib_verify_extern_mac(ATCADevice device, const uint8_t *message, const uint8_t* signature, const uint8_t* public_key, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified); +ATCA_STATUS calib_verify_stored(ATCADevice device, const uint8_t *message, const uint8_t *signature, uint16_t key_id, bool *is_verified); +ATCA_STATUS calib_verify_stored_mac(ATCADevice device, const uint8_t *message, const uint8_t *signature, uint16_t key_id, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified); +ATCA_STATUS calib_verify_validate(ATCADevice device, uint16_t key_id, const uint8_t *signature, const uint8_t *other_data, bool *is_verified); +ATCA_STATUS calib_verify_invalidate(ATCADevice device, uint16_t key_id, const uint8_t *signature, const uint8_t *other_data, bool *is_verified); + +// Write command functions +ATCA_STATUS calib_write(ATCADevice device, uint8_t zone, uint16_t address, const uint8_t *value, const uint8_t *mac); +ATCA_STATUS calib_write_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, const uint8_t *data, uint8_t len); +ATCA_STATUS calib_write_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, size_t offset_bytes, const uint8_t *data, size_t length); +ATCA_STATUS calib_write_pubkey(ATCADevice device, uint16_t slot, const uint8_t *public_key); +ATCA_STATUS calib_write_config_zone(ATCADevice device, const uint8_t* config_data); +// ECC204 Write command functions +ATCA_STATUS calib_ecc204_write(ATCADevice device, uint8_t zone, uint16_t address, const uint8_t *value, + const uint8_t *mac); +ATCA_STATUS calib_ecc204_write_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, + uint8_t offset, const uint8_t *data, uint8_t len); +ATCA_STATUS calib_ecc204_write_config_zone(ATCADevice device, const uint8_t* config_data); +ATCA_STATUS calib_ecc204_write_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, size_t block, + const uint8_t *data, size_t length); + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, const uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id); +#else +ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, const uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_ecc204_write_enc(ATCADevice device, uint16_t slot, uint8_t* data, uint8_t* transport_key, + uint8_t key_id); +#else +ATCA_STATUS calib_ecc204_write_enc(ATCADevice device, uint16_t slot, uint8_t* data, uint8_t* transport_key, + uint8_t key_id, uint8_t num_in[NONCE_NUMIN_SIZE]); +#endif + +ATCA_STATUS calib_write_config_counter(ATCADevice device, uint16_t counter_id, uint32_t counter_value); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_command.c b/drivers/ecc108a/cryptoauthlib/calib/calib_command.c new file mode 100644 index 0000000..f8d6fc5 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_command.c @@ -0,0 +1,766 @@ +/** + * \file + * \brief Microchip CryptoAuthentication device command builder - this is the main object that builds the command + * byte strings for the given device. It does not execute the command. The basic flow is to call + * a command method to build the command you want given the parameters and then send that byte string + * through the device interface. + * + * The primary goal of the command builder is to wrap the given parameters with the correct packet size and CRC. + * The caller should first fill in the parameters required in the ATCAPacket parameter given to the command. + * The command builder will deal with the mechanics of creating a valid packet using the parameter information. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief ATCACommand CheckMAC method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atCheckMAC(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_CHECKMAC; + packet->txsize = CHECKMAC_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Counter method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atCounter(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_COUNTER; + packet->txsize = COUNTER_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand DeriveKey method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] has_mac hasMAC determines if MAC data is present in the packet input + * \return ATCA_SUCCESS + */ +ATCA_STATUS atDeriveKey(ATCADeviceType device_type, ATCAPacket *packet, bool has_mac) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_DERIVE_KEY; + + // hasMAC must be given since the packet does not have any implicit information to + // know if it has a mac or not unless the size is preset + if (has_mac) + { + packet->txsize = DERIVE_KEY_COUNT_LARGE; + } + else + { + packet->txsize = DERIVE_KEY_COUNT_SMALL; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand ECDH method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atECDH(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_ECDH; + packet->txsize = ECDH_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Generate Digest method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] is_no_mac_key Should be true if GenDig is being run on a slot that has its SlotConfig.NoMac bit set + * \return ATCA_SUCCESS + */ +ATCA_STATUS atGenDig(ATCADeviceType device_type, ATCAPacket *packet, bool is_no_mac_key) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_GENDIG; + + if (packet->param1 == GENDIG_ZONE_SHARED_NONCE) // shared nonce mode + { + packet->txsize = GENDIG_COUNT + 32; + } + else if (is_no_mac_key) + { + packet->txsize = GENDIG_COUNT + 4; // noMac keys use 4 bytes of OtherData in calculation + } + else + { + packet->txsize = GENDIG_COUNT; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Generate Key method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atGenKey(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_GENKEY; + + if (packet->param1 & GENKEY_MODE_PUBKEY_DIGEST) + { + packet->txsize = GENKEY_COUNT_DATA; + } + else + { + packet->txsize = GENKEY_COUNT; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand HMAC method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atHMAC(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_HMAC; + packet->txsize = HMAC_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Info method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atInfo(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_INFO; + packet->txsize = INFO_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Lock method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atLock(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_LOCK; + packet->txsize = LOCK_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand MAC method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atMAC(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + // variable packet size + packet->opcode = ATCA_MAC; + if (!(packet->param1 & MAC_MODE_BLOCK2_TEMPKEY)) + { + packet->txsize = MAC_COUNT_LONG; + } + else + { + packet->txsize = MAC_COUNT_SHORT; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Nonce method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atNonce(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + // variable packet size + uint8_t calc_mode = packet->param1 & NONCE_MODE_MASK; + + packet->opcode = ATCA_NONCE; + + if ((calc_mode == NONCE_MODE_SEED_UPDATE || calc_mode == NONCE_MODE_NO_SEED_UPDATE)) + { + // Calculated nonce mode, 20 byte NumInm + packet->txsize = NONCE_COUNT_SHORT; + } + else if (calc_mode == NONCE_MODE_PASSTHROUGH) + { + // PAss-through nonce mode + if ((packet->param1 & NONCE_MODE_INPUT_LEN_MASK) == NONCE_MODE_INPUT_LEN_64) + { + // 64 byte NumIn + packet->txsize = NONCE_COUNT_LONG_64; + } + else + { + // 32 byte NumIn + packet->txsize = NONCE_COUNT_LONG; + } + } + else + { + return ATCA_TRACE(ATCA_BAD_PARAM, "atNonce - failed; Invalid mode received"); + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Pause method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atPause(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_PAUSE; + packet->txsize = PAUSE_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand PrivWrite method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atPrivWrite(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_PRIVWRITE; + packet->txsize = PRIVWRITE_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Random method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atRandom(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_RANDOM; + packet->txsize = RANDOM_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Read method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atRead(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_READ; + packet->txsize = READ_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand SecureBoot method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atSecureBoot(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + packet->opcode = ATCA_SECUREBOOT; + packet->txsize = ATCA_CMD_SIZE_MIN; + + //variable transmit size based on mode encoding + switch (packet->param1 & SECUREBOOT_MODE_MASK) + { + case SECUREBOOT_MODE_FULL: + case SECUREBOOT_MODE_FULL_COPY: + packet->txsize += (SECUREBOOT_DIGEST_SIZE + SECUREBOOT_SIGNATURE_SIZE); + break; + + case SECUREBOOT_MODE_FULL_STORE: + packet->txsize += SECUREBOOT_DIGEST_SIZE; + break; + + default: + return ATCA_TRACE(ATCA_BAD_PARAM, "atSecureBoot - failed; Invalid mode received"); + break; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand SHA method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] write_context_size the length of the sha write_context data + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atSHA(ATCADeviceType device_type, ATCAPacket *packet, uint16_t write_context_size) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_SHA; + + switch (packet->param1 & SHA_MODE_MASK) + { + case SHA_MODE_SHA256_START: // START + case SHA_MODE_HMAC_START: + case 0x03: // SHA_MODE_SHA256_PUBLIC || SHA_MODE_ECC204_HMAC_START + packet->txsize = ATCA_CMD_SIZE_MIN; + break; + + case SHA_MODE_SHA256_UPDATE: // UPDATE + packet->txsize = (uint8_t)(ATCA_CMD_SIZE_MIN + packet->param2); + break; + + case SHA_MODE_SHA256_END: // END + case SHA_MODE_HMAC_END: + // check the given packet for a size variable in param2. If it is > 0, it should + // be 0-63, incorporate that size into the packet + packet->txsize = (uint8_t)(ATCA_CMD_SIZE_MIN + packet->param2); + break; + + case SHA_MODE_READ_CONTEXT: + packet->txsize = ATCA_CMD_SIZE_MIN; + break; + + case SHA_MODE_WRITE_CONTEXT: + packet->txsize = (uint8_t)(ATCA_CMD_SIZE_MIN + write_context_size); + break; + } + + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Sign method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atSign(ATCADeviceType device_type, ATCAPacket *packet) +{ + // Set the opcode & parameters + packet->opcode = ATCA_SIGN; + packet->txsize = SIGN_COUNT; + if (ECC204 == device_type) + { + packet->txsize += ATCA_SHA_DIGEST_SIZE; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand UpdateExtra method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atUpdateExtra(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_UPDATE_EXTRA; + packet->txsize = UPDATE_COUNT; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand ECDSA Verify method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS atVerify(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_VERIFY; + + // variable packet size based on mode + switch (packet->param1 & VERIFY_MODE_MASK) + { + case VERIFY_MODE_STORED: + packet->txsize = VERIFY_256_STORED_COUNT; + break; + + case VERIFY_MODE_VALIDATE_EXTERNAL: + packet->txsize = VERIFY_256_EXTERNAL_COUNT; + break; + + case VERIFY_MODE_EXTERNAL: + packet->txsize = VERIFY_256_EXTERNAL_COUNT; + break; + + case VERIFY_MODE_VALIDATE: + case VERIFY_MODE_INVALIDATE: + packet->txsize = VERIFY_256_VALIDATE_COUNT; + break; + + default: + return ATCA_TRACE(ATCA_BAD_PARAM, "atVerify - failed; Invalid mode received"); + } + + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Write method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] has_mac Flag to indicate whether a mac is present or not + * \return ATCA_SUCCESS + */ +ATCA_STATUS atWrite(ATCADeviceType device_type, ATCAPacket *packet, bool has_mac) +{ + // Set the opcode & parameters + packet->opcode = ATCA_WRITE; + + packet->txsize = 7; + if (ECC204 == device_type) + { +#ifdef ATCA_ECC204_SUPPORT + if (ATCA_ECC204_ZONE_CONFIG == packet->param1) + { + packet->txsize += 16; + } + else if (ATCA_ECC204_ZONE_DATA == packet->param1) + { + packet->txsize += ATCA_BLOCK_SIZE; + } +#else + return ATCA_UNIMPLEMENTED; +#endif + } + else + { + if (packet->param1 & ATCA_ZONE_READWRITE_32) + { + packet->txsize += ATCA_BLOCK_SIZE; + } + else + { + packet->txsize += ATCA_WORD_SIZE; + } + } + + if (has_mac) + { + packet->txsize += WRITE_MAC_SIZE; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand AES method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atAES(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_AES; + packet->txsize = ATCA_CMD_SIZE_MIN; + + if ((packet->param1 & AES_MODE_OP_MASK) == AES_MODE_GFM) + { + packet->txsize += ATCA_AES_GFM_SIZE; + } + else + { + packet->txsize += AES_DATA_SIZE; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand AES method + * \param[in] ca_cmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_SUCCESS + */ +ATCA_STATUS atSelfTest(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_SELFTEST; + packet->txsize = ATCA_CMD_SIZE_MIN; + atCalcCrc(packet); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand KDF method + * \param[in] ca_cmd Instance + * \param[in] packet Pointer to the packet containing the command being + * built. + * \return ATCA_SUCCESS + */ +ATCA_STATUS atKDF(ATCADeviceType device_type, ATCAPacket *packet) +{ + ((void)device_type); + + // Set the opcode & parameters + packet->opcode = ATCA_KDF; + + // Set TX size + if ((packet->param1 & KDF_MODE_ALG_MASK) == KDF_MODE_ALG_AES) + { + // AES algorithm has a fixed message size + packet->txsize = ATCA_CMD_SIZE_MIN + KDF_DETAILS_SIZE + AES_DATA_SIZE; + } + else + { + // All other algorithms encode message size in the last byte of details + packet->txsize = ATCA_CMD_SIZE_MIN + KDF_DETAILS_SIZE + packet->data[3]; + } + atCalcCrc(packet); + return ATCA_SUCCESS; +} + + +/** \brief Calculates CRC over the given raw data and returns the CRC in + * little-endian byte order. + * + * \param[in] length Size of data not including the CRC byte positions + * \param[in] data Pointer to the data over which to compute the CRC + * \param[out] crc_le Pointer to the place where the two-bytes of CRC will be + * returned in little-endian byte order. + */ +void atCRC(size_t length, const uint8_t *data, uint8_t *crc_le) +{ + size_t counter; + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) + { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) + { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + crc_register <<= 1; + if (data_bit != crc_bit) + { + crc_register ^= polynom; + } + } + } + crc_le[0] = (uint8_t)(crc_register & 0x00FF); + crc_le[1] = (uint8_t)(crc_register >> 8); +} + + +/** \brief This function calculates CRC and adds it to the correct offset in the packet data + * \param[in] packet Packet to calculate CRC data for + */ + +void atCalcCrc(ATCAPacket *packet) +{ + uint8_t length, *crc; + + packet->param2 = ATCA_UINT16_HOST_TO_LE(packet->param2); + + length = packet->txsize - ATCA_CRC_SIZE; + // computer pointer to CRC in the packet + crc = &(packet->txsize) + length; + + // stuff CRC into packet + atCRC(length, &(packet->txsize), crc); +} + + +/** \brief This function checks the consistency of a response. + * \param[in] response pointer to response + * \return ATCA_SUCCESS on success, otherwise ATCA_RX_CRC_ERROR + */ + +ATCA_STATUS atCheckCrc(const uint8_t *response) +{ + uint8_t crc[ATCA_CRC_SIZE]; + uint8_t count = response[ATCA_COUNT_IDX]; + + count -= ATCA_CRC_SIZE; + atCRC(count, response, crc); + + return (crc[0] == response[count] && crc[1] == response[count + 1]) ? ATCA_SUCCESS : ATCA_RX_CRC_ERROR; +} + + +/** \brief determines if a given device type is a SHA device or a superset of a SHA device + * \param[in] device_type Type of device to check for family type + * \return boolean indicating whether the given device is a SHA family device. + */ + +bool atIsSHAFamily(ATCADeviceType device_type) +{ + switch (device_type) + { + case ATSHA204A: + case ATSHA206A: + return true; + break; + + default: + return false; + break; + } +} + +/** \brief determines if a given device type is an ECC device or a superset of a ECC device + * \param[in] device_type Type of device to check for family type + * \return boolean indicating whether the given device is an ECC family device. + */ +bool atIsECCFamily(ATCADeviceType device_type) +{ + switch (device_type) + { + case ATECC108A: + case ATECC508A: + case ATECC608: + case ECC204: + return true; + break; + default: + return false; + break; + } +} + +/** \brief checks for basic error frame in data + * \param[in] data pointer to received data - expected to be in the form of a CA device response frame + * \return ATCA_SUCCESS on success, otherwise an error code. + */ + +ATCA_STATUS isATCAError(uint8_t *data) +{ + if (data[0] == 0x04) // error packets are always 4 bytes long + { + switch (data[1]) + { + case 0x00: //No Error + return ATCA_SUCCESS; + case 0x01: // checkmac or verify failed + return ATCA_CHECKMAC_VERIFY_FAILED; + break; + case 0x03: // command received byte length, opcode or parameter was illegal + return ATCA_PARSE_ERROR; + break; + case 0x05: // computation error during ECC processing causing invalid results + return ATCA_STATUS_ECC; + break; + case 0x07: // chip is in self test failure mode + return ATCA_STATUS_SELFTEST_ERROR; + break; + case 0x08: //random number generator health test error + return ATCA_HEALTH_TEST_ERROR; + case 0x0f: // chip can't execute the command + return ATCA_EXECUTION_ERROR; + break; + case 0x11: // chip was successfully woken up + return ATCA_WAKE_SUCCESS; + break; + case 0xff: // bad crc found (command not properly received by device) or other comm error + return ATCA_STATUS_CRC; + break; + default: + return ATCA_GEN_FAIL; + break; + } + } + else + { + return ATCA_SUCCESS; + } +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_command.h b/drivers/ecc108a/cryptoauthlib/calib/calib_command.h new file mode 100644 index 0000000..949eb67 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_command.h @@ -0,0 +1,744 @@ +/** + * \file + * \brief Microchip Crypto Auth device command object - this is a command builder only, it does + * not send the command. The result of a command method is a fully formed packet, ready to send + * to the ATCAIFace object to dispatch. + * + * This command object supports the ATSHA and ATECC device family. + * The command list is a superset of all device commands for this family. The command object + * differentiates the packet contents based on specific device type within the family. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ +/* lint --e{755} */ + +#ifndef CALIB_COMMAND_H +#define CALIB_COMMAND_H + +#include +#ifdef __cplusplus +extern "C" { +#endif + + + +/* add ATCACommand declarations here + * + * since these are still C functions, not classes, naming is an important + * consideration to keep the namespace from colliding with other 3rd party + * libraries or even ourselves/ASF. + * + * Basic conventions: + * all methods start with the prefix 'at' + * all method names must be unique, obviously + * all method implementations should be proceeded by their Doxygen comment header + * + **/ + + +// this is the ATCACommand parameter structure. The caller to the command method must +// initialize param1, param2 and data if appropriate. The command method will fill in the rest +// and initialize the packet so it's ready to send via the ATCAIFace. +// this particular structure mimics the ATSHA and ATECC family device's command structures + +// Note: pack @ 2 is required, @ 1 causes word alignment crash (though it should not), a known bug in GCC. +// @2, the wire still has the intended byte alignment with arm-eabi. this is likely the least portable part of atca + + +#ifdef ATCA_NO_PRAGMA_PACK +typedef struct __attribute__ ((packed)) +#else +#pragma pack( push, ATCAPacket, 2 ) +typedef struct +#endif +/** \brief an ATCA packet structure. This is a superset of the packet transmitted on the wire. It's also + * used as a buffer for receiving the response + */ +{ + + // used for transmit/send + uint8_t _reserved; // used by HAL layer as needed (I/O tokens, Word address values) + + //--- start of packet i/o frame---- + uint8_t txsize; + uint8_t opcode; + uint8_t param1; // often same as mode + uint16_t param2; + uint8_t data[192]; // includes 2-byte CRC. data size is determined by largest possible data section of any + // command + crc (see: x08 verify data1 + data2 + data3 + data4) + // this is an explicit design trade-off (space) resulting in simplicity in use + // and implementation + //--- end of packet i/o frame + + // used for receive + uint8_t execTime; // execution time of command by opcode + + // structure should be packed since it will be transmitted over the wire + // this method varies by compiler. As new compilers are supported, add their structure packing method here + +} ATCAPacket; + +#ifndef ATCA_NO_PRAGMA_PACK +#pragma pack( pop, ATCAPacket) +#endif + + +ATCA_STATUS atCheckMAC(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atCounter(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atDeriveKey(ATCADeviceType device_type, ATCAPacket *packet, bool has_mac); +ATCA_STATUS atECDH(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atGenDig(ATCADeviceType device_type, ATCAPacket *packet, bool is_no_mac_key); +ATCA_STATUS atGenKey(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atHMAC(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atInfo(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atLock(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atMAC(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atNonce(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atPause(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atPrivWrite(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atRandom(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atRead(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atSecureBoot(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atSHA(ATCADeviceType device_type, ATCAPacket *packet, uint16_t write_context_size); +ATCA_STATUS atSign(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atUpdateExtra(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atVerify(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atWrite(ATCADeviceType device_type, ATCAPacket *packet, bool has_mac); +ATCA_STATUS atAES(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atSelfTest(ATCADeviceType device_type, ATCAPacket *packet); +ATCA_STATUS atKDF(ATCADeviceType device_type, ATCAPacket *packet); + +bool atIsSHAFamily(ATCADeviceType device_type); +bool atIsECCFamily(ATCADeviceType device_type); +ATCA_STATUS isATCAError(uint8_t *data); + + +// command helpers +void atCRC(size_t length, const uint8_t *data, uint8_t *crc_le); +void atCalcCrc(ATCAPacket *pkt); +ATCA_STATUS atCheckCrc(const uint8_t *response); + + +/* command definitions */ + +//! minimum number of bytes in command (from count byte to second CRC byte) +#define ATCA_CMD_SIZE_MIN ((uint8_t)7) +//! maximum size of command packet (Verify) +#define ATCA_CMD_SIZE_MAX ((uint8_t)4 * 36 + 7) +//! status byte for success +#define CMD_STATUS_SUCCESS ((uint8_t)0x00) +//! status byte after wake-up +#define CMD_STATUS_WAKEUP ((uint8_t)0x11) +//! command parse error +#define CMD_STATUS_BYTE_PARSE ((uint8_t)0x03) +//! command ECC error +#define CMD_STATUS_BYTE_ECC ((uint8_t)0x05) +//! command execution error +#define CMD_STATUS_BYTE_EXEC ((uint8_t)0x0F) +//! communication error +#define CMD_STATUS_BYTE_COMM ((uint8_t)0xFF) + +/** \name Opcodes for Crypto Authentication device commands + @{ */ +#define ATCA_CHECKMAC ((uint8_t)0x28) //!< CheckMac command op-code +#define ATCA_DERIVE_KEY ((uint8_t)0x1C) //!< DeriveKey command op-code +#define ATCA_INFO ((uint8_t)0x30) //!< Info command op-code +#define ATCA_GENDIG ((uint8_t)0x15) //!< GenDig command op-code +#define ATCA_GENKEY ((uint8_t)0x40) //!< GenKey command op-code +#define ATCA_HMAC ((uint8_t)0x11) //!< HMAC command op-code +#define ATCA_LOCK ((uint8_t)0x17) //!< Lock command op-code +#define ATCA_MAC ((uint8_t)0x08) //!< MAC command op-code +#define ATCA_NONCE ((uint8_t)0x16) //!< Nonce command op-code +#define ATCA_PAUSE ((uint8_t)0x01) //!< Pause command op-code +#define ATCA_PRIVWRITE ((uint8_t)0x46) //!< PrivWrite command op-code +#define ATCA_RANDOM ((uint8_t)0x1B) //!< Random command op-code +#define ATCA_READ ((uint8_t)0x02) //!< Read command op-code +#define ATCA_SIGN ((uint8_t)0x41) //!< Sign command op-code +#define ATCA_UPDATE_EXTRA ((uint8_t)0x20) //!< UpdateExtra command op-code +#define ATCA_VERIFY ((uint8_t)0x45) //!< GenKey command op-code +#define ATCA_WRITE ((uint8_t)0x12) //!< Write command op-code +#define ATCA_ECDH ((uint8_t)0x43) //!< ECDH command op-code +#define ATCA_COUNTER ((uint8_t)0x24) //!< Counter command op-code +#define ATCA_SHA ((uint8_t)0x47) //!< SHA command op-code +#define ATCA_AES ((uint8_t)0x51) //!< AES command op-code +#define ATCA_KDF ((uint8_t)0x56) //!< KDF command op-code +#define ATCA_SECUREBOOT ((uint8_t)0x80) //!< Secure Boot command op-code +#define ATCA_SELFTEST ((uint8_t)0x77) //!< Self test command op-code + + + + +/** @} */ + + +/** \name Definitions of Data and Packet Sizes + @{ */ +#define ATCA_BLOCK_SIZE (32) //!< size of a block +#define ATCA_WORD_SIZE (4) //!< size of a word +#define ATCA_PUB_KEY_PAD (4) //!< size of the public key pad +#define ATCA_SERIAL_NUM_SIZE (9) //!< number of bytes in the device serial number +#define ATCA_RSP_SIZE_VAL ((uint8_t)7) //!< size of response packet containing four bytes of data +#define ATCA_KEY_COUNT (16) //!< number of keys +#define ATCA_ECC_CONFIG_SIZE (128) //!< size of configuration zone +#define ATCA_SHA_CONFIG_SIZE (88) //!< size of configuration zone +#define ATCA_ECC204_CONFIG_SIZE (64) //!< size of ECC204 configuration zone +#define ATCA_ECC204_CONFIG_SLOT_SIZE (16) //!< size of ECC204 configuration slot size +#define ATCA_OTP_SIZE (64) //!< size of OTP zone +#define ATCA_DATA_SIZE (ATCA_KEY_COUNT * ATCA_KEY_SIZE) //!< size of data zone +#define ATCA_AES_GFM_SIZE ATCA_BLOCK_SIZE //!< size of GFM data + +#define ATCA_CHIPMODE_OFFSET (19) //!< ChipMode byte offset within the configuration zone +#define ATCA_CHIPMODE_I2C_ADDRESS_FLAG ((uint8_t)0x01) //!< ChipMode I2C Address in UserExtraAdd flag +#define ATCA_CHIPMODE_TTL_ENABLE_FLAG ((uint8_t)0x02) //!< ChipMode TTLenable flag +#define ATCA_CHIPMODE_WATCHDOG_MASK ((uint8_t)0x04) //!< ChipMode watchdog duration mask +#define ATCA_CHIPMODE_WATCHDOG_SHORT ((uint8_t)0x00) //!< ChipMode short watchdog (~1.3s) +#define ATCA_CHIPMODE_WATCHDOG_LONG ((uint8_t)0x04) //!< ChipMode long watchdog (~13s) +#define ATCA_CHIPMODE_CLOCK_DIV_MASK ((uint8_t)0xF8) //!< ChipMode clock divider mask +#define ATCA_CHIPMODE_CLOCK_DIV_M0 ((uint8_t)0x00) //!< ChipMode clock divider M0 +#define ATCA_CHIPMODE_CLOCK_DIV_M1 ((uint8_t)0x28) //!< ChipMode clock divider M1 +#define ATCA_CHIPMODE_CLOCK_DIV_M2 ((uint8_t)0x68) //!< ChipMode clock divider M2 + +#define ATCA_COUNT_SIZE ((uint8_t)1) //!< Number of bytes in the command packet Count +#define ATCA_CRC_SIZE ((uint8_t)2) //!< Number of bytes in the command packet CRC +#define ATCA_PACKET_OVERHEAD (ATCA_COUNT_SIZE + ATCA_CRC_SIZE) //!< Number of bytes in the command packet + +#define ATCA_PUB_KEY_SIZE (64) //!< size of a p256 public key +#define ATCA_PRIV_KEY_SIZE (32) //!< size of a p256 private key +#define ATCA_SIG_SIZE (64) //!< size of a p256 signature +#define ATCA_KEY_SIZE (32) //!< size of a symmetric SHA key +#define RSA2048_KEY_SIZE (256) //!< size of a RSA private key + +#define ATCA_RSP_SIZE_MIN ((uint8_t)4) //!< minimum number of bytes in response +#define ATCA_RSP_SIZE_4 ((uint8_t)7) //!< size of response packet containing 4 bytes data +#define ATCA_RSP_SIZE_72 ((uint8_t)75) //!< size of response packet containing 64 bytes data +#define ATCA_RSP_SIZE_64 ((uint8_t)67) //!< size of response packet containing 64 bytes data +#define ATCA_RSP_SIZE_32 ((uint8_t)35) //!< size of response packet containing 32 bytes data +#define ATCA_RSP_SIZE_16 ((uint8_t)19) //!< size of response packet containing 16 bytes data +#define ATCA_RSP_SIZE_MAX ((uint8_t)75) //!< maximum size of response packet (GenKey and Verify command) + +#define OUTNONCE_SIZE (32) //!< Size of the OutNonce response expected from several commands + +/** \name Definitions for Command Parameter Ranges + @{ */ +#define ATCA_KEY_ID_MAX ((uint8_t)15) //!< maximum value for key id +#define ATCA_OTP_BLOCK_MAX ((uint8_t)1) //!< maximum value for OTP block +/** @} */ + +/** \name Definitions for Indexes Common to All Commands + @{ */ +#define ATCA_COUNT_IDX (0) //!< command packet index for count +#define ATCA_OPCODE_IDX (1) //!< command packet index for op-code +#define ATCA_PARAM1_IDX (2) //!< command packet index for first parameter +#define ATCA_PARAM2_IDX (3) //!< command packet index for second parameter +#define ATCA_DATA_IDX (5) //!< command packet index for data load +#define ATCA_RSP_DATA_IDX (1) //!< buffer index of data in response +/** @} */ + +/** \name Definitions for Zone and Address Parameters + @{ */ +#define ATCA_ZONE_MASK ((uint8_t)0x03) //!< Zone mask +#define ATCA_ZONE_ENCRYPTED ((uint8_t)0x40) //!< Zone bit 6 set: Write is encrypted with an unlocked data zone. +#define ATCA_ZONE_READWRITE_32 ((uint8_t)0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes. +#define ATCA_ADDRESS_MASK_CONFIG (0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone. +#define ATCA_ADDRESS_MASK_OTP (0x000F) //!< Address bits 4 to 7 are 0 for OTP zone. +#define ATCA_ADDRESS_MASK (0x007F) //!< Address bit 7 to 15 are always 0. +#define ATCA_TEMPKEY_KEYID (0xFFFF) //!< KeyID when referencing TempKey +/** @} */ + +/** \name Definitions for Key types + @{ */ +#define ATCA_B283_KEY_TYPE 0 //!< B283 NIST ECC key +#define ATCA_K283_KEY_TYPE 1 //!< K283 NIST ECC key +#define ATCA_P256_KEY_TYPE 4 //!< P256 NIST ECC key +#define ATCA_AES_KEY_TYPE 6 //!< AES-128 Key +#define ATCA_SHA_KEY_TYPE 7 //!< SHA key or other data +/** @} */ + +/** \name Definitions for the AES Command + @{ */ +#define AES_MODE_IDX ATCA_PARAM1_IDX //!< AES command index for mode +#define AES_KEYID_IDX ATCA_PARAM2_IDX //!< AES command index for key id +#define AES_INPUT_IDX ATCA_DATA_IDX //!< AES command index for input data +#define AES_COUNT (23) //!< AES command packet size +#define AES_MODE_MASK ((uint8_t)0xC7) //!< AES mode bits 3 to 5 are 0 +#define AES_MODE_KEY_BLOCK_MASK ((uint8_t)0xC0) //!< AES mode mask for key block field +#define AES_MODE_OP_MASK ((uint8_t)0x07) //!< AES mode operation mask +#define AES_MODE_ENCRYPT ((uint8_t)0x00) //!< AES mode: Encrypt +#define AES_MODE_DECRYPT ((uint8_t)0x01) //!< AES mode: Decrypt +#define AES_MODE_GFM ((uint8_t)0x03) //!< AES mode: GFM calculation +#define AES_MODE_KEY_BLOCK_POS (6) //!< Bit shift for key block in mode +#define AES_DATA_SIZE (16) //!< size of AES encrypt/decrypt data +#define AES_RSP_SIZE ATCA_RSP_SIZE_16 //!< AES command response packet size +/** @} */ + +/** \name Definitions for the CheckMac Command + @{ */ +#define CHECKMAC_MODE_IDX ATCA_PARAM1_IDX //!< CheckMAC command index for mode +#define CHECKMAC_KEYID_IDX ATCA_PARAM2_IDX //!< CheckMAC command index for key identifier +#define CHECKMAC_CLIENT_CHALLENGE_IDX ATCA_DATA_IDX //!< CheckMAC command index for client challenge +#define CHECKMAC_CLIENT_RESPONSE_IDX (37) //!< CheckMAC command index for client response +#define CHECKMAC_DATA_IDX (69) //!< CheckMAC command index for other data +#define CHECKMAC_COUNT (84) //!< CheckMAC command packet size +#define CHECKMAC_MODE_CHALLENGE ((uint8_t)0x00) //!< CheckMAC mode 0: first SHA block from key id +#define CHECKMAC_MODE_BLOCK2_TEMPKEY ((uint8_t)0x01) //!< CheckMAC mode bit 0: second SHA block from TempKey +#define CHECKMAC_MODE_BLOCK1_TEMPKEY ((uint8_t)0x02) //!< CheckMAC mode bit 1: first SHA block from TempKey +#define CHECKMAC_MODE_SOURCE_FLAG_MATCH ((uint8_t)0x04) //!< CheckMAC mode bit 2: match TempKey.SourceFlag +#define CHECKMAC_MODE_INCLUDE_OTP_64 ((uint8_t)0x20) //!< CheckMAC mode bit 5: include first 64 OTP bits +#define CHECKMAC_MODE_MASK ((uint8_t)0x27) //!< CheckMAC mode bits 3, 4, 6, and 7 are 0. +#define CHECKMAC_CLIENT_CHALLENGE_SIZE (32) //!< CheckMAC size of client challenge +#define CHECKMAC_CLIENT_RESPONSE_SIZE (32) //!< CheckMAC size of client response +#define CHECKMAC_OTHER_DATA_SIZE (13) //!< CheckMAC size of "other data" +#define CHECKMAC_CLIENT_COMMAND_SIZE (4) //!< CheckMAC size of client command header size inside "other data" +#define CHECKMAC_CMD_MATCH (0) //!< CheckMAC return value when there is a match +#define CHECKMAC_CMD_MISMATCH (1) //!< CheckMAC return value when there is a mismatch +#define CHECKMAC_RSP_SIZE ATCA_RSP_SIZE_MIN //!< CheckMAC response packet size +/** @} */ + +/** \name Definitions for the Counter command + @{ */ +#define COUNTER_COUNT ATCA_CMD_SIZE_MIN +#define COUNTER_MODE_IDX ATCA_PARAM1_IDX //!< Counter command index for mode +#define COUNTER_KEYID_IDX ATCA_PARAM2_IDX //!< Counter command index for key id +#define COUNTER_MODE_MASK ((uint8_t)0x01) //!< Counter mode bits 1 to 7 are 0 +#define COUNTER_MAX_VALUE ((uint32_t)2097151) //!< Counter maximum value of the counter +#define COUNTER_MODE_READ ((uint8_t)0x00) //!< Counter command mode for reading +#define COUNTER_MODE_INCREMENT ((uint8_t)0x01) //!< Counter command mode for incrementing +#define COUNTER_RSP_SIZE ATCA_RSP_SIZE_4 //!< Counter command response packet size +#define COUNTER_SIZE ATCA_RSP_SIZE_MIN //!< Counter size in binary +/** @} */ + +/** \name Definitions for the DeriveKey Command + @{ */ +#define DERIVE_KEY_RANDOM_IDX ATCA_PARAM1_IDX //!< DeriveKey command index for random bit +#define DERIVE_KEY_TARGETKEY_IDX ATCA_PARAM2_IDX //!< DeriveKey command index for target slot +#define DERIVE_KEY_MAC_IDX ATCA_DATA_IDX //!< DeriveKey command index for optional MAC +#define DERIVE_KEY_COUNT_SMALL ATCA_CMD_SIZE_MIN //!< DeriveKey command packet size without MAC +#define DERIVE_KEY_MODE ((uint8_t)0x04) //!< DeriveKey command mode set to 4 as in datasheet +#define DERIVE_KEY_COUNT_LARGE (39) //!< DeriveKey command packet size with MAC +#define DERIVE_KEY_RANDOM_FLAG ((uint8_t)4) //!< DeriveKey 1. parameter; has to match TempKey.SourceFlag +#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size +#define DERIVE_KEY_RSP_SIZE ATCA_RSP_SIZE_MIN //!< DeriveKey response packet size +/** @} */ + +/** \name Definitions for the ECDH Command + @{ */ +#define ECDH_PREFIX_MODE ((uint8_t)0x00) +#define ECDH_COUNT (ATCA_CMD_SIZE_MIN + ATCA_PUB_KEY_SIZE) +#define ECDH_MODE_SOURCE_MASK ((uint8_t)0x01) +#define ECDH_MODE_SOURCE_EEPROM_SLOT ((uint8_t)0x00) +#define ECDH_MODE_SOURCE_TEMPKEY ((uint8_t)0x01) +#define ECDH_MODE_OUTPUT_MASK ((uint8_t)0x02) +#define ECDH_MODE_OUTPUT_CLEAR ((uint8_t)0x00) +#define ECDH_MODE_OUTPUT_ENC ((uint8_t)0x02) +#define ECDH_MODE_COPY_MASK ((uint8_t)0x0C) +#define ECDH_MODE_COPY_COMPATIBLE ((uint8_t)0x00) +#define ECDH_MODE_COPY_EEPROM_SLOT ((uint8_t)0x04) +#define ECDH_MODE_COPY_TEMP_KEY ((uint8_t)0x08) +#define ECDH_MODE_COPY_OUTPUT_BUFFER ((uint8_t)0x0C) +#define ECDH_KEY_SIZE ATCA_BLOCK_SIZE //!< ECDH output data size +#define ECDH_RSP_SIZE ATCA_RSP_SIZE_64 //!< ECDH command packet size +/** @} */ + +/** \name Definitions for the GenDig Command + @{ */ +#define GENDIG_ZONE_IDX ATCA_PARAM1_IDX //!< GenDig command index for zone +#define GENDIG_KEYID_IDX ATCA_PARAM2_IDX //!< GenDig command index for key id +#define GENDIG_DATA_IDX ATCA_DATA_IDX //!< GenDig command index for optional data +#define GENDIG_COUNT ATCA_CMD_SIZE_MIN //!< GenDig command packet size without "other data" +#define GENDIG_ZONE_CONFIG ((uint8_t)0) //!< GenDig zone id config. Use KeyID to specify any of the four 256-bit blocks of the Configuration zone. +#define GENDIG_ZONE_OTP ((uint8_t)1) //!< GenDig zone id OTP. Use KeyID to specify either the first or second 256-bit block of the OTP zone. +#define GENDIG_ZONE_DATA ((uint8_t)2) //!< GenDig zone id data. Use KeyID to specify a slot in the Data zone or a transport key in the hardware array. +#define GENDIG_ZONE_SHARED_NONCE ((uint8_t)3) //!< GenDig zone id shared nonce. KeyID specifies the location of the input value in the message generation. +#define GENDIG_ZONE_COUNTER ((uint8_t)4) //!< GenDig zone id counter. KeyID specifies the monotonic counter ID to be included in the message generation. +#define GENDIG_ZONE_KEY_CONFIG ((uint8_t)5) //!< GenDig zone id key config. KeyID specifies the slot for which the configuration information is to be included in the message generation. +#define GENDIG_RSP_SIZE ATCA_RSP_SIZE_MIN //!< GenDig command response packet size +/** @} */ + +/** \name Definitions for the GenKey Command + @{ */ +#define GENKEY_MODE_IDX ATCA_PARAM1_IDX //!< GenKey command index for mode +#define GENKEY_KEYID_IDX ATCA_PARAM2_IDX //!< GenKey command index for key id +#define GENKEY_DATA_IDX (5) //!< GenKey command index for other data +#define GENKEY_COUNT ATCA_CMD_SIZE_MIN //!< GenKey command packet size without "other data" +#define GENKEY_COUNT_DATA (10) //!< GenKey command packet size with "other data" +#define GENKEY_OTHER_DATA_SIZE (3) //!< GenKey size of "other data" +#define GENKEY_MODE_MASK ((uint8_t)0x1C) //!< GenKey mode bits 0 to 1 and 5 to 7 are 0 +#define GENKEY_MODE_PRIVATE ((uint8_t)0x04) //!< GenKey mode: private key generation +#define GENKEY_MODE_PUBLIC ((uint8_t)0x00) //!< GenKey mode: public key calculation +#define GENKEY_MODE_DIGEST ((uint8_t)0x08) //!< GenKey mode: PubKey digest will be created after the public key is calculated +#define GENKEY_MODE_PUBKEY_DIGEST ((uint8_t)0x10) //!< GenKey mode: Calculate PubKey digest on the public key in KeyId +#define GENKEY_MODE_MAC ((uint8_t)0x20) //!< Genkey mode: Calculate MAC of public key + session key +#define GENKEY_PRIVATE_TO_TEMPKEY ((uint16_t)0xFFFF) //!< GenKey Create private key and store to tempkey (608 only) +#define GENKEY_RSP_SIZE_SHORT ATCA_RSP_SIZE_MIN //!< GenKey response packet size in Digest mode +#define GENKEY_RSP_SIZE_LONG ATCA_RSP_SIZE_64 //!< GenKey response packet size when returning a public key +/** @} */ + +/** \name Definitions for the HMAC Command + @{ */ +#define HMAC_MODE_IDX ATCA_PARAM1_IDX //!< HMAC command index for mode +#define HMAC_KEYID_IDX ATCA_PARAM2_IDX //!< HMAC command index for key id +#define HMAC_COUNT ATCA_CMD_SIZE_MIN //!< HMAC command packet size +#define HMAC_MODE_FLAG_TK_RAND ((uint8_t)0x00) //!< HMAC mode bit 2: The value of this bit must match the value in TempKey.SourceFlag or the command will return an error. +#define HMAC_MODE_FLAG_TK_NORAND ((uint8_t)0x04) //!< HMAC mode bit 2: The value of this bit must match the value in TempKey.SourceFlag or the command will return an error. +#define HMAC_MODE_FLAG_OTP88 ((uint8_t)0x10) //!< HMAC mode bit 4: Include the first 88 OTP bits (OTP[0] through OTP[10]) in the message.; otherwise, the corresponding message bits are set to zero. Not applicable for ATECC508A. +#define HMAC_MODE_FLAG_OTP64 ((uint8_t)0x20) //!< HMAC mode bit 5: Include the first 64 OTP bits (OTP[0] through OTP[7]) in the message.; otherwise, the corresponding message bits are set to zero. If Mode[4] is set, the value of this mode bit is ignored. Not applicable for ATECC508A. +#define HMAC_MODE_FLAG_FULLSN ((uint8_t)0x40) //!< HMAC mode bit 6: If set, include the 48 bits SN[2:3] and SN[4:7] in the message.; otherwise, the corresponding message bits are set to zero. +#define HMAC_MODE_MASK ((uint8_t)0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0. +#define HMAC_DIGEST_SIZE (32) //!< HMAC size of digest response +#define HMAC_RSP_SIZE ATCA_RSP_SIZE_32 //!< HMAC command response packet size +/** @} */ + +/** \name Definitions for the Info Command + @{ */ +#define INFO_PARAM1_IDX ATCA_PARAM1_IDX //!< Info command index for 1. parameter +#define INFO_PARAM2_IDX ATCA_PARAM2_IDX //!< Info command index for 2. parameter +#define INFO_COUNT ATCA_CMD_SIZE_MIN //!< Info command packet size +#define INFO_MODE_REVISION ((uint8_t)0x00) //!< Info mode Revision +#define INFO_MODE_KEY_VALID ((uint8_t)0x01) //!< Info mode KeyValid +#define INFO_MODE_STATE ((uint8_t)0x02) //!< Info mode State +#define INFO_MODE_LOCK_STATUS ((uint8_t)0x02) //!< Info mode Lock status for ECC204 device +#define INFO_MODE_GPIO ((uint8_t)0x03) //!< Info mode GPIO +#define INFO_MODE_VOL_KEY_PERMIT ((uint8_t)0x04) //!< Info mode GPIO +#define INFO_MODE_MAX ((uint8_t)0x03) //!< Info mode maximum value +#define INFO_NO_STATE ((uint8_t)0x00) //!< Info mode is not the state mode. +#define INFO_OUTPUT_STATE_MASK ((uint8_t)0x01) //!< Info output state mask +#define INFO_DRIVER_STATE_MASK ((uint8_t)0x02) //!< Info driver state mask +#define INFO_PARAM2_SET_LATCH_STATE ((uint16_t)0x0002) //!< Info param2 to set the persistent latch state. +#define INFO_PARAM2_LATCH_SET ((uint16_t)0x0001) //!< Info param2 to set the persistent latch +#define INFO_PARAM2_LATCH_CLEAR ((uint16_t)0x0000) //!< Info param2 to clear the persistent latch +#define INFO_SIZE ((uint8_t)0x04) //!< Info return size +#define INFO_RSP_SIZE ATCA_RSP_SIZE_VAL //!< Info command response packet size +/** @} */ + +/** \name Definitions for the KDF Command + @{ */ +#define KDF_MODE_IDX ATCA_PARAM1_IDX //!< KDF command index for mode +#define KDF_KEYID_IDX ATCA_PARAM2_IDX //!< KDF command index for key id +#define KDF_DETAILS_IDX ATCA_DATA_IDX //!< KDF command index for details +#define KDF_DETAILS_SIZE 4 //!< KDF details (param3) size +#define KDF_MESSAGE_IDX (ATCA_DATA_IDX + KDF_DETAILS_SIZE) + +#define KDF_MODE_SOURCE_MASK ((uint8_t)0x03) //!< KDF mode source key mask +#define KDF_MODE_SOURCE_TEMPKEY ((uint8_t)0x00) //!< KDF mode source key in TempKey +#define KDF_MODE_SOURCE_TEMPKEY_UP ((uint8_t)0x01) //!< KDF mode source key in upper TempKey +#define KDF_MODE_SOURCE_SLOT ((uint8_t)0x02) //!< KDF mode source key in a slot +#define KDF_MODE_SOURCE_ALTKEYBUF ((uint8_t)0x03) //!< KDF mode source key in alternate key buffer + +#define KDF_MODE_TARGET_MASK ((uint8_t)0x1C) //!< KDF mode target key mask +#define KDF_MODE_TARGET_TEMPKEY ((uint8_t)0x00) //!< KDF mode target key in TempKey +#define KDF_MODE_TARGET_TEMPKEY_UP ((uint8_t)0x04) //!< KDF mode target key in upper TempKey +#define KDF_MODE_TARGET_SLOT ((uint8_t)0x08) //!< KDF mode target key in slot +#define KDF_MODE_TARGET_ALTKEYBUF ((uint8_t)0x0C) //!< KDF mode target key in alternate key buffer +#define KDF_MODE_TARGET_OUTPUT ((uint8_t)0x10) //!< KDF mode target key in output buffer +#define KDF_MODE_TARGET_OUTPUT_ENC ((uint8_t)0x14) //!< KDF mode target key encrypted in output buffer + +#define KDF_MODE_ALG_MASK ((uint8_t)0x60) //!< KDF mode algorithm mask +#define KDF_MODE_ALG_PRF ((uint8_t)0x00) //!< KDF mode PRF algorithm +#define KDF_MODE_ALG_AES ((uint8_t)0x20) //!< KDF mode AES algorithm +#define KDF_MODE_ALG_HKDF ((uint8_t)0x40) //!< KDF mode HKDF algorithm + +#define KDF_DETAILS_PRF_KEY_LEN_MASK ((uint32_t)0x00000003) //!< KDF details for PRF, source key length mask +#define KDF_DETAILS_PRF_KEY_LEN_16 ((uint32_t)0x00000000) //!< KDF details for PRF, source key length is 16 bytes +#define KDF_DETAILS_PRF_KEY_LEN_32 ((uint32_t)0x00000001) //!< KDF details for PRF, source key length is 32 bytes +#define KDF_DETAILS_PRF_KEY_LEN_48 ((uint32_t)0x00000002) //!< KDF details for PRF, source key length is 48 bytes +#define KDF_DETAILS_PRF_KEY_LEN_64 ((uint32_t)0x00000003) //!< KDF details for PRF, source key length is 64 bytes + +#define KDF_DETAILS_PRF_TARGET_LEN_MASK ((uint32_t)0x00000100) //!< KDF details for PRF, target length mask +#define KDF_DETAILS_PRF_TARGET_LEN_32 ((uint32_t)0x00000000) //!< KDF details for PRF, target length is 32 bytes +#define KDF_DETAILS_PRF_TARGET_LEN_64 ((uint32_t)0x00000100) //!< KDF details for PRF, target length is 64 bytes + +#define KDF_DETAILS_PRF_AEAD_MASK ((uint32_t)0x00000600) //!< KDF details for PRF, AEAD processing mask +#define KDF_DETAILS_PRF_AEAD_MODE0 ((uint32_t)0x00000000) //!< KDF details for PRF, AEAD no processing +#define KDF_DETAILS_PRF_AEAD_MODE1 ((uint32_t)0x00000200) //!< KDF details for PRF, AEAD First 32 go to target, second 32 go to output buffer + +#define KDF_DETAILS_AES_KEY_LOC_MASK ((uint32_t)0x00000003) //!< KDF details for AES, key location mask + +#define KDF_DETAILS_HKDF_MSG_LOC_MASK ((uint32_t)0x00000003) //!< KDF details for HKDF, message location mask +#define KDF_DETAILS_HKDF_MSG_LOC_SLOT ((uint32_t)0x00000000) //!< KDF details for HKDF, message location in slot +#define KDF_DETAILS_HKDF_MSG_LOC_TEMPKEY ((uint32_t)0x00000001) //!< KDF details for HKDF, message location in TempKey +#define KDF_DETAILS_HKDF_MSG_LOC_INPUT ((uint32_t)0x00000002) //!< KDF details for HKDF, message location in input parameter +#define KDF_DETAILS_HKDF_MSG_LOC_IV ((uint32_t)0x00000003) //!< KDF details for HKDF, message location is a special IV function +#define KDF_DETAILS_HKDF_ZERO_KEY ((uint32_t)0x00000004) //!< KDF details for HKDF, key is 32 bytes of zero +/** @} */ + +/** \name Definitions for the Lock Command + @{ */ +#define LOCK_ZONE_IDX ATCA_PARAM1_IDX //!< Lock command index for zone +#define LOCK_SUMMARY_IDX ATCA_PARAM2_IDX //!< Lock command index for summary +#define LOCK_COUNT ATCA_CMD_SIZE_MIN //!< Lock command packet size +#define LOCK_ZONE_CONFIG ((uint8_t)0x00) //!< Lock zone is Config +#define LOCK_ZONE_DATA ((uint8_t)0x01) //!< Lock zone is OTP or Data +#define LOCK_ZONE_DATA_SLOT ((uint8_t)0x02) //!< Lock slot of Data +#define LOCK_ECC204_ZONE_DATA ((uint8_t)0x00) //!< Lock ECC204 Data zone by slot +#define LOCK_ECC204_ZONE_CONFIG ((uint8_t)0x01) //!< Lock ECC204 configuration zone by slot +#define LOCK_ZONE_NO_CRC ((uint8_t)0x80) //!< Lock command: Ignore summary. +#define LOCK_ZONE_MASK (0xBF) //!< Lock parameter 1 bits 6 are 0. +#define ATCA_UNLOCKED (0x55) //!< Value indicating an unlocked zone +#define ATCA_LOCKED (0x00) //!< Value indicating a locked zone +#define LOCK_RSP_SIZE ATCA_RSP_SIZE_MIN //!< Lock command response packet size +/** @} */ + +/** \name Definitions for the MAC Command + @{ */ +#define MAC_MODE_IDX ATCA_PARAM1_IDX //!< MAC command index for mode +#define MAC_KEYID_IDX ATCA_PARAM2_IDX //!< MAC command index for key id +#define MAC_CHALLENGE_IDX ATCA_DATA_IDX //!< MAC command index for optional challenge +#define MAC_COUNT_SHORT ATCA_CMD_SIZE_MIN //!< MAC command packet size without challenge +#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge +#define MAC_MODE_CHALLENGE ((uint8_t)0x00) //!< MAC mode 0: first SHA block from data slot +#define MAC_MODE_BLOCK2_TEMPKEY ((uint8_t)0x01) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_BLOCK1_TEMPKEY ((uint8_t)0x02) //!< MAC mode bit 1: first SHA block from TempKey +#define MAC_MODE_SOURCE_FLAG_MATCH ((uint8_t)0x04) //!< MAC mode bit 2: match TempKey.SourceFlag +#define MAC_MODE_PTNONCE_TEMPKEY ((uint8_t)0x06) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_PASSTHROUGH ((uint8_t)0x07) //!< MAC mode bit 0-2: pass-through mode +#define MAC_MODE_INCLUDE_OTP_88 ((uint8_t)0x10) //!< MAC mode bit 4: include first 88 OTP bits +#define MAC_MODE_INCLUDE_OTP_64 ((uint8_t)0x20) //!< MAC mode bit 5: include first 64 OTP bits +#define MAC_MODE_INCLUDE_SN ((uint8_t)0x40) //!< MAC mode bit 6: include serial number +#define MAC_CHALLENGE_SIZE (32) //!< MAC size of challenge +#define MAC_SIZE (32) //!< MAC size of response +#define MAC_MODE_MASK ((uint8_t)0x77) //!< MAC mode bits 3 and 7 are 0. +#define MAC_RSP_SIZE ATCA_RSP_SIZE_32 //!< MAC command response packet size +/** @} */ + +/** \name Definitions for the Nonce Command + @{ */ +#define NONCE_MODE_IDX ATCA_PARAM1_IDX //!< Nonce command index for mode +#define NONCE_PARAM2_IDX ATCA_PARAM2_IDX //!< Nonce command index for 2. parameter +#define NONCE_INPUT_IDX ATCA_DATA_IDX //!< Nonce command index for input data +#define NONCE_COUNT_SHORT (ATCA_CMD_SIZE_MIN + 20) //!< Nonce command packet size for 20 bytes of NumIn +#define NONCE_COUNT_LONG (ATCA_CMD_SIZE_MIN + 32) //!< Nonce command packet size for 32 bytes of NumIn +#define NONCE_COUNT_LONG_64 (ATCA_CMD_SIZE_MIN + 64) //!< Nonce command packet size for 64 bytes of NumIn +#define NONCE_MODE_MASK ((uint8_t)0x03) //!< Nonce mode bits 2 to 7 are 0. +#define NONCE_MODE_SEED_UPDATE ((uint8_t)0x00) //!< Nonce mode: update seed +#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t)0x01) //!< Nonce mode: do not update seed +#define NONCE_MODE_INVALID ((uint8_t)0x02) //!< Nonce mode 2 is invalid. +#define NONCE_MODE_PASSTHROUGH ((uint8_t)0x03) //!< Nonce mode: pass-through +#define NONCE_MODE_GEN_SESSION_KEY ((uint8_t)0x02) //!< NOnce mode: Generate session key in ECC204 device + +#define NONCE_MODE_INPUT_LEN_MASK ((uint8_t)0x20) //!< Nonce mode: input size mask +#define NONCE_MODE_INPUT_LEN_32 ((uint8_t)0x00) //!< Nonce mode: input size is 32 bytes +#define NONCE_MODE_INPUT_LEN_64 ((uint8_t)0x20) //!< Nonce mode: input size is 64 bytes + +#define NONCE_MODE_TARGET_MASK ((uint8_t)0xC0) //!< Nonce mode: target mask +#define NONCE_MODE_TARGET_TEMPKEY ((uint8_t)0x00) //!< Nonce mode: target is TempKey +#define NONCE_MODE_TARGET_MSGDIGBUF ((uint8_t)0x40) //!< Nonce mode: target is Message Digest Buffer +#define NONCE_MODE_TARGET_ALTKEYBUF ((uint8_t)0x80) //!< Nonce mode: target is Alternate Key Buffer + +#define NONCE_ZERO_CALC_MASK ((uint16_t)0x8000) //!< Nonce zero (param2): calculation mode mask +#define NONCE_ZERO_CALC_RANDOM ((uint16_t)0x0000) //!< Nonce zero (param2): calculation mode random, use RNG in calculation and return RNG output +#define NONCE_ZERO_CALC_TEMPKEY ((uint16_t)0x8000) //!< Nonce zero (param2): calculation mode TempKey, use TempKey in calculation and return new TempKey value + +#define NONCE_NUMIN_SIZE (20) //!< Nonce NumIn size for random modes +#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce NumIn size for 32-byte pass-through mode + +#define NONCE_RSP_SIZE_SHORT ATCA_RSP_SIZE_MIN //!< Nonce command response packet size with no output +#define NONCE_RSP_SIZE_LONG ATCA_RSP_SIZE_32 //!< Nonce command response packet size with output +/** @} */ + +/** \name Definitions for the Pause Command + @{ */ +#define PAUSE_SELECT_IDX ATCA_PARAM1_IDX //!< Pause command index for Selector +#define PAUSE_PARAM2_IDX ATCA_PARAM2_IDX //!< Pause command index for 2. parameter +#define PAUSE_COUNT ATCA_CMD_SIZE_MIN //!< Pause command packet size +#define PAUSE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< Pause command response packet size +/** @} */ + +/** \name Definitions for the PrivWrite Command + @{ */ +#define PRIVWRITE_ZONE_IDX ATCA_PARAM1_IDX //!< PrivWrite command index for zone +#define PRIVWRITE_KEYID_IDX ATCA_PARAM2_IDX //!< PrivWrite command index for KeyID +#define PRIVWRITE_VALUE_IDX ( 5) //!< PrivWrite command index for value +#define PRIVWRITE_MAC_IDX (41) //!< PrivWrite command index for MAC +#define PRIVWRITE_COUNT (75) //!< PrivWrite command packet size +#define PRIVWRITE_ZONE_MASK ((uint8_t)0x40) //!< PrivWrite zone bits 0 to 5 and 7 are 0. +#define PRIVWRITE_MODE_ENCRYPT ((uint8_t)0x40) //!< PrivWrite mode: encrypted +#define PRIVWRITE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< PrivWrite command response packet size +/** @} */ + +/** \name Definitions for the Random Command + @{ */ +#define RANDOM_MODE_IDX ATCA_PARAM1_IDX //!< Random command index for mode +#define RANDOM_PARAM2_IDX ATCA_PARAM2_IDX //!< Random command index for 2. parameter +#define RANDOM_COUNT ATCA_CMD_SIZE_MIN //!< Random command packet size +#define RANDOM_SEED_UPDATE ((uint8_t)0x00) //!< Random mode for automatic seed update +#define RANDOM_NO_SEED_UPDATE ((uint8_t)0x01) //!< Random mode for no seed update +#define RANDOM_NUM_SIZE ((uint8_t)32) //!< Number of bytes in the data packet of a random command +#define RANDOM_RSP_SIZE ATCA_RSP_SIZE_32 //!< Random command response packet size +/** @} */ + +/** \name Definitions for the Read Command + @{ */ +#define READ_ZONE_IDX ATCA_PARAM1_IDX //!< Read command index for zone +#define READ_ADDR_IDX ATCA_PARAM2_IDX //!< Read command index for address +#define READ_COUNT ATCA_CMD_SIZE_MIN //!< Read command packet size +#define READ_ZONE_MASK ((uint8_t)0x83) //!< Read zone bits 2 to 6 are 0. +#define READ_4_RSP_SIZE ATCA_RSP_SIZE_VAL //!< Read command response packet size when reading 4 bytes +#define READ_32_RSP_SIZE ATCA_RSP_SIZE_32 //!< Read command response packet size when reading 32 bytes +/** @} */ + +/** \name Definitions for the SecureBoot Command + @{ */ +#define SECUREBOOT_MODE_IDX ATCA_PARAM1_IDX //!< SecureBoot command index for mode +#define SECUREBOOT_DIGEST_SIZE (32) //!< SecureBoot digest input size +#define SECUREBOOT_SIGNATURE_SIZE (64) //!< SecureBoot signature input size +#define SECUREBOOT_COUNT_DIG (ATCA_CMD_SIZE_MIN + SECUREBOOT_DIGEST_SIZE) //!< SecureBoot command packet size for just a digest +#define SECUREBOOT_COUNT_DIG_SIG (ATCA_CMD_SIZE_MIN + SECUREBOOT_DIGEST_SIZE + SECUREBOOT_SIGNATURE_SIZE) //!< SecureBoot command packet size for a digest and signature +#define SECUREBOOT_MAC_SIZE (32) //!< SecureBoot MAC output size +#define SECUREBOOT_RSP_SIZE_NO_MAC ATCA_RSP_SIZE_MIN //!< SecureBoot response packet size for no MAC +#define SECUREBOOT_RSP_SIZE_MAC (ATCA_PACKET_OVERHEAD + SECUREBOOT_MAC_SIZE) //!< SecureBoot response packet size with MAC + +#define SECUREBOOT_MODE_MASK ((uint8_t)0x07) //!< SecureBoot mode mask +#define SECUREBOOT_MODE_FULL ((uint8_t)0x05) //!< SecureBoot mode Full +#define SECUREBOOT_MODE_FULL_STORE ((uint8_t)0x06) //!< SecureBoot mode FullStore +#define SECUREBOOT_MODE_FULL_COPY ((uint8_t)0x07) //!< SecureBoot mode FullCopy +#define SECUREBOOT_MODE_PROHIBIT_FLAG ((uint8_t)0x40) //!< SecureBoot mode flag to prohibit SecureBoot until next power cycle +#define SECUREBOOT_MODE_ENC_MAC_FLAG ((uint8_t)0x80) //!< SecureBoot mode flag for encrypted digest and returning validating MAC + +#define SECUREBOOTCONFIG_OFFSET (70) //!< SecureBootConfig byte offset into the configuration zone +#define SECUREBOOTCONFIG_MODE_MASK ((uint16_t)0x0003) //!< Mask for SecureBootMode field in SecureBootConfig value +#define SECUREBOOTCONFIG_MODE_DISABLED ((uint16_t)0x0000) //!< Disabled SecureBootMode in SecureBootConfig value +#define SECUREBOOTCONFIG_MODE_FULL_BOTH ((uint16_t)0x0001) //!< Both digest and signature always required SecureBootMode in SecureBootConfig value +#define SECUREBOOTCONFIG_MODE_FULL_SIG ((uint16_t)0x0002) //!< Signature stored SecureBootMode in SecureBootConfig value +#define SECUREBOOTCONFIG_MODE_FULL_DIG ((uint16_t)0x0003) //!< Digest stored SecureBootMode in SecureBootConfig value +/** @} */ + +/** \name Definitions for the SelfTest Command + @{ */ +#define SELFTEST_MODE_IDX ATCA_PARAM1_IDX //!< SelfTest command index for mode +#define SELFTEST_COUNT ATCA_CMD_SIZE_MIN //!< SelfTest command packet size +#define SELFTEST_MODE_RNG ((uint8_t)0x01) //!< SelfTest mode RNG DRBG function +#define SELFTEST_MODE_ECDSA_SIGN_VERIFY ((uint8_t)0x02) //!< SelfTest mode ECDSA verify function +#define SELFTEST_MODE_ECDH ((uint8_t)0x08) //!< SelfTest mode ECDH function +#define SELFTEST_MODE_AES ((uint8_t)0x10) //!< SelfTest mode AES encrypt function +#define SELFTEST_MODE_SHA ((uint8_t)0x20) //!< SelfTest mode SHA function +#define SELFTEST_MODE_ALL ((uint8_t)0x3B) //!< SelfTest mode all algorithms +#define SELFTEST_RSP_SIZE ATCA_RSP_SIZE_MIN //!< SelfTest command response packet size +/** @} */ + +/** \name Definitions for the SHA Command + @{ */ +#define SHA_COUNT_SHORT ATCA_CMD_SIZE_MIN +#define SHA_COUNT_LONG ATCA_CMD_SIZE_MIN //!< Just a starting size +#define ATCA_SHA_DIGEST_SIZE (32) +#define SHA_DATA_MAX (64) + +#define SHA_MODE_MASK ((uint8_t)0x07) //!< Mask the bit 0-2 +#define SHA_MODE_SHA256_START ((uint8_t)0x00) //!< Initialization, does not accept a message +#define SHA_MODE_SHA256_UPDATE ((uint8_t)0x01) //!< Add 64 bytes in the meesage to the SHA context +#define SHA_MODE_SHA256_END ((uint8_t)0x02) //!< Complete the calculation and return the digest +#define SHA_MODE_SHA256_PUBLIC ((uint8_t)0x03) //!< Add 64 byte ECC public key in the slot to the SHA context +#define SHA_MODE_HMAC_START ((uint8_t)0x04) //!< Initialization, HMAC calculation +#define SHA_MODE_ECC204_HMAC_START ((uint8_t)0x03) //!< Initialization, HMAC calculation for ECC204 +#define SHA_MODE_HMAC_UPDATE ((uint8_t)0x01) //!< Add 64 bytes in the meesage to the SHA context +#define SHA_MODE_HMAC_END ((uint8_t)0x05) //!< Complete the HMAC computation and return digest +#define SHA_MODE_608_HMAC_END ((uint8_t)0x02) //!< Complete the HMAC computation and return digest... Different command on 608 +#define SHA_MODE_ECC204_HMAC_END ((uint8_t)0x02) //!< Complete the HMAC computation and return digest... Different mode on ECC204 +#define SHA_MODE_READ_CONTEXT ((uint8_t)0x06) //!< Read current SHA-256 context out of the device +#define SHA_MODE_WRITE_CONTEXT ((uint8_t)0x07) //!< Restore a SHA-256 context into the device +#define SHA_MODE_TARGET_MASK ((uint8_t)0xC0) //!< Resulting digest target location mask + +#define SHA_RSP_SIZE ATCA_RSP_SIZE_32 //!< SHA command response packet size +#define SHA_RSP_SIZE_SHORT ATCA_RSP_SIZE_MIN //!< SHA command response packet size only status code +#define SHA_RSP_SIZE_LONG ATCA_RSP_SIZE_32 //!< SHA command response packet size +/** @} */ + +/** @} *//** \name Definitions for the Sign Command + @{ */ +#define SIGN_MODE_IDX ATCA_PARAM1_IDX //!< Sign command index for mode +#define SIGN_KEYID_IDX ATCA_PARAM2_IDX //!< Sign command index for key id +#define SIGN_COUNT ATCA_CMD_SIZE_MIN //!< Sign command packet size +#define SIGN_MODE_MASK ((uint8_t)0xE1) //!< Sign mode bits 1 to 4 are 0 +#define SIGN_MODE_INTERNAL ((uint8_t)0x00) //!< Sign mode 0: internal +#define SIGN_MODE_INVALIDATE ((uint8_t)0x01) //!< Sign mode bit 1: Signature will be used for Verify(Invalidate) +#define SIGN_MODE_INCLUDE_SN ((uint8_t)0x40) //!< Sign mode bit 6: include serial number +#define SIGN_MODE_EXTERNAL ((uint8_t)0x80) //!< Sign mode bit 7: external +#define SIGN_MODE_SOURCE_MASK ((uint8_t)0x20) //!< Sign mode message source mask +#define SIGN_MODE_SOURCE_TEMPKEY ((uint8_t)0x00) //!< Sign mode message source is TempKey +#define SIGN_MODE_SOURCE_MSGDIGBUF ((uint8_t)0x20) //!< Sign mode message source is the Message Digest Buffer +#define SIGN_RSP_SIZE ATCA_RSP_SIZE_MAX //!< Sign command response packet size +/** @} */ + +/** \name Definitions for the UpdateExtra Command + @{ */ +#define UPDATE_MODE_IDX ATCA_PARAM1_IDX //!< UpdateExtra command index for mode +#define UPDATE_VALUE_IDX ATCA_PARAM2_IDX //!< UpdateExtra command index for new value +#define UPDATE_COUNT ATCA_CMD_SIZE_MIN //!< UpdateExtra command packet size +#define UPDATE_MODE_USER_EXTRA ((uint8_t)0x00) //!< UpdateExtra mode update UserExtra (config byte 84) +#define UPDATE_MODE_SELECTOR ((uint8_t)0x01) //!< UpdateExtra mode update Selector (config byte 85) +#define UPDATE_MODE_USER_EXTRA_ADD UPDATE_MODE_SELECTOR //!< UpdateExtra mode update UserExtraAdd (config byte 85) +#define UPDATE_MODE_DEC_COUNTER ((uint8_t)0x02) //!< UpdateExtra mode: decrement counter +#define UPDATE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< UpdateExtra command response packet size +/** @} */ + +/** \name Definitions for the Verify Command + @{ */ +#define VERIFY_MODE_IDX ATCA_PARAM1_IDX //!< Verify command index for mode +#define VERIFY_KEYID_IDX ATCA_PARAM2_IDX //!< Verify command index for key id +#define VERIFY_DATA_IDX ( 5) //!< Verify command index for data +#define VERIFY_256_STORED_COUNT ( 71) //!< Verify command packet size for 256-bit key in stored mode +#define VERIFY_283_STORED_COUNT ( 79) //!< Verify command packet size for 283-bit key in stored mode +#define VERIFY_256_VALIDATE_COUNT ( 90) //!< Verify command packet size for 256-bit key in validate mode +#define VERIFY_283_VALIDATE_COUNT ( 98) //!< Verify command packet size for 283-bit key in validate mode +#define VERIFY_256_EXTERNAL_COUNT (135) //!< Verify command packet size for 256-bit key in external mode +#define VERIFY_283_EXTERNAL_COUNT (151) //!< Verify command packet size for 283-bit key in external mode +#define VERIFY_256_KEY_SIZE ( 64) //!< Verify key size for 256-bit key +#define VERIFY_283_KEY_SIZE ( 72) //!< Verify key size for 283-bit key +#define VERIFY_256_SIGNATURE_SIZE ( 64) //!< Verify signature size for 256-bit key +#define VERIFY_283_SIGNATURE_SIZE ( 72) //!< Verify signature size for 283-bit key +#define VERIFY_OTHER_DATA_SIZE ( 19) //!< Verify size of "other data" +#define VERIFY_MODE_MASK ((uint8_t)0x07) //!< Verify mode bits 3 to 7 are 0 +#define VERIFY_MODE_STORED ((uint8_t)0x00) //!< Verify mode: stored +#define VERIFY_MODE_VALIDATE_EXTERNAL ((uint8_t)0x01) //!< Verify mode: validate external +#define VERIFY_MODE_EXTERNAL ((uint8_t)0x02) //!< Verify mode: external +#define VERIFY_MODE_VALIDATE ((uint8_t)0x03) //!< Verify mode: validate +#define VERIFY_MODE_INVALIDATE ((uint8_t)0x07) //!< Verify mode: invalidate +#define VERIFY_MODE_SOURCE_MASK ((uint8_t)0x20) //!< Verify mode message source mask +#define VERIFY_MODE_SOURCE_TEMPKEY ((uint8_t)0x00) //!< Verify mode message source is TempKey +#define VERIFY_MODE_SOURCE_MSGDIGBUF ((uint8_t)0x20) //!< Verify mode message source is the Message Digest Buffer +#define VERIFY_MODE_MAC_FLAG ((uint8_t)0x80) //!< Verify mode: MAC +#define VERIFY_KEY_B283 ((uint16_t)0x0000) //!< Verify key type: B283 +#define VERIFY_KEY_K283 ((uint16_t)0x0001) //!< Verify key type: K283 +#define VERIFY_KEY_P256 ((uint16_t)0x0004) //!< Verify key type: P256 +#define VERIFY_RSP_SIZE ATCA_RSP_SIZE_MIN //!< Verify command response packet size +#define VERIFY_RSP_SIZE_MAC ATCA_RSP_SIZE_32 //!< Verify command response packet size with validating MAC +/** @} */ + +/** \name Definitions for the Write Command + @{ */ +#define WRITE_ZONE_IDX ATCA_PARAM1_IDX //!< Write command index for zone +#define WRITE_ADDR_IDX ATCA_PARAM2_IDX //!< Write command index for address +#define WRITE_VALUE_IDX ATCA_DATA_IDX //!< Write command index for data +#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data +#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data +#define WRITE_MAC_SIZE (32) //!< Write MAC size +#define WRITE_ZONE_MASK ((uint8_t)0xC3) //!< Write zone bits 2 to 5 are 0. +#define WRITE_ZONE_WITH_MAC ((uint8_t)0x40) //!< Write zone bit 6: write encrypted with MAC +#define WRITE_ZONE_OTP ((uint8_t)1) //!< Write zone id OTP +#define WRITE_ZONE_DATA ((uint8_t)2) //!< Write zone id data +#define WRITE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< Write command response packet size +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_derivekey.c b/drivers/ecc108a/cryptoauthlib/calib/calib_derivekey.c new file mode 100644 index 0000000..dfc3881 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_derivekey.c @@ -0,0 +1,86 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for DeriveKey command. + * + * The DeriveKey command combines the current value of a key with the nonce + * stored in TempKey using SHA-256 and derives a new key. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, and ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Executes the DeviveKey command for deriving a new key from a + * nonce (TempKey) and an existing key. + * + * \param[in] device Device context pointer + * \param[in] mode Bit 2 must match the value in TempKey.SourceFlag + * \param[in] target_key Key slot to be written + * \param[in] mac Optional 32 byte MAC used to validate operation. NULL + * if not required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_derivekey(ATCADevice device, uint8_t mode, uint16_t target_key, const uint8_t* mac) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + do + { + if (device == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // build a deriveKey command (pass through mode) + packet.param1 = mode; + packet.param2 = target_key; + + if (mac != NULL) + { + memcpy(packet.data, mac, MAC_SIZE); + } + + if ((status = atDeriveKey(atcab_get_device_type_ext(device), &packet, mac != NULL)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atDeriveKey - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_derivekey - execution failed"); + break; + } + + } + while (0); + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_execution.c b/drivers/ecc108a/cryptoauthlib/calib/calib_execution.c new file mode 100644 index 0000000..0cc5833 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_execution.c @@ -0,0 +1,563 @@ +/** + * \file + * \brief Implements an execution handler that executes a given command on a + * device and returns the results. + * + * This implementation wraps Polling and No polling (simple wait) schemes into + * a single method and use it across the library. Polling is used by default, + * however, by defining the ATCA_NO_POLL symbol the code will instead wait an + * estimated max execution time before requesting the result. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + + +#if defined(ATCA_NO_POLL) && defined(ATCA_ATECC608_SUPPORT) && !defined(ATCA_ATECC608A_SUPPORT) +#warning "ATECC608B supports only polling mode, if you are using an ATECC608A specify ATCA_ATECC608A_SUPPORT manually" +#endif + + +#ifdef ATCA_NO_POLL +// *INDENT-OFF* - Preserve time formatting from the code formatter +/*Execution times for ATSHA204A supported commands...*/ +static const device_execution_time_t device_execution_time_204[] = { + { ATCA_CHECKMAC, 38}, + { ATCA_DERIVE_KEY, 62}, + { ATCA_GENDIG, 43}, + { ATCA_HMAC, 69}, + { ATCA_INFO, 2}, + { ATCA_LOCK, 24}, + { ATCA_MAC, 35}, + { ATCA_NONCE, 60}, + { ATCA_PAUSE, 2}, + { ATCA_RANDOM, 50}, + { ATCA_READ, 5}, + { ATCA_SHA, 22}, + { ATCA_UPDATE_EXTRA, 12}, + { ATCA_WRITE, 42} +}; + +/*Execution times for ATSHA206A supported commands...*/ +static const device_execution_time_t device_execution_time_206[] = { + { ATCA_DERIVE_KEY, 62}, + { ATCA_INFO, 2}, + { ATCA_MAC, 35}, + { ATCA_READ, 5}, + { ATCA_WRITE, 42} +}; + +/*Execution times for ATECC108A supported commands...*/ +static const device_execution_time_t device_execution_time_108[] = { + { ATCA_CHECKMAC, 13}, + { ATCA_COUNTER, 20}, + { ATCA_DERIVE_KEY, 50}, + { ATCA_GENDIG, 11}, + { ATCA_GENKEY, 115}, + { ATCA_HMAC, 23}, + { ATCA_INFO, 2}, + { ATCA_LOCK, 32}, + { ATCA_MAC, 14}, + { ATCA_NONCE, 29}, + { ATCA_PAUSE, 3}, + { ATCA_PRIVWRITE, 48}, + { ATCA_RANDOM, 23}, + { ATCA_READ, 5}, + { ATCA_SHA, 9}, + { ATCA_SIGN, 60}, + { ATCA_UPDATE_EXTRA, 10}, + { ATCA_VERIFY, 72}, + { ATCA_WRITE, 26} +}; + +/*Execution times for ATECC508A supported commands...*/ +static const device_execution_time_t device_execution_time_508[] = { + { ATCA_CHECKMAC, 13}, + { ATCA_COUNTER, 20}, + { ATCA_DERIVE_KEY, 50}, + { ATCA_ECDH, 58}, + { ATCA_GENDIG, 11}, + { ATCA_GENKEY, 115}, + { ATCA_HMAC, 23}, + { ATCA_INFO, 2}, + { ATCA_LOCK, 32}, + { ATCA_MAC, 14}, + { ATCA_NONCE, 29}, + { ATCA_PAUSE, 3}, + { ATCA_PRIVWRITE, 48}, + { ATCA_RANDOM, 23}, + { ATCA_READ, 5}, + { ATCA_SHA, 9}, + { ATCA_SIGN, 60}, + { ATCA_UPDATE_EXTRA, 10}, + { ATCA_VERIFY, 72}, + { ATCA_WRITE, 26} +}; + +/*Execution times for ATECC608-M0 supported commands...*/ +static const device_execution_time_t device_execution_time_608_m0[] = { + { ATCA_AES, 27}, + { ATCA_CHECKMAC, 40}, + { ATCA_COUNTER, 25}, + { ATCA_DERIVE_KEY, 50}, + { ATCA_ECDH, 75}, + { ATCA_GENDIG, 25}, + { ATCA_GENKEY, 115}, + { ATCA_INFO, 5}, + { ATCA_KDF, 165}, + { ATCA_LOCK, 35}, + { ATCA_MAC, 55}, + { ATCA_NONCE, 20}, + { ATCA_PRIVWRITE, 50}, + { ATCA_RANDOM, 23}, + { ATCA_READ, 5}, + { ATCA_SECUREBOOT, 80}, + { ATCA_SELFTEST, 250}, + { ATCA_SHA, 36}, + { ATCA_SIGN, 115}, + { ATCA_UPDATE_EXTRA, 10}, + { ATCA_VERIFY, 105}, + { ATCA_WRITE, 45} +}; + +/*Execution times for ATECC608-M1 supported commands...*/ +static const device_execution_time_t device_execution_time_608_m1[] = { + { ATCA_AES, 27}, + { ATCA_CHECKMAC, 40}, + { ATCA_COUNTER, 25}, + { ATCA_DERIVE_KEY, 50}, + { ATCA_ECDH, 172}, + { ATCA_GENDIG, 35}, + { ATCA_GENKEY, 215}, + { ATCA_INFO, 5}, + { ATCA_KDF, 165}, + { ATCA_LOCK, 35}, + { ATCA_MAC, 55}, + { ATCA_NONCE, 20}, + { ATCA_PRIVWRITE, 50}, + { ATCA_RANDOM, 23}, + { ATCA_READ, 5}, + { ATCA_SECUREBOOT, 160}, + { ATCA_SELFTEST, 625}, + { ATCA_SHA, 42}, + { ATCA_SIGN, 220}, + { ATCA_UPDATE_EXTRA, 10}, + { ATCA_VERIFY, 295}, + { ATCA_WRITE, 45} +}; + +/*Execution times for ATECC608-M2 supported commands...*/ +static const device_execution_time_t device_execution_time_608_m2[] = { + { ATCA_AES, 27}, + { ATCA_CHECKMAC, 40}, + { ATCA_COUNTER, 25}, + { ATCA_DERIVE_KEY, 50}, + { ATCA_ECDH, 531}, + { ATCA_GENDIG, 35}, + { ATCA_GENKEY, 653}, + { ATCA_INFO, 5}, + { ATCA_KDF, 165}, + { ATCA_LOCK, 35}, + { ATCA_MAC, 55}, + { ATCA_NONCE, 20}, + { ATCA_PRIVWRITE, 50}, + { ATCA_RANDOM, 23}, + { ATCA_READ, 5}, + { ATCA_SECUREBOOT, 480}, + { ATCA_SELFTEST, 2324}, + { ATCA_SHA, 75}, + { ATCA_SIGN, 665}, + { ATCA_UPDATE_EXTRA, 10}, + { ATCA_VERIFY, 1085}, + { ATCA_WRITE, 45} +}; + +/*Execution times for ECC204 supported commands...*/ +static const device_execution_time_t device_execution_time_ecc204[] = { + { ATCA_COUNTER, 1}, + { ATCA_GENKEY, 100}, + { ATCA_INFO, 1}, + { ATCA_LOCK, 6}, + { ATCA_NONCE, 35}, + { ATCA_READ, 1}, + { ATCA_SELFTEST, 110}, + { ATCA_SHA, 4}, + { ATCA_SIGN, 100}, + { ATCA_WRITE, 10} +}; +// *INDENT-ON* +#endif + +#ifdef ATCA_NO_POLL +/** \brief return the typical execution time for the given command + * \param[in] opcode Opcode value of the command + * \param[in] ca_cmd Command object for which the execution times are associated + * \return ATCA_SUCCESS + */ +ATCA_STATUS calib_get_execution_time(uint8_t opcode, ATCADevice device) +{ + ATCA_STATUS status = ATCA_SUCCESS; + const device_execution_time_t *execution_times; + uint8_t i, no_of_commands; + + + switch (device->mIface.mIfaceCFG->devtype) + { + case ATSHA204A: + execution_times = device_execution_time_204; + no_of_commands = sizeof(device_execution_time_204) / sizeof(device_execution_time_t); + break; + + case ATSHA206A: + execution_times = device_execution_time_206; + no_of_commands = sizeof(device_execution_time_206) / sizeof(device_execution_time_t); + break; + + case ATECC108A: + execution_times = device_execution_time_108; + no_of_commands = sizeof(device_execution_time_108) / sizeof(device_execution_time_t); + break; + + case ATECC508A: + execution_times = device_execution_time_508; + no_of_commands = sizeof(device_execution_time_508) / sizeof(device_execution_time_t); + break; + + case ATECC608: + if (device->clock_divider == ATCA_CHIPMODE_CLOCK_DIV_M1) + { + execution_times = device_execution_time_608_m1; + no_of_commands = sizeof(device_execution_time_608_m1) / sizeof(device_execution_time_t); + } + else if (device->clock_divider == ATCA_CHIPMODE_CLOCK_DIV_M2) + { + execution_times = device_execution_time_608_m2; + no_of_commands = sizeof(device_execution_time_608_m2) / sizeof(device_execution_time_t); + } + else + { + // Assume default M0 clock divider + execution_times = device_execution_time_608_m0; + no_of_commands = sizeof(device_execution_time_608_m0) / sizeof(device_execution_time_t); + } + break; + + case ECC204: + execution_times = device_execution_time_ecc204; + no_of_commands = sizeof(device_execution_time_ecc204) / sizeof(device_execution_time_t); + break; + + default: + no_of_commands = 0; + execution_times = NULL; + break; + } + + device->execution_time_msec = ATCA_UNSUPPORTED_CMD; + + for (i = 0; i < no_of_commands; i++) + { + if (execution_times[i].opcode == opcode) + { + device->execution_time_msec = execution_times[i].execution_time_msec; + break; + } + } + + if (device->execution_time_msec == ATCA_UNSUPPORTED_CMD) + { + status = ATCA_BAD_OPCODE; + } + + return status; +} +#endif + +ATCA_STATUS calib_execute_send(ATCADevice device, uint8_t device_address, uint8_t* txdata, uint16_t txlength) +{ + ATCA_STATUS status = ATCA_COMM_FAIL; + + if (!txdata || !txlength) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + +#ifdef ATCA_HAL_LEGACY_API + ((void)device_address); + status = atsend(&device->mIface, 0xFF, (uint8_t*)txdata, (int)txlength - 1); +#else + if (atca_iface_is_kit(&device->mIface)) + { + status = atsend(&device->mIface, 0xFF, (uint8_t*)txdata, (int)txlength - 1); + } + else + { + status = atcontrol(&device->mIface, ATCA_HAL_CONTROL_SELECT, NULL, 0); + if (ATCA_UNIMPLEMENTED == status || ATCA_SUCCESS == status) + { + /* Send the command packet to the device */ + status = atsend(&device->mIface, device_address, (uint8_t*)txdata, (int)txlength); + } + (void)atcontrol(&device->mIface, ATCA_HAL_CONTROL_DESELECT, NULL, 0); + } +#endif + + return status; +} + + +ATCA_STATUS calib_execute_receive(ATCADevice device, uint8_t device_address, uint8_t* rxdata, uint16_t* rxlength) +{ + ATCA_STATUS status = ATCA_COMM_FAIL; + + if ((NULL == rxlength) || (NULL == rxdata)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + +#ifdef ATCA_HAL_LEGACY_API + ((void)device_address); + status = atreceive(&device->mIface, 0, rxdata, rxlength); +#else + uint16_t read_length = 1; + uint8_t word_address; + + if (atca_iface_is_kit(&device->mIface)) + { + status = atreceive(&device->mIface, 0, rxdata, rxlength); + } + else + { + do + { + status = atcontrol(&device->mIface, ATCA_HAL_CONTROL_SELECT, NULL, 0); + if (ATCA_UNIMPLEMENTED != status && ATCA_SUCCESS != status) + { + break; + } + + /*Send Word address to device...*/ + if (ATCA_SWI_IFACE == device->mIface.mIfaceCFG->iface_type) + { + word_address = CALIB_SWI_FLAG_TX; + } + else + { + word_address = 0; + } + + // Skip word address send for ECC204 device + if (ECC204 != device->mIface.mIfaceCFG->devtype) + { + if (ATCA_SUCCESS != (status = atsend(&device->mIface, device_address, &word_address, sizeof(word_address)))) + { + break; + } + } + + /* Read length bytes to know number of bytes to read */ + status = atreceive(&device->mIface, device_address, rxdata, &read_length); + if (ATCA_SUCCESS != status) + { + ATCA_TRACE(status, "atreceive - failed"); + break; + } + + /*Calculate bytes to read based on device response*/ + read_length = rxdata[0]; + + if (read_length > *rxlength) + { + status = ATCA_TRACE(ATCA_SMALL_BUFFER, "rxdata is small buffer"); + break; + } + + if (read_length < 4) + { + status = ATCA_TRACE(ATCA_RX_FAIL, "packet size is invalid"); + break; + } + + /* Read given length bytes from device */ + read_length -= 1; + + status = atreceive(&device->mIface, device_address, &rxdata[1], &read_length); + + if (ATCA_SUCCESS != status) + { + status = ATCA_TRACE(status, "atreceive - failed"); + break; + } + + read_length += 1; + + *rxlength = read_length; + } + while (0); + + (void)atcontrol(&device->mIface, ATCA_HAL_CONTROL_DESELECT, NULL, 0); + } +#endif + + return status; +} + +/** \brief Wakes up device, sends the packet, waits for command completion, + * receives response, and puts the device into the idle state. + * + * \param[in,out] packet As input, the packet to be sent. As output, the + * data buffer in the packet structure will contain the + * response. + * \param[in] device CryptoAuthentication device to send the command to. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_execute_command(ATCAPacket* packet, ATCADevice device) +{ + ATCA_STATUS status; + uint32_t execution_or_wait_time; + uint32_t max_delay_count; + uint16_t rxsize; + uint8_t device_address = atcab_get_device_address(device); + int retries = 1; + + do + { +#ifdef ATCA_NO_POLL + if ((status = calib_get_execution_time(packet->opcode, device)) != ATCA_SUCCESS) + { + return status; + } + execution_or_wait_time = device->execution_time_msec; + max_delay_count = 0; +#else + execution_or_wait_time = ATCA_POLLING_INIT_TIME_MSEC; + max_delay_count = ATCA_POLLING_MAX_TIME_MSEC / ATCA_POLLING_FREQUENCY_TIME_MSEC; +#endif + retries = atca_iface_get_retries(&device->mIface); + do + { + if (ATCA_DEVICE_STATE_ACTIVE != device->device_state) + { + if (ATCA_SUCCESS == (status = calib_wakeup(device))) + { + device->device_state = ATCA_DEVICE_STATE_ACTIVE; + } + } + + /* Send the command packet to the device */ + if (ATCA_I2C_IFACE == device->mIface.mIfaceCFG->iface_type) + { + packet->_reserved = 0x03; + } + else if (ATCA_SWI_IFACE == device->mIface.mIfaceCFG->iface_type) + { + packet->_reserved = CALIB_SWI_FLAG_CMD; + } + else if ((ATCA_SWI_GPIO_IFACE == device->mIface.mIfaceCFG->iface_type) && (ECC204 == device->mIface.mIfaceCFG->devtype)) + { + packet->_reserved = 0x03; + } + if (ATCA_RX_NO_RESPONSE == (status = calib_execute_send(device, device_address, (uint8_t*)packet, packet->txsize + 1))) + { + device->device_state = ATCA_DEVICE_STATE_UNKNOWN; + } + else + { + if (ATCA_DEVICE_STATE_ACTIVE != device->device_state) + { + device->device_state = ATCA_DEVICE_STATE_ACTIVE; + } + retries = 0; + } + + } + while (0 < retries--); + + if (ATCA_SUCCESS != status) + { + break; + } + + // Delay for execution time or initial wait before polling + atca_delay_ms(execution_or_wait_time); + + do + { + memset(packet->data, 0, sizeof(packet->data)); + // receive the response + rxsize = sizeof(packet->data); + + if (ATCA_SUCCESS == (status = calib_execute_receive(device, device_address, packet->data, &rxsize))) + { + break; + } + +#ifndef ATCA_NO_POLL + // delay for polling frequency time + atca_delay_ms(ATCA_POLLING_FREQUENCY_TIME_MSEC); +#endif + } + while (max_delay_count-- > 0); + + if (status != ATCA_SUCCESS) + { + break; + } + + // Check response size + if (rxsize < 4) + { + if (rxsize > 0) + { + status = ATCA_RX_FAIL; + } + else + { + status = ATCA_RX_NO_RESPONSE; + } + break; + } + + if ((status = atCheckCrc(packet->data)) != ATCA_SUCCESS) + { + break; + } + + if ((status = isATCAError(packet->data)) != ATCA_SUCCESS) + { + break; + } + } + while (0); + + // Skip Idle for ECC204 device + if (ECC204 != device->mIface.mIfaceCFG->devtype) + { + (void)calib_idle(device); + device->device_state = ATCA_DEVICE_STATE_IDLE; + } + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_execution.h b/drivers/ecc108a/cryptoauthlib/calib/calib_execution.h new file mode 100644 index 0000000..df94884 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_execution.h @@ -0,0 +1,78 @@ +/** + * \file + * \brief Defines an execution handler that executes a given command on a + * device and returns the results. + * + * The basic flow is to wake the device, send the command, wait/poll for + * completion, and finally receives the response from the device and does + * basic checks before returning to caller. + * + * This handler supports the ATSHA and ATECC device family. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +#ifndef CALIB_EXECUTION_H +#define CALIB_EXECUTION_H + +#include "atca_status.h" +#include "calib_command.h" +#include "atca_device.h" +#include "atca_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ATCA_UNSUPPORTED_CMD ((uint16_t)0xFFFF) + +#define CALIB_SWI_FLAG_WAKE 0x00 //!< flag preceding a command +#define CALIB_SWI_FLAG_CMD 0x77 //!< flag preceding a command +#define CALIB_SWI_FLAG_TX 0x88 //!< flag requesting a response +#define CALIB_SWI_FLAG_IDLE 0xBB //!< flag requesting to go into Idle mode +#define CALIB_SWI_FLAG_SLEEP 0xCC //!< flag requesting to go into Sleep mode + +#ifdef ATCA_NO_POLL +/** \brief Structure to hold the device execution time and the opcode for the + * corresponding command + */ +typedef struct +{ + uint8_t opcode; + uint16_t execution_time_msec; +}device_execution_time_t; + +ATCA_STATUS calib_get_execution_time(uint8_t opcode, ATCADevice device); +#endif + +#ifndef ATCA_HAL_LEGACY_API +ATCA_STATUS calib_execute_receive(ATCADevice device, uint8_t device_address, uint8_t* rxdata, uint16_t* rxlength); +#endif + +ATCA_STATUS calib_execute_command(ATCAPacket* packet, ATCADevice device); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_gendig.c b/drivers/ecc108a/cryptoauthlib/calib/calib_gendig.c new file mode 100644 index 0000000..ec00966 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_gendig.c @@ -0,0 +1,92 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for GenDig command. + * + * The GenDig command uses SHA-256 to combine a stored value with the contents + * of TempKey, which must have been valid prior to the execution of this + * command. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, and ATECC608A/B. There are differences in the modes that + * they support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Issues a GenDig command, which performs a SHA256 hash on the source data indicated by zone with the + * contents of TempKey. See the CryptoAuth datasheet for your chip to see what the values of zone + * correspond to. + * \param[in] device Device context pointer + * \param[in] zone Designates the source of the data to hash with TempKey. + * \param[in] key_id Indicates the key, OTP block, or message order for shared nonce mode. + * \param[in] other_data Four bytes of data for SHA calculation when using a NoMac key, 32 bytes for + * "Shared Nonce" mode, otherwise ignored (can be NULL). + * \param[in] other_data_size Size of other_data in bytes. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_gendig(ATCADevice device, uint8_t zone, uint16_t key_id, const uint8_t *other_data, uint8_t other_data_size) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + bool is_no_mac_key = false; + + if ((device == NULL) || (other_data_size > 0 && other_data == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + // build gendig command + packet.param1 = zone; + packet.param2 = key_id; + + if (packet.param1 == GENDIG_ZONE_SHARED_NONCE && other_data_size >= ATCA_BLOCK_SIZE) + { + memcpy(&packet.data[0], &other_data[0], ATCA_BLOCK_SIZE); + } + else if (packet.param1 == GENDIG_ZONE_DATA && other_data_size >= ATCA_WORD_SIZE) + { + memcpy(&packet.data[0], &other_data[0], ATCA_WORD_SIZE); + is_no_mac_key = true; + } + + if ((status = atGenDig(atcab_get_device_type_ext(device), &packet, is_no_mac_key)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atGenDig - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_gendig - execution failed"); + break; + } + + } + while (0); + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_genkey.c b/drivers/ecc108a/cryptoauthlib/calib/calib_genkey.c new file mode 100644 index 0000000..539f4b6 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_genkey.c @@ -0,0 +1,199 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for GenKey command. + * + * The GenKey command is used for creating ECC private keys, generating ECC + * public keys, and for digest calculations involving public keys. + * + * \note List of devices that support this command - ATECC108A, ATECC508A, + * ATECC608A/B. There are differences in the modes that they support. + * Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Issues GenKey command, which can generate a private key, compute a + * public key, nd/or compute a digest of a public key. + * + * \param[in] device Device context pointer + * \param[in] mode Mode determines what operations the GenKey + * command performs. + * \param[in] key_id Slot to perform the GenKey command on. + * \param[in] other_data OtherData for PubKey digest calculation. Can be set + * to NULL otherwise. + * \param[out] public_key If the mode indicates a public key will be + * calculated, it will be returned here. Format will + * be the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_genkey_base(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* other_data, uint8_t* public_key) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + do + { + if (device == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // Build GenKey command + packet.param1 = mode; + packet.param2 = key_id; + if (other_data) + { + memcpy(packet.data, other_data, GENKEY_OTHER_DATA_SIZE); + } + + if ((status = atGenKey(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atGenKey - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_genkey_base - execution failed"); + break; + } + + if (public_key != NULL) + { + if (packet.data[ATCA_COUNT_IDX] == (ATCA_PUB_KEY_SIZE + ATCA_PACKET_OVERHEAD)) + { + memcpy(public_key, &packet.data[ATCA_RSP_DATA_IDX], ATCA_PUB_KEY_SIZE); + } + else + { + status = ATCA_TRACE(ATCA_RX_FAIL, "Received response failure"); + } + } + } + while (0); + + return status; +} + +/** \brief Issues GenKey command, which generates a new random private key in + * slot and returns the public key. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot number where an ECC private key is configured. + * Can also be ATCA_TEMPKEY_KEYID to generate a private + * key in TempKey. + * \param[out] public_key Public key will be returned here. Format will be + * the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_genkey(ATCADevice device, uint16_t key_id, uint8_t *public_key) +{ + return calib_genkey_base(device, GENKEY_MODE_PRIVATE, key_id, NULL, public_key); +} + +/** \brief Uses GenKey command to calculate the public key from an existing + * private key in a slot. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot number of the private key. + * \param[out] public_key Public key will be returned here. Format will be + * the X and Y integers in big-endian format. + * 64 bytes for P256 curve. Set to NULL if public key + * isn't required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_get_pubkey(ATCADevice device, uint16_t key_id, uint8_t *public_key) +{ + return calib_genkey_base(device, GENKEY_MODE_PUBLIC, key_id, NULL, public_key); +} + +/** \brief Uses Genkey command to calculate SHA256 digest MAC of combining public key + * and session key + * + * \param[in] device Device Context pointer + * \param[out] public_key Public key will be returned here. Format will be + * the X and Y integers in big-endian format. + * 64 bytes for P256 curve. + * \param[out] mac Combine public key referenced by keyID with current value + * of session key, calculate a SHA256 digest and return that MAC here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_genkey_mac(ATCADevice device, uint8_t* public_key, uint8_t* mac) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_BAD_PARAM; + + if (device) + { + packet.param1 = GENKEY_MODE_MAC; + packet.param2 = (uint16_t)0x00; + + status = atGenKey(atcab_get_device_type_ext(device), &packet); + if (ATCA_SUCCESS == status) + { + status = atca_execute_command(&packet, device); + } + + if (ATCA_SUCCESS == status) + { + if ((ATCA_PUB_KEY_SIZE + ATCA_PACKET_OVERHEAD + MAC_SIZE) == packet.data[ATCA_COUNT_IDX]) + { + if (public_key) + { + memcpy(public_key, &packet.data[ATCA_RSP_DATA_IDX], ATCA_PUB_KEY_SIZE); + } + if (mac) + { + memcpy(mac, &packet.data[ATCA_RSP_DATA_IDX + ATCA_PUB_KEY_SIZE], MAC_SIZE); + } + } + else + { + status = ATCA_TRACE(ATCA_RX_FAIL, "Received response failure"); + } + + } + else + { + ATCA_TRACE(status, "calib_genkey_mac - failed"); + } + + } + else + { + ATCA_TRACE(status, "NULL pointer encountered"); + } + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_helpers.c b/drivers/ecc108a/cryptoauthlib/calib/calib_helpers.c new file mode 100644 index 0000000..96e0b6e --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_helpers.c @@ -0,0 +1,264 @@ +/** + * \file + * \brief CryptoAuthLib Basic API - Helper Functions to + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Executes Read command, which reads the configuration zone to see if + * the specified slot is locked. + * + * \param[in] device Device context pointer + * \param[in] slot Slot to query for locked (slot 0-15) + * \param[out] is_locked Lock state returned here. True if locked. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_is_slot_locked(ATCADevice device, uint16_t slot, bool* is_locked) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t data[ATCA_WORD_SIZE]; + uint16_t slot_locked; + + do + { + if ((slot > 15) || (is_locked == NULL)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Either Invalid slot or NULL pointer received"); + break; + } + + // Read the word with the lock bytes ( SlotLock[2], RFU[2] ) (config block = 2, word offset = 6) + if ((status = calib_read_zone(device, ATCA_ZONE_CONFIG, 0, 2 /*block*/, 6 /*offset*/, data, ATCA_WORD_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + + slot_locked = ((uint16_t)data[0]) | ((uint16_t)data[1] << 8); + *is_locked = ((slot_locked & (1 << slot)) == 0); + } + while (0); + + return status; +} + +/** \brief Executes Read command, which reads the configuration zone to see if + * the specified zone is locked. + * + * \param[in] device Device context pointer + * \param[in] zone The zone to query for locked (use LOCK_ZONE_CONFIG or + * LOCK_ZONE_DATA). + * \param[out] is_locked Lock state returned here. True if locked. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_is_locked(ATCADevice device, uint8_t zone, bool* is_locked) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t data[ATCA_WORD_SIZE]; + + do + { + if (is_locked == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // Read the word with the lock bytes (UserExtra, Selector, LockValue, LockConfig) (config block = 2, word offset = 5) + if ((status = calib_read_zone(device, ATCA_ZONE_CONFIG, 0, 2 /*block*/, 5 /*offset*/, data, ATCA_WORD_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + + // Determine the index into the word_data based on the zone we are querying for + switch (zone) + { + case LOCK_ZONE_CONFIG: *is_locked = (data[3] != 0x55); break; + case LOCK_ZONE_DATA: *is_locked = (data[2] != 0x55); break; + default: status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); break; + } + } + while (0); + + return status; +} + + +#ifdef ATCA_ECC204_SUPPORT +/** \brief Use Info command to check ECC204 Config zone lock status + * + * \param[in] device Device context pointer + * \param[out] is_locked return lock status + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_is_config_locked(ATCADevice device, bool* is_locked) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint16_t param2; + uint8_t slot = 0; + + if (NULL == is_locked) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + while (slot <= 3) + { + param2 = ATCA_ECC204_ZONE_CONFIG | (slot << 1); + if (ATCA_SUCCESS != (status = calib_info_lock_status(device, param2, (uint8_t*)is_locked))) + { + *is_locked = false; + break; + } + + if (*is_locked) + { + slot += 1; // increment slot + } + else + { + break; + } + } + + return status; +} + +/** \brief Use Info command to check ECC204 Data zone lock status + * + * \param[in] device Device context pointer + * \param[out] is_locked return lock status + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_is_data_locked(ATCADevice device, bool* is_locked) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint16_t param2; + uint8_t slot = 0; + + if (NULL == is_locked) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + while (slot <= 3) + { + param2 = ATCA_ECC204_ZONE_DATA | (slot << 1); + if (ATCA_SUCCESS != (status = calib_info_lock_status(device, param2, (uint8_t*)is_locked))) + { + *is_locked = false; + break; + } + + if (*is_locked) + { + slot += 1; // increment slot + } + else + { + break; + } + } + + return status; +} + +/** \brief Use Info command to check config/data is locked or not + * + * \param[in] device Device contect pointer + * \param[in] zone Config/Data zone + * \param[out] is_locked return lock status here + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_is_locked(ATCADevice device, uint8_t zone, bool* is_locked) +{ + ATCA_STATUS status = ATCA_SUCCESS; + + if (ATCA_ZONE_CONFIG == zone) + { + status = calib_ecc204_is_config_locked(device, is_locked); + } + else if (ATCA_ZONE_DATA == zone) + { + status = calib_ecc204_is_data_locked(device, is_locked); + } + else + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); + } + + return status; +} + +#endif + + +/** \brief Check if a slot is a private key + * + * \param[in] device Device context pointer + * \param[in] slot Slot to query (slot 0-15) + * \param[out] is_private return true if private + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_is_private(ATCADevice device, uint16_t slot, bool* is_private) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + ATCADeviceType dev_type = atcab_get_device_type_ext(device); + + if (device && is_private) + { + switch (dev_type) + { + case ATECC108A: + /* fallthrough */ + case ATECC508A: + /* fallthrough */ + case ATECC608: + { + uint8_t key_config[2] = { 0 }; + if (ATCA_SUCCESS == (status = calib_read_bytes_zone(device, ATCA_ZONE_CONFIG, 0, ATCA_KEY_CONFIG_OFFSET((size_t)slot), key_config, sizeof(key_config)))) + { + *is_private = (key_config[0] & ATCA_KEY_CONFIG_PRIVATE_MASK); + } + break; + } +#ifdef ATCA_ECC204_SUPPORT + case ECC204: + break; +#endif + default: + *is_private = false; + break; + } + } + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_info.c b/drivers/ecc108a/cryptoauthlib/calib/calib_info.c new file mode 100644 index 0000000..7f4a287 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_info.c @@ -0,0 +1,204 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Info command. + * + * Info command returns a variety of static and dynamic information about the + * device and its state. Also is used to control the GPIO pin and the persistent + * latch. + * + * \note The ATSHA204A refers to this command as DevRev instead of Info, + * however, the OpCode and operation is the same. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A & ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Issues an Info command, which return internal device information and + * can control GPIO and the persistent latch. + * + * \param[in] device Device context pointer + * \param[in] mode Selects which mode to be used for info command. + * \param[in] param2 Selects the particular fields for the mode. + * \param[out] out_data Response from info command (4 bytes). Can be set to + * NULL if not required. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_info_base(ATCADevice device, uint8_t mode, uint16_t param2, uint8_t* out_data) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + if (device == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + // build an info command + packet.param1 = mode; + packet.param2 = param2; + + do + { + if ((status = atInfo(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atInfo - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + // For ECC204, Lock status and Key valid modes return their status in first byte. + // So, need to consider 01 as valid response as it presents lock/keyvalid status. + if (((INFO_MODE_LOCK_STATUS == mode) || (INFO_MODE_KEY_VALID == mode)) + && (ECC204 == device->mIface.mIfaceCFG->devtype)) + { + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + { + status = ATCA_SUCCESS; + } + } + else + { + ATCA_TRACE(status, "calib_info_base - execution failed"); + break; + } + } + + uint8_t response = packet.data[ATCA_COUNT_IDX]; + + if (response && out_data) + { + if (((INFO_MODE_LOCK_STATUS == mode) || (INFO_MODE_KEY_VALID == mode)) + && (ECC204 == device->mIface.mIfaceCFG->devtype)) + { + memcpy(out_data, &packet.data[ATCA_RSP_DATA_IDX], 1); + } + else if (response >= 7) + { + memcpy(out_data, &packet.data[ATCA_RSP_DATA_IDX], 4); + } + else + { + // do nothing + } + + } + } + while (0); + + return status; +} + +/** \brief Use the Info command to get the device revision (DevRev). + * \param[in] device Device context pointer + * \param[out] revision Device revision is returned here (4 bytes). + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_info(ATCADevice device, uint8_t* revision) +{ + if (revision == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + return calib_info_base(device, INFO_MODE_REVISION, 0, revision); +} + +/** \brief Use the Info command to get the persistent latch current state for + * an ATECC608 device. + * + * \param[in] device Device context pointer + * \param[out] state The state is returned here. Set (true) or Cler (false). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ + +ATCA_STATUS calib_info_get_latch(ATCADevice device, bool* state) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t out_data[4]; + + if (state == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + if (ATCA_SUCCESS != (status = calib_info_base(device, INFO_MODE_VOL_KEY_PERMIT, 0, out_data))) + { + return ATCA_TRACE(status, "calib_info_base - failed"); + } + + *state = (out_data[0] == 1); + + return status; +} + +/** \brief Use the Info command to set the persistent latch state for an + * ATECC608 device. + * + * \param[in] device Device context pointer + * \param[out] state Persistent latch state. Set (true) or clear (false). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_info_set_latch(ATCADevice device, bool state) +{ + uint16_t param2 = INFO_PARAM2_SET_LATCH_STATE; + + param2 |= state ? INFO_PARAM2_LATCH_SET : INFO_PARAM2_LATCH_CLEAR; + return calib_info_base(device, INFO_MODE_VOL_KEY_PERMIT, param2, NULL); +} + +/** \brief Use Info command to check ECC Private key stored in key slot is valid or not + * + * \param[in] device Device context pointer + * \param[in] key_id ECC private key slot id + * For ECC204, key_id is 0x00 + * \param[out] is_valid return private key is valid or invalid + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_info_privkey_valid(ATCADevice device, uint16_t key_id, uint8_t* is_valid) +{ + return calib_info_base(device, INFO_MODE_KEY_VALID, key_id, is_valid); +} + +#ifdef ATCA_ECC204_SUPPORT +/** \brief Use Info command to ECC204 config/data zone lock status + * + * \param[in] device Device context pointer + * \param[in] param2 selects the zone and slot + * \param[out] is_locked return lock status here + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_info_lock_status(ATCADevice device, uint16_t param2, uint8_t* is_locked) +{ + return calib_info_base(device, INFO_MODE_LOCK_STATUS, param2, is_locked); +} +#endif diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_lock.c b/drivers/ecc108a/cryptoauthlib/calib/calib_lock.c new file mode 100644 index 0000000..f7fee5f --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_lock.c @@ -0,0 +1,258 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Lock command. + * + * The Lock command prevents future modifications of the Configuration zone, + * enables configured policies for Data and OTP zones, and can render + * individual slots read-only regardless of configuration. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief The Lock command prevents future modifications of the Configuration + * and/or Data and OTP zones. If the device is so configured, then + * this command can be used to lock individual data slots. This + * command fails if the designated area is already locked. + * + * \param[in] device Device context pointer + * \param[in] mode Zone, and/or slot, and summary check (bit 7). + * \param[in] summary_crc CRC of the config or data zones. Ignored for + * slot locks or when mode bit 7 is set. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_lock(ATCADevice device, uint8_t mode, uint16_t summary_crc) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + if (device == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + // build command for lock zone and send + memset(&packet, 0, sizeof(packet)); + packet.param1 = mode; + packet.param2 = summary_crc; + + do + { + if ((status = atLock(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atLock - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_lock - execution failed"); + break; + } + + } + while (0); + + return status; +} + +/** \brief Unconditionally (no CRC required) lock the config zone. + * + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_lock_config_zone(ATCADevice device) +{ + return calib_lock(device, LOCK_ZONE_NO_CRC | LOCK_ZONE_CONFIG, 0); +} + +/** \brief Lock the config zone with summary CRC. + * + * The CRC is calculated over the entire config zone contents. 88 bytes for + * ATSHA devices, 128 bytes for ATECC devices. Lock will fail if the provided + * CRC doesn't match the internally calculated one. + * + * \param[in] device Device context pointer + * \param[in] summary_crc Expected CRC over the config zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_lock_config_zone_crc(ATCADevice device, uint16_t summary_crc) +{ + return calib_lock(device, LOCK_ZONE_CONFIG, summary_crc); +} + +/** \brief Unconditionally (no CRC required) lock the data zone (slots and OTP). + * + * ConfigZone must be locked and DataZone must be unlocked for the zone to be successfully locked. + * + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_lock_data_zone(ATCADevice device) +{ + return calib_lock(device, LOCK_ZONE_NO_CRC | LOCK_ZONE_DATA, 0); +} + +/** \brief Lock the data zone (slots and OTP) with summary CRC. + * + * The CRC is calculated over the concatenated contents of all the slots and + * OTP at the end. Private keys (KeyConfig.Private=1) are skipped. Lock will + * fail if the provided CRC doesn't match the internally calculated one. + * + * \param[in] device Device context pointer + * \param[in] summary_crc Expected CRC over the data zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_lock_data_zone_crc(ATCADevice device, uint16_t summary_crc) +{ + return calib_lock(device, LOCK_ZONE_DATA, summary_crc); +} + +/** \brief Lock an individual slot in the data zone on an ATECC device. Not + * available for ATSHA devices. Slot must be configured to be slot + * lockable (KeyConfig.Lockable=1). + * + * \param[in] device Device context pointer + * \param[in] slot Slot to be locked in data zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_lock_data_slot(ATCADevice device, uint16_t slot) +{ + return calib_lock(device, ((uint8_t)slot << 2) | LOCK_ZONE_DATA_SLOT, 0); +} + +/** \brief Use Lock command to lock individual configuration zone slots + * + * \param[in] device Device context pointer + * \param[in] slot The slot number to be locked + * \param[in] summary_crc CRC calculated over all 16 bytes within the selected + * slot of the configuration zone. + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_lock_config_slot(ATCADevice device, uint16_t slot, uint16_t summary_crc) +{ + uint8_t mode = (uint8_t)(LOCK_ECC204_ZONE_CONFIG | (slot << 1)); + + if (!summary_crc) + { + mode |= LOCK_ZONE_NO_CRC; + } + + return calib_lock(device, mode, summary_crc); +} + +/** \brief Use lock command to lock complete configuration zone + * + * \param[in] device Device context pointer + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_lock_config_zone(ATCADevice device) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t slot = 0; + uint8_t mode; + + while (slot <= 3) + { + mode = (uint8_t)(LOCK_ZONE_NO_CRC | LOCK_ECC204_ZONE_CONFIG | (slot << 1)); + + if (ATCA_SUCCESS != (status = calib_lock(device, mode, 0))) + { + // ECC204 returns execution error if slot is already locked. + // Consider already locked status as valid while locking the config zone. + if (status == ATCA_EXECUTION_ERROR) + { + status = ATCA_SUCCESS; + } + else + { + ATCA_TRACE(status, "calib_ecc204_lock_config_zone - failed"); + break; + } + } + + slot += 1; //Increment slot + } + + return status; +} + +/** \brief Use lock command to lock data zone slot + * + * \param[in] device Device context pointer + * \param[in] slot The slot number to be locked + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_lock_data_slot(ATCADevice device, uint16_t slot) +{ + return calib_lock(device, (uint8_t)(LOCK_ECC204_ZONE_DATA | (slot << 1)), 0); +} + +/** \brief Use lock command to lock complete Data zone + * + * \param[in] device Device context pointer + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_lock_data_zone(ATCADevice device) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t slot = 0; + uint8_t mode; + + while (slot <= 3) + { + mode = LOCK_ZONE_NO_CRC | LOCK_ECC204_ZONE_DATA | (slot << 1); + + if (ATCA_SUCCESS != (status = calib_lock(device, mode, 0))) + { + // ECC204 returns execution error if slot is already locked. + // Consider already locked status as valid while locking the config zone. + if (status == ATCA_EXECUTION_ERROR) + { + status = ATCA_SUCCESS; + } + else + { + ATCA_TRACE(status, "calib_ecc204_lock_data_zone - failed"); + break; + } + } + + slot += 1; //Increment slot + } + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_privwrite.c b/drivers/ecc108a/cryptoauthlib/calib/calib_privwrite.c new file mode 100644 index 0000000..f17c8c4 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_privwrite.c @@ -0,0 +1,193 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for PrivWrite command. + * + * The PrivWrite command is used to write externally generated ECC private keys + * into the device. + * + * \note List of devices that support this command - ATECC108A, ATECC508A, and + * ATECC608A/B. There are differences in the modes that they support. Refer + * to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" +#include "host/atca_host.h" + +/** \brief Executes PrivWrite command, to write externally generated ECC + * private keys into the device. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot to write the external private key into. + * \param[in] priv_key External private key (36 bytes) to be written. + * The first 4 bytes should be zero for P256 curve. + * \param[in] write_key_id Write key slot. Ignored if write_key is NULL. + * \param[in] write_key Write key (32 bytes). If NULL, perform an + * unencrypted PrivWrite, which is only available when + * the data zone is unlocked. + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +// FIXME do we want this function? +#ifndef ATCA_TIDAL +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_priv_write(ATCADevice device, uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32]) +{ + uint8_t num_in[NONCE_NUMIN_SIZE] = { 0 }; + +#else +ATCA_STATUS calib_priv_write(ATCADevice device, uint16_t key_id, const uint8_t priv_key[36], uint16_t write_key_id, const uint8_t write_key[32], const uint8_t num_in[NONCE_NUMIN_SIZE]) +{ +#endif + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + atca_nonce_in_out_t nonce_params; + atca_gen_dig_in_out_t gen_dig_param; + atca_write_mac_in_out_t host_mac_param; + atca_temp_key_t temp_key; + uint8_t serial_num[32]; // Buffer is larger than the 9 bytes required to make reads easier + uint8_t rand_out[RANDOM_NUM_SIZE] = { 0 }; + uint8_t cipher_text[36] = { 0 }; + uint8_t host_mac[MAC_SIZE] = { 0 }; + uint8_t other_data[4] = { 0 }; + + if ((device == NULL) || (priv_key == NULL) || (key_id > 15)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Either NULL pointer or invalid slot received"); + } + + do + { + if (write_key == NULL) + { + // Caller requested an unencrypted PrivWrite, which is only allowed when the data zone is unlocked + // build an PrivWrite command + packet.param1 = 0x00; // Mode is unencrypted write + packet.param2 = key_id; // Key ID + memcpy(&packet.data[0], priv_key, 36); // Private key + memset(&packet.data[36], 0, 32); // MAC (ignored for unencrypted write) + } + else + { + // Read the device SN + if ((status = calib_read_zone(device, ATCA_ZONE_CONFIG, 0, 0, 0, serial_num, 32)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + // Make the SN continuous by moving SN[4:8] right after SN[0:3] + memmove(&serial_num[4], &serial_num[8], 5); + + // Send the random Nonce command + if ((status = calib_nonce_rand(device, num_in, rand_out)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_nonce_rand - failed"); + break; + } + + // Calculate Tempkey + memset(&temp_key, 0, sizeof(temp_key)); + memset(&nonce_params, 0, sizeof(nonce_params)); + nonce_params.mode = NONCE_MODE_SEED_UPDATE; + nonce_params.zero = 0; + nonce_params.num_in = &num_in[0]; + nonce_params.rand_out = rand_out; + nonce_params.temp_key = &temp_key; + if ((status = atcah_nonce(&nonce_params)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atcah_nonce - failed"); + break; + } + + // Supply OtherData so GenDig behavior is the same for keys with SlotConfig.NoMac set + other_data[0] = ATCA_GENDIG; + other_data[1] = GENDIG_ZONE_DATA; + other_data[2] = (uint8_t)(write_key_id); + other_data[3] = (uint8_t)(write_key_id >> 8); + + // Send the GenDig command + if ((status = calib_gendig(device, GENDIG_ZONE_DATA, write_key_id, other_data, sizeof(other_data))) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_gendig - failed"); + break; + } + + // Calculate Tempkey + // NoMac bit isn't being considered here on purpose to remove having to read SlotConfig. + // OtherData is built to get the same result regardless of the NoMac bit. + memset(&gen_dig_param, 0, sizeof(gen_dig_param)); + gen_dig_param.zone = GENDIG_ZONE_DATA; + gen_dig_param.sn = serial_num; + gen_dig_param.key_id = write_key_id; + gen_dig_param.is_key_nomac = false; + gen_dig_param.stored_value = write_key; + gen_dig_param.other_data = other_data; + gen_dig_param.temp_key = &temp_key; + if ((status = atcah_gen_dig(&gen_dig_param)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atcah_gen_dig - failed"); + break; + } + + // Calculate Auth MAC and cipher text + memset(&host_mac_param, 0, sizeof(host_mac_param)); + host_mac_param.zone = PRIVWRITE_MODE_ENCRYPT; + host_mac_param.key_id = key_id; + host_mac_param.sn = serial_num; + host_mac_param.input_data = &priv_key[0]; + host_mac_param.encrypted_data = cipher_text; + host_mac_param.auth_mac = host_mac; + host_mac_param.temp_key = &temp_key; + if ((status = atcah_privwrite_auth_mac(&host_mac_param)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atcah_privwrite_auth_mac - failed"); + break; + } + + // build a write command for encrypted writes + packet.param1 = PRIVWRITE_MODE_ENCRYPT; // Mode is encrypted write + packet.param2 = key_id; // Key ID + memcpy(&packet.data[0], cipher_text, sizeof(cipher_text)); + memcpy(&packet.data[sizeof(cipher_text)], host_mac, sizeof(host_mac)); + } + + if ((status = atPrivWrite(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atPrivWrite - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_priv_write - execution failed"); + break; + } + + } + while (0); + + return status; +} +#endif // ifndef ATCA_TIDAL diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_random.c b/drivers/ecc108a/cryptoauthlib/calib/calib_random.c new file mode 100644 index 0000000..90516a1 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_random.c @@ -0,0 +1,88 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Random command. + * + * The Random command generates a random number for use by the system. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Executes Random command, which generates a 32 byte random number + * from the CryptoAuth device. + * + * \param[in] device Device context pointer + * \param[out] rand_out 32 bytes of random data is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_random(ATCADevice device, uint8_t *rand_out) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + do + { + if (device == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // build an random command + packet.param1 = RANDOM_SEED_UPDATE; + packet.param2 = 0x0000; + + if ((status = atRandom(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atRandom - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_random - execution failed"); + break; + } + + if (packet.data[ATCA_COUNT_IDX] != RANDOM_RSP_SIZE) + { + status = ATCA_TRACE(ATCA_RX_FAIL, "Unexpected response size"); + break; + } + + if (rand_out) + { + memcpy(rand_out, &packet.data[ATCA_RSP_DATA_IDX], RANDOM_NUM_SIZE); + } + } + while (0); + + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_read.c b/drivers/ecc108a/cryptoauthlib/calib/calib_read.c new file mode 100644 index 0000000..315a7e7 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_read.c @@ -0,0 +1,923 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Read command. + * + * The Read command reads words either 4-byte words or 32-byte blocks from one + * of the memory zones of the device. The data may optionally be encrypted + * before being returned to the system. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" +#include "host/atca_host.h" + +/** \brief Executes Read command, which reads either 4 or 32 bytes of data from + * a given slot, configuration zone, or the OTP zone. + * + * When reading a slot or OTP, data zone must be locked and the slot + * configuration must not be secret for a slot to be successfully read. + * + * \param[in] device Device context pointer + * \param[in] zone Zone to be read from device. Options are + * ATCA_ZONE_CONFIG, ATCA_ZONE_OTP, or ATCA_ZONE_DATA. + * \param[in] slot Slot number for data zone and ignored for other zones. + * \param[in] block 32 byte block index within the zone. + * \param[in] offset 4 byte work index within the block. Ignored for 32 byte + * reads. + * \param[out] data Read data is returned here. + * \param[in] len Length of the data to be read. Must be either 4 or 32. + * + * returns ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_read_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint8_t *data, uint8_t len) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + uint16_t addr; + + do + { + // Check the input parameters + if ((device == NULL) || (data == NULL)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + if (len != 4 && len != 32) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid length received"); + break; + } + + // The get address function checks the remaining variables + if ((status = calib_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_get_addr - failed"); + break; + } + + // If there are 32 bytes to read, then OR the bit into the mode + if (len == ATCA_BLOCK_SIZE) + { + zone = zone | ATCA_ZONE_READWRITE_32; + } + + // build a read command + packet.param1 = zone; + packet.param2 = addr; + + if ((status = atRead(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atRead - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - execution failed"); + break; + } + + memcpy(data, &packet.data[1], len); + } + while (0); + + return status; +} +/** \brief Executes Read command, which reads the 9 byte serial number of the + * device from the config zone. + * + * \param[in] device Device context pointer + * \param[out] serial_number 9 byte serial number is returned here. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_read_serial_number(ATCADevice device, uint8_t* serial_number) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t read_buf[ATCA_BLOCK_SIZE]; + + if (!serial_number) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + if ((status = calib_read_zone(device, ATCA_ZONE_CONFIG, 0, 0, 0, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + memcpy(&serial_number[0], &read_buf[0], 4); + memcpy(&serial_number[4], &read_buf[8], 5); + } + while (0); + + return status; +} + + +/** \brief Executes Read command on a slot configured for encrypted reads and + * decrypts the data to return it as plaintext. + * + * Data zone must be locked for this command to succeed. Can only read 32 byte + * blocks. + * + * \param[in] device Device context pointer + * \param[in] key_id The slot ID to read from. + * \param[in] block Index of the 32 byte block within the slot to read. + * \param[out] data Decrypted (plaintext) data from the read is returned + * here (32 bytes). + * \param[in] enc_key 32 byte ReadKey for the slot being read. + * \param[in] enc_key_id KeyID of the ReadKey being used. + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * returns ATCA_SUCCESS on success, otherwise an error code. + */ +// FIXME do we want this function? +#ifndef ATCA_TIDAL +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_read_enc(ATCADevice device, uint16_t key_id, uint8_t block, uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id) +{ + uint8_t num_in[NONCE_NUMIN_SIZE] = { 0 }; + +#else +ATCA_STATUS calib_read_enc(ATCADevice device, uint16_t key_id, uint8_t block, uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]) +{ +#endif + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t zone = ATCA_ZONE_DATA | ATCA_ZONE_READWRITE_32; + atca_nonce_in_out_t nonce_params; + atca_gen_dig_in_out_t gen_dig_param; + atca_temp_key_t temp_key; + uint8_t serial_num[32]; + uint8_t rand_out[RANDOM_NUM_SIZE] = { 0 }; + uint8_t other_data[4] = { 0 }; + int i = 0; + + do + { + // Verify inputs parameters + if (data == NULL || enc_key == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // Read the device SN + if ((status = calib_read_zone(device, ATCA_ZONE_CONFIG, 0, 0, 0, serial_num, 32)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + // Make the SN continuous by moving SN[4:8] right after SN[0:3] + memmove(&serial_num[4], &serial_num[8], 5); + + // Send the random Nonce command + if ((status = calib_nonce_rand(device, num_in, rand_out)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Nonce failed"); break; + } + + // Calculate Tempkey + memset(&temp_key, 0, sizeof(temp_key)); + memset(&nonce_params, 0, sizeof(nonce_params)); + nonce_params.mode = NONCE_MODE_SEED_UPDATE; + nonce_params.zero = 0; + nonce_params.num_in = (uint8_t*)&num_in[0]; + nonce_params.rand_out = rand_out; + nonce_params.temp_key = &temp_key; + if ((status = atcah_nonce(&nonce_params)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Calc TempKey failed"); break; + } + + // Supply OtherData so GenDig behavior is the same for keys with SlotConfig.NoMac set + other_data[0] = ATCA_GENDIG; + other_data[1] = GENDIG_ZONE_DATA; + other_data[2] = (uint8_t)(enc_key_id); + other_data[3] = (uint8_t)(enc_key_id >> 8); + + // Send the GenDig command + if ((status = calib_gendig(device, GENDIG_ZONE_DATA, enc_key_id, other_data, sizeof(other_data))) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "GenDig failed"); break; + } + + // Calculate Tempkey + // NoMac bit isn't being considered here on purpose to remove having to read SlotConfig. + // OtherData is built to get the same result regardless of the NoMac bit. + memset(&gen_dig_param, 0, sizeof(gen_dig_param)); + gen_dig_param.key_id = enc_key_id; + gen_dig_param.is_key_nomac = false; + gen_dig_param.sn = serial_num; + gen_dig_param.stored_value = enc_key; + gen_dig_param.zone = GENDIG_ZONE_DATA; + gen_dig_param.other_data = other_data; + gen_dig_param.temp_key = &temp_key; + if ((status = atcah_gen_dig(&gen_dig_param)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, ""); break; + } + + // Read Encrypted + if ((status = calib_read_zone(device, zone, key_id, block, 0, data, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Read encrypted failed"); break; + } + + // Decrypt + for (i = 0; i < ATCA_BLOCK_SIZE; i++) + { + data[i] = data[i] ^ temp_key.value[i]; + } + + status = ATCA_SUCCESS; + + } + while (0); + + + return status; +} +#endif // ifndef ATCA_TIDAL + +/** \brief Executes Read command to read the complete device configuration + * zone. + * + * \param[in] device Device context pointer + * \param[out] config_data Configuration zone data is returned here. 88 bytes + * for ATSHA devices, 128 bytes for ATECC devices. + * + * \returns ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_read_config_zone(ATCADevice device, uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + do + { + // Verify the inputs + if (config_data == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + if (atIsSHAFamily(device->mIface.mIfaceCFG->devtype)) + { + status = calib_read_bytes_zone(device, ATCA_ZONE_CONFIG, 0, 0x00, config_data, ATCA_SHA_CONFIG_SIZE); + } + else + { + status = calib_read_bytes_zone(device, ATCA_ZONE_CONFIG, 0, 0x00, config_data, ATCA_ECC_CONFIG_SIZE); + } + + if (status != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_bytes_zone - failed"); + break; + } + + } + while (0); + + return status; +} + +/** \brief Compares a specified configuration zone with the configuration zone + * currently on the device. + * + * This only compares the static portions of the configuration zone and skips + * those that are unique per device (first 16 bytes) and areas that can change + * after the configuration zone has been locked (e.g. LastKeyUse). + * + * \param[in] device Device context pointer + * \param[in] config_data Full configuration data to compare the device + * against. + * \param[out] same_config Result is returned here. True if the static portions + * on the configuration zones are the same. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_cmp_config_zone(ATCADevice device, uint8_t* config_data, bool* same_config) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t device_config_data[ATCA_ECC_CONFIG_SIZE]; /** Max for all configs */ + size_t config_size = 0; + + do + { + // Check the inputs + if ((config_data == NULL) || (same_config == NULL)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + // Set the boolean to false + *same_config = false; + + // Read all of the configuration bytes from the device + if ((status = calib_read_config_zone(device, device_config_data)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Read config zone failed"); break; + } + + /* Get the config size of the device being tested */ + if (ATCA_SUCCESS != (status = calib_get_zone_size(device, ATCA_ZONE_CONFIG, 0, &config_size))) + { + ATCA_TRACE(status, "Failed to get config zone size"); break; + } + + /* Compare the lower writable bytes (16-51) */ + if (memcmp(&device_config_data[16], &config_data[16], 52 - 16)) + { + /* Difference found */ + break; + } + + if (ATECC608 == device->mIface.mIfaceCFG->devtype) + { + /* Skip Counter[0], Counter[1], which can change during operation */ + + /* Compare UseLock through Reserved (68 --> 83) */ + if (memcmp(&device_config_data[68], &config_data[68], 84 - 68)) + { + /* Difference found */ + break; + } + + /* Skip UserExtra, UserExtraAdd, LockValue, LockConfig, and SlotLocked */ + + } + else + { + /* Skip the counter & LastKeyUse bytes [52-83] */ + /* Skip User Extra & Selector [84-85] */ + /* Skip all lock bytes [86-89] */ + } + + if (90 < config_size) + { + /* Compare the upper writable bytes (90-config_size) */ + if (memcmp(&device_config_data[90], &config_data[90], config_size - 90)) + { + /* Difference found */ + break; + } + } + + /* All Matched */ + *same_config = true; + } + while (0); + + return status; +} + + +/** \brief Executes Read command to read a 64 byte ECDSA P256 signature from a + * slot configured for clear reads. + * + * \param[in] device Device context pointer + * \param[in] slot Slot number to read from. Only slots 8 to 15 are large + * enough for a signature. + * \param[out] sig Signature will be returned here (64 bytes). Format will be + * the 32 byte R and S big-endian integers concatenated. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_read_sig(ATCADevice device, uint16_t slot, uint8_t* sig) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + do + { + // Check the value of the slot + if (sig == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + if (slot < 8 || slot > 15) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot received"); + break; + } + + // Read the first block + if ((status = calib_read_zone(device, ATCA_ZONE_DATA, slot, 0, 0, &sig[0], ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + + // Read the second block + if ((status = calib_read_zone(device, ATCA_ZONE_DATA, slot, 1, 0, &sig[ATCA_BLOCK_SIZE], ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + } + while (0); + + return status; +} + +/** \brief Executes Read command to read an ECC P256 public key from a slot + * configured for clear reads. + * + * This function assumes the public key is stored using the ECC public key + * format specified in the datasheet. + * + * \param[in] device Device context pointer + * \param[in] slot Slot number to read from. Only slots 8 to 15 are + * large enough for a public key. + * \param[out] public_key Public key is returned here (64 bytes). Format will + * be the 32 byte X and Y big-endian integers + * concatenated. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_read_pubkey(ATCADevice device, uint16_t slot, uint8_t *public_key) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t read_buf[ATCA_BLOCK_SIZE]; + uint8_t block = 0; + uint8_t offset = 0; + uint8_t cpy_index = 0; + uint8_t cpy_size = 0; + uint8_t read_index = 0; + + // Check the pointers + if (public_key == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + // Check the value of the slot + if (slot < 8 || slot > 0xF) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot received"); + } + + do + { + // The 64 byte P256 public key gets written to a 72 byte slot in the following pattern + // | Block 1 | Block 2 | Block 3 | + // | Pad: 4 Bytes | PubKey[0:27] | PubKey[28:31] | Pad: 4 Bytes | PubKey[32:55] | PubKey[56:63] | + + // Read the block + block = 0; + if ((status = calib_read_zone(device, ATCA_ZONE_DATA, slot, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + + // Copy. Account for 4 byte pad + cpy_size = ATCA_BLOCK_SIZE - ATCA_PUB_KEY_PAD; + read_index = ATCA_PUB_KEY_PAD; + memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size); + cpy_index += cpy_size; + + // Read the next block + block = 1; + if ((status = calib_read_zone(device, ATCA_ZONE_DATA, slot, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + + // Copy. First four bytes + cpy_size = ATCA_PUB_KEY_PAD; + read_index = 0; + memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size); + cpy_index += cpy_size; + // Copy. Skip four bytes + read_index = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD; + cpy_size = ATCA_BLOCK_SIZE - read_index; + memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size); + cpy_index += cpy_size; + + // Read the next block + block = 2; + if ((status = calib_read_zone(device, ATCA_ZONE_DATA, slot, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + + // Copy. The remaining 8 bytes + cpy_size = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD; + read_index = 0; + memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size); + + } + while (0); + + return status; +} + +/** \brief Used to read an arbitrary number of bytes from any zone configured + * for clear reads. + * + * This function will issue the Read command as many times as is required to + * read the requested data. + * + * \param[in] device Device context pointer + * \param[in] zone Zone to read data from. Option are ATCA_ZONE_CONFIG(0), + * ATCA_ZONE_OTP(1), or ATCA_ZONE_DATA(2). + * \param[in] slot Slot number to read from if zone is ATCA_ZONE_DATA(2). + * Ignored for all other zones. + * \param[in] offset Byte offset within the zone to read from. + * \param[out] data Read data is returned here. + * \param[in] length Number of bytes to read starting from the offset. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_read_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, size_t offset, uint8_t *data, size_t length) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + size_t zone_size = 0; + uint8_t read_buf[32]; + size_t data_idx = 0; + size_t cur_block = 0; + size_t cur_offset = 0; + uint8_t read_size = ATCA_BLOCK_SIZE; + size_t read_buf_idx = 0; + size_t copy_length = 0; + size_t read_offset = 0; + + if (zone != ATCA_ZONE_CONFIG && zone != ATCA_ZONE_OTP && zone != ATCA_ZONE_DATA) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); + } + if (zone == ATCA_ZONE_DATA && slot > 15) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot received"); + } + if (length == 0) + { + return ATCA_SUCCESS; // Always succeed reading 0 bytes + } + if (data == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + if (ATCA_SUCCESS != (status = calib_get_zone_size(device, zone, slot, &zone_size))) + { + ATCA_TRACE(status, "calib_get_zone_size - failed"); + break; + } + if (offset + length > zone_size) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); // Can't read past the end of a zone + + } + cur_block = offset / ATCA_BLOCK_SIZE; + + while (data_idx < length) + { + if (read_size == ATCA_BLOCK_SIZE && zone_size - cur_block * ATCA_BLOCK_SIZE < ATCA_BLOCK_SIZE) + { + // We have less than a block to read and can't read past the end of the zone, switch to word reads + read_size = ATCA_WORD_SIZE; + cur_offset = ((data_idx + offset) / ATCA_WORD_SIZE) % (ATCA_BLOCK_SIZE / ATCA_WORD_SIZE); + } + + // Read next chunk of data + if (ATCA_SUCCESS != (status = calib_read_zone(device, zone, slot, (uint8_t)cur_block, (uint8_t)cur_offset, read_buf, read_size))) + { + ATCA_TRACE(status, "calib_read_zone - falied"); + break; + } + + // Calculate where in the read buffer we need data from + read_offset = cur_block * ATCA_BLOCK_SIZE + cur_offset * ATCA_WORD_SIZE; + if (read_offset < offset) + { + read_buf_idx = offset - read_offset; // Read data starts before the requested chunk + } + else + { + read_buf_idx = 0; // Read data is within the requested chunk + + } + // Calculate how much data from the read buffer we want to copy + if (length - data_idx < read_size - read_buf_idx) + { + copy_length = length - data_idx; + } + else + { + copy_length = read_size - read_buf_idx; + } + + memcpy(&data[data_idx], &read_buf[read_buf_idx], copy_length); + data_idx += copy_length; + if (read_size == ATCA_BLOCK_SIZE) + { + cur_block += 1; + } + else + { + cur_offset += 1; + } + } + if (status != ATCA_SUCCESS) + { + break; + } + } + while (false); + + return status; +} + +#if defined(ATCA_ECC204_SUPPORT) +/** \brief Use Read command to reads words 16 bytes from one of the slots in the EEPROM Configuration + * zone or 32 bytes in Data zone. + * + * \param[in] device Device context pointer + * \param[in] zone Selects config or data zone + * \param[in] slot select slot in config or data zone + * \param[in] block select the lock in given slot + * \param[in] offset 16 byte work index within the block. Ignored for 32 byte + * reads. + * \param[out] data Read data is returned here. + * \param[in] len Length of the data to be read. Must be either 16 or 32. + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_read_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, size_t offset, + uint8_t* data, uint8_t len) +{ + ATCA_STATUS status = ATCA_SUCCESS; + ATCAPacket packet; + uint16_t addr; + uint8_t read_zone; + + (void)offset; + + read_zone = (zone == ATCA_ZONE_CONFIG) ? ATCA_ECC204_ZONE_CONFIG : ATCA_ECC204_ZONE_DATA; + + + if ((NULL == device) || (NULL == data)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Encountered Null pointer"); + } + else if (ATCA_ZONE_DATA == zone) + { + if (32 != len) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); + } + else if ((0x00 == slot) || (0x03 == slot)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot number received"); + } + else + { + read_zone = ATCA_ECC204_ZONE_DATA; + } + } + else if (ATCA_ECC204_ZONE_CONFIG == zone) + { + if (16 != len) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); + } + else + { + read_zone = ATCA_ECC204_ZONE_CONFIG; + } + } + + if (ATCA_SUCCESS == status) + { + if (ATCA_SUCCESS != (status = calib_ecc204_get_addr(read_zone, slot, block, 0, &addr))) + { + ATCA_TRACE(status, "Address Encoding failed"); + } + + if (ATCA_SUCCESS == status) + { + // Build packets + packet.param1 = read_zone; + packet.param2 = addr; + + (void)atRead(atcab_get_device_type_ext(device), &packet); + + // Execute read command + if (ATCA_SUCCESS != (status = atca_execute_command(&packet, device))) + { + ATCA_TRACE(status, "Read command failed"); + } + else + { + memcpy(data, &packet.data[ATCA_RSP_DATA_IDX], len); + } + + } + } + + return status; +} + +/** \brief Use Read command to read configuration zone of ECC204 device + * + * \param[in] device Device context pointer + * \param[out] config_data returns config data of 64 bytes + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_read_config_zone(ATCADevice device, uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t slot = 0; + + while (slot <= 3) + { + if (ATCA_SUCCESS != (status = calib_ecc204_read_zone(device, ATCA_ECC204_ZONE_CONFIG, + slot, 0, 0, + &config_data[ATCA_ECC204_CONFIG_SLOT_SIZE * slot], + ATCA_ECC204_CONFIG_SLOT_SIZE))) + { + ATCA_TRACE(status, "calib_ecc204_read_zone - failed"); + break; + } + slot += 1; // Increment slot to read next slot + } + + return status; +} + +/** \brief Use Read command to read serial number of device + * + * \param[in] device Device context pointer + * \param[in] serial_number 9 bytes ECC204 device serial number return here + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_read_serial_number(ATCADevice device, uint8_t* serial_number) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t read_buf[ATCA_ECC204_CONFIG_SLOT_SIZE]; + + + status = calib_ecc204_read_zone(device, ATCA_ECC204_ZONE_CONFIG, 0, 0, 0, read_buf, + ATCA_ECC204_CONFIG_SLOT_SIZE); + + if (ATCA_SUCCESS == status) + { + memcpy(serial_number, read_buf, ATCA_SERIAL_NUM_SIZE); + } + + return status; +} + +/** \brief Used to read an arbitrary number of bytes from any zone configured + * for clear reads. This function supports only for ECC204 device. + * + * This function will issue the Read command as many times as is required to + * read the requested data. + * + * \param[in] device Device context pointer + * \param[in] zone Zone to read data from. Option are ATCA_ZONE_CONFIG(1), + * or ATCA_ZONE_DATA(0). + * \param[in] slot Slot number to read from + * Ignored for all other zones. + * \param[in] offset Byte offset within the zone to read from. + * \param[out] data Read data is returned here. + * \param[in] length Number of bytes to read starting from the offset. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_ecc204_read_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, + size_t offset, uint8_t* data, size_t length) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t block_size = (zone == ATCA_ECC204_ZONE_CONFIG) ? ATCA_ECC204_CONFIG_SLOT_SIZE : ATCA_BLOCK_SIZE; + uint8_t no_of_blocks; + uint8_t data_idx = 0; + size_t cur_block = 0; + + if ((NULL == device) || (NULL == data)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Encountered NULL pointer"); + } + else if ((ATCA_ECC204_ZONE_DATA == zone) && (((length > 64) && (2 == slot)) || + ((length > 320) && (1 == slot)) || (3 == slot) || (0 == slot))) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); + } + else if (0 == length) + { + return ATCA_SUCCESS; + } + + cur_block = offset / block_size; + no_of_blocks = (uint8_t)(length / block_size); + while (no_of_blocks--) + { + if (ATCA_SUCCESS != (status = calib_ecc204_read_zone(device, zone, slot, cur_block, 0, + &data[block_size * data_idx], + block_size))) + { + ATCA_TRACE(status, "calib_ecc204_read_zone failed"); + break; + } + + if (zone == ATCA_ECC204_ZONE_CONFIG) + { + slot += 1; + } + else + { + cur_block += 1; + } + data_idx += 1; // increment data index + } + + return status; +} + +/** \brief Compares a specified configuration zone with the configuration zone + * currently on the ECC204 device. + * + * This only compares the static portions of the configuration zone and skips + * those that are unique per device (first 16 bytes) and areas that can change + * after the configuration zone has been locked (e.g. Counter). + * + * \param[in] device Device context pointer + * \param[in] config_data Full configuration data to compare the device + * against. + * \param[out] same_config Result is returned here. True if the static portions + * on the configuration zones are the same. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_ecc204_cmp_config_zone(ATCADevice device, uint8_t* config_data, bool* same_config) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t device_config_data[ATCA_ECC204_CONFIG_SIZE]; + + if ((NULL == device) || (NULL == config_data) || (NULL == same_config)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + if (ATCA_SUCCESS == status) + { + *same_config = false; + if (ATCA_SUCCESS != (status = calib_ecc204_read_config_zone(device, device_config_data))) + { + ATCA_TRACE(status, "calib_ecc204_read_config_zone - failed"); + } + } + + if (ATCA_SUCCESS == status) + { + // compare slot 1 and slot 3 data && skip first 16 bytes and counter value + if (!((memcmp(&device_config_data[16], &config_data[16], ATCA_ECC204_CONFIG_SLOT_SIZE)) || + (memcmp(&device_config_data[48], &config_data[48], ATCA_ECC204_CONFIG_SLOT_SIZE)))) + { + *same_config = true; + } + } + + return status; +} + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_sign.c b/drivers/ecc108a/cryptoauthlib/calib/calib_sign.c new file mode 100644 index 0000000..940abf2 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_sign.c @@ -0,0 +1,252 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Sign command. + * + * The Sign command generates a signature using the private key in slot with + * ECDSA algorithm. + * + * \note List of devices that support this command - ATECC108A, ATECC508A, and + * ATECC608A/B. There are differences in the modes that they support. Refer + * to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Executes the Sign command, which generates a signature using the + * ECDSA algorithm. + * + * \param[in] device Device context pointer + * \param[in] mode Mode determines what the source of the message to be + * signed. + * \param[in] key_id Private key slot used to sign the message. + * \param[out] signature Signature is returned here. Format is R and S + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sign_base(ATCADevice device, uint8_t mode, uint16_t key_id, uint8_t *signature) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + if ((device == NULL) || (signature == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + // Build sign command + packet.param1 = mode; + packet.param2 = key_id; + if ((status = atSign(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atSign - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_sign_base - execution failed"); + break; + } + + if (signature != NULL) + { + if (packet.data[ATCA_COUNT_IDX] == (ATCA_SIG_SIZE + ATCA_PACKET_OVERHEAD)) + { + memcpy(signature, &packet.data[ATCA_RSP_DATA_IDX], ATCA_SIG_SIZE); + } + else + { + status = ATCA_RX_FAIL; + } + + } + } + while (0); + + return status; +} + +/** \brief Executes Sign command, to sign a 32-byte external message using the + * private key in the specified slot. The message to be signed + * will be loaded into the Message Digest Buffer to the + * ATECC608 device or TempKey for other devices. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot of the private key to be used to sign the + * message. + * \param[in] msg 32-byte message to be signed. Typically the SHA256 + * hash of the full message. + * \param[out] signature Signature will be returned here. Format is R and S + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sign(ATCADevice device, uint16_t key_id, const uint8_t *msg, uint8_t *signature) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t nonce_target = NONCE_MODE_TARGET_TEMPKEY; + uint8_t sign_source = SIGN_MODE_SOURCE_TEMPKEY; + + do + { + // Make sure RNG has updated its seed + if ((status = calib_random(device, NULL)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_random - failed"); + break; + } + + // Load message into device + if (ATECC608 == device->mIface.mIfaceCFG->devtype) + { + // Use the Message Digest Buffer for the ATECC608 + nonce_target = NONCE_MODE_TARGET_MSGDIGBUF; + sign_source = SIGN_MODE_SOURCE_MSGDIGBUF; + } + if ((status = calib_nonce_load(device, nonce_target, msg, 32)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_nonce_load - failed"); + break; + } + + // Sign the message + if ((status = calib_sign_base(device, SIGN_MODE_EXTERNAL | sign_source, key_id, signature)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_sign_base - failed"); + break; + } + } + while (0); + + return status; +} + +/** \brief Executes Sign command to sign an internally generated message. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot of the private key to be used to sign the + * message. + * \param[in] is_invalidate Set to true if the signature will be used with + * the Verify(Invalidate) command. false for all + * other cases. + * \param[in] is_full_sn Set to true if the message should incorporate + * the device's full serial number. + * \param[out] signature Signature is returned here. Format is R and S + * integers in big-endian format. 64 bytes for + * P256 curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sign_internal(ATCADevice device, uint16_t key_id, bool is_invalidate, bool is_full_sn, uint8_t *signature) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t mode = SIGN_MODE_INTERNAL; + + do + { + // Sign the message + if (is_invalidate) + { + mode |= SIGN_MODE_INVALIDATE; + } + + if (is_full_sn) + { + mode |= SIGN_MODE_INCLUDE_SN; + } + + if ((status = calib_sign_base(device, mode, key_id, signature)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_sign_base - failed"); + break; + } + + } + while (0); + + return status; +} + +/** \brief Execute sign command to sign the 32 bytes message digest using private key + * mentioned in slot. + * + * \param[in] device Device context pointer + * \param[in] key_id points to private key slot + * \param[in] msg 32 bytes message digest + * \param[out] signature Signature is returned here. Format is R and S + * integers in big-endian format. 64 bytes for + * P256 curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_sign(ATCADevice device, uint16_t key_id, const uint8_t* msg, uint8_t* signature) +{ + ATCA_STATUS status = ATCA_SUCCESS; + ATCAPacket packet; + + packet.param1 = 0x00; + packet.param2 = key_id; + + if ((NULL == device) || (NULL == msg)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + if (ATCA_SUCCESS == status) + { + // copy message digest into i/o buffer + memcpy(packet.data, msg, ATCA_SHA256_DIGEST_SIZE); + + (void)atSign(atcab_get_device_type_ext(device), &packet); + + if (ATCA_SUCCESS != (status = atca_execute_command(&packet, device))) + { + ATCA_TRACE(status, "calib_ecc204_sign - execution failed"); + } + } + + if (ATCA_SUCCESS == status) + { + if (signature != NULL) + { + if (packet.data[ATCA_COUNT_IDX] == (ATCA_SIG_SIZE + ATCA_PACKET_OVERHEAD)) + { + memcpy(signature, &packet.data[ATCA_RSP_DATA_IDX], ATCA_SIG_SIZE); + } + else + { + status = ATCA_RX_FAIL; + } + + } + } + + return status; +} diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_write.c b/drivers/ecc108a/cryptoauthlib/calib/calib_write.c new file mode 100644 index 0000000..d07b686 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_write.c @@ -0,0 +1,885 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Write command. + * + * The Write command writes either one 4-byte word or a 32-byte block to one of + * the EEPROM zones on the device. Depending upon the value of the WriteConfig + * byte for a slot, the data may be required to be encrypted by the system prior + * to being sent to the device + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, and ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" +#include "host/atca_host.h" + +/** + * \brief Executes the Write command, which writes either one four byte word or + * a 32-byte block to one of the EEPROM zones on the device. Depending + * upon the value of the WriteConfig byte for this slot, the data may be + * required to be encrypted by the system prior to being sent to the + * device. This command cannot be used to write slots configured as ECC + * private keys. + * + * \param[in] device Device context pointer + * \param[in] zone Zone/Param1 for the write command. + * \param[in] address Address/Param2 for the write command. + * \param[in] value Plain-text data to be written or cipher-text for + * encrypted writes. 32 or 4 bytes depending on bit 7 in the + * zone. + * \param[in] mac MAC required for encrypted writes (32 bytes). Set to NULL + * if not required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_write(ATCADevice device, uint8_t zone, uint16_t address, const uint8_t *value, const uint8_t *mac) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + if ((device == NULL) || (value == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + // Build the write command + packet.param1 = zone; + packet.param2 = address; + if (zone & ATCA_ZONE_READWRITE_32) + { + // 32-byte write + memcpy(packet.data, value, 32); + // Only 32-byte writes can have a MAC + if (mac) + { + memcpy(&packet.data[32], mac, 32); + } + } + else + { + // 4-byte write + memcpy(packet.data, value, 4); + } + + if ((status = atWrite(atcab_get_device_type_ext(device), &packet, mac && (zone & ATCA_ZONE_READWRITE_32))) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atWrite - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_write - execution failed"); + break; + } + + } + while (0); + + return status; +} + +/** \brief Executes the Write command, which writes either 4 or 32 bytes of + * data into a device zone. + * + * \param[in] device Device context pointer + * \param[in] zone Device zone to write to (0=config, 1=OTP, 2=data). + * \param[in] slot If writing to the data zone, it is the slot to write to, + * otherwise it should be 0. + * \param[in] block 32-byte block to write to. + * \param[in] offset 4-byte word within the specified block to write to. If + * performing a 32-byte write, this should be 0. + * \param[in] data Data to be written. + * \param[in] len Number of bytes to be written. Must be either 4 or 32. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_write_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, const uint8_t *data, uint8_t len) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint16_t addr; + + // Check the input parameters + if (data == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + if (len != 4 && len != 32) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid length received"); + } + + do + { + // The get address function checks the remaining variables + if ((status = calib_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_get_addr - failed"); + break; + } + + // If there are 32 bytes to write, then xor the bit into the mode + if (len == ATCA_BLOCK_SIZE) + { + zone = zone | ATCA_ZONE_READWRITE_32; + } + + status = calib_write(device, zone, addr, data, NULL); + + } + while (0); + + return status; +} + + +/** \brief Executes the Write command, which performs an encrypted write of + * a 32 byte block into given slot. + * + * The function takes clear text bytes and encrypts them for writing over the + * wire. Data zone must be locked and the slot configuration must be set to + * encrypted write for the block to be successfully written. + * + * \param[in] device Device context pointer + * \param[in] key_id Slot ID to write to. + * \param[in] block Index of the 32 byte block to write in the slot. + * \param[in] data 32 bytes of clear text data to be written to the slot + * \param[in] enc_key WriteKey to encrypt with for writing + * \param[in] enc_key_id The KeyID of the WriteKey + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * returns ATCA_SUCCESS on success, otherwise an error code. + */ + +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, const uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id) +{ + uint8_t num_in[NONCE_NUMIN_SIZE] = { 0 }; + +#else +ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, const uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]) +{ +#endif + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t zone = ATCA_ZONE_DATA | ATCA_ZONE_READWRITE_32; + atca_nonce_in_out_t nonce_params; + atca_gen_dig_in_out_t gen_dig_param; + atca_write_mac_in_out_t write_mac_param; + atca_temp_key_t temp_key; + uint8_t serial_num[32]; + uint8_t rand_out[RANDOM_NUM_SIZE] = { 0 }; + uint8_t cipher_text[ATCA_KEY_SIZE] = { 0 }; + uint8_t mac[WRITE_MAC_SIZE] = { 0 }; + uint8_t other_data[4] = { 0 }; + uint16_t addr; + + do + { + // Verify inputs parameters + if (data == NULL || enc_key == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // Read the device SN + if ((status = calib_read_zone(device, ATCA_ZONE_CONFIG, 0, 0, 0, serial_num, 32)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_read_zone - failed"); + break; + } + // Make the SN continuous by moving SN[4:8] right after SN[0:3] + memmove(&serial_num[4], &serial_num[8], 5); + + + // Random Nonce inputs + memset(&temp_key, 0, sizeof(temp_key)); + memset(&nonce_params, 0, sizeof(nonce_params)); + nonce_params.mode = NONCE_MODE_SEED_UPDATE; + nonce_params.zero = 0; + nonce_params.num_in = &num_in[0]; + nonce_params.rand_out = rand_out; + nonce_params.temp_key = &temp_key; + + // Send the random Nonce command + if ((status = calib_nonce_rand(device, num_in, rand_out)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Nonce failed"); + break; + } + + // Calculate Tempkey + if ((status = atcah_nonce(&nonce_params)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Calc TempKey failed"); + break; + } + + // Supply OtherData so GenDig behavior is the same for keys with SlotConfig.NoMac set + other_data[0] = ATCA_GENDIG; + other_data[1] = GENDIG_ZONE_DATA; + other_data[2] = (uint8_t)(enc_key_id); + other_data[3] = (uint8_t)(enc_key_id >> 8); + + // Send the GenDig command + if ((status = calib_gendig(device, GENDIG_ZONE_DATA, enc_key_id, other_data, sizeof(other_data))) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "GenDig failed"); + break; + } + + // Calculate Tempkey + // NoMac bit isn't being considered here on purpose to remove having to read SlotConfig. + // OtherData is built to get the same result regardless of the NoMac bit. + memset(&gen_dig_param, 0, sizeof(gen_dig_param)); + gen_dig_param.key_id = enc_key_id; + gen_dig_param.is_key_nomac = false; + gen_dig_param.sn = serial_num; + gen_dig_param.stored_value = enc_key; + gen_dig_param.zone = GENDIG_ZONE_DATA; + gen_dig_param.other_data = other_data; + gen_dig_param.temp_key = &temp_key; + if ((status = atcah_gen_dig(&gen_dig_param)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atcah_gen_dig() failed"); + break; + } + + // The get address function checks the remaining variables + if ((status = calib_get_addr(ATCA_ZONE_DATA, key_id, block, 0, &addr)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Get address failed"); + break; + } + + // Setting bit 6 to indicate input data is encrypted + write_mac_param.zone = zone | ATCA_ZONE_ENCRYPTED; + write_mac_param.key_id = addr; + write_mac_param.sn = serial_num; + write_mac_param.input_data = data; + write_mac_param.encrypted_data = cipher_text; + write_mac_param.auth_mac = mac; + write_mac_param.temp_key = &temp_key; + + if ((status = atcah_write_auth_mac(&write_mac_param)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Calculate Auth MAC failed"); + break; + } + + status = calib_write(device, write_mac_param.zone, write_mac_param.key_id, write_mac_param.encrypted_data, write_mac_param.auth_mac); + + } + while (0); + + return status; +} + +/** \brief Executes the Write command, which writes the configuration zone. + * + * First 16 bytes are skipped as they are not writable. LockValue and + * LockConfig are also skipped and can only be changed via the Lock + * command. + * + * This command may fail if UserExtra and/or Selector bytes have + * already been set to non-zero values. + * + * \param[in] device Device context pointer + * \param[in] config_data Data to the config zone data. This should be 88 + * bytes for SHA devices and 128 bytes for ECC + * devices. + * + * \returns ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_write_config_zone(ATCADevice device, const uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + size_t config_size = 0; + + if (config_data == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + // Get config zone size for the device + if (ATCA_SUCCESS != (status = calib_get_zone_size(device, ATCA_ZONE_CONFIG, 0, &config_size))) + { + ATCA_TRACE(status, "calib_get_zone_size - failed"); + break; + } + + // Write config zone excluding UserExtra and Selector + if (ATCA_SUCCESS != (status = calib_write_bytes_zone(device, ATCA_ZONE_CONFIG, 0, 16, &config_data[16], config_size - 16))) + { + ATCA_TRACE(status, "calib_write_bytes_zone - failed"); + break; + } + + // Write the UserExtra and Selector. This may fail if either value is already non-zero. + if (ATCA_SUCCESS != (status = calib_updateextra(device, UPDATE_MODE_USER_EXTRA, config_data[84]))) + { + ATCA_TRACE(status, "calib_updateextra - failed"); + break; + } + + if (ATCA_SUCCESS != (status = calib_updateextra(device, UPDATE_MODE_SELECTOR, config_data[85]))) + { + ATCA_TRACE(status, "calib_updateextra - failed"); + break; + } + } + while (0); + + return status; +} + +/** \brief Uses the write command to write a public key to a slot in the + * proper format. + * + * \param[in] device Device context pointer + * \param[in] slot Slot number to write. Only slots 8 to 15 are large + * enough to store a public key. + * \param[in] public_key Public key to write into the slot specified. X and Y + * integers in big-endian format. 64 bytes for P256 + * curve. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_write_pubkey(ATCADevice device, uint16_t slot, const uint8_t *public_key) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t public_key_formatted[ATCA_BLOCK_SIZE * 3]; + uint8_t block; + + // Check the pointers + if (public_key == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + // The 64 byte P256 public key gets written to a 72 byte slot in the following pattern + // | Block 1 | Block 2 | Block 3 | + // | Pad: 4 Bytes | PubKey[0:27] | PubKey[28:31] | Pad: 4 Bytes | PubKey[32:55] | PubKey[56:63] | + + memset(public_key_formatted, 0, sizeof(public_key_formatted)); + memcpy(&public_key_formatted[4], &public_key[0], 32); // Move X to padded position + memcpy(&public_key_formatted[40], &public_key[32], 32); // Move Y to padded position + + // Using this instead of calib_write_zone_bytes, as that function doesn't work when + // the data zone is unlocked + for (block = 0; block < 3; block++) + { + if (ATCA_SUCCESS != (status = calib_write_zone(device, ATCA_ZONE_DATA, slot, block, 0, &public_key_formatted[ATCA_BLOCK_SIZE * block], ATCA_BLOCK_SIZE))) + { + ATCA_TRACE(status, "calib_write_zone - failed"); + break; + } + } + + return status; +} + +/** \brief Executes the Write command, which writes data into the + * configuration, otp, or data zones with a given byte offset and + * length. Offset and length must be multiples of a word (4 bytes). + * + * Config zone must be unlocked for writes to that zone. If data zone is + * unlocked, only 32-byte writes are allowed to slots and OTP and the offset + * and length must be multiples of 32 or the write will fail. + * + * \param[in] device Device context pointer + * \param[in] zone Zone to write data to: ATCA_ZONE_CONFIG(0), + * ATCA_ZONE_OTP(1), or ATCA_ZONE_DATA(2). + * \param[in] slot If zone is ATCA_ZONE_DATA(2), the slot number to + * write to. Ignored for all other zones. + * \param[in] offset_bytes Byte offset within the zone to write to. Must be + * a multiple of a word (4 bytes). + * \param[in] data Data to be written. + * \param[in] length Number of bytes to be written. Must be a multiple + * of a word (4 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_write_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, size_t offset_bytes, const uint8_t *data, size_t length) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + size_t zone_size = 0; + size_t data_idx = 0; + size_t cur_block = 0; + size_t cur_word = 0; + + if (zone != ATCA_ZONE_CONFIG && zone != ATCA_ZONE_OTP && zone != ATCA_ZONE_DATA) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); + } + if (zone == ATCA_ZONE_DATA && slot > 15) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid slot received"); + } + if (length == 0) + { + return ATCA_SUCCESS; // Always succeed writing 0 bytes + } + if (data == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + if (offset_bytes % ATCA_WORD_SIZE != 0 || length % ATCA_WORD_SIZE != 0) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Either Invalid length or offset received"); + } + + do + { + if (ATCA_SUCCESS != (status = calib_get_zone_size(device, zone, slot, &zone_size))) + { + ATCA_TRACE(status, "calib_get_zone_size - failed"); + break; + } + if (offset_bytes + length > zone_size) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); + } + + cur_block = offset_bytes / ATCA_BLOCK_SIZE; + cur_word = (offset_bytes % ATCA_BLOCK_SIZE) / ATCA_WORD_SIZE; + + while (data_idx < length) + { + // The last item makes sure we handle the selector, user extra, and lock bytes in the config properly + if (cur_word == 0 && length - data_idx >= ATCA_BLOCK_SIZE && !(zone == ATCA_ZONE_CONFIG && cur_block == 2)) + { + if (ATCA_SUCCESS != (status = calib_write_zone(device, zone, slot, (uint8_t)cur_block, 0, &data[data_idx], ATCA_BLOCK_SIZE))) + { + ATCA_TRACE(status, "calib_write_zone - failed"); + break; + } + data_idx += ATCA_BLOCK_SIZE; + cur_block += 1; + } + else + { + // Skip trying to change UserExtra, Selector, LockValue, and LockConfig which require the UpdateExtra command to change + if (!(zone == ATCA_ZONE_CONFIG && cur_block == 2 && cur_word == 5)) + { + if (ATCA_SUCCESS != (status = calib_write_zone(device, zone, slot, (uint8_t)cur_block, (uint8_t)cur_word, &data[data_idx], ATCA_WORD_SIZE))) + { + ATCA_TRACE(status, "calib_write_zone - failed"); + break; + } + } + data_idx += ATCA_WORD_SIZE; + cur_word += 1; + if (cur_word == ATCA_BLOCK_SIZE / ATCA_WORD_SIZE) + { + cur_block += 1; + cur_word = 0; + } + } + } + } + while (false); + + return status; +} + +/** \brief Initialize one of the monotonic counters in device with a specific + * value. + * + * The monotonic counters are stored in the configuration zone using a special + * format. This encodes a binary count value into the 8 byte encoded value + * required. Can only be set while the configuration zone is unlocked. + * + * \param[in] device Device context pointer + * \param[in] counter_id Counter to be written. + * \param[in] counter_value Counter value to set. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_write_config_counter(ATCADevice device, uint16_t counter_id, uint32_t counter_value) +{ + uint16_t lin_a, lin_b, bin_a, bin_b; + uint8_t bytes[8]; + uint8_t idx = 0; + ATCA_STATUS status = ATCA_GEN_FAIL; + + if (counter_id > 1 || counter_value > COUNTER_MAX_VALUE) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Either invalid counter id or counter value received"); + } + + lin_a = 0xFFFF >> (counter_value % 32); + lin_b = 0xFFFF >> ((counter_value >= 16) ? (counter_value - 16) % 32 : 0); + bin_a = (uint16_t)(counter_value / 32); + bin_b = (counter_value >= 16) ? ((uint16_t)((counter_value - 16) / 32)) : 0; + + bytes[idx++] = lin_a >> 8; + bytes[idx++] = lin_a & 0xFF; + bytes[idx++] = lin_b >> 8; + bytes[idx++] = lin_b & 0xFF; + + bytes[idx++] = bin_a >> 8; + bytes[idx++] = bin_a & 0xFF; + bytes[idx++] = bin_b >> 8; + bytes[idx++] = bin_b & 0xFF; + + status = calib_write_bytes_zone(device, ATCA_ZONE_CONFIG, 0, 52 + counter_id * 8, bytes, sizeof(bytes)); + + return status; +} + +#if defined(ATCA_ECC204_SUPPORT) +/** \brief Execute write command to write either 16 byte or 32 byte to one of the EEPROM zones + * on the ECC204 device. + * + * \param[in] device Device context pointer + * \param[in] zone Zone/Param1 for the write command. + * \param[in] address Address/Param2 for the write command. + * \param[in] value Plain-text data to be written or cipher-text for + * encrypted writes. 32 or 16 bytes depending on zone. + * \param[in] mac MAC required for encrypted writes (32 bytes). Set to NULL + * if not required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_ecc204_write(ATCADevice device, uint8_t zone, uint16_t address, const uint8_t *value, + const uint8_t *mac) +{ + ATCA_STATUS status = ATCA_SUCCESS; + ATCAPacket packet; + + if ((NULL == device) && (NULL == value)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + if (ATCA_SUCCESS == status) + { + packet.param1 = zone; + packet.param2 = address; + + if (ATCA_ECC204_ZONE_CONFIG == zone) + { + memcpy(packet.data, value, 16); + } + else if (ATCA_ECC204_ZONE_DATA == zone) + { + memcpy(packet.data, value, ATCA_BLOCK_SIZE); + } + else + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid zone received"); + } + + if (ATCA_SUCCESS == status) + { + if (mac && (ATCA_ECC204_ZONE_DATA == zone)) + { + memcpy(&packet.data[ATCA_BLOCK_SIZE], mac, MAC_SIZE); + } + + (void)atWrite(atcab_get_device_type_ext(device), &packet, mac && (ATCA_ECC204_ZONE_DATA == zone)); + } + } + + if (ATCA_SUCCESS == status) + { + if (ATCA_SUCCESS != (status = atca_execute_command(&packet, device))) + { + ATCA_TRACE(status, "calib_ecc204_write - execution failed"); + } + } + + return status; + +} + +/** \brief Execute write command to write data into configuration zone or data zone + * This function only support ECC204 device + * + * \param[in] device Device context pointer + * \param[in] zone Device zone to write (config=1, data=0) + * \param[in] slot the slot number to be witten + * \param[in] block 32-byte block to write + * \param[in] offset ignore for ECC204 device + * \param[in] data Data to be written into slot + * \param[in] len Number of bytes to be written. Must be either 16 or 32. + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_write_zone(ATCADevice device, uint8_t zone, uint16_t slot, uint8_t block, + uint8_t offset, const uint8_t *data, uint8_t len) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint16_t addr; + uint8_t write_zone = (zone == ATCA_ZONE_CONFIG) ? ATCA_ECC204_ZONE_CONFIG : ATCA_ECC204_ZONE_DATA; + + ((void)offset); + + if ((NULL == device) && (NULL == data)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + else if (((ATCA_ECC204_ZONE_CONFIG == write_zone) && (16 != len)) || + ((ATCA_ECC204_ZONE_DATA == write_zone) && (ATCA_BLOCK_SIZE != len))) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "Invalid length received"); + } + + if (ATCA_SUCCESS == status) + { + if (ATCA_SUCCESS != (status = calib_ecc204_get_addr(write_zone, slot, block, 0, &addr))) + { + ATCA_TRACE(status, "calib_ecc204_get_addr - failed"); + } + + if (ATCA_SUCCESS == status) + { + status = calib_ecc204_write(device, write_zone, addr, data, NULL); + } + } + + return status; +} + +/** \brief Use write command to write configuration data into ECC204 config zone + * + * \param[in] device Device context pointer + * \param[in] config_data configuration data + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +ATCA_STATUS calib_ecc204_write_config_zone(ATCADevice device, const uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t slot = 1; + + if ((NULL == device) || (NULL == config_data)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + if (ATCA_SUCCESS == status) + { + while (slot <= 3) + { + if (ATCA_SUCCESS != (status = calib_ecc204_write_zone(device, ATCA_ECC204_ZONE_CONFIG, slot, + 0, 0, &config_data[16 * slot], 16))) + { + ATCA_TRACE(status, "calib_ecc204_write_zone - failed"); + } + slot += 1; // Increment slot + } + } + + return status; +} + +/** \brief Executes write command, performs an encrypted write of a 32 byte block into given slot. + * + * \param[in] device Device context pointer + * \param[in] slot key slot to be written + * \param[in] data 32 bytes of clear text data + * \param[in] transport_key Transport key + * \param[in] key_id Transport key id + * \param[in] num_in 20 byte host nonce to inject into Nonce calculation + * + * \return ATCA_SUCCESS on success, otherwise an error code + */ +#if defined(ATCA_USE_CONSTANT_HOST_NONCE) +ATCA_STATUS calib_ecc204_write_enc(ATCADevice device, uint16_t slot, uint8_t* data, uint8_t* transport_key, + uint8_t transport_key_id) +{ + uint8_t num_in[NONCE_NUMIN_SIZE] = { 0 }; + +#else +ATCA_STATUS calib_ecc204_write_enc(ATCADevice device, uint16_t slot, uint8_t* data, uint8_t* transport_key, + uint8_t transport_key_id, uint8_t num_in[NONCE_NUMIN_SIZE]) +{ +#endif + ATCA_STATUS status = ATCA_SUCCESS; + atca_nonce_in_out_t nonce_params; + atca_write_mac_in_out_t write_mac_param; + atca_temp_key_t temp_key; + atca_session_key_in_out_t session_key_params; + uint8_t rand_out[RANDOM_NUM_SIZE] = { 0 }; + uint8_t serial_number[ATCA_SERIAL_NUM_SIZE] = { 0 }; + uint8_t session_key[ATCA_KEY_SIZE] = { 0 }; + uint8_t cipher_text[ATCA_KEY_SIZE] = { 0 }; + uint8_t mac[WRITE_MAC_SIZE] = { 0 }; + uint16_t addr; + + if ((NULL == data) || (NULL == transport_key)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encounteed"); + } + + do + { + // Read device serial number + if (ATCA_SUCCESS != (status = calib_ecc204_read_serial_number(device, serial_number))) + { + ATCA_TRACE(status, "Read serial number failed"); + break; + } + + // Generate session key on device + if (ATCA_SUCCESS != (status = calib_nonce_gen_session_key(device, transport_key_id, num_in, rand_out))) + { + ATCA_TRACE(status, "Session key generation failed"); + break; + } + + // Random Nonce inputs + memset(&temp_key, 0, sizeof(temp_key)); + memset(&nonce_params, 0, sizeof(nonce_params)); + nonce_params.mode = NONCE_MODE_SEED_UPDATE; + nonce_params.zero = transport_key_id; + nonce_params.num_in = &num_in[0]; + nonce_params.rand_out = rand_out; + nonce_params.temp_key = &temp_key; + + // Calculate Nonce + if ((status = atcah_nonce(&nonce_params)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "Calculate nonce failed"); + break; + } + + // Session key inputs + memset(&session_key_params, 0, sizeof(session_key_params)); + session_key_params.transport_key = transport_key; + session_key_params.transport_key_id = transport_key_id; + session_key_params.sn = serial_number; + session_key_params.nonce = temp_key.value; + session_key_params.session_key = session_key; + + // calculate session key on host + if (ATCA_SUCCESS != (status = atcah_gen_session_key(&session_key_params))) + { + ATCA_TRACE(status, "Host session key generation failed"); + break; + } + + if (ATCA_SUCCESS != (status = calib_ecc204_get_addr(ATCA_ECC204_ZONE_DATA, slot, 0, 0, &addr))) + { + ATCA_TRACE(status, "Calculate slot address failed"); + break; + } + + // copy session key into temp variable + memcpy(temp_key.value, session_key, ATCA_KEY_SIZE); + + // Write mac inputs + write_mac_param.zone = ATCA_ECC204_ZONE_DATA; + write_mac_param.key_id = addr; + write_mac_param.sn = serial_number; + write_mac_param.input_data = data; + write_mac_param.encrypted_data = cipher_text; + write_mac_param.auth_mac = mac; + write_mac_param.temp_key = &temp_key; + + // calculate MAC on host + if (ATCA_SUCCESS != (status = atcah_ecc204_write_auth_mac(&write_mac_param))) + { + ATCA_TRACE(status, "Data encryption failed"); + break; + } + + status = calib_ecc204_write(device, write_mac_param.zone, write_mac_param.key_id, write_mac_param.encrypted_data, write_mac_param.auth_mac); + } + while (0); + + return status; +} + +/** \brief Use Write command to write bytes + * + * This function will issue the write command as many times as is required to + * read the requested data. + * + * \param[in] device Device context pointer + * \param[in] zone It accepts only ATCA_ZONE_DATA for ECC204 device + * \param[in] slot slot number to write to. + * \param[in] block offset bytes ignored + * \param[in] data data to be written + * \param[in] length number of bytes to e written + * + * \return ATCA_SUCCESS on success, otheriwse an error code + */ +ATCA_STATUS calib_ecc204_write_bytes_zone(ATCADevice device, uint8_t zone, uint16_t slot, size_t block, + const uint8_t *data, size_t length) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t block_size = ATCA_BLOCK_SIZE; + uint8_t no_of_blocks; + uint8_t data_idx = 0; + + if ((NULL == device) || (NULL == data)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Encountered NULL pointer"); + } + else if (ATCA_ZONE_DATA == zone) + { + if (((length > 64) && (2 == slot)) || ((length > 320) && (1 == slot)) || (0 == slot)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); + } + } + else if (ATCA_ZONE_CONFIG == zone) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid parameter received"); + } + else if (0 == length) + { + return ATCA_SUCCESS; + } + + no_of_blocks = (uint8_t)(length / block_size); + while (no_of_blocks--) + { + if (ATCA_SUCCESS != (status = calib_ecc204_write_zone(device, zone, slot, (uint8_t)block, 0, + &data[block_size * data_idx], + block_size))) + { + ATCA_TRACE(status, "calib_ecc204_write_zone failed"); + break; + } + + block += 1; // Read next block + data_idx += 1; // increment data index + } + + return status; +} + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/cryptoauthlib.h b/drivers/ecc108a/cryptoauthlib/cryptoauthlib.h new file mode 100644 index 0000000..0839afd --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/cryptoauthlib.h @@ -0,0 +1,130 @@ +/** + * \file + * \brief Single aggregation point for all CryptoAuthLib header files + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#ifndef _ATCA_LIB_H +#define _ATCA_LIB_H + +#include +#include +#include +#include +#include +#include + +/** Library Configuration File - All build attributes should be included in + atca_config.h */ +#include "atca_config.h" +#include "atca_compiler.h" +#include "atca_version.h" + +/* Configuration Macros to detect device classes */ +#if defined(ATCA_ATSHA204A_SUPPORT) || defined(ATCA_ATSHA206A_SUPPORT) +#define ATCA_SHA_SUPPORT 1 +#endif + +/* Make sure all configuration options work */ +#if defined(ATCA_ATECC608A_SUPPORT) && !defined(ATCA_ATECC608_SUPPORT) +#define ATCA_ATECC608_SUPPORT +#endif + +#if defined(ATCA_ATECC108A_SUPPORT) || defined(ATCA_ATECC508A_SUPPORT) \ + || defined(ATCA_ATECC608_SUPPORT) +#define ATCA_ECC_SUPPORT 1 +#endif + +/* Classic Cryptoauth Devices */ +#if defined(ATCA_SHA_SUPPORT) || defined(ATCA_ECC_SUPPORT) || defined(ATCA_ECC204_SUPPORT) +#define ATCA_CA_SUPPORT 1 +#else +#define ATCA_CA_SUPPORT 0 +#endif + +/* New Trust Anchor Devices */ +#if defined(ATCA_TA100_SUPPORT) +#define ATCA_TA_SUPPORT 1 +#else +#define ATCA_TA_SUPPORT 0 +#endif + +#include "atca_status.h" +#include "atca_debug.h" +#include "atca_iface.h" +#include "atca_helpers.h" +#include "hal/atca_hal.h" + +/* Common Cryptographic Definitions */ +#define ATCA_SHA256_BLOCK_SIZE (64) +#define ATCA_SHA256_DIGEST_SIZE (32) + +#define ATCA_AES128_BLOCK_SIZE (16) +#define ATCA_AES128_KEY_SIZE (16) + +#define ATCA_ECCP256_KEY_SIZE (32) +#define ATCA_ECCP256_PUBKEY_SIZE (64) +#define ATCA_ECCP256_SIG_SIZE (64) + +#define ATCA_ZONE_CONFIG ((uint8_t)0x00) +#define ATCA_ZONE_OTP ((uint8_t)0x01) +#define ATCA_ZONE_DATA ((uint8_t)0x02) + +#if defined(ATCA_ECC204_SUPPORT) +#define ATCA_ECC204_ZONE_DATA ((uint8_t)0x00) +#define ATCA_ECC204_ZONE_CONFIG ((uint8_t)0x01) +#endif + +/** Place resulting digest both in Output buffer and TempKey */ +#define SHA_MODE_TARGET_TEMPKEY ((uint8_t)0x00) +/** Place resulting digest both in Output buffer and Message Digest Buffer */ +#define SHA_MODE_TARGET_MSGDIGBUF ((uint8_t)0x40) +/** Place resulting digest both in Output buffer ONLY */ +#define SHA_MODE_TARGET_OUT_ONLY ((uint8_t)0xC0) + +#if ATCA_CA_SUPPORT || defined(ATCA_USE_ATCAB_FUNCTIONS) +#include "atca_cfgs.h" +#include "atca_device.h" +#include "calib/calib_basic.h" +#include "calib/calib_command.h" +#include "calib/calib_aes_gcm.h" +#endif + +#if ATCA_TA_SUPPORT +#include "talib/talib_status.h" +#include "talib/talib_basic.h" +#endif + +#include "atca_basic.h" + +#define ATCA_STRINGIFY(x) #x +#define ATCA_TOSTRING(x) ATCA_STRINGIFY(x) + +#ifdef ATCA_PRINTF + #define ATCA_TRACE(s, m) atca_trace_msg(s, __FILE__ ":" ATCA_TOSTRING(__LINE__) ":%x:" m "\n") +#else + #define ATCA_TRACE(s, m) atca_trace(s) +#endif + +#endif diff --git a/drivers/ecc108a/cryptoauthlib/hal/atca_hal.c b/drivers/ecc108a/cryptoauthlib/hal/atca_hal.c new file mode 100644 index 0000000..d7fa1ef --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/hal/atca_hal.c @@ -0,0 +1,548 @@ +/** + * \file + * \brief low-level HAL - methods used to setup indirection to physical layer interface. + * this level does the dirty work of abstracting the higher level ATCAIFace methods from the + * low-level physical interfaces. Its main goal is to keep low-level details from bleeding into + * the logical interface implemetation. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +/* when incorporating ATCA HAL into your application, you need to adjust the #defines in atca_hal.h to include + * and exclude appropriate interfaces - this optimizes memory use when not using a specific iface implementation in your application */ + +#include "cryptoauthlib.h" +#include "atca_hal.h" + +#ifndef ATCA_MAX_HAL_CACHE +#define ATCA_MAX_HAL_CACHE +#endif + +#ifdef ATCA_HAL_I2C +static ATCAHAL_t hal_i2c = { + hal_i2c_init, + hal_i2c_post_init, + hal_i2c_send, + hal_i2c_receive, + hal_i2c_control, + hal_i2c_release +}; +#endif + +#ifdef ATCA_HAL_SWI_UART +static ATCAHAL_t hal_swi_uart = { + hal_swi_init, + hal_swi_post_init, + hal_swi_send, + hal_swi_receive, + hal_swi_control, + hal_swi_release +}; +#endif + +#if defined(ATCA_HAL_SWI_GPIO) || defined(ATCA_HAL_SWI_BB) +static ATCAHAL_t hal_swi_gpio = { + hal_swi_gpio_init, + hal_swi_gpio_post_init, + hal_swi_gpio_send, + hal_swi_gpio_receive, + hal_swi_gpio_control, + hal_swi_gpio_release +}; +#endif + +#if defined(ATCA_HAL_UART) || defined(ATCA_HAL_SWI_UART) || defined(ATCA_HAL_KIT_UART) +static ATCAHAL_t hal_uart = { + hal_uart_init, + hal_uart_post_init, + hal_uart_send, + hal_uart_receive, + hal_uart_control, + hal_uart_release +}; +#endif + +#ifdef ATCA_HAL_SPI +static ATCAHAL_t hal_spi = { + hal_spi_init, + hal_spi_post_init, + hal_spi_send, + hal_spi_receive, + hal_spi_control, + hal_spi_release +}; +#endif + +#if defined(ATCA_HAL_GPIO) || defined(ATCA_HAL_BB) +static ATCAHAL_t hal_gpio = { + hal_gpio_init, + hal_gpio_post_init, + hal_gpio_send, /* Set IO State */ + hal_gpio_receive, /* Read IO State */ + hal_gpio_control, + hal_gpio_release +}; +#endif + +#ifdef ATCA_HAL_KIT_HID +static ATCAHAL_t hal_hid = { + hal_kit_hid_init, + hal_kit_hid_post_init, + hal_kit_hid_send, + hal_kit_hid_receive, + hal_kit_hid_control, + hal_kit_hid_release +}; +#endif + +#if defined(ATCA_HAL_KIT_HID) || defined(ATCA_HAL_KIT_UART) +#include "kit_protocol.h" +static ATCAHAL_t hal_kit_v1 = { + kit_init, + kit_post_init, + kit_send, + kit_receive, + kit_control, + kit_release +}; +#endif + +#ifdef ATCA_HAL_KIT_BRIDGE +static ATCAHAL_t hal_kit_bridge = { + hal_kit_init, + hal_kit_post_init, + hal_kit_send, + hal_kit_receive, + hal_kit_control, + hal_kit_release +}; +#endif + +#ifdef ATCA_HAL_CUSTOM +static ATCAHAL_t hal_custom; +#endif + +/** \brief Structure that holds the hal/phy maping for different interface types + */ +typedef struct +{ + uint8_t iface_type; /**< */ + ATCAHAL_t* hal; /**< */ + ATCAHAL_t* phy; /**< Physical interface for the specific HAL*/ +} atca_hal_list_entry_t; + + +static atca_hal_list_entry_t atca_registered_hal_list[ATCA_MAX_HAL_CACHE] = { +#ifdef ATCA_HAL_I2C + { ATCA_I2C_IFACE, &hal_i2c, NULL }, +#endif +#ifdef ATCA_HAL_SWI_UART + { ATCA_SWI_IFACE, &hal_swi_uart, &hal_uart }, +#endif +#ifdef ATCA_HAL_KIT_UART + { ATCA_UART_IFACE, &hal_kit_v1, &hal_uart }, +#elif defined(ATCA_HAL_UART) + { ATCA_UART_IFACE, &hal_uart, NULL }, +#endif +#ifdef ATCA_HAL_SPI + { ATCA_SPI_IFACE, &hal_spi, NULL }, +#endif +#ifdef ATCA_HAL_KIT_HID + { ATCA_HID_IFACE, &hal_kit_v1, &hal_hid }, +#endif +#ifdef ATCA_HAL_KIT_BRIDGE + { ATCA_KIT_IFACE, &hal_kit_bridge, NULL }, +#endif +#if defined(ATCA_HAL_SWI_GPIO) || defined(ATCA_HAL_SWI_BB) + { ATCA_SWI_GPIO_IFACE, &hal_swi_gpio, &hal_gpio }, +#endif +}; + +static const size_t atca_registered_hal_list_size = sizeof(atca_registered_hal_list) / sizeof(atca_hal_list_entry_t); + + +/** \brief Internal function to get a value from the hal cache + * \param[in] iface_type - the type of physical interface to register + * \param[out] hal pointer to the existing ATCAHAL_t structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +static ATCA_STATUS hal_iface_get_registered(ATCAIfaceType iface_type, ATCAHAL_t** hal, ATCAHAL_t **phy) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + + if (hal && phy) + { + size_t i; + for (i = 0; i < atca_registered_hal_list_size; i++) + { + if (iface_type == atca_registered_hal_list[i].iface_type) + { + break; + } + } + + if (i < atca_registered_hal_list_size) + { + *hal = atca_registered_hal_list[i].hal; + *phy = atca_registered_hal_list[i].phy; + status = ATCA_SUCCESS; + } + else + { + status = ATCA_GEN_FAIL; + } + } + + return status; +} + +/** \brief Internal function to set a value in the hal cache + * \param[in] iface_type - the type of physical interface to register + * \param[in] hal pointer to the existing ATCAHAL_t structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +static ATCA_STATUS hal_iface_set_registered(ATCAIfaceType iface_type, ATCAHAL_t* hal, ATCAHAL_t* phy) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + + if (hal) + { + size_t i; + size_t empty = atca_registered_hal_list_size; + for (i = 0; i < atca_registered_hal_list_size; i++) + { + if (iface_type == atca_registered_hal_list[i].iface_type) + { + break; + } + else if (empty == atca_registered_hal_list_size) + { + if (!atca_registered_hal_list[i].hal && !atca_registered_hal_list[i].phy) + { + empty = i; + } + } + } + + if (i < atca_registered_hal_list_size) + { + atca_registered_hal_list[i].hal = hal; + atca_registered_hal_list[i].phy = phy; + status = ATCA_SUCCESS; + } + else if (empty < atca_registered_hal_list_size) + { + atca_registered_hal_list[empty].hal = hal; + atca_registered_hal_list[empty].hal = phy; + status = ATCA_SUCCESS; + } + else + { + status = ATCA_ALLOC_FAILURE; + } + + } + + return status; +} + +/** \brief Register/Replace a HAL with a + * \param[in] iface_type - the type of physical interface to register + * \param[in] hal pointer to the new ATCAHAL_t structure to register + * \param[out] old pointer to the existing ATCAHAL_t structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS hal_iface_register_hal(ATCAIfaceType iface_type, ATCAHAL_t *hal, ATCAHAL_t **old_hal, ATCAHAL_t* phy, ATCAHAL_t** old_phy) +{ + ATCA_STATUS status; + + status = (old_hal && old_phy) ? hal_iface_get_registered(iface_type, old_hal, old_phy) : ATCA_SUCCESS; + + if (ATCA_SUCCESS == status) + { + status = hal_iface_set_registered(iface_type, hal, phy); + } + + return ATCA_SUCCESS; +} + +/** \brief Standard HAL API for ATCA to initialize a physical interface + * \param[in] cfg pointer to ATCAIfaceCfg object + * \param[in] hal pointer to ATCAHAL_t intermediate data structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS hal_iface_init(ATCAIfaceCfg *cfg, ATCAHAL_t **hal, ATCAHAL_t **phy) +{ + ATCA_STATUS status = ATCA_BAD_PARAM; + + if (cfg && hal) + { + status = hal_iface_get_registered(cfg->iface_type, hal, phy); + +#ifdef ATCA_HAL_CUSTOM + if (ATCA_CUSTOM_IFACE == cfg->iface_type) + { + *hal = hal_malloc(sizeof(ATCAHAL_t)); + if (*hal) + { + (*hal)->halinit = cfg->atcacustom.halinit; + (*hal)->halpostinit = cfg->atcacustom.halpostinit; + (*hal)->halreceive = cfg->atcacustom.halreceive; + (*hal)->halsend = cfg->atcacustom.halsend; + (*hal)->halcontrol = hal_custom_control; + (*hal)->halrelease = cfg->atcacustom.halrelease; + status = ATCA_SUCCESS; + } + else + { + status = ATCA_ALLOC_FAILURE; + } + } +#endif + } + + return status; +} + +/** \brief releases a physical interface, HAL knows how to interpret hal_data + * \param[in] iface_type - the type of physical interface to release + * \param[in] hal_data - pointer to opaque hal data maintained by HAL implementation for this interface type + * \return ATCA_SUCCESS on success, otherwise an error code. + */ + +ATCA_STATUS hal_iface_release(ATCAIfaceType iface_type, void *hal_data) +{ + ATCA_STATUS status; + ATCAHAL_t * hal; + ATCAHAL_t* phy; + + status = hal_iface_get_registered(iface_type, &hal, &phy); + + if (ATCA_SUCCESS == status) + { + if (hal && hal->halrelease) + { + status = hal->halrelease(hal_data); + } + + if (phy && phy->halrelease) + { + ATCA_STATUS phy_status = phy->halrelease(hal_data); + + if (ATCA_SUCCESS == status) + { + status = phy_status; + } + } + } + + return status; +} + +/** \brief Utility function for hal_wake to check the reply. + * \param[in] response Wake response to be checked. + * \param[in] response_size Size of the response to check. + * \return ATCA_SUCCESS for expected wake, ATCA_STATUS_SELFTEST_ERROR if the + * power on self test failed, ATCA_WAKE_FAILED for other failures. + */ +ATCA_STATUS hal_check_wake(const uint8_t* response, int response_size) +{ + const uint8_t expected_response[4] = { 0x04, 0x11, 0x33, 0x43 }; + const uint8_t selftest_fail_resp[4] = { 0x04, 0x07, 0xC4, 0x40 }; + + if (response_size != 4) + { + return ATCA_WAKE_FAILED; + } + if (memcmp(response, expected_response, 4) == 0) + { + return ATCA_SUCCESS; + } + if (memcmp(response, selftest_fail_resp, 4) == 0) + { + return ATCA_STATUS_SELFTEST_ERROR; + } + return ATCA_WAKE_FAILED; +} + +/** \brief Utility function for hal_wake to check the reply. + * \param[in] word_address Command to check + * \return true if the word_address is considered a command + */ +uint8_t hal_is_command_word(uint8_t word_address) +{ + return 0xFF == word_address || 0x03 == word_address || 0x10 == word_address; +} + + +#if !defined(ATCA_NO_HEAP) && defined(ATCA_TESTS_ENABLED) && defined(ATCA_PLATFORM_MALLOC) + +void* (*g_hal_malloc_f)(size_t) = ATCA_PLATFORM_MALLOC; +void (*g_hal_free_f)(void*) = ATCA_PLATFORM_FREE; + +void* hal_malloc(size_t size) +{ + return g_hal_malloc_f(size); +} + +void hal_free(void* ptr) +{ + g_hal_free_f(ptr); +} + +void hal_test_set_memory_f(void* (*malloc_func)(size_t), void (*free_func)(void*)) +{ + g_hal_malloc_f = malloc_func; + g_hal_free_f = free_func; +} + +#endif + +#if defined(ATCA_HAL_LEGACY_API) && defined(ATCA_HAL_I2C) +ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +{ + (void)param; + (void)paramlen; + + switch (option) + { + case ATCA_HAL_CONTROL_WAKE: + return hal_i2c_wake(iface); + case ATCA_HAL_CONTROL_IDLE: + return hal_i2c_idle(iface); + case ATCA_HAL_CONTROL_SLEEP: + return hal_i2c_sleep(iface); + case ATCA_HAL_CONTROL_SELECT: + /* fallthrough */ + case ATCA_HAL_CONTROL_DESELECT: + return ATCA_SUCCESS; + default: + return ATCA_BAD_PARAM; + } +} +#endif + +#if defined(ATCA_HAL_LEGACY_API) && defined(ATCA_HAL_SWI) +ATCA_STATUS hal_swi_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +{ + (void)param; + (void)paramlen; + + switch (option) + { + case ATCA_HAL_CONTROL_WAKE: + return hal_swi_wake(iface); + case ATCA_HAL_CONTROL_IDLE: + return hal_swi_idle(iface); + case ATCA_HAL_CONTROL_SLEEP: + return hal_swi_sleep(iface); + case ATCA_HAL_CONTROL_SELECT: + /* fallthrough */ + case ATCA_HAL_CONTROL_DESELECT: + return ATCA_SUCCESS; + default: + return ATCA_BAD_PARAM; + } +} +#endif + +#if defined(ATCA_HAL_LEGACY_API) && defined(ATCA_HAL_UART) +ATCA_STATUS hal_uart_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +{ + (void)param; + (void)paramlen; + + switch (option) + { + case ATCA_HAL_CONTROL_WAKE: + return hal_uart_wake(iface); + case ATCA_HAL_CONTROL_IDLE: + return hal_uart_idle(iface); + case ATCA_HAL_CONTROL_SLEEP: + return hal_uart_sleep(iface); + case ATCA_HAL_CONTROL_SELECT: + /* fallthrough */ + case ATCA_HAL_CONTROL_DESELECT: + return ATCA_SUCCESS; + default: + return ATCA_BAD_PARAM; + } +} +#endif + +#if defined(ATCA_HAL_LEGACY_API) && defined(ATCA_HAL_SPI) +ATCA_STATUS hal_spi_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +{ + (void)param; + (void)paramlen; + + if (iface) + { + switch (option) + { + case ATCA_HAL_CONTROL_WAKE: + return hal_spi_wake(iface); + case ATCA_HAL_CONTROL_IDLE: + return hal_spi_idle(iface); + case ATCA_HAL_CONTROL_SLEEP: + return hal_spi_sleep(iface); + case ATCA_HAL_CONTROL_SELECT: + /* fallthrough */ + case ATCA_HAL_CONTROL_DESELECT: + return ATCA_SUCCESS; + default: + break; + } + } + return ATCA_BAD_PARAM; +} +#endif + +#if defined(ATCA_HAL_CUSTOM) +ATCA_STATUS hal_custom_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +{ + (void)param; + (void)paramlen; + + if (iface && iface->mIfaceCFG) + { + switch (option) + { + case ATCA_HAL_CONTROL_WAKE: + return iface->mIfaceCFG->atcacustom.halwake(iface); + case ATCA_HAL_CONTROL_IDLE: + return iface->mIfaceCFG->atcacustom.halidle(iface); + case ATCA_HAL_CONTROL_SLEEP: + return iface->mIfaceCFG->atcacustom.halsleep(iface); + case ATCA_HAL_CONTROL_SELECT: + /* fallthrough */ + case ATCA_HAL_CONTROL_DESELECT: + return ATCA_SUCCESS; + default: + break; + } + } + return ATCA_BAD_PARAM; +} +#endif diff --git a/drivers/ecc108a/cryptoauthlib/hal/atca_hal.h b/drivers/ecc108a/cryptoauthlib/hal/atca_hal.h new file mode 100644 index 0000000..9999256 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/hal/atca_hal.h @@ -0,0 +1,238 @@ +/** + * \file + * \brief low-level HAL - methods used to setup indirection to physical layer interface + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +#ifndef ATCA_HAL_H_ +#define ATCA_HAL_H_ + +#include + +#include "atca_config.h" + +#include "atca_status.h" +#include "atca_iface.h" + + +/** \defgroup hal_ Hardware abstraction layer (hal_) + * + * \brief + * These methods define the hardware abstraction layer for communicating with a CryptoAuth device + * + @{ */ + +typedef struct +{ + ATCA_STATUS (*send)(void* ctx, uint8_t* txdata, uint16_t txlen); /**< Must be a blocking send */ + ATCA_STATUS (*recv)(void* ctx, uint8_t* rxdata, uint16_t* rxlen); /**< Must be a blocking receive */ + void* (*packet_alloc)(size_t bytes); /**< Allocate a phy packet */ + void (*packet_free)(void* packet); /**< Free a phy packet */ + void* hal_data; /**< Physical layer context */ +} atca_hal_kit_phy_t; + +#ifdef __cplusplus +extern "C" { +#endif + +ATCA_STATUS hal_iface_init(ATCAIfaceCfg *, ATCAHAL_t** hal, ATCAHAL_t** phy); +ATCA_STATUS hal_iface_release(ATCAIfaceType, void* hal_data); + +ATCA_STATUS hal_check_wake(const uint8_t* response, int response_size); + +#ifdef ATCA_HAL_I2C +ATCA_STATUS hal_i2c_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_i2c_post_init(ATCAIface iface); +ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#ifdef ATCA_LEGACY_HAL +ATCA_STATUS hal_i2c_wake(ATCAIface iface); +ATCA_STATUS hal_i2c_idle(ATCAIface iface); +ATCA_STATUS hal_i2c_sleep(ATCAIface iface); +#endif +ATCA_STATUS hal_i2c_release(void *hal_data); +#endif + +#ifdef ATCA_HAL_SWI_UART +ATCA_STATUS hal_swi_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_swi_post_init(ATCAIface iface); +ATCA_STATUS hal_swi_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS hal_swi_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_swi_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#ifdef ATCA_LEGACY_HAL +ATCA_STATUS hal_swi_wake(ATCAIface iface); +ATCA_STATUS hal_swi_idle(ATCAIface iface); +ATCA_STATUS hal_swi_sleep(ATCAIface iface); +#endif +ATCA_STATUS hal_swi_release(void *hal_data); +#endif + +#if defined(ATCA_HAL_SWI_GPIO) || defined(ATCA_HAL_SWI_BB) +ATCA_STATUS hal_swi_gpio_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_swi_gpio_post_init(ATCAIface iface); +ATCA_STATUS hal_swi_gpio_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS hal_swi_gpio_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_swi_gpio_release(void *hal_data); +ATCA_STATUS hal_swi_gpio_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#endif + +#if defined(ATCA_HAL_GPIO) || defined(ATCA_HAL_BB) +ATCA_STATUS hal_gpio_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_gpio_post_init(ATCAIface iface); +ATCA_STATUS hal_gpio_send(ATCAIface iface, uint8_t word_address, uint8_t* pin_state, int unused_param); +ATCA_STATUS hal_gpio_receive(ATCAIface iface, uint8_t word_address, uint8_t* pin_state, uint16_t* unused_param); +ATCA_STATUS hal_gpio_release(void *hal_data); +ATCA_STATUS hal_gpio_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#endif + +#if defined(ATCA_HAL_SWI_UART) || defined(ATCA_HAL_KIT_UART) || defined(ATCA_HAL_UART) +ATCA_STATUS hal_uart_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_uart_post_init(ATCAIface iface); +ATCA_STATUS hal_uart_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS hal_uart_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_uart_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#ifdef ATCA_LEGACY_HAL +ATCA_STATUS hal_uart_wake(ATCAIface iface); +ATCA_STATUS hal_uart_idle(ATCAIface iface); +ATCA_STATUS hal_uart_sleep(ATCAIface iface); +#endif +ATCA_STATUS hal_uart_release(void *hal_data); +#endif + +#ifdef ATCA_HAL_SPI +ATCA_STATUS hal_spi_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_spi_post_init(ATCAIface iface); +ATCA_STATUS hal_spi_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS hal_spi_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_spi_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#ifdef ATCA_LEGACY_HAL +ATCA_STATUS hal_spi_wake(ATCAIface iface); +ATCA_STATUS hal_spi_idle(ATCAIface iface); +ATCA_STATUS hal_spi_sleep(ATCAIface iface); +#endif +ATCA_STATUS hal_spi_release(void *hal_data); +#endif + +#ifdef ATCA_HAL_KIT_HID +ATCA_STATUS hal_kit_hid_init(ATCAIface iface, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_kit_hid_post_init(ATCAIface iface); +ATCA_STATUS hal_kit_hid_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength); +ATCA_STATUS hal_kit_hid_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_kit_hid_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +ATCA_STATUS hal_kit_hid_release(void *hal_data); +#endif + +#ifdef ATCA_HAL_KIT_BRIDGE +ATCA_STATUS hal_kit_init(ATCAIface iface, ATCAIfaceCfg* cfg); +ATCA_STATUS hal_kit_post_init(ATCAIface iface); +ATCA_STATUS hal_kit_send(ATCAIface iface, uint8_t word_address, uint8_t* txdata, int txlength); +ATCA_STATUS hal_kit_receive(ATCAIface iface, uint8_t word_address, uint8_t* rxdata, uint16_t* rxlength); +ATCA_STATUS hal_kit_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +ATCA_STATUS hal_kit_release(void* hal_data); +#endif + +#ifdef ATCA_HAL_CUSTOM +ATCA_STATUS hal_custom_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen); +#endif + +/* Polling defaults if not overwritten by the configuration */ +#ifndef ATCA_POLLING_INIT_TIME_MSEC +#define ATCA_POLLING_INIT_TIME_MSEC 1 +#endif + +#ifndef ATCA_POLLING_FREQUENCY_TIME_MSEC +#define ATCA_POLLING_FREQUENCY_TIME_MSEC 2 +#endif + +#ifndef ATCA_POLLING_MAX_TIME_MSEC +#define ATCA_POLLING_MAX_TIME_MSEC 2500 +#endif + +/* */ +typedef enum +{ + ATCA_HAL_CONTROL_WAKE = 0, + ATCA_HAL_CONTROL_IDLE = 1, + ATCA_HAL_CONTROL_SLEEP = 2, + ATCA_HAL_CONTROL_RESET = 3, + ATCA_HAL_CONTROL_SELECT = 4, + ATCA_HAL_CONTROL_DESELECT = 5, + ATCA_HAL_CHANGE_BAUD = 6, + ATCA_HAL_FLUSH_BUFFER = 7, + ATCA_HAL_CONTROL_DIRECTION = 8 +} ATCA_HAL_CONTROL; + +/** \brief Timer API for legacy implementations */ +#ifndef atca_delay_ms +void atca_delay_ms(uint32_t ms); +#endif + +#ifndef atca_delay_us +void atca_delay_us(uint32_t us); +#endif + +/** \brief Timer API implemented at the HAL level */ +void hal_rtos_delay_ms(uint32_t ms); +void hal_delay_ms(uint32_t ms); +void hal_delay_us(uint32_t us); + +/** \brief Optional hal interfaces */ +ATCA_STATUS hal_create_mutex(void ** ppMutex, char* pName); +ATCA_STATUS hal_destroy_mutex(void * pMutex); +ATCA_STATUS hal_lock_mutex(void * pMutex); +ATCA_STATUS hal_unlock_mutex(void * pMutex); + +#ifndef ATCA_NO_HEAP +#ifdef ATCA_TESTS_ENABLED +void hal_test_set_memory_f(void* (*malloc_func)(size_t), void (*free_func)(void*)); +#endif + +#if defined(ATCA_TESTS_ENABLED) || !defined(ATCA_PLATFORM_MALLOC) +void* hal_malloc(size_t size); +void hal_free(void* ptr); +#else +#define hal_malloc ATCA_PLATFORM_MALLOC +#define hal_free ATCA_PLATFORM_FREE +#endif +#endif + +#ifdef memset_s +#define hal_memset_s memset_s +#else +#define hal_memset_s atcab_memset_s +#endif + + +ATCA_STATUS hal_iface_register_hal(ATCAIfaceType iface_type, ATCAHAL_t *hal, ATCAHAL_t **old_hal, ATCAHAL_t* phy, ATCAHAL_t** old_phy); +uint8_t hal_is_command_word(uint8_t word_address); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ATCA_HAL_H_ */ diff --git a/drivers/ecc108a/cryptoauthlib/hal/hal_esp32_mp_softi2c.c b/drivers/ecc108a/cryptoauthlib/hal/hal_esp32_mp_softi2c.c new file mode 100644 index 0000000..2479762 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/hal/hal_esp32_mp_softi2c.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include "extmod/machine_i2c.h" +#include "ports/esp32/modmachine.h" +#include "esp_err.h" +#include "esp_log.h" +#include "cryptoauthlib.h" +#include "py/runtime.h" + +#define SCL_S 41 +#define SDA_S 42 + +const char* TAG = "HAL_SOFTI2C"; + +/* For debugging on the production board over USB */ +#define HAL_SOFTI2C_DEBUG 0 +#define hal_softi2c_debug_print(fmt, ...) \ + do { if (HAL_SOFTI2C_DEBUG) mp_printf(fmt, __VA_ARGS__); } while (0) + + +/** \brief method to change the bus speed of I2C + * \param[in] iface interface on which to change bus speed + * \param[in] speed baud rate (typically 100000 or 400000) + */ +ATCA_STATUS hal_i2c_change_baud(ATCAIface iface, uint32_t speed) +{ + // FIXME: implement + return ATCA_SUCCESS; +} + +ATCA_STATUS hal_i2c_init(ATCAIface iface, ATCAIfaceCfg *cfg) +{ + hal_softi2c_debug_print(&mp_plat_print, "hal_i2c_init\n"); + + // FIXME: read cfg + + mp_obj_t pin_scl = mp_obj_new_int(SCL_S); + mp_obj_t pin_sda = mp_obj_new_int(SDA_S); + mp_obj_t args[] = { + machine_pin_type.make_new(&machine_pin_type, 1, 0, &pin_scl), + machine_pin_type.make_new(&machine_pin_type, 1, 0, &pin_sda), + /* following is actually mp_map_elem_t[] */ + MP_ROM_QSTR(MP_QSTR_freq), mp_obj_new_int(100000), + }; + mp_obj_t i2c = mp_machine_soft_i2c_type.make_new(&mp_machine_soft_i2c_type, 2, 1, args); + hal_softi2c_debug_print(&mp_plat_print, "SoftI2C(pin_scl, pin_sda, freq=freq) returned 0x%x\n", i2c); + iface->hal_data = (void *) i2c; + + return ATCA_SUCCESS; +} + +/** \brief HAL implementation of I2C post init + * \param[in] iface instance + * \return ATCA_SUCCESS + */ +ATCA_STATUS hal_i2c_post_init(ATCAIface iface) +{ + return ATCA_SUCCESS; +} + +/** \brief HAL implementation of I2C send + * \param[in] iface instance + * \param[in] word_address device transaction type + * \param[in] txdata pointer to space to bytes to send + * \param[in] txlength number of bytes to send + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t address, uint8_t *txdata, int txlength) +{ + hal_softi2c_debug_print(&mp_plat_print, "hal_i2c_send\n"); + mp_obj_base_t *i2c = (mp_obj_base_t *) iface->hal_data; + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t *) mp_machine_soft_i2c_type.protocol; + + mp_machine_i2c_buf_t buf = {.len = txlength, .buf = (uint8_t *)txdata}; + int acks = i2c_p->transfer(i2c, address, 1, &buf, MP_MACHINE_I2C_FLAG_STOP); + hal_softi2c_debug_print(&mp_plat_print, "i2c.transfer returned 0x%x\n", acks); + if (acks < 0) { + return acks; + } + return ATCA_SUCCESS; +} + +/** \brief HAL implementation of I2C receive function + * \param[in] iface Device to interact with. + * \param[in] address Device address + * \param[out] rxdata Data received will be returned here. + * \param[in,out] rxlength As input, the size of the rxdata buffer. + * As output, the number of bytes received. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t address, uint8_t *rxdata, uint16_t *rxlength) +{ + hal_softi2c_debug_print(&mp_plat_print, "hal_i2c_receive\n"); + mp_obj_base_t *i2c = (mp_obj_base_t *) iface->hal_data; + mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t *) mp_machine_soft_i2c_type.protocol; + + mp_machine_i2c_buf_t buf = {.len = *rxlength, .buf = rxdata}; + int status = i2c_p->transfer(i2c, address, 1, &buf, MP_MACHINE_I2C_FLAG_READ | MP_MACHINE_I2C_FLAG_STOP); + hal_softi2c_debug_print(&mp_plat_print, "i2c.transfer returned 0x%x\n", status); + if (status < 0) { + return status; + } + // rxlength will be the number of bytes received + return ATCA_SUCCESS; +} + +/** \brief manages reference count on given bus and releases resource if no more refences exist + * \param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS hal_i2c_release(void *hal_data) +{ + hal_softi2c_debug_print(&mp_plat_print, "hal_i2c_release\n"); + mp_obj_base_t *i2c = (mp_obj_base_t *) hal_data; + // FIXME: delete i2c + return ATCA_SUCCESS; +} + +/** \brief Perform control operations for the kit protocol + * \param[in] iface Interface to interact with. + * \param[in] option Control parameter identifier + * \param[in] param Optional pointer to parameter value + * \param[in] paramlen Length of the parameter + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen) +{ + hal_softi2c_debug_print(&mp_plat_print, "hal_i2c_control\n"); + mp_obj_base_t *i2c = (mp_obj_base_t *) iface->hal_data; + return ATCA_UNIMPLEMENTED; +} diff --git a/drivers/ecc108a/cryptoauthlib/host/atca_host.h b/drivers/ecc108a/cryptoauthlib/host/atca_host.h new file mode 100644 index 0000000..2cfcc95 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/host/atca_host.h @@ -0,0 +1,465 @@ +/** + * \file + * \brief Definitions and Prototypes for ATCA Utility Functions + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + + +#ifndef ATCA_HOST_H +#define ATCA_HOST_H + +#include +#include "cryptoauthlib.h" // contains definitions used by chip and these routines +#include "calib/calib_basic.h" + +/** \defgroup atcah Host side crypto methods (atcah_) + * + * \brief + * Use these functions if your system does not use an ATCADevice as a host but + * implements the host in firmware. The functions provide host-side cryptographic functionality + * for an ATECC client device. They are intended to accompany the CryptoAuthLib functions. + * They can be called directly from an application, or integrated into an API. + * + * Modern compilers can garbage-collect unused functions. If your compiler does not support this feature, + * you can just discard this module from your project if you do use an ATECC as a host. Or, if you don't, + * delete the functions you do not use. + @{ */ + +/** \name Definitions for ATECC Message Sizes to Calculate a SHA256 Hash + + * \brief "||" is the concatenation operator. + * The number in braces is the length of the hash input value in bytes. + @{ */ + +//! RandOut{32} || NumIn{20} || OpCode{1} || Mode{1} || LSB of Param2{1} +#define ATCA_MSG_SIZE_NONCE (55) + + +/** \brief (Key or TempKey){32} || (Challenge or TempKey){32} || OpCode{1} || Mode{1} || Param2{2} +|| (OTP0_7 or 0){8} || (OTP8_10 or 0){3} || SN8{1} || (SN4_7 or 0){4} || SN0_1{2} || (SN2_3 or 0){2} +*/ +#define ATCA_MSG_SIZE_MAC (88) +#define ATCA_MSG_SIZE_HMAC (88) + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2} || SN8{1} || SN0_1{2} || 0{25} || TempKey{32} +#define ATCA_MSG_SIZE_GEN_DIG (96) + + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2} || SN8{1} || SN0_1{2} || 0{25} || TempKey{32} +#define ATCA_MSG_SIZE_DERIVE_KEY (96) + + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2} || SN8{1} || SN0_1{2} +#define ATCA_MSG_SIZE_DERIVE_KEY_MAC (39) + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2}|| SN8{1} || SN0_1{2} || 0{25} || TempKey{32} +#define ATCA_MSG_SIZE_ENCRYPT_MAC (96) + +//! TransportKey{32} || 0x15{1} || 0x00{1} || KeyId{2} || SN8{1} || SN0_1{2} || 0{25} || Nonce{32} +#define ATCA_MSG_SIZE_SESSION_KEY (96) + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2}|| SN8{1} || SN0_1{2} || 0{21} || PlainText{36} +#define ATCA_MSG_SIZE_PRIVWRITE_MAC (96) + +#define ATCA_COMMAND_HEADER_SIZE ( 4) +#define ATCA_GENDIG_ZEROS_SIZE (25) +#define ATCA_WRITE_MAC_ZEROS_SIZE (25) +#define ATCA_PRIVWRITE_MAC_ZEROS_SIZE (21) +#define ATCA_PRIVWRITE_PLAIN_TEXT_SIZE (36) +#define ATCA_DERIVE_KEY_ZEROS_SIZE (25) +#define ATCA_HMAC_BLOCK_SIZE (64) +#define ENCRYPTION_KEY_SIZE (64) + +/** @} */ + +/** \name Default Fixed Byte Values of Serial Number (SN[0:1] and SN[8]) + @{ */ +#define ATCA_SN_0_DEF (0x01) +#define ATCA_SN_1_DEF (0x23) +#define ATCA_SN_8_DEF (0xEE) +/** @} */ + + +/** \name Definition for TempKey Mode + @{ */ +//! mode mask for MAC command when using TempKey +#define MAC_MODE_USE_TEMPKEY_MASK ((uint8_t)0x03) +/** @} */ + +/** \brief Structure to hold TempKey fields + */ +typedef struct atca_temp_key +{ + uint8_t value[ATCA_KEY_SIZE * 2]; //!< Value of TempKey (64 bytes for ATECC608 only) + unsigned key_id : 4; //!< If TempKey was derived from a slot or transport key (GenDig or GenKey), that key ID is saved here. + unsigned source_flag : 1; //!< Indicates id TempKey started from a random nonce (0) or not (1). + unsigned gen_dig_data : 1; //!< TempKey was derived from the GenDig command. + unsigned gen_key_data : 1; //!< TempKey was derived from the GenKey command (ATECC devices only). + unsigned no_mac_flag : 1; //!< TempKey was derived from a key that has the NoMac bit set preventing the use of the MAC command. Known as CheckFlag in ATSHA devices). + unsigned valid : 1; //!< TempKey is valid. + uint8_t is_64; //!< TempKey has 64 bytes of valid data +} atca_temp_key_t; + + +/** \struct atca_include_data_in_out + * \brief Input / output parameters for function atca_include_data(). + * \var atca_include_data_in_out::p_temp + * \brief [out] pointer to output buffer + * \var atca_include_data_in_out::otp + * \brief [in] pointer to one-time-programming data + * \var atca_include_data_in_out::sn + * \brief [in] pointer to serial number data + */ +struct atca_include_data_in_out +{ + uint8_t * p_temp; + const uint8_t *otp; + const uint8_t *sn; + uint8_t mode; +}; + + +/** \struct atca_nonce_in_out + * \brief Input/output parameters for function atca_nonce(). + * \var atca_nonce_in_out::mode + * \brief [in] Mode parameter used in Nonce command (Param1). + * \var atca_nonce_in_out::zero + * \brief [in] Zero parameter used in Nonce command (Param2). + * \var atca_nonce_in_out::num_in + * \brief [in] Pointer to 20-byte NumIn data used in Nonce command. + * \var atca_nonce_in_out::rand_out + * \brief [in] Pointer to 32-byte RandOut data from Nonce command. + * \var atca_nonce_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +typedef struct atca_nonce_in_out +{ + uint8_t mode; + uint16_t zero; + const uint8_t * num_in; + const uint8_t * rand_out; + struct atca_temp_key *temp_key; +} atca_nonce_in_out_t; + + +typedef struct atca_io_decrypt_in_out +{ + const uint8_t* io_key; //!< IO protection key (32 bytes). + const uint8_t* out_nonce; //!< OutNonce returned from command (32 bytes). + uint8_t* data; //!< As input, encrypted data. As output, decrypted data. + size_t data_size; //!< Size of data in bytes (32 or 64). +} atca_io_decrypt_in_out_t; + +typedef struct atca_verify_mac +{ + uint8_t mode; //!< Mode (Param1) parameter used in Verify command. + uint16_t key_id; //!< KeyID (Param2) used in Verify command. + const uint8_t* signature; //!< Signature used in Verify command (64 bytes). + const uint8_t* other_data; //!< OtherData used in Verify command (19 bytes). + const uint8_t* msg_dig_buf; //!< Message digest buffer (64 bytes). + const uint8_t* io_key; //!< IO protection key value (32 bytes). + const uint8_t* sn; //!< Serial number (9 bytes). + const atca_temp_key_t* temp_key; //!< TempKey + uint8_t* mac; //!< Calculated verification MAC is returned here (32 bytes). +} atca_verify_mac_in_out_t; + + +typedef struct atca_secureboot_enc_in_out +{ + const uint8_t* io_key; //!< IO protection key value (32 bytes) + const struct atca_temp_key* temp_key; //!< Current value of TempKey + const uint8_t* digest; //!< Plaintext digest as input + uint8_t* hashed_key; //!< Calculated key is returned here (32 bytes) + uint8_t* digest_enc; //!< Encrypted (ciphertext) digest is return here (32 bytes) +} atca_secureboot_enc_in_out_t; + + +typedef struct atca_secureboot_mac_in_out +{ + uint8_t mode; //!< SecureBoot mode (param1) + uint16_t param2; //!< SecureBoot param2 + uint16_t secure_boot_config; //!< SecureBootConfig value from configuration zone + const uint8_t* hashed_key; //!< Hashed key. SHA256(IO Protection Key | TempKey) + const uint8_t* digest; //!< Digest (unencrypted) + const uint8_t* signature; //!< Signature (can be NULL if not required) + uint8_t* mac; //!< MAC is returned here +} atca_secureboot_mac_in_out_t; + +/** \struct atca_mac_in_out + * \brief Input/output parameters for function atca_mac(). + * \var atca_mac_in_out::mode + * \brief [in] Mode parameter used in MAC command (Param1). + * \var atca_mac_in_out::key_id + * \brief [in] KeyID parameter used in MAC command (Param2). + * \var atca_mac_in_out::challenge + * \brief [in] Pointer to 32-byte Challenge data used in MAC command, depending on mode. + * \var atca_mac_in_out::key + * \brief [in] Pointer to 32-byte key used to generate MAC digest. + * \var atca_mac_in_out::otp + * \brief [in] Pointer to 11-byte OTP, optionally included in MAC digest, depending on mode. + * \var atca_mac_in_out::sn + * \brief [in] Pointer to 9-byte SN, optionally included in MAC digest, depending on mode. + * \var atca_mac_in_out::response + * \brief [out] Pointer to 32-byte SHA-256 digest (MAC). + * \var atca_mac_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ + + + +typedef struct atca_mac_in_out +{ + uint8_t mode; + uint16_t key_id; + const uint8_t * challenge; + const uint8_t * key; + const uint8_t * otp; + const uint8_t * sn; + uint8_t * response; + struct atca_temp_key *temp_key; +} atca_mac_in_out_t; + + +/** \struct atca_hmac_in_out + * \brief Input/output parameters for function atca_hmac(). + * \var atca_hmac_in_out::mode + * \brief [in] Mode parameter used in HMAC command (Param1). + * \var atca_hmac_in_out::key_id + * \brief [in] KeyID parameter used in HMAC command (Param2). + * \var atca_hmac_in_out::key + * \brief [in] Pointer to 32-byte key used to generate HMAC digest. + * \var atca_hmac_in_out::otp + * \brief [in] Pointer to 11-byte OTP, optionally included in HMAC digest, depending on mode. + * \var atca_hmac_in_out::sn + * \brief [in] Pointer to 9-byte SN, optionally included in HMAC digest, depending on mode. + * \var atca_hmac_in_out::response + * \brief [out] Pointer to 32-byte SHA-256 HMAC digest. + * \var atca_hmac_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_hmac_in_out +{ + uint8_t mode; + uint16_t key_id; + const uint8_t * key; + const uint8_t * otp; + const uint8_t * sn; + uint8_t * response; + struct atca_temp_key *temp_key; +}; + + +/** + * \brief Input/output parameters for function atcah_gen_dig(). + */ +typedef struct atca_gen_dig_in_out +{ + uint8_t zone; //!< [in] Zone/Param1 for the GenDig command + uint16_t key_id; //!< [in] KeyId/Param2 for the GenDig command + uint16_t slot_conf; //!< [in] Slot config for the GenDig command + uint16_t key_conf; //!< [in] Key config for the GenDig command + uint8_t slot_locked; //!< [in] slot locked for the GenDig command + uint32_t counter; //!< [in] counter for the GenDig command + bool is_key_nomac; //!< [in] Set to true if the slot pointed to be key_id has the SotConfig.NoMac bit set + const uint8_t * sn; //!< [in] Device serial number SN[0:8]. Only SN[0:1] and SN[8] are required though. + const uint8_t * stored_value; //!< [in] 32-byte slot value, config block, OTP block as specified by the Zone/KeyId parameters + const uint8_t * other_data; //!< [in] 32-byte value for shared nonce zone, 4-byte value if is_key_nomac is true, ignored and/or NULL otherwise + struct atca_temp_key *temp_key; //!< [inout] Current state of TempKey +} atca_gen_dig_in_out_t; + +/** + * \brief Input/output parameters for function atcah_write_auth_mac() and atcah_privwrite_auth_mac(). + */ +typedef struct atca_write_mac_in_out +{ + uint8_t zone; //!< Zone/Param1 for the Write or PrivWrite command + uint16_t key_id; //!< KeyID/Param2 for the Write or PrivWrite command + const uint8_t * sn; //!< Device serial number SN[0:8]. Only SN[0:1] and SN[8] are required though. + const uint8_t * input_data; //!< Data to be encrypted. 32 bytes for Write command, 36 bytes for PrivWrite command. + uint8_t * encrypted_data; //!< Encrypted version of input_data will be returned here. 32 bytes for Write command, 36 bytes for PrivWrite command. + uint8_t * auth_mac; //!< Write MAC will be returned here. 32 bytes. + struct atca_temp_key *temp_key; //!< Current state of TempKey. +} atca_write_mac_in_out_t; + +/** + * \brief Input/output parameters for function atcah_derive_key(). + */ +struct atca_derive_key_in_out +{ + uint8_t mode; //!< Mode (param 1) of the derive key command + uint16_t target_key_id; //!< Key ID (param 2) of the target slot to run the command on + const uint8_t * sn; //!< Device serial number SN[0:8]. Only SN[0:1] and SN[8] are required though. + const uint8_t * parent_key; //!< Parent key to be used in the derive key calculation (32 bytes). + uint8_t * target_key; //!< Derived key will be returned here (32 bytes). + struct atca_temp_key *temp_key; //!< Current state of TempKey. +}; + + +/** + * \brief Input/output parameters for function atcah_derive_key_mac(). + */ +struct atca_derive_key_mac_in_out +{ + uint8_t mode; //!< Mode (param 1) of the derive key command + uint16_t target_key_id; //!< Key ID (param 2) of the target slot to run the command on + const uint8_t *sn; //!< Device serial number SN[0:8]. Only SN[0:1] and SN[8] are required though. + const uint8_t *parent_key; //!< Parent key to be used in the derive key calculation (32 bytes). + uint8_t * mac; //!< DeriveKey MAC will be returned here. +}; + + +/** \struct atca_decrypt_in_out + * \brief Input/output parameters for function atca_decrypt(). + * \var atca_decrypt_in_out::crypto_data + * \brief [in,out] Pointer to 32-byte data. Input encrypted data from Read command (Contents field), output decrypted. + * \var atca_decrypt_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_decrypt_in_out +{ + uint8_t * crypto_data; + struct atca_temp_key *temp_key; +}; + + +/** \brief Input/output parameters for function atcah_check_mac(). + */ +typedef struct atca_check_mac_in_out +{ + uint8_t mode; //!< [in] CheckMac command Mode + uint16_t key_id; //!< [in] CheckMac command KeyID + const uint8_t *sn; //!< [in] Device serial number SN[0:8]. Only SN[0:1] and SN[8] are required though. + const uint8_t *client_chal; //!< [in] ClientChal data, 32 bytes. Can be NULL if mode[0] is 1. + uint8_t * client_resp; //!< [out] Calculated ClientResp will be returned here. + const uint8_t *other_data; //!< [in] OtherData, 13 bytes + const uint8_t *otp; //!< [in] First 8 bytes of the OTP zone data. Can be NULL is mode[5] is 0. + const uint8_t *slot_key; //!< [in] 32 byte key value in the slot specified by slot_id. Can be NULL if mode[1] is 1. + /// [in] If this is not NULL, it assumes CheckMac copy is enabled for the specified key_id (ReadKey=0). If key_id + /// is even, this should be the 32-byte key value for the slot key_id+1, otherwise this should be set to slot_key. + const uint8_t * target_key; + struct atca_temp_key *temp_key; //!< [in,out] Current state of TempKey. Required if mode[0] or mode[1] are 1. +} atca_check_mac_in_out_t; + + +/** \struct atca_verify_in_out + * \brief Input/output parameters for function atcah_verify(). + * \var atca_verify_in_out::curve_type + * \brief [in] Curve type used in Verify command (Param2). + * \var atca_verify_in_out::signature + * \brief [in] Pointer to ECDSA signature to be verified + * \var atca_verify_in_out::public_key + * \brief [in] Pointer to the public key to be used for verification + * \var atca_verify_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +typedef struct atca_verify_in_out +{ + uint16_t curve_type; + const uint8_t * signature; + const uint8_t * public_key; + struct atca_temp_key *temp_key; +} atca_verify_in_out_t; + +/** \brief Input/output parameters for calculating the PubKey digest put into + * TempKey by the GenKey command with the + * atcah_gen_key_msg() function. + */ +typedef struct atca_gen_key_in_out +{ + uint8_t mode; //!< [in] GenKey Mode + uint16_t key_id; //!< [in] GenKey KeyID + const uint8_t * public_key; //!< [in] Public key to be used in the PubKey digest. X and Y integers in big-endian format. 64 bytes for P256 curve. + size_t public_key_size; //!< [in] Total number of bytes in the public key. 64 bytes for P256 curve. + const uint8_t * other_data; //!< [in] 3 bytes required when bit 4 of the mode is set. Can be NULL otherwise. + const uint8_t * sn; //!< [in] Device serial number SN[0:8] (9 bytes). Only SN[0:1] and SN[8] are required though. + struct atca_temp_key *temp_key; //!< [in,out] As input the current state of TempKey. As output, the resulting PubKEy digest. +} atca_gen_key_in_out_t; + +/** \brief Input/output parameters for calculating the message and digest used + * by the Sign(internal) command. Used with the + * atcah_sign_internal_msg() function. + */ +typedef struct atca_sign_internal_in_out +{ + uint8_t mode; //!< [in] Sign Mode + uint16_t key_id; //!< [in] Sign KeyID + uint16_t slot_config; //!< [in] SlotConfig[TempKeyFlags.keyId] + uint16_t key_config; //!< [in] KeyConfig[TempKeyFlags.keyId] + uint8_t use_flag; //!< [in] UseFlag[TempKeyFlags.keyId], 0x00 for slots 8 and above and for ATECC508A + uint8_t update_count; //!< [in] UpdateCount[TempKeyFlags.keyId], 0x00 for slots 8 and above and for ATECC508A + bool is_slot_locked; //!< [in] Is TempKeyFlags.keyId slot locked. + bool for_invalidate; //!< [in] Set to true if this will be used for the Verify(Invalidate) command. + const uint8_t * sn; //!< [in] Device serial number SN[0:8] (9 bytes) + const struct atca_temp_key *temp_key; //!< [in] The current state of TempKey. + uint8_t* message; //!< [out] Full 55 byte message the Sign(internal) command will build. Can be NULL if not required. + uint8_t* verify_other_data; //!< [out] The 19 byte OtherData bytes to be used with the Verify(In/Validate) command. Can be NULL if not required. + uint8_t* digest; //!< [out] SHA256 digest of the full 55 byte message. Can be NULL if not required. +} atca_sign_internal_in_out_t; + +/** \brief Input/Output paramters for calculating the session key + * by the nonce command. Used with the atcah_gen_session_key() function. + */ +typedef struct atca_session_key_in_out +{ + uint8_t* transport_key; + uint16_t transport_key_id; + const uint8_t* sn; + uint8_t* nonce; + uint8_t* session_key; +}atca_session_key_in_out_t; + +#ifdef __cplusplus +extern "C" { +#endif + +ATCA_STATUS atcah_nonce(struct atca_nonce_in_out *param); +ATCA_STATUS atcah_mac(struct atca_mac_in_out *param); +ATCA_STATUS atcah_check_mac(struct atca_check_mac_in_out *param); +ATCA_STATUS atcah_hmac(struct atca_hmac_in_out *param); +ATCA_STATUS atcah_gen_dig(struct atca_gen_dig_in_out *param); +ATCA_STATUS atcah_gen_mac(struct atca_gen_dig_in_out *param); +ATCA_STATUS atcah_write_auth_mac(struct atca_write_mac_in_out *param); +ATCA_STATUS atcah_privwrite_auth_mac(struct atca_write_mac_in_out *param); +ATCA_STATUS atcah_derive_key(struct atca_derive_key_in_out *param); +ATCA_STATUS atcah_derive_key_mac(struct atca_derive_key_mac_in_out *param); +ATCA_STATUS atcah_decrypt(struct atca_decrypt_in_out *param); +ATCA_STATUS atcah_sha256(int32_t len, const uint8_t *message, uint8_t *digest); +uint8_t *atcah_include_data(struct atca_include_data_in_out *param); +ATCA_STATUS atcah_gen_key_msg(struct atca_gen_key_in_out *param); +ATCA_STATUS atcah_config_to_sign_internal(ATCADeviceType device_type, struct atca_sign_internal_in_out *param, const uint8_t* config); +ATCA_STATUS atcah_sign_internal_msg(ATCADeviceType device_type, struct atca_sign_internal_in_out *param); +ATCA_STATUS atcah_verify_mac(atca_verify_mac_in_out_t *param); +ATCA_STATUS atcah_secureboot_enc(atca_secureboot_enc_in_out_t* param); +ATCA_STATUS atcah_secureboot_mac(atca_secureboot_mac_in_out_t *param); +ATCA_STATUS atcah_encode_counter_match(uint32_t counter, uint8_t * counter_match); +ATCA_STATUS atcah_io_decrypt(struct atca_io_decrypt_in_out *param); +ATCA_STATUS atcah_ecc204_write_auth_mac(struct atca_write_mac_in_out *param); +ATCA_STATUS atcah_gen_session_key(atca_session_key_in_out_t *param); +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif //ATCA_HOST_H diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c new file mode 100644 index 0000000..b924bdc --- /dev/null +++ b/drivers/ecc108a/ecc108a.c @@ -0,0 +1,51 @@ +#include "py/runtime.h" +#include "atca_iface.h" +#include "atca_basic.h" + + +bool inited = false; +ATCAIfaceCfg cfg_atecc108a_i2c_default = { + .iface_type = ATCA_I2C_IFACE, + .devtype = ATECC108A, + { + .atcai2c.address = 0x60, + .atcai2c.bus = 0, + /* This is overridden in hal/hal_esp32_i2c.c but also read elsewhere */ + .atcai2c.baud = 100000, + }, + .wake_delay = 1500, + .rx_retries = 2 +}; + +STATIC mp_obj_t ecc108a_read_config() { + + int status = atcab_init(&cfg_atecc108a_i2c_default); + if (status < 0) { + mp_raise_OSError(status); + } + status = atcab_wakeup(); + if (status < 0) { + mp_raise_OSError(status); + } + + uint8_t buf[128] = {0}; + for (int i = 0; i < sizeof(buf); i += 32) { + status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 0, i, &buf[i], 32); + } + return mp_obj_new_bytearray_by_ref(sizeof(buf), buf); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_read_config_obj, ecc108a_read_config); + + +STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecc108a) }, + { MP_ROM_QSTR(MP_QSTR_read_config), MP_ROM_PTR(&ecc108a_read_config_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(ecc108a_module_globals, ecc108a_module_globals_table); + +const mp_obj_module_t ecc108a_user_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&ecc108a_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_ecc108a, ecc108a_user_module, 1); diff --git a/drivers/ecc108a/micropython.cmake b/drivers/ecc108a/micropython.cmake new file mode 100644 index 0000000..9b4bb3f --- /dev/null +++ b/drivers/ecc108a/micropython.cmake @@ -0,0 +1,58 @@ +# Create an INTERFACE library for our C module. +add_library(usermod_ecc108a INTERFACE) + +# Add our source files to the lib +target_sources(usermod_ecc108a INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/ecc108a.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_basic.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_cfgs.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_debug.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_device.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_helpers.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_iface.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_utils_sizes.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/cryptoauthlib.h +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_hmac.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_lock.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_secureboot.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_mac.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_nonce.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_updateextra.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_write.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_read.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_aes_gcm.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_ecdh.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_gendig.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_derivekey.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_genkey.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_execution.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_verify.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_sign.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_helpers.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_counter.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_selftest.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_basic.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_random.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_command.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_sha.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_privwrite.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_kdf.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_aes.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_checkmac.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_info.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/hal/atca_hal.c +# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/hal/hal_esp32_i2c.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/hal/hal_esp32_mp_softi2c.c +) + +target_include_directories(usermod_tidal_usb INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/hal + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/host +) + +# Link our INTERFACE library to the usermod target. +target_link_libraries(usermod INTERFACE usermod_ecc108a) + diff --git a/drivers/micropython.cmake b/drivers/micropython.cmake index 8158dc2..0e74971 100644 --- a/drivers/micropython.cmake +++ b/drivers/micropython.cmake @@ -9,6 +9,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/tidal_usb/micropython.cmake) # Add the st7789 driver include(${CMAKE_CURRENT_LIST_DIR}/../st7789/st7789/micropython.cmake) +# ECC108A driver +include(${CMAKE_CURRENT_LIST_DIR}/ecc108a/micropython.cmake) list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/components/esp_http_client" diff --git a/modules/ecc108a_tools/dump_config.py b/modules/ecc108a_tools/dump_config.py new file mode 100644 index 0000000..8dff53c --- /dev/null +++ b/modules/ecc108a_tools/dump_config.py @@ -0,0 +1,57 @@ +import ecc108a + +def run(): + config = ecc108a.read_config() + + serial_number = config[0:4] + config[8:13] + serial_number_str = ' '.join(f'{c:02x}' for c in serial_number) + print(f"Serial number: {serial_number_str}") + print(f"Revision number: {hex(int.from_bytes(config[4:8], 'little'))}") + print(f"Reserved 1: {hex(config[13])}") + print(f"Interface mode: {'I2C' if config[14] & 1 else 'SWI'}") + print(f"Reserved 2: {hex(config[14] & 0xfe)} {hex(config[15])}") + if config[14] & 1: + print(f"I2C address: {hex(config[16])}") + else: + print(f"GPIO mode: {hex(config[16])}") + print(f"Reserved 3: {hex(config[17])}") + otp_modes = {0xaa: 'read-only', 0x55: 'consumption', 0x0: 'legacy'} + print(f"OTP mode: {hex(config[18])} ({otp_modes.get(config[18], 'unknown')})") + print(f"Selector mode: {'only zero' if config[19] & 1 else 'unlimited'}") + print(f"TTL reference mode: {'VCC' if config[19] & 2 else 'fixed'}") + print(f"Watchdog timeout: {'10s' if config[19] & 4 else '1.3s'}") + print(f"Reserved 4: {hex(config[19] & 0xf8)}") + + print(f"UserExtra: {hex(config[84])}") + print(f"Selector: {hex(config[85])}") + lock_state = {0x55: 'unlocked', 0: 'locked'} + print(f"LockValue: {hex(config[86])} ({lock_state[config[86]]})") + print(f"LockConfig: {hex(config[87])} ({lock_state[config[87]]})") + + slotlocked = int.from_bytes(config[88:90], 'little') + + print(f"Reserved 5: {hex(config[90])}") # "must be zero" actually 0xffff, and changes when keys are modified somehow + print(f"Reserved 6: {hex(config[91])}") + + for cert in range(4): + print(f"X509format[{cert}].PublicPosition: {config[92 + cert] & 0xf}") + print(f"X509format[{cert}].TemplateLength: {(config[92 + cert] >> 4) & 0xf}") + + for key in range(16): + print(f"Key {key}:") + print(f" SlotLocked: {'1 (unlocked)' if slotlocked & (1 << key) else '0 (locked)'}") + + slotconfig = int.from_bytes(config[key * 2:][20:22], 'little') + keyconfig = int.from_bytes(config[key * 2:][96:98], 'little') + + if key < 8: + print(f" UseFlag: {hex(config[52 + key * 2])}") + update_count = config[53 + key * 2] + print(f" UpdateCount: {config[53 + key * 2]}") + + if key == 15: + keyuse_str = ' '.join(f'{c:02x}' for c in config[68:84]) + print(f" Key use: {keyuse_str}") + + # If private, Sign, GenKey and PrivWrite are the only commands that work, and vice versa + From 260af72b8c0472a4045a7ac0d196273465e7ae03 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sat, 30 Jul 2022 18:32:41 +0100 Subject: [PATCH 06/32] Add get serial number for ecc108 --- drivers/ecc108a/ecc108a.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index b924bdc..c122f61 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -19,12 +19,12 @@ ATCAIfaceCfg cfg_atecc108a_i2c_default = { STATIC mp_obj_t ecc108a_read_config() { - int status = atcab_init(&cfg_atecc108a_i2c_default); - if (status < 0) { + ATCA_STATUS status = atcab_init(&cfg_atecc108a_i2c_default); + if (status != ATCA_SUCCESS) { mp_raise_OSError(status); } status = atcab_wakeup(); - if (status < 0) { + if (status != ATCA_SUCCESS) { mp_raise_OSError(status); } @@ -37,9 +37,30 @@ STATIC mp_obj_t ecc108a_read_config() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_read_config_obj, ecc108a_read_config); +STATIC mp_obj_t ecc108a_get_serial_number() { + uint8_t serial[9] = { 0 }; + char serial_str[27] = ""; + ATCA_STATUS status = atcab_read_serial_number(&serial); + if (status != ATCA_SUCCESS) { + mp_raise_OSError(status); + } + + sprintf(&serial_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + serial[0], serial[1], serial[2], + serial[3], serial[4], serial[5], + serial[6], serial[7], serial[8] + ); + + return mp_obj_new_str(serial_str, 26); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_get_serial_number_obj, ecc108a_get_serial_number); + + + STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecc108a) }, { MP_ROM_QSTR(MP_QSTR_read_config), MP_ROM_PTR(&ecc108a_read_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&ecc108a_get_serial_number_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ecc108a_module_globals, ecc108a_module_globals_table); From ed6dc1df6507146e30299b3c3ea6ab6e8c4aed13 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sat, 30 Jul 2022 20:19:47 +0100 Subject: [PATCH 07/32] Update ECC108A interface Fix reading of config zone to get all 128 bytes, split initialisation into a helper function and initial (non-working) version of genkey. --- drivers/ecc108a/ecc108a.c | 52 +++++++++++++------ .../{dump_config.py => __init__.py} | 8 +-- 2 files changed, 42 insertions(+), 18 deletions(-) rename modules/ecc108a_tools/{dump_config.py => __init__.py} (91%) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index c122f61..67c1832 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -17,22 +17,25 @@ ATCAIfaceCfg cfg_atecc108a_i2c_default = { .rx_retries = 2 }; -STATIC mp_obj_t ecc108a_read_config() { - - ATCA_STATUS status = atcab_init(&cfg_atecc108a_i2c_default); - if (status != ATCA_SUCCESS) { - mp_raise_OSError(status); - } - status = atcab_wakeup(); +void assert_ATCA_SUCCESS(ATCA_STATUS status) { if (status != ATCA_SUCCESS) { mp_raise_OSError(status); } +} + +STATIC mp_obj_t ecc108a_init() { + assert_ATCA_SUCCESS(atcab_init(&cfg_atecc108a_i2c_default)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_init_obj, ecc108a_init); + + +STATIC mp_obj_t ecc108a_read_config() { + assert_ATCA_SUCCESS(atcab_wakeup()); uint8_t buf[128] = {0}; - for (int i = 0; i < sizeof(buf); i += 32) { - status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 0, i, &buf[i], 32); - } - return mp_obj_new_bytearray_by_ref(sizeof(buf), buf); + assert_ATCA_SUCCESS(atcab_read_config_zone(&buf)); + return mp_obj_new_bytearray(sizeof(buf), buf); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_read_config_obj, ecc108a_read_config); @@ -40,10 +43,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_read_config_obj, ecc108a_read_config); STATIC mp_obj_t ecc108a_get_serial_number() { uint8_t serial[9] = { 0 }; char serial_str[27] = ""; - ATCA_STATUS status = atcab_read_serial_number(&serial); - if (status != ATCA_SUCCESS) { - mp_raise_OSError(status); - } + + assert_ATCA_SUCCESS(atcab_wakeup()); + assert_ATCA_SUCCESS(atcab_read_serial_number(&serial)); sprintf(&serial_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", serial[0], serial[1], serial[2], @@ -56,11 +58,31 @@ STATIC mp_obj_t ecc108a_get_serial_number() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_get_serial_number_obj, ecc108a_get_serial_number); +STATIC mp_obj_t ecc108a_genkey() { + uint8_t pubkey[64] = { 0 }; + + assert_ATCA_SUCCESS(atcab_wakeup()); + assert_ATCA_SUCCESS(atcab_genkey(ATCA_TEMPKEY_KEYID, &pubkey)); + + for (int i=0;i<64;i++) { + if (i%8 == 0) { + printf("\n"); + } + printf("%02x ", pubkey[i]); + } + printf("\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_genkey_obj, ecc108a_genkey); + + STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecc108a) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&ecc108a_init_obj) }, { MP_ROM_QSTR(MP_QSTR_read_config), MP_ROM_PTR(&ecc108a_read_config_obj) }, { MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&ecc108a_get_serial_number_obj) }, + { MP_ROM_QSTR(MP_QSTR_genkey), MP_ROM_PTR(&ecc108a_genkey_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ecc108a_module_globals, ecc108a_module_globals_table); diff --git a/modules/ecc108a_tools/dump_config.py b/modules/ecc108a_tools/__init__.py similarity index 91% rename from modules/ecc108a_tools/dump_config.py rename to modules/ecc108a_tools/__init__.py index 8dff53c..2ebf050 100644 --- a/modules/ecc108a_tools/dump_config.py +++ b/modules/ecc108a_tools/__init__.py @@ -1,6 +1,9 @@ import ecc108a +lock_state = {0x55: 'unlocked', 0: 'locked'} + def run(): + ecc108a.init() config = ecc108a.read_config() serial_number = config[0:4] + config[8:13] @@ -24,9 +27,8 @@ def run(): print(f"UserExtra: {hex(config[84])}") print(f"Selector: {hex(config[85])}") - lock_state = {0x55: 'unlocked', 0: 'locked'} - print(f"LockValue: {hex(config[86])} ({lock_state[config[86]]})") - print(f"LockConfig: {hex(config[87])} ({lock_state[config[87]]})") + print(f"LockValue: {hex(config[86])} ({lock_state.get(config[86])})") + print(f"LockConfig: {hex(config[87])} ({lock_state.get(config[87])})") slotlocked = int.from_bytes(config[88:90], 'little') From 6995c4729ece21808b243fb2c5712bf58e7eef54 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 21 Aug 2022 13:52:44 +0100 Subject: [PATCH 08/32] Attempts to configure keys This sets up slot configs, suspected bit packing errors causing this not to work. It also exposes the lock functions in Python. Be very careful. --- .../ecc108a/cryptoauthlib/calib/calib_write.c | 4 +- drivers/ecc108a/ecc108a.c | 136 +++++++++++++++++- drivers/ecc108a/micropython.cmake | 2 +- modules/ecc108a_tools/__init__.py | 2 + 4 files changed, 138 insertions(+), 6 deletions(-) diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_write.c b/drivers/ecc108a/cryptoauthlib/calib/calib_write.c index d07b686..acd9aa0 100644 --- a/drivers/ecc108a/cryptoauthlib/calib/calib_write.c +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_write.c @@ -187,6 +187,8 @@ ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, c ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, const uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE]) { #endif + return ATCA_EXECUTION_ERROR; + /* ATCA_STATUS status = ATCA_GEN_FAIL; uint8_t zone = ATCA_ZONE_DATA | ATCA_ZONE_READWRITE_32; atca_nonce_in_out_t nonce_params; @@ -299,7 +301,7 @@ ATCA_STATUS calib_write_enc(ATCADevice device, uint16_t key_id, uint8_t block, c } while (0); - return status; + return status;*/ } /** \brief Executes the Write command, which writes the configuration zone. diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 67c1832..e48af9f 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -2,6 +2,29 @@ #include "atca_iface.h" #include "atca_basic.h" +struct SlotConfig { + uint16_t ReadKey : 4; + uint16_t NoMac : 1; + uint16_t LimitedUse : 1; + uint16_t EncryptRead : 1; + uint16_t IsSecret : 1; + uint16_t WriteKey : 4; + uint16_t WriteConfig : 4; +} __attribute__((packed)); + +struct KeyConfig { + uint16_t Private : 1; + uint16_t PubInfo : 1; + uint16_t KeyType : 3; + uint16_t Lockable : 1; + uint16_t ReqRandom : 1; + uint16_t ReqAuth : 1; + uint16_t AuthKey : 4; + uint16_t IntrusionDisable : 1; + uint16_t RFU : 1; + uint16_t X509Id : 2; +} __attribute__((packed)); + bool inited = false; ATCAIfaceCfg cfg_atecc108a_i2c_default = { @@ -17,6 +40,42 @@ ATCAIfaceCfg cfg_atecc108a_i2c_default = { .rx_retries = 2 }; + +void pack_slot_config(struct SlotConfig config, uint8_t *config_zone) { + // Is this right? + config_zone[0] = ( + config.ReadKey << 4 | + config.NoMac << 3 | + config.LimitedUse << 2 | + config.EncryptRead << 1 | + config.IsSecret << 0 + ); + config_zone[1] = ( + config.WriteKey << 4 | + config.WriteConfig << 0 + ); +} + + +void pack_key_config(struct KeyConfig config, uint8_t *config_zone) { + // Is this right? + config_zone[0] = ( + config.Private << 7 | + config.PubInfo << 6 | + config.KeyType << 3 | + config.Lockable << 2 | + config.ReqRandom << 1 | + config.ReqAuth << 0 + ); + config_zone[1] = ( + config.AuthKey << 4 | + config.IntrusionDisable << 2 | + config.RFU << 1 | + config.X509Id << 0 + ); +} + + void assert_ATCA_SUCCESS(ATCA_STATUS status) { if (status != ATCA_SUCCESS) { mp_raise_OSError(status); @@ -58,11 +117,76 @@ STATIC mp_obj_t ecc108a_get_serial_number() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_get_serial_number_obj, ecc108a_get_serial_number); -STATIC mp_obj_t ecc108a_genkey() { +STATIC mp_obj_t ecc108a_provision_slot() { + uint8_t buf[128] = {0}; + + assert_ATCA_SUCCESS(atcab_read_config_zone(&buf)); + struct SlotConfig slot_config = { + .ReadKey = 0b1100, // Bit 0 - sign arbitrary messages + // Bit 1 - sign internal messages + .NoMac = 0, // Bit 4 - Do not disable HMAC + .LimitedUse = 0, // Bit 5 - No usage limitations + .EncryptRead = 0, // Bit 6 - Cleartext read okay + .IsSecret = 1, // Bit 7 - Contents are secret + .WriteKey = 0b0000, // Bits 9-11 - Write using key 0 + .WriteConfig = 0b1110 // Bit 12 - Source key, parent + // Bit 13 - Clear text write off + // Bit 14 - Encryption on + // Bit 15 - Unset No authorising MAC needed + }; + struct KeyConfig key_config = { + .Private = 1, // Bit 0 - Contains private key + .PubInfo = 1, // Bit 1 - Allow public key access + .KeyType = 4, // Bits 2 to 4 - P256 key + .Lockable = 1, // Bit 5 - Individual lockable + .ReqRandom = 0, // Bit 6 - No random nonce needed + .ReqAuth = 0, // Bit 7 - No prior auth needed + .AuthKey = 0, // Bits 8 to 11 - Use key 0 for auth + .IntrusionDisable = 0, // Bit 12 - Ignore intrusion latch + .RFU = 0, // Bit 13 - Fixed value + .X509Id = 0 // Bits 14 and 15 - 0 as not a public key + }; + + // Patch this config into each of the 16 slots + for (uint8_t i = 0; i < 16 ; i++) { + pack_slot_config(slot_config, &buf[20 + 2*i]); + pack_key_config(key_config, &buf[96 + 2*i]); + } + + assert_ATCA_SUCCESS(atcab_write_config_zone(&buf)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_provision_slot_obj, ecc108a_provision_slot); + + +STATIC mp_obj_t ecc108a_lock_data_zone() { + assert_ATCA_SUCCESS(atcab_lock_data_zone()); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_lock_data_zone_obj, ecc108a_lock_data_zone); + + +STATIC mp_obj_t ecc108a_lock_config_zone() { + assert_ATCA_SUCCESS(atcab_lock_config_zone()); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_lock_config_zone_obj, ecc108a_lock_config_zone); + + +STATIC mp_obj_t ecc108a_lock_slot(mp_obj_t slot_id) { + uint8_t slot = mp_obj_get_int(slot_id); + assert_ATCA_SUCCESS(atcab_lock_data_slot(slot)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ecc108a_lock_slot_obj, ecc108a_lock_slot); + + +STATIC mp_obj_t ecc108a_genkey(mp_obj_t slot_id) { uint8_t pubkey[64] = { 0 }; + uint8_t slot = mp_obj_get_int(slot_id); - assert_ATCA_SUCCESS(atcab_wakeup()); - assert_ATCA_SUCCESS(atcab_genkey(ATCA_TEMPKEY_KEYID, &pubkey)); + //assert_ATCA_SUCCESS(atcab_wakeup()); + assert_ATCA_SUCCESS(atcab_genkey(slot, &pubkey)); for (int i=0;i<64;i++) { if (i%8 == 0) { @@ -73,7 +197,7 @@ STATIC mp_obj_t ecc108a_genkey() { printf("\n"); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_genkey_obj, ecc108a_genkey); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ecc108a_genkey_obj, ecc108a_genkey); @@ -81,6 +205,10 @@ STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecc108a) }, { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&ecc108a_init_obj) }, { MP_ROM_QSTR(MP_QSTR_read_config), MP_ROM_PTR(&ecc108a_read_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_provision_slot), MP_ROM_PTR(&ecc108a_provision_slot_obj) }, + { MP_ROM_QSTR(MP_QSTR_lock_data_zone), MP_ROM_PTR(&ecc108a_lock_data_zone_obj) }, + { MP_ROM_QSTR(MP_QSTR_lock_config_zone), MP_ROM_PTR(&ecc108a_lock_config_zone_obj) }, + { MP_ROM_QSTR(MP_QSTR_lock_slot), MP_ROM_PTR(&ecc108a_lock_slot_obj) }, { MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&ecc108a_get_serial_number_obj) }, { MP_ROM_QSTR(MP_QSTR_genkey), MP_ROM_PTR(&ecc108a_genkey_obj) }, }; diff --git a/drivers/ecc108a/micropython.cmake b/drivers/ecc108a/micropython.cmake index 9b4bb3f..7a90513 100644 --- a/drivers/ecc108a/micropython.cmake +++ b/drivers/ecc108a/micropython.cmake @@ -17,7 +17,7 @@ target_sources(usermod_ecc108a INTERFACE # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_secureboot.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_mac.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_nonce.c -# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_updateextra.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_updateextra.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_write.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_read.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_aes_gcm.c diff --git a/modules/ecc108a_tools/__init__.py b/modules/ecc108a_tools/__init__.py index 2ebf050..1774086 100644 --- a/modules/ecc108a_tools/__init__.py +++ b/modules/ecc108a_tools/__init__.py @@ -45,6 +45,8 @@ def run(): slotconfig = int.from_bytes(config[key * 2:][20:22], 'little') keyconfig = int.from_bytes(config[key * 2:][96:98], 'little') + print(f" SlotConfig: {slotconfig:04x}") + print(f" KeyConfig: {keyconfig:04x}") if key < 8: print(f" UseFlag: {hex(config[52 + key * 2])}") From 6cec8896e90b9a049b1a92fbb5b3bc78e9da1c1c Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 21 Aug 2022 13:54:42 +0100 Subject: [PATCH 09/32] Include calib updatextra --- .../cryptoauthlib/calib/calib_updateextra.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_updateextra.c diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_updateextra.c b/drivers/ecc108a/cryptoauthlib/calib/calib_updateextra.c new file mode 100644 index 0000000..7f55bea --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_updateextra.c @@ -0,0 +1,84 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for UpdateExtra command. + * + * The UpdateExtra command is used to update the values of the two extra bytes + * within the Configuration zone after the Configuration zone has been locked. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, and ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Executes UpdateExtra command to update the values of the two + * extra bytes within the Configuration zone (bytes 84 and 85). + * + * Can also be used to decrement the limited use counter associated with the + * key in slot NewValue. + * + * \param[in] device Device context pointer + * \param[in] mode Mode determines what operations the UpdateExtra + * command performs. + * \param[in] new_value Value to be written. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_updateextra(ATCADevice device, uint8_t mode, uint16_t new_value) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + + do + { + if (device == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // Build command + memset(&packet, 0, sizeof(packet)); + packet.param1 = mode; + packet.param2 = new_value; + + if ((status = atUpdateExtra(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atUpdateExtra - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_updateextra - execution failed"); + break; + } + + } + while (0); + + return status; +} From 7b0596a88228f13e6bbc45e15312693653601a45 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 29 Aug 2022 18:27:11 +0100 Subject: [PATCH 10/32] Provision ATECC108A and offer some initial helper functions This allows provisioning the 108A to the point that genkey can be called, and offers helper functions for some basic funtionality. These functions can easily brick your badge, so don't run them unless you know what you're doing. The crypto outputs haven't been verified yet. --- .../ecc108a/cryptoauthlib/calib/calib_nonce.c | 236 ++++++++++++++++++ drivers/ecc108a/ecc108a.c | 164 ++++++------ drivers/ecc108a/micropython.cmake | 2 +- 3 files changed, 307 insertions(+), 95 deletions(-) create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_nonce.c diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_nonce.c b/drivers/ecc108a/cryptoauthlib/calib/calib_nonce.c new file mode 100644 index 0000000..35e65fd --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_nonce.c @@ -0,0 +1,236 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Nonce command. + * + * The Nonce command generates a nonce for use by a subsequent commands of the + * device by combining an internally generated random number with an input value + * from the system. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, and ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +/** \brief Executes Nonce command, which loads a random or fixed nonce/data + * into the device for use by subsequent commands. + * + * \param[in] device Device context pointer + * \param[in] mode Controls the mechanism of the internal RNG or fixed + * write. + * \param[in] param2 Param2, normally 0, but can be used to indicate a + * nonce calculation mode (bit 15). + * For ECC204, represent tarnsport key id greater than + * or equal to 0x8000 + * \param[in] num_in Input value to either be included in the nonce + * calculation in random modes (20 bytes) or to be + * written directly (32 bytes or 64 bytes(ATECC608)) + * in pass-through mode. + * \param[out] rand_out If using a random mode, the internally generated + * 32-byte random number that was used in the nonce + * calculation is returned here. Can be NULL if not + * needed. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_nonce_base(ATCADevice device, uint8_t mode, uint16_t param2, const uint8_t *num_in, uint8_t* rand_out) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t nonce_mode = mode & NONCE_MODE_MASK; + + do + { + if (device == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + break; + } + + // build a nonce command + packet.param1 = mode; + packet.param2 = param2; + + // Copy the right amount of NumIn data + if ((nonce_mode == NONCE_MODE_SEED_UPDATE) || (nonce_mode == NONCE_MODE_NO_SEED_UPDATE) + || (NONCE_MODE_GEN_SESSION_KEY == nonce_mode)) + { + memcpy(packet.data, num_in, NONCE_NUMIN_SIZE); + } + else if (nonce_mode == NONCE_MODE_PASSTHROUGH) + { + if ((mode & NONCE_MODE_INPUT_LEN_MASK) == NONCE_MODE_INPUT_LEN_64) + { + memcpy(packet.data, num_in, 64); + } + else + { + memcpy(packet.data, num_in, 32); + } + } + else + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid nonce mode received"); + } + + if ((status = atNonce(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atNonce - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_nonce_base - execution failed"); + break; + } + + if ((rand_out != NULL) && (packet.data[ATCA_COUNT_IDX] >= 35)) + { + memcpy(&rand_out[0], &packet.data[ATCA_RSP_DATA_IDX], 32); + } + + } + while (0); + + return status; +} + + +/** \brief Execute a Nonce command in pass-through mode to initialize TempKey + * to a specified value. + * + * \param[in] device Device context pointer + * \param[in] num_in Data to be loaded into TempKey (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_nonce(ATCADevice device, const uint8_t *num_in) +{ + return calib_nonce_base(device, NONCE_MODE_PASSTHROUGH, 0, num_in, NULL); +} + + +/** \brief Execute a Nonce command in pass-through mode to load one of the + * device's internal buffers with a fixed value. + * + * For the ATECC608, available targets are TempKey (32 or 64 bytes), Message + * Digest Buffer (32 or 64 bytes), or the Alternate Key Buffer (32 bytes). For + * all other devices, only TempKey (32 bytes) is available. + * + * \param[in] device Device context pointer + * \param[in] target Target device buffer to load. Can be + * NONCE_MODE_TARGET_TEMPKEY, + * NONCE_MODE_TARGET_MSGDIGBUF, or + * NONCE_MODE_TARGET_ALTKEYBUF. + * \param[in] num_in Data to load into the buffer. + * \param[in] num_in_size Size of num_in in bytes. Can be 32 or 64 bytes + * depending on device and target. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_nonce_load(ATCADevice device, uint8_t target, const uint8_t *num_in, uint16_t num_in_size) +{ + uint8_t mode = NONCE_MODE_PASSTHROUGH | (NONCE_MODE_TARGET_MASK & target); + + if (num_in_size == 32) + { + mode |= NONCE_MODE_INPUT_LEN_32; + } + else if (num_in_size == 64) + { + mode |= NONCE_MODE_INPUT_LEN_64; + } + else + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid size received"); + } + + return calib_nonce_base(device, mode, 0, num_in, NULL); +} + +/** \brief Execute a Nonce command to generate a random nonce combining a host + * nonce (num_in) and a device random number. + * + * \param[in] device Device context pointer + * \param[in] num_in Host nonce to be combined with the device random + * number (20 bytes). + * \param[out] rand_out Internally generated 32-byte random number that was + * used in the nonce/challenge calculation is returned + * here. Can be NULL if not needed. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_nonce_rand(ATCADevice device, const uint8_t *num_in, uint8_t* rand_out) +{ + return calib_nonce_base(device, NONCE_MODE_SEED_UPDATE, 0, num_in, rand_out); +} + +/** \brief Execute a Nonce command in pass-through mode to initialize TempKey + * to a specified value. + * + * \param[in] device Device context pointer + * \param[in] num_in Data to be loaded into TempKey (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_challenge(ATCADevice device, const uint8_t *num_in) +{ + return calib_nonce_base(device, NONCE_MODE_PASSTHROUGH, 0, num_in, NULL); +} + +/** \brief Execute a Nonce command to generate a random challenge combining + * a host nonce (num_in) and a device random number. + * + * \param[in] device Device context pointer + * \param[in] num_in Host nonce to be combined with the device random + * number (20 bytes). + * \param[out] rand_out Internally generated 32-byte random number that was + * used in the nonce/challenge calculation is returned + * here. Can be NULL if not needed. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_challenge_seed_update(ATCADevice device, const uint8_t *num_in, uint8_t* rand_out) +{ + return calib_nonce_base(device, NONCE_MODE_SEED_UPDATE, 0, num_in, rand_out); +} + +/** \brief Use Nonce command to generate session key for use by a subsequent write command + * This Mode only supports in ECC204 device. + * \param[in] device Device context pointer + * \param[in] param2 Key id points to transport key + * \param[in] num_in Input value from host system + * \param[out] rand_out Internally generate random number of 32 bytes + * returned here + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_nonce_gen_session_key(ATCADevice device, uint16_t param2, uint8_t* num_in, + uint8_t* rand_out) +{ + return calib_nonce_base(device, NONCE_MODE_GEN_SESSION_KEY, param2, num_in, rand_out); +} diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index e48af9f..48ce386 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -1,29 +1,8 @@ #include "py/runtime.h" #include "atca_iface.h" #include "atca_basic.h" - -struct SlotConfig { - uint16_t ReadKey : 4; - uint16_t NoMac : 1; - uint16_t LimitedUse : 1; - uint16_t EncryptRead : 1; - uint16_t IsSecret : 1; - uint16_t WriteKey : 4; - uint16_t WriteConfig : 4; -} __attribute__((packed)); - -struct KeyConfig { - uint16_t Private : 1; - uint16_t PubInfo : 1; - uint16_t KeyType : 3; - uint16_t Lockable : 1; - uint16_t ReqRandom : 1; - uint16_t ReqAuth : 1; - uint16_t AuthKey : 4; - uint16_t IntrusionDisable : 1; - uint16_t RFU : 1; - uint16_t X509Id : 2; -} __attribute__((packed)); +#include "py/objstr.h" +#include bool inited = false; @@ -41,41 +20,6 @@ ATCAIfaceCfg cfg_atecc108a_i2c_default = { }; -void pack_slot_config(struct SlotConfig config, uint8_t *config_zone) { - // Is this right? - config_zone[0] = ( - config.ReadKey << 4 | - config.NoMac << 3 | - config.LimitedUse << 2 | - config.EncryptRead << 1 | - config.IsSecret << 0 - ); - config_zone[1] = ( - config.WriteKey << 4 | - config.WriteConfig << 0 - ); -} - - -void pack_key_config(struct KeyConfig config, uint8_t *config_zone) { - // Is this right? - config_zone[0] = ( - config.Private << 7 | - config.PubInfo << 6 | - config.KeyType << 3 | - config.Lockable << 2 | - config.ReqRandom << 1 | - config.ReqAuth << 0 - ); - config_zone[1] = ( - config.AuthKey << 4 | - config.IntrusionDisable << 2 | - config.RFU << 1 | - config.X509Id << 0 - ); -} - - void assert_ATCA_SUCCESS(ATCA_STATUS status) { if (status != ATCA_SUCCESS) { mp_raise_OSError(status); @@ -118,39 +62,31 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_get_serial_number_obj, ecc108a_get_seri STATIC mp_obj_t ecc108a_provision_slot() { + // Retrieve the current configuration zone uint8_t buf[128] = {0}; - assert_ATCA_SUCCESS(atcab_read_config_zone(&buf)); - struct SlotConfig slot_config = { - .ReadKey = 0b1100, // Bit 0 - sign arbitrary messages - // Bit 1 - sign internal messages - .NoMac = 0, // Bit 4 - Do not disable HMAC - .LimitedUse = 0, // Bit 5 - No usage limitations - .EncryptRead = 0, // Bit 6 - Cleartext read okay - .IsSecret = 1, // Bit 7 - Contents are secret - .WriteKey = 0b0000, // Bits 9-11 - Write using key 0 - .WriteConfig = 0b1110 // Bit 12 - Source key, parent - // Bit 13 - Clear text write off - // Bit 14 - Encryption on - // Bit 15 - Unset No authorising MAC needed - }; - struct KeyConfig key_config = { - .Private = 1, // Bit 0 - Contains private key - .PubInfo = 1, // Bit 1 - Allow public key access - .KeyType = 4, // Bits 2 to 4 - P256 key - .Lockable = 1, // Bit 5 - Individual lockable - .ReqRandom = 0, // Bit 6 - No random nonce needed - .ReqAuth = 0, // Bit 7 - No prior auth needed - .AuthKey = 0, // Bits 8 to 11 - Use key 0 for auth - .IntrusionDisable = 0, // Bit 12 - Ignore intrusion latch - .RFU = 0, // Bit 13 - Fixed value - .X509Id = 0 // Bits 14 and 15 - 0 as not a public key - }; + + uint16_t slot_config = + ATCA_SLOT_CONFIG_EXT_SIG_MASK | + ATCA_SLOT_CONFIG_INT_SIG_MASK | + ATCA_SLOT_CONFIG_IS_SECRET_MASK | + ATCA_SLOT_CONFIG_WRITE_KEY(0) | + ATCA_SLOT_CONFIG_WRITE_CONFIG(0b0110) + ; + uint16_t key_config = + ATCA_KEY_CONFIG_PRIVATE_MASK | + ATCA_KEY_CONFIG_PUB_INFO_MASK | + ATCA_KEY_CONFIG_KEY_TYPE(4) | + ATCA_KEY_CONFIG_LOCKABLE_MASK + ; // Patch this config into each of the 16 slots for (uint8_t i = 0; i < 16 ; i++) { - pack_slot_config(slot_config, &buf[20 + 2*i]); - pack_key_config(key_config, &buf[96 + 2*i]); + uint16_t *target_slot_config = &buf[20 + 2*i]; + *target_slot_config = slot_config; + + uint16_t *target_key_config = &buf[96 + 2*i]; + *target_key_config = key_config; } assert_ATCA_SUCCESS(atcab_write_config_zone(&buf)); @@ -188,18 +124,56 @@ STATIC mp_obj_t ecc108a_genkey(mp_obj_t slot_id) { //assert_ATCA_SUCCESS(atcab_wakeup()); assert_ATCA_SUCCESS(atcab_genkey(slot, &pubkey)); - for (int i=0;i<64;i++) { - if (i%8 == 0) { - printf("\n"); - } - printf("%02x ", pubkey[i]); - } - printf("\n"); - return mp_const_none; + // Return X, Y tuple + mp_obj_t tuple[2]; + uint32_t x = (pubkey[0] << 0*8) | (pubkey[1] << 1*8) | (pubkey[2] << 2*8) | (pubkey[3] << 3*8); + uint32_t y = (pubkey[4] << 0*8) | (pubkey[5] << 1*8) | (pubkey[6] << 2*8) | (pubkey[7] << 3*8); + tuple[0] = mp_obj_new_int_from_ull(x); + tuple[1] = mp_obj_new_int_from_ull(y); + return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(ecc108a_genkey_obj, ecc108a_genkey); +STATIC mp_obj_t ecc108a_get_pubkey(mp_obj_t slot_id) { + uint8_t pubkey[64] = { 0 }; + uint8_t slot = mp_obj_get_int(slot_id); + + //assert_ATCA_SUCCESS(atcab_wakeup()); + assert_ATCA_SUCCESS(atcab_get_pubkey(slot, &pubkey)); + + // Return X, Y tuple + mp_obj_t tuple[2]; + uint32_t x = (pubkey[0] << 0*8) | (pubkey[1] << 1*8) | (pubkey[2] << 2*8) | (pubkey[3] << 3*8); + uint32_t y = (pubkey[4] << 0*8) | (pubkey[5] << 1*8) | (pubkey[6] << 2*8) | (pubkey[7] << 3*8); + tuple[0] = mp_obj_new_int_from_ull(x); + tuple[1] = mp_obj_new_int_from_ull(y); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ecc108a_get_pubkey_obj, ecc108a_get_pubkey); + + +STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { + uint8_t signature[64] = { 0 }; + uint8_t slot = mp_obj_get_int(slot_id); + + mp_check_self(mp_obj_is_str_or_bytes(message)); + GET_STR_DATA_LEN(message, msg, str_len); + + //assert_ATCA_SUCCESS(atcab_wakeup()); + assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); + + // Return R, S tuple + mp_obj_t tuple[2]; + uint32_t r = (signature[0] << 0*8) | (signature[1] << 1*8) | (signature[2] << 2*8) | (signature[3] << 3*8); + uint32_t s = (signature[4] << 0*8) | (signature[5] << 1*8) | (signature[6] << 2*8) | (signature[7] << 3*8); + tuple[0] = mp_obj_new_int_from_ull(r); + tuple[1] = mp_obj_new_int_from_ull(s); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ecc108a_sign_obj, ecc108a_sign); + + STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecc108a) }, @@ -211,6 +185,8 @@ STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_lock_slot), MP_ROM_PTR(&ecc108a_lock_slot_obj) }, { MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&ecc108a_get_serial_number_obj) }, { MP_ROM_QSTR(MP_QSTR_genkey), MP_ROM_PTR(&ecc108a_genkey_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_pubkey), MP_ROM_PTR(&ecc108a_get_pubkey_obj) }, + { MP_ROM_QSTR(MP_QSTR_ecc108a_sign), MP_ROM_PTR(&ecc108a_sign_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ecc108a_module_globals, ecc108a_module_globals_table); diff --git a/drivers/ecc108a/micropython.cmake b/drivers/ecc108a/micropython.cmake index 7a90513..316bf39 100644 --- a/drivers/ecc108a/micropython.cmake +++ b/drivers/ecc108a/micropython.cmake @@ -16,7 +16,7 @@ target_sources(usermod_ecc108a INTERFACE ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_lock.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_secureboot.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_mac.c -# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_nonce.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_nonce.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_updateextra.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_write.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_read.c From 51ee31377b609e6e5005aa95393d80a7fc4e160d Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 27 Nov 2022 14:36:30 +0000 Subject: [PATCH 11/32] U2F Implementation includes crypto functions At this stage, the critical cryptographic functions of the U2F implementation are linked in. Unfortunately, it's not yet working, currently because the signature parameters aren't parsing correctly. I'm somewhat concerned that the fido raw message formats document specifies that cryptographic signatures are over the input bytestring, rather than the SHA-256 of that bytestring. The 108A only allows signatures of 32-byte strings, so I've gone that way. I don't think that's the problem I'm seeing yet though, I think it's a more general problem parsing. In addition, the code is currently hard-coded to use handle 1 for attestation and handle 6 for authentication. This is because only handle 6 is set up correctly on my main test device. Handle 1 will need the keys from keys/* loaded into it - I'm aware that it's silly to put a key in git, but in this case it's not part of the trust path and we have no way of distributing the key without exposing it unless we do it in person in 2024. No work yet on setting up the UI. --- .../ecc108a/cryptoauthlib/calib/calib_sha.c | 544 ++++++ .../cryptoauthlib/calib/calib_verify.c | 463 +++++ .../ecc108a/cryptoauthlib/host/atca_host.c | 1739 +++++++++++++++++ drivers/ecc108a/micropython.cmake | 5 +- drivers/tidal_usb/tidal_usb_console.c | 2 +- drivers/tidal_usb/tidal_usb_hid.c | 5 +- drivers/tidal_usb/tidal_usb_u2f.c | 17 +- drivers/tidal_usb/tidal_usb_u2f.h | 2 +- drivers/tidal_usb/u2f_crypto.c | 99 +- drivers/tidal_usb/u2f_crypto.h | 7 +- esp-iot-solution.diff | 4 +- keys/attestation.crt | 15 + keys/attestation.csr | 10 + keys/attestation.der | Bin 0 -> 590 bytes keys/attestation.h | 53 + keys/private.pem | 5 + keys/public.pem | 4 + modules/boot.py | 2 + tildamk6/sdkconfig.board | 5 +- 19 files changed, 2940 insertions(+), 41 deletions(-) create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_sha.c create mode 100644 drivers/ecc108a/cryptoauthlib/calib/calib_verify.c create mode 100644 drivers/ecc108a/cryptoauthlib/host/atca_host.c create mode 100644 keys/attestation.crt create mode 100644 keys/attestation.csr create mode 100644 keys/attestation.der create mode 100644 keys/attestation.h create mode 100644 keys/private.pem create mode 100644 keys/public.pem diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_sha.c b/drivers/ecc108a/cryptoauthlib/calib/calib_sha.c new file mode 100644 index 0000000..a8d9c23 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_sha.c @@ -0,0 +1,544 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for SHA command. + * + * The SHA command Computes a SHA-256 or HMAC/SHA digest for general purpose + * use by the host system. + * + * \note List of devices that support this command - ATSHA204A, ATECC108A, + * ATECC508A, and ATECC608A/B. There are differences in the modes that they + * support. Refer to device datasheets for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" + +typedef struct +{ + uint32_t total_msg_size; //!< Total number of message bytes processed + uint32_t block_size; //!< Number of bytes in current block + uint8_t block[ATCA_SHA256_BLOCK_SIZE * 2]; //!< Unprocessed message storage +} hw_sha256_ctx; + +/** \brief Executes SHA command, which computes a SHA-256 or HMAC/SHA-256 + * digest for general purpose use by the host system. + * + * Only the Start(0) and Compute(1) modes are available for ATSHA devices. + * + * \param[in] device Device context pointer + * \param[in] mode SHA command mode Start(0), Update/Compute(1), + * End(2), Public(3), HMACstart(4), HMACend(5), + * Read_Context(6), or Write_Context(7). Also + * message digest target location for the + * ATECC608. + * \param[in] length Number of bytes in the message parameter or + * KeySlot for the HMAC key if Mode is + * HMACstart(4) or Public(3). + * \param[in] message Message bytes to be hashed or Write_Context if + * restoring a context on the ATECC608. Can be + * NULL if not required by the mode. + * \param[out] data_out Data returned by the command (digest or + * context). + * \param[in,out] data_out_size As input, the size of the data_out buffer. As + * output, the number of bytes returned in + * data_out. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_base(ATCADevice device, uint8_t mode, uint16_t length, const uint8_t* message, uint8_t* data_out, uint16_t* data_out_size) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t cmd_mode = (mode & SHA_MODE_MASK); + + if (device == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + if (cmd_mode != SHA_MODE_SHA256_PUBLIC && cmd_mode != SHA_MODE_HMAC_START && + cmd_mode != SHA_MODE_ECC204_HMAC_START && length > 0 && message == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); // message data indicated, but nothing provided + } + if (data_out != NULL && data_out_size == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + do + { + //Build Command + packet.param1 = mode; + packet.param2 = length; + + if (cmd_mode != SHA_MODE_SHA256_PUBLIC && cmd_mode != SHA_MODE_HMAC_START && + cmd_mode != SHA_MODE_ECC204_HMAC_START) + { + memcpy(packet.data, message, (size_t)length); + } + + if ((status = atSHA(atcab_get_device_type_ext(device), &packet, length)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atSHA - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_sha_base - exection failed"); + break; + } + + if ((data_out != NULL) && (packet.data[ATCA_COUNT_IDX] > 4)) + { + if (packet.data[ATCA_COUNT_IDX] - ATCA_PACKET_OVERHEAD > *data_out_size) + { + status = ATCA_SMALL_BUFFER; + break; + } + *data_out_size = packet.data[ATCA_COUNT_IDX] - ATCA_PACKET_OVERHEAD; + memcpy(data_out, &packet.data[ATCA_RSP_DATA_IDX], *data_out_size); + } + } + while (0); + + return status; +} + +/** \brief Executes SHA command to initialize SHA-256 calculation engine + * \param[in] device Device context pointer + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_start(ATCADevice device) +{ + return calib_sha_base(device, SHA_MODE_SHA256_START, 0, NULL, NULL, NULL); +} + +/** \brief Executes SHA command to add 64 bytes of message data to the current + * context. + * + * \param[in] device Device context pointer + * \param[in] message 64 bytes of message data to add to add to operation. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_update(ATCADevice device, const uint8_t *message) +{ + return calib_sha_base(device, SHA_MODE_SHA256_UPDATE, 64, message, NULL, NULL); +} + +/** \brief Executes SHA command to complete SHA-256 or HMAC/SHA-256 operation. + * + * \param[in] device Device context pointer + * \param[out] digest Digest from SHA-256 or HMAC/SHA-256 will be returned + * here (32 bytes). + * \param[in] length Length of any remaining data to include in hash. Max 64 + * bytes. + * \param[in] message Remaining data to include in hash. NULL if length is 0. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_end(ATCADevice device, uint8_t *digest, uint16_t length, const uint8_t *message) +{ + uint16_t digest_size = 32; + + return calib_sha_base(device, SHA_MODE_SHA256_END, length, message, digest, &digest_size); +} + +/** \brief Executes SHA command to read the SHA-256 context back. Only for + * ATECC608 with SHA-256 contexts. HMAC not supported. + * + * \param[in] device Device context pointer + * \param[out] context Context data is returned here. + * \param[in,out] context_size As input, the size of the context buffer in + * bytes. As output, the size of the returned + * context data. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_read_context(ATCADevice device, uint8_t* context, uint16_t* context_size) +{ + return calib_sha_base(device, SHA_MODE_READ_CONTEXT, 0, NULL, context, context_size); +} + +/** \brief Executes SHA command to write (restore) a SHA-256 context into the + * the device. Only supported for ATECC608 with SHA-256 contexts. + * + * \param[in] device Device context pointer + * \param[in] context Context data to be restored. + * \param[in] context_size Size of the context data in bytes. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_write_context(ATCADevice device, const uint8_t* context, uint16_t context_size) +{ + return calib_sha_base(device, SHA_MODE_WRITE_CONTEXT, context_size, context, NULL, NULL); +} + +/** \brief Use the SHA command to compute a SHA-256 digest. + * + * \param[in] device Device context pointer + * \param[in] length Size of message parameter in bytes. + * \param[in] message Message data to be hashed. + * \param[out] digest Digest is returned here (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha(ATCADevice device, uint16_t length, const uint8_t *message, uint8_t *digest) +{ + return calib_hw_sha2_256(device, message, length, digest); +} + +/** \brief Initialize a SHA context for performing a hardware SHA-256 operation + * on a device. Note that only one SHA operation can be run at a time. + * + * \param[in] device Device context pointer + * \param[in] ctx SHA256 context + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_hw_sha2_256_init(ATCADevice device, atca_sha256_ctx_t* ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + return calib_sha_start(device); +} + +/** \brief Add message data to a SHA context for performing a hardware SHA-256 + * operation on a device. + * + * \param[in] device Device context pointer + * \param[in] ctx SHA256 context + * \param[in] data Message data to be added to hash. + * \param[in] data_size Size of data in bytes. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_hw_sha2_256_update(ATCADevice device, atca_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint32_t block_count; + uint32_t rem_size = ATCA_SHA256_BLOCK_SIZE - ctx->block_size; + size_t copy_size = data_size > rem_size ? (size_t)rem_size : data_size; + uint32_t i = 0; + + // Copy data into current block + memcpy(&ctx->block[ctx->block_size], data, copy_size); + + if (ctx->block_size + data_size < ATCA_SHA256_BLOCK_SIZE) + { + // Not enough data to finish off the current block + ctx->block_size += (uint32_t)data_size; + return ATCA_SUCCESS; + } + + // Process the current block + if (ATCA_SUCCESS != (status = calib_sha_update(device, ctx->block))) + { + return ATCA_TRACE(status, "calib_sha_update - failed"); + } + + // Process any additional blocks + data_size -= copy_size; // Adjust to the remaining message bytes + block_count = (uint32_t)(data_size / ATCA_SHA256_BLOCK_SIZE); + for (i = 0; i < block_count; i++) + { + if (ATCA_SUCCESS != (status = calib_sha_update(device, &data[copy_size + i * ATCA_SHA256_BLOCK_SIZE]))) + { + return ATCA_TRACE(status, "calib_sha_update - failed"); + } + } + + // Save any remaining data + ctx->total_msg_size += (block_count + 1) * ATCA_SHA256_BLOCK_SIZE; + ctx->block_size = data_size % ATCA_SHA256_BLOCK_SIZE; + memcpy(ctx->block, &data[copy_size + block_count * ATCA_SHA256_BLOCK_SIZE], (size_t)ctx->block_size); + + return ATCA_SUCCESS; +} + +/** \brief Finish SHA-256 digest for a SHA context for performing a hardware + * SHA-256 operation on a device. + * + * \param[in] device Device context pointer + * \param[in] ctx SHA256 context + * \param[out] digest SHA256 digest is returned here (32 bytes) + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_hw_sha2_256_finish(ATCADevice device, atca_sha256_ctx_t* ctx, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint32_t msg_size_bits; + uint32_t pad_zero_count; + uint16_t digest_size; + + if (device == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + if (device->mIface.mIfaceCFG->devtype == ATSHA204A) + { + // ATSHA204A only implements the raw 64-byte block operation, but + // doesn't add in the final footer information. So we do that manually + // here. + + // Calculate the total message size in bits + ctx->total_msg_size += ctx->block_size; + msg_size_bits = (ctx->total_msg_size * 8); + + // Calculate the number of padding zero bytes required between the 1 bit byte and the ATCA_SHA256_BLOCK_SIZEbit message size in bits. + pad_zero_count = (ATCA_SHA256_BLOCK_SIZE - ((ctx->block_size + 9) % ATCA_SHA256_BLOCK_SIZE)) % ATCA_SHA256_BLOCK_SIZE; + + // Append a single 1 bit + ctx->block[ctx->block_size++] = 0x80; + + // Add padding zeros plus upper 4 bytes of total message size in bits (only supporting 32bit message bit counts) + memset(&ctx->block[ctx->block_size], 0, (size_t)pad_zero_count + 4); + ctx->block_size += pad_zero_count + 4; + + // Add the total message size in bits to the end of the current block. Technically this is + // supposed to be 8 bytes. This shortcut will reduce the max message size to 536,870,911 bytes. + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 24); + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 16); + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 8); + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 0); + + digest_size = 32; + if (ATCA_SUCCESS != (status = calib_sha_base(device, SHA_MODE_SHA256_UPDATE, ATCA_SHA256_BLOCK_SIZE, ctx->block, digest, &digest_size))) + { + return ATCA_TRACE(status, "calib_sha_base - failed"); + } + + if (ctx->block_size > ATCA_SHA256_BLOCK_SIZE) + { + digest_size = 32; + if (ATCA_SUCCESS != (status = calib_sha_base(device, SHA_MODE_SHA256_UPDATE, ATCA_SHA256_BLOCK_SIZE, &ctx->block[ATCA_SHA256_BLOCK_SIZE], digest, &digest_size))) + { + return ATCA_TRACE(status, "calib_sha_base - failed"); + } + } + } + else + { + if (ATCA_SUCCESS != (status = calib_sha_end(device, digest, (uint16_t)ctx->block_size, ctx->block))) + { + return ATCA_TRACE(status, "calib_sha_end - failed"); + } + } + + return ATCA_SUCCESS; +} + +/** \brief Use the SHA command to compute a SHA-256 digest. + * + * \param[in] device Device context pointer + * \param[in] data Message data to be hashed. + * \param[in] data_size Size of data in bytes. + * \param[out] digest Digest is returned here (32 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_hw_sha2_256(ATCADevice device, const uint8_t * data, size_t data_size, uint8_t* digest) +{ + ATCA_STATUS status = ATCA_SUCCESS; + atca_sha256_ctx_t ctx; + + if (ATCA_SUCCESS != (status = calib_hw_sha2_256_init(device, &ctx))) + { + return ATCA_TRACE(status, "calib_hw_sha2_256_init - failed"); + } + + if (ATCA_SUCCESS != (status = calib_hw_sha2_256_update(device, &ctx, data, data_size))) + { + return ATCA_TRACE(status, "calib_hw_sha2_256_update - failed"); + } + + if (ATCA_SUCCESS != (status = calib_hw_sha2_256_finish(device, &ctx, digest))) + { + return ATCA_TRACE(status, "calib_hw_sha2_256_finish - failed"); + } + + return ATCA_SUCCESS; +} + +/** \brief Executes SHA command to start an HMAC/SHA-256 operation + * + * \param[in] device Device context pointer + * \param[in] ctx HMAC/SHA-256 context + * \param[in] key_slot Slot key id to use for the HMAC calculation + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_hmac_init(ATCADevice device, atca_hmac_sha256_ctx_t* ctx, uint16_t key_slot) +{ + uint8_t mode = SHA_MODE_HMAC_START; + + if ((NULL == ctx) || (NULL == device)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer encountered"); + } + + memset(ctx, 0, sizeof(*ctx)); + + if (ECC204 == device->mIface.mIfaceCFG->devtype) + { + mode = SHA_MODE_ECC204_HMAC_START; + } + + return calib_sha_base(device, mode, key_slot, NULL, NULL, NULL); +} + +/** \brief Executes SHA command to add an arbitrary amount of message data to + * a HMAC/SHA-256 operation. + * + * \param[in] device Device context pointer + * \param[in] ctx HMAC/SHA-256 context + * \param[in] data Message data to add + * \param[in] data_size Size of message data in bytes + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_hmac_update(ATCADevice device, atca_hmac_sha256_ctx_t* ctx, const uint8_t* data, size_t data_size) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint32_t block_count; + uint32_t rem_size = ATCA_SHA256_BLOCK_SIZE - ctx->block_size; + size_t copy_size = data_size > rem_size ? (size_t)rem_size : data_size; + uint32_t i = 0; + + // Copy data into current block + memcpy(&ctx->block[ctx->block_size], data, copy_size); + + if (ctx->block_size + data_size < ATCA_SHA256_BLOCK_SIZE) + { + // Not enough data to finish off the current block + ctx->block_size += (uint32_t)data_size; + return ATCA_SUCCESS; + } + + // Process the current block + if (ATCA_SUCCESS != (status = calib_sha_base(device, SHA_MODE_HMAC_UPDATE, ATCA_SHA256_BLOCK_SIZE, ctx->block, NULL, NULL))) + { + return ATCA_TRACE(status, "calib_sha_base - failed"); + } + + // Process any additional blocks + data_size -= copy_size; // Adjust to the remaining message bytes + block_count = (uint32_t)(data_size / ATCA_SHA256_BLOCK_SIZE); + for (i = 0; i < block_count; i++) + { + if (ATCA_SUCCESS != (status = calib_sha_base(device, SHA_MODE_HMAC_UPDATE, ATCA_SHA256_BLOCK_SIZE, &data[copy_size + i * ATCA_SHA256_BLOCK_SIZE], NULL, NULL))) + { + return ATCA_TRACE(status, "calib_sha_base - failed"); + } + } + + // Save any remaining data + ctx->total_msg_size += (block_count + 1) * ATCA_SHA256_BLOCK_SIZE; + ctx->block_size = data_size % ATCA_SHA256_BLOCK_SIZE; + memcpy(ctx->block, &data[copy_size + block_count * ATCA_SHA256_BLOCK_SIZE], (size_t)ctx->block_size); + + return ATCA_SUCCESS; +} + +/** \brief Executes SHA command to complete a HMAC/SHA-256 operation. + * + * \param[in] device Device context pointer + * \param[in] ctx HMAC/SHA-256 context + * \param[out] digest HMAC/SHA-256 result is returned here (32 bytes). + * \param[in] target Where to save the digest internal to the device. + * For ATECC608, can be SHA_MODE_TARGET_TEMPKEY, + * SHA_MODE_TARGET_MSGDIGBUF, or SHA_MODE_TARGET_OUT_ONLY. + * For all other devices, SHA_MODE_TARGET_TEMPKEY is the + * only option. + * For ECC204, target is ignored (0x00) + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_hmac_finish(ATCADevice device, atca_hmac_sha256_ctx_t *ctx, uint8_t* digest, uint8_t target) +{ + uint8_t mode = SHA_MODE_HMAC_END; + uint16_t digest_size = 32; + + if (device == NULL) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + if (ATECC608A == device->mIface.mIfaceCFG->devtype) + { + mode = SHA_MODE_608_HMAC_END; + } + else if (ECC204 == device->mIface.mIfaceCFG->devtype) + { + mode = SHA_MODE_ECC204_HMAC_END; + } + else if (target != SHA_MODE_TARGET_TEMPKEY) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "Invalid target received"); + } + + mode |= target; + + return calib_sha_base(device, mode, (uint16_t)ctx->block_size, ctx->block, digest, &digest_size); +} + +/** \brief Use the SHA command to compute an HMAC/SHA-256 operation. + * + * \param[in] device Device context pointer + * \param[in] data Message data to be hashed. + * \param[in] data_size Size of data in bytes. + * \param[in] key_slot Slot key id to use for the HMAC calculation + * \param[out] digest Digest is returned here (32 bytes). + * \param[in] target Where to save the digest internal to the device. + * For ATECC608, can be SHA_MODE_TARGET_TEMPKEY, + * SHA_MODE_TARGET_MSGDIGBUF, or + * SHA_MODE_TARGET_OUT_ONLY. For all other devices, + * SHA_MODE_TARGET_TEMPKEY is the only option. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_sha_hmac(ATCADevice device, const uint8_t * data, size_t data_size, uint16_t key_slot, uint8_t* digest, uint8_t target) +{ + ATCA_STATUS status = ATCA_SUCCESS; + atca_hmac_sha256_ctx_t ctx; + + if (ATCA_SUCCESS != (status = calib_sha_hmac_init(device, &ctx, key_slot))) + { + return ATCA_TRACE(status, "calib_sha_hmac_init - failed"); + } + + if (ATCA_SUCCESS != (status = calib_sha_hmac_update(device, &ctx, data, data_size))) + { + return ATCA_TRACE(status, "calib_sha_hmac_update - failed"); + } + + if (ATCA_SUCCESS != (status = calib_sha_hmac_finish(device, &ctx, digest, target))) + { + return ATCA_TRACE(status, "calib_sha_hmac_finish - failed"); + } + + return ATCA_SUCCESS; +} \ No newline at end of file diff --git a/drivers/ecc108a/cryptoauthlib/calib/calib_verify.c b/drivers/ecc108a/cryptoauthlib/calib/calib_verify.c new file mode 100644 index 0000000..f51c5f1 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/calib/calib_verify.c @@ -0,0 +1,463 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods for Verify command. + * + * The Verify command takes an ECDSA [R,S] signature and verifies that it is + * correctly generated given an input message digest and public key. + * + * \note List of devices that support this command - ATECC108A, ATECC508A, and + * ATECC608A/B. There are differences in the modes that they support. Refer + * to device datasheet for full details. + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "cryptoauthlib.h" +#include "host/atca_host.h" + +/** \brief Executes the Verify command, which takes an ECDSA [R,S] signature + * and verifies that it is correctly generated from a given message and + * public key. In all cases, the signature is an input to the command. + * + * For the Stored, External, and ValidateExternal Modes, the contents of + * TempKey (or Message Digest Buffer in some cases for the ATECC608) should + * contain the 32 byte message. + * + * \param[in] device Device context pointer + * \param[in] mode Verify command mode and options + * \param[in] key_id Stored mode, the slot containing the public key to + * be used for the verification. + * ValidateExternal mode, the slot containing the + * public key to be validated. + * External mode, KeyID contains the curve type to be + * used to Verify the signature. + * Validate or Invalidate mode, the slot containing + * the public key to be (in)validated. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key If mode is External, the public key to be used for + * verification. X and Y integers in big-endian format. + * 64 bytes for P256 curve. NULL for all other modes. + * \param[in] other_data If mode is Validate, the bytes used to generate the + * message for the validation (19 bytes). NULL for all + * other modes. + * \param[out] mac If mode indicates a validating MAC, then the MAC will + * will be returned here. Can be NULL otherwise. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +ATCA_STATUS calib_verify(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* signature, const uint8_t* public_key, const uint8_t* other_data, uint8_t* mac) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t verify_mode = (mode & VERIFY_MODE_MASK); + + do + { + if ((device == NULL) || (verify_mode == VERIFY_MODE_EXTERNAL && public_key == NULL) || + (signature == NULL)) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer recived"); + break; + } + + if ((verify_mode == VERIFY_MODE_VALIDATE || verify_mode == VERIFY_MODE_INVALIDATE) && other_data == NULL) + { + status = ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer recived"); + break; + } + + // Build the verify command + packet.param1 = mode; + packet.param2 = key_id; + memcpy(&packet.data[0], signature, ATCA_SIG_SIZE); + if (verify_mode == VERIFY_MODE_EXTERNAL) + { + memcpy(&packet.data[ATCA_SIG_SIZE], public_key, ATCA_PUB_KEY_SIZE); + } + else if (other_data) + { + memcpy(&packet.data[ATCA_SIG_SIZE], other_data, VERIFY_OTHER_DATA_SIZE); + } + + if ((status = atVerify(atcab_get_device_type_ext(device), &packet)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "atVerify - failed"); + break; + } + + if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_verify - execution failed"); + break; + } + + // The Verify command may return MAC if requested + if ((mac != NULL) && (packet.data[ATCA_COUNT_IDX] >= (ATCA_PACKET_OVERHEAD + MAC_SIZE))) + { + memcpy(mac, &packet.data[ATCA_RSP_DATA_IDX], MAC_SIZE); + } + + } + while (false); + + return status; +} + +/** \brief Executes the Verify command with verification MAC for the External + * or Stored Verify modes.. This function is only available on the + * ATECC608. + * + * \param[in] device Device context pointer + * \param[in] mode Verify command mode. Can be VERIFY_MODE_EXTERNAL or + * VERIFY_MODE_STORED. + * \param[in] key_id For VERIFY_MODE_STORED mode, the slot containing the + * public key to be used for the verification. + * For VERIFY_MODE_EXTERNAL mode, KeyID contains the + * curve type to be used to Verify the signature. Only + * VERIFY_KEY_P256 supported. + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key For VERIFY_MODE_EXTERNAL mode, the public key to be + * used for verification. X and Y integers in + * big-endian format. 64 bytes for P256 curve. Null for + * VERIFY_MODE_STORED mode. + * \param[in] num_in System nonce (32 byte) used for the verification + * MAC. + * \param[in] io_key IO protection key for verifying the validation MAC. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +static ATCA_STATUS calib_verify_extern_stored_mac(ATCADevice device, uint8_t mode, uint16_t key_id, const uint8_t* message, const uint8_t* signature, const uint8_t* public_key, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t msg_dig_buf[64]; + atca_verify_mac_in_out_t verify_mac_params; + uint8_t mac[SECUREBOOT_MAC_SIZE]; + uint8_t host_mac[SECUREBOOT_MAC_SIZE]; + + do + { + if ((is_verified == NULL) || (signature == NULL) || (message == NULL) || (num_in == NULL) + || (io_key == NULL) || ((mode & VERIFY_MODE_MASK) == VERIFY_MODE_EXTERNAL && public_key == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer recived"); + } + + *is_verified = false; + + // When using the message digest buffer as the message source, the + // second 32 bytes in the buffer will be the MAC system nonce. + memcpy(&msg_dig_buf[0], message, 32); + memcpy(&msg_dig_buf[32], num_in, 32); + if ((status = calib_nonce_load(device, NONCE_MODE_TARGET_MSGDIGBUF, msg_dig_buf, 64)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_nonce_load - failed"); + break; + } + + // Calculate the expected MAC + memset(&verify_mac_params, 0, sizeof(verify_mac_params)); + verify_mac_params.mode = mode | VERIFY_MODE_SOURCE_MSGDIGBUF | VERIFY_MODE_MAC_FLAG; + verify_mac_params.key_id = key_id; + verify_mac_params.signature = signature; + verify_mac_params.msg_dig_buf = msg_dig_buf; + verify_mac_params.io_key = io_key; + verify_mac_params.temp_key = NULL; + verify_mac_params.sn = NULL; + verify_mac_params.mac = host_mac; + /* if (ATCA_SUCCESS != (status = atcah_verify_mac(&verify_mac_params))) + { + ATCA_TRACE(status, "atcah_verify_mac - failed"); + break; + }*/ + + if (ATCA_SUCCESS != (status = calib_verify(device, verify_mac_params.mode, verify_mac_params.key_id, signature, public_key, NULL, mac))) + { + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + { + status = ATCA_SUCCESS; // Verify failed, but command succeeded + } + break; + } + + *is_verified = (memcmp(host_mac, mac, MAC_SIZE) == 0); + } + while (0); + + return status; +} + +/** \brief Executes the Verify command, which verifies a signature (ECDSA + * verify operation) with all components (message, signature, and + * public key) supplied. The message to be signed will be loaded into + * the Message Digest Buffer to the ATECC608 device or TempKey for + * other devices. + * + * \param[in] device Device context pointer + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key The public key to be used for verification. X and + * Y integers in big-endian format. 64 bytes for + * P256 curve. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS calib_verify_extern(ATCADevice device, const uint8_t *message, const uint8_t *signature, const uint8_t *public_key, bool *is_verified) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t nonce_target = NONCE_MODE_TARGET_TEMPKEY; + uint8_t verify_source = VERIFY_MODE_SOURCE_TEMPKEY; + + if ((device == NULL) || (is_verified == NULL) || (signature == NULL) || (message == NULL) || + (public_key == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + *is_verified = false; + + do + { + // Load message into device + if (ATECC608 == device->mIface.mIfaceCFG->devtype) + { + // Use the Message Digest Buffer for the ATECC608 + nonce_target = NONCE_MODE_TARGET_MSGDIGBUF; + verify_source = VERIFY_MODE_SOURCE_MSGDIGBUF; + } + if ((status = calib_nonce_load(device, nonce_target, message, 32)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_nonce_load - failed"); + break; + } + + status = calib_verify(device, VERIFY_MODE_EXTERNAL | verify_source, VERIFY_KEY_P256, signature, public_key, NULL, NULL); + + *is_verified = (status == ATCA_SUCCESS); + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + { + status = ATCA_SUCCESS; // Verify failed, but command succeeded + } + } + while (0); + + return status; +} + +/** \brief Executes the Verify command with verification MAC, which verifies a + * signature (ECDSA verify operation) with all components (message, + * signature, and public key) supplied. This function is only available + * on the ATECC608. + * + * \param[in] device Device context pointer + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] public_key The public key to be used for verification. X and + * Y integers in big-endian format. 64 bytes for + * P256 curve. + * \param[in] num_in System nonce (32 byte) used for the verification + * MAC. + * \param[in] io_key IO protection key for verifying the validation MAC. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS calib_verify_extern_mac(ATCADevice device, const uint8_t *message, const uint8_t* signature, const uint8_t* public_key, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified) +{ + return calib_verify_extern_stored_mac(device, VERIFY_MODE_EXTERNAL, VERIFY_KEY_P256, message, signature, public_key, num_in, io_key, is_verified); +} + +/** \brief Executes the Verify command, which verifies a signature (ECDSA + * verify operation) with a public key stored in the device. The + * message to be signed will be loaded into the Message Digest Buffer + * to the ATECC608 device or TempKey for other devices. + * + * \param[in] device Device context pointer + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] key_id Slot containing the public key to be used in the + * verification. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS calib_verify_stored(ATCADevice device, const uint8_t *message, const uint8_t *signature, uint16_t key_id, bool *is_verified) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t nonce_target = NONCE_MODE_TARGET_TEMPKEY; + uint8_t verify_source = VERIFY_MODE_SOURCE_TEMPKEY; + + if ((device == NULL) || (is_verified == NULL) || (signature == NULL) || (message == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + *is_verified = false; + + do + { + // Load message into device + if (ATECC608 == device->mIface.mIfaceCFG->devtype) + { + // Use the Message Digest Buffer for the ATECC608 + nonce_target = NONCE_MODE_TARGET_MSGDIGBUF; + verify_source = VERIFY_MODE_SOURCE_MSGDIGBUF; + } + if ((status = calib_nonce_load(device, nonce_target, message, 32)) != ATCA_SUCCESS) + { + ATCA_TRACE(status, "calib_nonce_load - failed"); + break; + } + + status = calib_verify(device, VERIFY_MODE_STORED | verify_source, key_id, signature, NULL, NULL, NULL); + + *is_verified = (status == ATCA_SUCCESS); + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + { + status = ATCA_SUCCESS; // Verify failed, but command succeeded + } + } + while (0); + + return status; +} + +/** \brief Executes the Verify command with verification MAC, which verifies a + * signature (ECDSA verify operation) with a public key stored in the + * device. This function is only available on the ATECC608. + * + * \param[in] device Device context pointer + * \param[in] message 32 byte message to be verified. Typically + * the SHA256 hash of the full message. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] key_id Slot containing the public key to be used in the + * verification. + * \param[in] num_in System nonce (32 byte) used for the verification + * MAC. + * \param[in] io_key IO protection key for verifying the validation MAC. + * \param[out] is_verified Boolean whether or not the message, signature, + * public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS calib_verify_stored_mac(ATCADevice device, const uint8_t *message, const uint8_t *signature, uint16_t key_id, const uint8_t* num_in, const uint8_t* io_key, bool* is_verified) +{ + return calib_verify_extern_stored_mac(device, VERIFY_MODE_STORED, key_id, message, signature, NULL, num_in, io_key, is_verified); +} + +/** \brief Executes the Verify command in Validate mode to validate a public + * key stored in a slot. + * + * This command can only be run after GenKey has been used to create a PubKey + * digest of the public key to be validated in TempKey (mode=0x10). + * + * \param[in] device Device context pointer + * \param[in] key_id Slot containing the public key to be validated. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] other_data 19 bytes of data used to build the verification + * message. + * \param[out] is_verified Boolean whether or not the message, signature, + * validation public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS calib_verify_validate(ATCADevice device, uint16_t key_id, const uint8_t *signature, const uint8_t *other_data, bool *is_verified) +{ + ATCA_STATUS status = ATCA_SUCCESS; + + if ((device == NULL) || (signature == NULL) || (other_data == NULL) || (is_verified == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + status = calib_verify(device, VERIFY_MODE_VALIDATE, key_id, signature, NULL, other_data, NULL); + + *is_verified = (status == ATCA_SUCCESS); + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + { + status = ATCA_SUCCESS; // Verify failed, but command succeeded + } + + return status; +} + +/** \brief Executes the Verify command in Invalidate mode which invalidates a + * previously validated public key stored in a slot. + * + * This command can only be run after GenKey has been used to create a PubKey + * digest of the public key to be invalidated in TempKey (mode=0x10). + * + * \param[in] device Device context pointer + * \param[in] key_id Slot containing the public key to be invalidated. + * \param[in] signature Signature to be verified. R and S integers in + * big-endian format. 64 bytes for P256 curve. + * \param[in] other_data 19 bytes of data used to build the verification + * message. + * \param[out] is_verified Boolean whether or not the message, signature, + * validation public key verified. + * + * \return ATCA_SUCCESS on verification success or failure, because the + * command still completed successfully. + */ +ATCA_STATUS calib_verify_invalidate(ATCADevice device, uint16_t key_id, const uint8_t *signature, const uint8_t *other_data, bool *is_verified) +{ + ATCA_STATUS status = ATCA_SUCCESS; + + if ((device == NULL) || (signature == NULL) || (other_data == NULL) || (is_verified == NULL)) + { + return ATCA_TRACE(ATCA_BAD_PARAM, "NULL pointer received"); + } + + status = calib_verify(device, VERIFY_MODE_INVALIDATE, key_id, signature, NULL, other_data, NULL); + + *is_verified = (status == ATCA_SUCCESS); + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + { + status = ATCA_SUCCESS; // Verify failed, but command succeeded + } + + return status; +} \ No newline at end of file diff --git a/drivers/ecc108a/cryptoauthlib/host/atca_host.c b/drivers/ecc108a/cryptoauthlib/host/atca_host.c new file mode 100644 index 0000000..93dfc81 --- /dev/null +++ b/drivers/ecc108a/cryptoauthlib/host/atca_host.c @@ -0,0 +1,1739 @@ +/** + * \file + * \brief Host side methods to support CryptoAuth computations + * + * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries. + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip software + * and any derivatives exclusively with Microchip products. It is your + * responsibility to comply with third party license terms applicable to your + * use of third party software (including open source software) that may + * accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, + * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE + * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF + * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE + * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL + * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED + * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR + * THIS SOFTWARE. + */ + +#include "atca_host.h" +#ifndef ATCA_TIDAL +#include "crypto/atca_crypto_sw_sha2.h" +#endif // ifndef ATCA_TIDAL + +#if ATCA_CA_SUPPORT + +/** \brief This function copies otp and sn data into a command buffer. + * + * \param[in,out] param pointer to parameter structure + * \return pointer to command buffer byte that was copied last + */ +#if ATCAH_INCLUDE_DATA +uint8_t *atcah_include_data(struct atca_include_data_in_out *param) +{ + if (param->mode & MAC_MODE_INCLUDE_OTP_88) + { + memcpy(param->p_temp, param->otp, 11); // use OTP[0:10], Mode:5 is overridden + param->p_temp += 11; + } + else + { + if (param->mode & MAC_MODE_INCLUDE_OTP_64) + { + memcpy(param->p_temp, param->otp, 8); // use 8 bytes OTP[0:7] for (6) + } + else + { + memset(param->p_temp, 0, 8); // use 8 zeros for (6) + } + param->p_temp += 8; + + memset(param->p_temp, 0, 3); // use 3 zeros for (7) + param->p_temp += 3; + } + + // (8) 1 byte SN[8] + *param->p_temp++ = param->sn[8]; + + // (9) 4 bytes SN[4:7] or zeros + if (param->mode & MAC_MODE_INCLUDE_SN) + { + memcpy(param->p_temp, ¶m->sn[4], 4); //use SN[4:7] for (9) + } + else + { + memset(param->p_temp, 0, 4); //use zeros for (9) + } + param->p_temp += 4; + + // (10) 2 bytes SN[0:1] + *param->p_temp++ = param->sn[0]; + *param->p_temp++ = param->sn[1]; + + // (11) 2 bytes SN[2:3] or zeros + if (param->mode & MAC_MODE_INCLUDE_SN) + { + memcpy(param->p_temp, ¶m->sn[2], 2); //use SN[2:3] for (11) + } + else + { + memset(param->p_temp, 0, 2); //use zeros for (9) + } + param->p_temp += 2; + + return param->p_temp; +} +#endif /* ATCAH_INCLUDE_DATA */ + +/** \brief This function calculates host side nonce with the parameters passed. + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_NONCE +ATCA_STATUS atcah_nonce(struct atca_nonce_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_NONCE]; + uint8_t *p_temp; + uint8_t calc_mode = param->mode & NONCE_MODE_MASK; + + // Check parameters + if (param->temp_key == NULL || param->num_in == NULL) + { + return ATCA_BAD_PARAM; + } + + // Calculate or pass-through the nonce to TempKey->Value + if ((calc_mode == NONCE_MODE_SEED_UPDATE) || (calc_mode == NONCE_MODE_NO_SEED_UPDATE)) + { + // RandOut is only required for these modes + if (param->rand_out == NULL) + { + return ATCA_BAD_PARAM; + } + + if ((param->zero & NONCE_ZERO_CALC_MASK) == NONCE_ZERO_CALC_TEMPKEY) + { + // Nonce calculation mode. Actual value of TempKey has been returned in RandOut + memcpy(param->temp_key->value, param->rand_out, 32); + + // TempKey flags aren't changed + } + else + { + // Calculate nonce using SHA-256 (refer to data sheet) + p_temp = temporary; + + memcpy(p_temp, param->rand_out, RANDOM_NUM_SIZE); + p_temp += RANDOM_NUM_SIZE; + + memcpy(p_temp, param->num_in, NONCE_NUMIN_SIZE); + p_temp += NONCE_NUMIN_SIZE; + + *p_temp++ = ATCA_NONCE; + *p_temp++ = param->mode; + *p_temp++ = 0x00; + + // Calculate SHA256 to get the nonce + atcac_sw_sha2_256(temporary, ATCA_MSG_SIZE_NONCE, param->temp_key->value); + + // Update TempKey flags + param->temp_key->source_flag = 0; // Random + param->temp_key->key_id = 0; + param->temp_key->gen_dig_data = 0; + param->temp_key->no_mac_flag = 0; + param->temp_key->valid = 1; + } + + // Update TempKey to only 32 bytes + param->temp_key->is_64 = 0; + } + else if ((param->mode & NONCE_MODE_MASK) == NONCE_MODE_PASSTHROUGH) + { + + if ((param->mode & NONCE_MODE_TARGET_MASK) == NONCE_MODE_TARGET_TEMPKEY) + { + // Pass-through mode for TempKey (other targets have no effect on TempKey) + if ((param->mode & NONCE_MODE_INPUT_LEN_MASK) == NONCE_MODE_INPUT_LEN_64) + { + memcpy(param->temp_key->value, param->num_in, 64); + param->temp_key->is_64 = 1; + } + else + { + memcpy(param->temp_key->value, param->num_in, 32); + param->temp_key->is_64 = 0; + } + + // Update TempKey flags + param->temp_key->source_flag = 1; // Not Random + param->temp_key->key_id = 0; + param->temp_key->gen_dig_data = 0; + param->temp_key->no_mac_flag = 0; + param->temp_key->valid = 1; + } + else //In the case of ECC608, passthrough message may be stored in message digest buffer/ Alternate Key buffer + { + + // Update TempKey flags + param->temp_key->source_flag = 1; //Not Random + param->temp_key->key_id = 0; + param->temp_key->gen_dig_data = 0; + param->temp_key->no_mac_flag = 0; + param->temp_key->valid = 0; + + } + } + else if ((NONCE_MODE_GEN_SESSION_KEY == calc_mode) && (param->zero >= 0x8000)) + { + // Calculate nonce using SHA-256 (refer to data sheet) + p_temp = temporary; + + memcpy(p_temp, param->rand_out, RANDOM_NUM_SIZE); + p_temp += RANDOM_NUM_SIZE; + + memcpy(p_temp, param->num_in, NONCE_NUMIN_SIZE); + p_temp += NONCE_NUMIN_SIZE; + + *p_temp++ = ATCA_NONCE; + *p_temp++ = param->mode; + *p_temp++ = (param->zero) & 0xFF; + + // Calculate SHA256 to get the nonce + atcac_sw_sha2_256(temporary, ATCA_MSG_SIZE_NONCE, param->temp_key->value); + } + else + { + return ATCA_BAD_PARAM; + } + + return ATCA_SUCCESS; +} +#endif /* atcah_nonce */ + +/** \brief Decrypt data that's been encrypted by the IO protection key. + * The ECDH and KDF commands on the ATECC608 are the only ones that + * support this operation. + * + * \param[in,out] param Parameters required to perform the operation. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_IO_DECRYPT +ATCA_STATUS atcah_io_decrypt(struct atca_io_decrypt_in_out *param) +{ + atcac_sha2_256_ctx ctx; + uint8_t key[ATCA_KEY_SIZE]; + size_t block = 0; + int i; + + if (param == NULL || param->io_key == NULL || param->out_nonce == NULL || param->data == NULL) + { + return ATCA_BAD_PARAM; + } + if (param->data_size % ATCA_BLOCK_SIZE != 0) + { + return ATCA_BAD_PARAM; + } + + for (block = 0; block < param->data_size / ATCA_BLOCK_SIZE; block++) + { + // Calculate key for block + atcac_sw_sha2_256_init(&ctx); + atcac_sw_sha2_256_update(&ctx, param->io_key, 32); + atcac_sw_sha2_256_update(&ctx, ¶m->out_nonce[block * 16], 16); + atcac_sw_sha2_256_finish(&ctx, key); + + // Decrypt block + for (i = 0; i < ATCA_BLOCK_SIZE; i++) + { + param->data[block * ATCA_BLOCK_SIZE + i] ^= key[i]; + } + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_IO_DECRYPT */ + +/** \brief Calculate the expected MAC on the host side for the Verify command. + * + * \param[in,out] param Data required to perform the operation. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_VERIFY_MAC +ATCA_STATUS atcah_verify_mac(atca_verify_mac_in_out_t *param) +{ + uint8_t verify_mode = (param->mode & VERIFY_MODE_MASK); + uint8_t verify_source = (param->mode & VERIFY_MODE_SOURCE_MASK); + atcac_sha2_256_ctx ctx; + uint8_t message[32]; + const uint8_t* nonce = NULL; + uint8_t input_params[4]; + const uint8_t sign_opcode = ATCA_SIGN; + + // Check parameters + if (param->signature == NULL || param->msg_dig_buf == NULL || param->io_key == NULL) + { + return ATCA_BAD_PARAM; + } + + // Get the verify message + if (verify_mode == VERIFY_MODE_VALIDATE || verify_mode == VERIFY_MODE_INVALIDATE) + { + if (param->other_data == NULL || param->temp_key == NULL || param->sn == NULL) + { + return ATCA_BAD_PARAM; + } + + // Message is calculated based on TempKey and OtherData + atcac_sw_sha2_256_init(&ctx); + atcac_sw_sha2_256_update(&ctx, param->temp_key->value, 32); + atcac_sw_sha2_256_update(&ctx, &sign_opcode, 1); + atcac_sw_sha2_256_update(&ctx, ¶m->other_data[0], 10); + atcac_sw_sha2_256_update(&ctx, ¶m->sn[8], 1); + atcac_sw_sha2_256_update(&ctx, ¶m->other_data[10], 4); + atcac_sw_sha2_256_update(&ctx, ¶m->sn[0], 2); + atcac_sw_sha2_256_update(&ctx, ¶m->other_data[14], 5); + atcac_sw_sha2_256_finish(&ctx, message); + } + else if (verify_source == VERIFY_MODE_SOURCE_MSGDIGBUF) + { + // Message source is the first 32 bytes of the message digest buffer + memcpy(message, param->msg_dig_buf, 32); + } + else + { + // Message source is the first 32 bytes of TempKey + if (param->temp_key == NULL) + { + return ATCA_BAD_PARAM; + } + memcpy(message, param->temp_key->value, 32); + } + + // Get the system nonce + if (verify_source == VERIFY_MODE_SOURCE_MSGDIGBUF) + { + nonce = ¶m->msg_dig_buf[32]; // System nonce is the second 32 bytes of the message digest buffer + } + else + { + nonce = ¶m->msg_dig_buf[0]; // System nonce is the first 32 bytes of the message digest buffer + + } + // Calculate MAC + atcac_sw_sha2_256_init(&ctx); + atcac_sw_sha2_256_update(&ctx, param->io_key, ATCA_KEY_SIZE); // IO protection key + atcac_sw_sha2_256_update(&ctx, message, 32); // Verify message + atcac_sw_sha2_256_update(&ctx, nonce, 32); // Host (system) nonce + atcac_sw_sha2_256_update(&ctx, param->signature, 64); // Signature + + // Add Verify input parameters + input_params[0] = ATCA_VERIFY; // Verify Opcode + input_params[1] = param->mode; // Verify Mode (Param1) + input_params[2] = (uint8_t)(param->key_id >> 0); // Verify Param2 (LSB) + input_params[3] = (uint8_t)(param->key_id >> 8); // Verify Param2 (MSB) + atcac_sw_sha2_256_update(&ctx, input_params, sizeof(input_params)); + + // Calculate SHA256 to get mac + atcac_sw_sha2_256_finish(&ctx, param->mac); + + return ATCA_SUCCESS; +} +#endif + +/** \brief Encrypts the digest for the SecureBoot command when using the + * encrypted digest / validating mac option. + * + * \param[in,out] param Data required to perform the operation. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_SECUREBOOT_ENC +ATCA_STATUS atcah_secureboot_enc(atca_secureboot_enc_in_out_t* param) +{ + atcac_sha2_256_ctx ctx; + size_t i; + + // Check parameters + if (param->digest == NULL || param->temp_key == NULL || param->hashed_key == NULL || param->io_key == NULL || param->digest_enc == NULL) + { + return ATCA_BAD_PARAM; + } + + // Calculate key for encrypting digest + atcac_sw_sha2_256_init(&ctx); + atcac_sw_sha2_256_update(&ctx, param->io_key, ATCA_KEY_SIZE); + atcac_sw_sha2_256_update(&ctx, param->temp_key->value, ATCA_KEY_SIZE); + atcac_sw_sha2_256_finish(&ctx, param->hashed_key); + + // Encrypt digest (XOR with key) + for (i = 0; i < SECUREBOOT_DIGEST_SIZE; i++) + { + param->digest_enc[i] = param->digest[i] ^ param->hashed_key[i]; + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_SECUREBOOT_ENC */ + +/** \brief Calculates the expected MAC returned from the SecureBoot command + * when verification is a success. + * + * The result of this function (param->mac) should be compared with the actual + * MAC returned to validate the response. + * + * \param[in,out] param Data required to perform the operation. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_SECUREBOOT_MAC +ATCA_STATUS atcah_secureboot_mac(atca_secureboot_mac_in_out_t *param) +{ + atcac_sha2_256_ctx ctx; + uint8_t input_params[4]; + + if (param->hashed_key == NULL || param->digest == NULL || param->mac == NULL) + { + return ATCA_BAD_PARAM; + } + + // Calculate MAC + atcac_sw_sha2_256_init(&ctx); + atcac_sw_sha2_256_update(&ctx, param->hashed_key, ATCA_KEY_SIZE); + atcac_sw_sha2_256_update(&ctx, param->digest, SECUREBOOT_DIGEST_SIZE); + + // Signature is only skipped when running the SecureBoot command in + // FullStore mode and SecureBootMode from the configuration zone is set to + // FullDig + if (!((param->mode & SECUREBOOT_MODE_MASK) == SECUREBOOT_MODE_FULL_STORE && + (param->secure_boot_config & SECUREBOOTCONFIG_MODE_MASK) == SECUREBOOTCONFIG_MODE_FULL_DIG)) + { + if (param->signature == NULL) + { + return ATCA_BAD_PARAM; + } + atcac_sw_sha2_256_update(&ctx, param->signature, SECUREBOOT_SIGNATURE_SIZE); + } + + // Add SecureBoot input parameters + input_params[0] = ATCA_SECUREBOOT; // SecureBoot Opcode + input_params[1] = param->mode; // SecureBoot Mode (Param1) + input_params[2] = (uint8_t)(param->param2 >> 0); // SecureBoot Param2 (LSB) + input_params[3] = (uint8_t)(param->param2 >> 8); // SecureBoot Param2 (MSB) + atcac_sw_sha2_256_update(&ctx, input_params, sizeof(input_params)); + + atcac_sw_sha2_256_finish(&ctx, param->mac); + + return ATCA_SUCCESS; +} +#endif /* ATCAH_SECUREBOOT_MAC */ + + +/** \brief This function generates an SHA-256 digest (MAC) of a key, challenge, and other information. + + The resulting digest will match with the one generated by the device when executing a MAC command. + The TempKey (if used) should be valid (temp_key.valid = 1) before executing this function. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_MAC +ATCA_STATUS atcah_mac(struct atca_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_MAC]; + uint8_t *p_temp; + struct atca_include_data_in_out include_data; + + // Initialize struct + include_data.otp = param->otp; + include_data.sn = param->sn; + include_data.mode = param->mode; + + // Check parameters + if (!param->response + || (param->mode & ~MAC_MODE_MASK) + || (!(param->mode & MAC_MODE_BLOCK1_TEMPKEY) && !param->key) + || (!(param->mode & MAC_MODE_BLOCK2_TEMPKEY) && !param->challenge) + || ((param->mode & MAC_MODE_USE_TEMPKEY_MASK) && !param->temp_key) + || (((param->mode & MAC_MODE_INCLUDE_OTP_64) || (param->mode & MAC_MODE_INCLUDE_OTP_88)) && !param->otp) + || ((param->mode & MAC_MODE_INCLUDE_SN) && !param->sn) + ) + { + return ATCA_BAD_PARAM; + } + + // Check TempKey fields validity if TempKey is used + if (((param->mode & MAC_MODE_USE_TEMPKEY_MASK) != 0) + // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + && (param->temp_key->no_mac_flag || (param->temp_key->valid != 1) + // If either mode parameter bit 0 or bit 1 are set, mode parameter bit 2 must match temp_key.source_flag. + // Logical not (!) is used to evaluate the expression to TRUE / FALSE first before comparison (!=). + || (!(param->mode & MAC_MODE_SOURCE_FLAG_MATCH) != !(param->temp_key->source_flag))) + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) first 32 bytes + memcpy(p_temp, param->mode & MAC_MODE_BLOCK1_TEMPKEY ? param->temp_key->value : param->key, ATCA_KEY_SIZE); // use Key[KeyID] + p_temp += ATCA_KEY_SIZE; + + // (2) second 32 bytes + memcpy(p_temp, param->mode & MAC_MODE_BLOCK2_TEMPKEY ? param->temp_key->value : param->challenge, ATCA_KEY_SIZE); // use Key[KeyID] + p_temp += ATCA_KEY_SIZE; + + // (3) 1 byte opcode + *p_temp++ = ATCA_MAC; + + // (4) 1 byte mode parameter + *p_temp++ = param->mode; + + // (5) 2 bytes keyID + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + include_data.p_temp = p_temp; + atcah_include_data(&include_data); + + // Calculate SHA256 to get the MAC digest + atcac_sw_sha2_256(temporary, ATCA_MSG_SIZE_MAC, param->response); + + // Update TempKey fields + if (param->temp_key) + { + param->temp_key->valid = 0; + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_MAC */ + + + +/** \brief This function performs the checkmac operation to generate client response on the host side . + * \param[in,out] param Input and output parameters + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_CHECK_MAC +ATCA_STATUS atcah_check_mac(struct atca_check_mac_in_out *param) +{ + uint8_t msg[ATCA_MSG_SIZE_MAC]; + bool is_temp_key_req = false; + + // Check parameters + if (param == NULL || param->other_data == NULL || param->sn == NULL || param->client_resp == NULL) + { + return ATCA_BAD_PARAM; + } + + if ((param->mode & CHECKMAC_MODE_BLOCK1_TEMPKEY) || (param->mode & CHECKMAC_MODE_BLOCK2_TEMPKEY)) + { + is_temp_key_req = true; // Message uses TempKey + } + else if ((param->mode == 0x01 || param->mode == 0x05) && param->target_key != NULL) + { + is_temp_key_req = true; // CheckMac copy will be performed + + } + if (is_temp_key_req && param->temp_key == NULL) + { + return ATCA_BAD_PARAM; + } + if (!(param->mode & CHECKMAC_MODE_BLOCK1_TEMPKEY) && param->slot_key == NULL) + { + return ATCA_BAD_PARAM; + } + if (!(param->mode & CHECKMAC_MODE_BLOCK2_TEMPKEY) && param->client_chal == NULL) + { + return ATCA_BAD_PARAM; + } + if ((param->mode & CHECKMAC_MODE_INCLUDE_OTP_64) && param->otp == NULL) + { + return ATCA_BAD_PARAM; + } + + if ((param->mode & CHECKMAC_MODE_BLOCK1_TEMPKEY) || (param->mode & CHECKMAC_MODE_BLOCK2_TEMPKEY)) + { + // This will use TempKey in message, check validity + if (!param->temp_key->valid) + { + return ATCA_EXECUTION_ERROR; // TempKey is not valid + } + if (((param->mode >> 2) & 0x01) != param->temp_key->source_flag) + { + return ATCA_EXECUTION_ERROR; // TempKey SourceFlag doesn't match bit 2 of the mode + } + } + + // Build the message + memset(msg, 0, sizeof(msg)); + if (param->mode & CHECKMAC_MODE_BLOCK1_TEMPKEY) + { + memcpy(&msg[0], param->temp_key->value, 32); + } + else + { + memcpy(&msg[0], param->slot_key, 32); + } + if (param->mode & CHECKMAC_MODE_BLOCK2_TEMPKEY) + { + memcpy(&msg[32], param->temp_key->value, 32); + } + else + { + memcpy(&msg[32], param->client_chal, 32); + } + memcpy(&msg[64], ¶m->other_data[0], 4); + if (param->mode & CHECKMAC_MODE_INCLUDE_OTP_64) + { + memcpy(&msg[68], param->otp, 8); + } + memcpy(&msg[76], ¶m->other_data[4], 3); + msg[79] = param->sn[8]; + memcpy(&msg[80], ¶m->other_data[7], 4); + memcpy(&msg[84], ¶m->sn[0], 2); + memcpy(&msg[86], ¶m->other_data[11], 2); + + // Calculate the client response + atcac_sw_sha2_256(msg, sizeof(msg), param->client_resp); + + // Update TempKey fields + if ((param->mode == 0x01 || param->mode == 0x05) && param->target_key != NULL) + { + // CheckMac Copy will be performed + memcpy(param->temp_key->value, param->target_key, ATCA_KEY_SIZE); + param->temp_key->gen_dig_data = 0; + param->temp_key->source_flag = 1; + param->temp_key->valid = 1; + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_CHECK_MAC */ + +/** \brief This function generates an HMAC / SHA-256 hash of a key and other information. + + The resulting hash will match with the one generated in the device by an HMAC command. + The TempKey has to be valid (temp_key.valid = 1) before executing this function. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_HMAC +ATCA_STATUS atcah_hmac(struct atca_hmac_in_out *param) +{ + // Local Variables + struct atca_include_data_in_out include_data; + uint8_t temporary[ATCA_HMAC_BLOCK_SIZE + ATCA_MSG_SIZE_HMAC]; + uint8_t i = 0; + uint8_t *p_temp = NULL; + + // Check parameters + if (!param->response || !param->key || !param->temp_key + || (param->mode & ~HMAC_MODE_MASK) + || (((param->mode & MAC_MODE_INCLUDE_OTP_64) || (param->mode & MAC_MODE_INCLUDE_OTP_88)) && !param->otp) + || (!param->sn) + ) + { + return ATCA_BAD_PARAM; + } + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->no_mac_flag || (param->temp_key->valid != 1) + // The mode parameter bit 2 must match temp_key.source_flag. + // Logical not (!) is used to evaluate the expression to TRUE / FALSE first before comparison (!=). + || (!(param->mode & MAC_MODE_SOURCE_FLAG_MATCH) != !(param->temp_key->source_flag)) + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start first calculation (inner) + p_temp = temporary; + + // XOR key with ipad + for (i = 0; i < ATCA_KEY_SIZE; i++) + { + *p_temp++ = param->key[i] ^ 0x36; + } + + // zero pad key out to block size + // Refer to fips-198 , length Key = 32 bytes, Block size = 512 bits = 64 bytes. + // So the Key must be padded with zeros. + memset(p_temp, 0x36, ATCA_HMAC_BLOCK_SIZE - ATCA_KEY_SIZE); + p_temp += ATCA_HMAC_BLOCK_SIZE - ATCA_KEY_SIZE; + + // Next append the stream of data 'text' + memset(p_temp, 0, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + *p_temp++ = ATCA_HMAC; + *p_temp++ = param->mode; + *p_temp++ = (uint8_t)(param->key_id >> 0); + *p_temp++ = (uint8_t)(param->key_id >> 8); + + include_data.otp = param->otp; + include_data.sn = param->sn; + include_data.mode = param->mode; + include_data.p_temp = p_temp; + atcah_include_data(&include_data); + + // Calculate SHA256 + // H((K0^ipad):text), use param.response for temporary storage + atcac_sw_sha2_256(temporary, ATCA_HMAC_BLOCK_SIZE + ATCA_MSG_SIZE_HMAC, param->response); + + + // Start second calculation (outer) + p_temp = temporary; + + // XOR K0 with opad + for (i = 0; i < ATCA_KEY_SIZE; i++) + { + *p_temp++ = param->key[i] ^ 0x5C; + } + + // zero pad key out to block size + // Refer to fips-198 , length Key = 32 bytes, Block size = 512 bits = 64 bytes. + // So the Key must be padded with zeros. + memset(p_temp, 0x5C, ATCA_HMAC_BLOCK_SIZE - ATCA_KEY_SIZE); + p_temp += ATCA_HMAC_BLOCK_SIZE - ATCA_KEY_SIZE; + + // Append result from last calculation H((K0 ^ ipad) || text) + memcpy(p_temp, param->response, ATCA_SHA_DIGEST_SIZE); + p_temp += ATCA_SHA_DIGEST_SIZE; + + // Calculate SHA256 to get the resulting HMAC + atcac_sw_sha2_256(temporary, ATCA_HMAC_BLOCK_SIZE + ATCA_SHA_DIGEST_SIZE, param->response); + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} +#endif /* ATCAH_HMAC */ + +/** \brief This function combines the current TempKey with a stored value. + + The stored value can be a data slot, OTP page, configuration zone, or hardware transport key. + The TempKey generated by this function will match with the TempKey in the device generated + when executing a GenDig command. + The TempKey should be valid (temp_key.valid = 1) before executing this function. + To use this function, an application first sends a GenDig command with a chosen stored value to the device. + This stored value must be known by the application and is passed to this GenDig calculation function. + The function calculates a new TempKey and returns it. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_GENDIG +ATCA_STATUS atcah_gen_dig(struct atca_gen_dig_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_GEN_DIG]; + uint8_t *p_temp; + + // Check parameters + if (param->sn == NULL || param->temp_key == NULL) + { + return ATCA_BAD_PARAM; + } + if ((param->zone <= GENDIG_ZONE_DATA) && (param->stored_value == NULL)) + { + return ATCA_BAD_PARAM; // Stored value cannot be null for Config,OTP and Data + } + + if ((param->zone == GENDIG_ZONE_SHARED_NONCE || (param->zone == GENDIG_ZONE_DATA && param->is_key_nomac)) && param->other_data == NULL) + { + return ATCA_BAD_PARAM; // Other data is required in these cases + } + + if (param->zone > 5) + { + return ATCA_BAD_PARAM; // Unknown zone + + } + // Start calculation + p_temp = temporary; + + + // (1) 32 bytes inputKey + if (param->zone == GENDIG_ZONE_SHARED_NONCE) + { + if (param->key_id & 0x8000) + { + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); // 32 bytes TempKey + } + else + { + memcpy(p_temp, param->other_data, ATCA_KEY_SIZE); // 32 bytes other data + + } + } + else if (param->zone == GENDIG_ZONE_COUNTER || param->zone == GENDIG_ZONE_KEY_CONFIG) + { + memset(p_temp, 0x00, ATCA_KEY_SIZE); // 32 bytes of zero. + + } + else + { + memcpy(p_temp, param->stored_value, ATCA_KEY_SIZE); // 32 bytes of stored data + + } + + p_temp += ATCA_KEY_SIZE; + + + if (param->zone == GENDIG_ZONE_DATA && param->is_key_nomac) + { + // If a key has the SlotConfig.NoMac bit set, then opcode and parameters come from OtherData + memcpy(p_temp, param->other_data, 4); + p_temp += 4; + } + else + { + // (2) 1 byte Opcode + *p_temp++ = ATCA_GENDIG; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 1 byte LSB of Param2 (keyID) + *p_temp++ = (uint8_t)(param->key_id & 0xFF); + if (param->zone == GENDIG_ZONE_SHARED_NONCE) + { + //(4) 1 byte zero for shared nonce mode + *p_temp++ = 0; + } + else + { + //(4) 1 byte MSB of Param2 (keyID) for other modes + *p_temp++ = (uint8_t)(param->key_id >> 8); + } + } + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + + // (7) + if (param->zone == GENDIG_ZONE_COUNTER) + { + *p_temp++ = 0; + *p_temp++ = (uint8_t)(param->counter & 0xFF); // (7) 4 bytes of counter + *p_temp++ = (uint8_t)(param->counter >> 8); + *p_temp++ = (uint8_t)(param->counter >> 16); + *p_temp++ = (uint8_t)(param->counter >> 24); + + memset(p_temp, 0x00, 20); // (7) 20 bytes of zero + p_temp += 20; + + } + else if (param->zone == GENDIG_ZONE_KEY_CONFIG) + { + *p_temp++ = 0; + *p_temp++ = param->slot_conf & 0xFF; // (7) 2 bytes of Slot config + *p_temp++ = (uint8_t)(param->slot_conf >> 8); + + *p_temp++ = param->key_conf & 0xFF; + *p_temp++ = (uint8_t)(param->key_conf >> 8); // (7) 2 bytes of key config + + *p_temp++ = param->slot_locked; // (7) 1 byte of slot locked + + memset(p_temp, 0x00, 19); // (7) 19 bytes of zero + p_temp += 19; + + + } + else + { + + memset(p_temp, 0, ATCA_GENDIG_ZEROS_SIZE); // (7) 25 zeros + p_temp += ATCA_GENDIG_ZEROS_SIZE; + + } + + + + + if (param->zone == GENDIG_ZONE_SHARED_NONCE && (param->key_id & 0x8000)) + { + memcpy(p_temp, param->other_data, ATCA_KEY_SIZE); // (8) 32 bytes OtherData + p_temp += ATCA_KEY_SIZE; + + } + else + { + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); // (8) 32 bytes TempKey + p_temp += ATCA_KEY_SIZE; + + } + + + + + + // Calculate SHA256 to get the new TempKey + atcac_sw_sha2_256(temporary, (p_temp - temporary), param->temp_key->value); + + // Update TempKey fields + param->temp_key->valid = 1; + + if ((param->zone == GENDIG_ZONE_DATA) && (param->key_id <= 15)) + { + param->temp_key->gen_dig_data = 1; + param->temp_key->key_id = (param->key_id & 0xF); // mask lower 4-bit only + if (param->is_key_nomac == 1) + { + param->temp_key->no_mac_flag = 1; + } + } + else + { + param->temp_key->gen_dig_data = 0; + param->temp_key->key_id = 0; + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_GENDIG */ + +/** \brief This function generates mac with session key with a plain text. + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_GEN_MAC +ATCA_STATUS atcah_gen_mac(struct atca_gen_dig_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_GEN_DIG]; + uint8_t *p_temp; + + // Check parameters + if (!param->stored_value || !param->temp_key) + { + return ATCA_BAD_PARAM; + } + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->no_mac_flag || (param->temp_key->valid != 1) + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes SessionKey + // (Config[KeyID] or OTP[KeyID] or Data.slot[KeyID] or TransportKey[KeyID]) + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_WRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_GENDIG_ZEROS_SIZE); + p_temp += ATCA_GENDIG_ZEROS_SIZE; + + // (8) 32 bytes PlainText + memcpy(p_temp, param->stored_value, ATCA_KEY_SIZE); + + // Calculate SHA256 to get the new TempKey + atcac_sw_sha2_256(temporary, ATCA_MSG_SIZE_GEN_DIG, param->temp_key->value); + + // Update TempKey fields + param->temp_key->valid = 1; + + if ((param->zone == GENDIG_ZONE_DATA) && (param->key_id <= 15)) + { + param->temp_key->gen_dig_data = 1; + param->temp_key->key_id = (param->key_id & 0xF); // mask lower 4-bit only + } + else + { + param->temp_key->gen_dig_data = 0; + param->temp_key->key_id = 0; + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_GEN_MAC */ + +/** \brief This function calculates the input MAC for the Write command. + + The Write command will need an input MAC if SlotConfig.WriteConfig.Encrypt is set. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_WRITE_AUTH_MAC +ATCA_STATUS atcah_write_auth_mac(struct atca_write_mac_in_out *param) +{ + uint8_t mac_input[ATCA_MSG_SIZE_ENCRYPT_MAC]; + uint8_t i; + uint8_t *p_temp; + + // Check parameters + if (!param->input_data || !param->temp_key) + { + return ATCA_BAD_PARAM; + } + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->no_mac_flag || (param->temp_key->valid != 1) + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + // Encrypt by XOR-ing Data with the TempKey + for (i = 0; i < 32; i++) + { + param->encrypted_data[i] = param->input_data[i] ^ param->temp_key->value[i]; + } + + // If the pointer *mac is provided by the caller then calculate input MAC + if (param->auth_mac) + { + // Start calculation + p_temp = mac_input; + + // (1) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_WRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_WRITE_MAC_ZEROS_SIZE); + p_temp += ATCA_WRITE_MAC_ZEROS_SIZE; + + // (8) 32 bytes PlainText + memcpy(p_temp, param->input_data, ATCA_KEY_SIZE); + + // Calculate SHA256 to get MAC + atcac_sw_sha2_256(mac_input, sizeof(mac_input), param->auth_mac); + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_WRITE_AUTH_MAC */ + +/** \brief This function calculates the input MAC for the PrivWrite command. + + The PrivWrite command will need an input MAC if SlotConfig.WriteConfig.Encrypt is set. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_PRIVWRITE_AUTH_MAC +ATCA_STATUS atcah_privwrite_auth_mac(struct atca_write_mac_in_out *param) +{ + uint8_t mac_input[ATCA_MSG_SIZE_PRIVWRITE_MAC]; + uint8_t i = 0; + uint8_t *p_temp = NULL; + uint8_t session_key2[32]; + + // Check parameters + if (!param->input_data || !param->temp_key) + { + return ATCA_BAD_PARAM; + } + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->no_mac_flag || (param->temp_key->valid != 1) + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + + /* Encrypt by XOR-ing Data with the TempKey + */ + + // Encrypt the next 28 bytes of the cipher text, which is the first part of the private key. + for (i = 0; i < 32; i++) + { + param->encrypted_data[i] = param->input_data[i] ^ param->temp_key->value[i]; + } + + // Calculate the new key for the last 4 bytes of the cipher text + atcac_sw_sha2_256(param->temp_key->value, 32, session_key2); + + // Encrypt the last 4 bytes of the cipher text, which is the remaining part of the private key + for (i = 32; i < 36; i++) + { + param->encrypted_data[i] = param->input_data[i] ^ session_key2[i - 32]; + } + + // If the pointer *mac is provided by the caller then calculate input MAC + if (param->auth_mac) + { + // Start calculation + p_temp = mac_input; + + // (1) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_PRIVWRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // (7) 21 zeros + memset(p_temp, 0, ATCA_PRIVWRITE_MAC_ZEROS_SIZE); + p_temp += ATCA_PRIVWRITE_MAC_ZEROS_SIZE; + + // (8) 36 bytes PlainText (Private Key) + memcpy(p_temp, param->input_data, ATCA_PRIVWRITE_PLAIN_TEXT_SIZE); + + // Calculate SHA256 to get the new TempKey + atcac_sw_sha2_256(mac_input, sizeof(mac_input), param->auth_mac); + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_PRIVWRITE_AUTH_MAC */ + +/** \brief This function derives a key with a key and TempKey. + + Used in conjunction with DeriveKey command, the key derived by this function will match the key in the device. + Two kinds of operation are supported: +
    +
  • Roll Key operation: target_key and parent_key parameters should be set to point to the same location (TargetKey).
  • +
  • Create Key operation: target_key should be set to point to TargetKey, parent_key should be set to point to ParentKey.
  • +
+ After executing this function, the initial value of target_key will be overwritten with the derived key. + The TempKey should be valid (temp_key.valid = 1) before executing this function. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_DERIVE_KEY +ATCA_STATUS atcah_derive_key(struct atca_derive_key_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_DERIVE_KEY]; + uint8_t *p_temp; + + // Check parameters + if (!param->parent_key || !param->target_key || !param->temp_key + || (param->mode & ~DERIVE_KEY_RANDOM_FLAG) || (param->target_key_id > ATCA_KEY_ID_MAX)) + { + return ATCA_BAD_PARAM; + } + + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->no_mac_flag || (param->temp_key->valid != 1) + // The random parameter bit 2 must match temp_key.source_flag + // Logical not (!) is used to evaluate the expression to TRUE / FALSE first before comparison (!=). + || (!(param->mode & DERIVE_KEY_RANDOM_FLAG) != !(param->temp_key->source_flag)) + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes parent key + memcpy(p_temp, param->parent_key, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_DERIVE_KEY; + + // (3) 1 byte Param1 (random) + *p_temp++ = param->mode; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->target_key_id & 0xFF; + *p_temp++ = (param->target_key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_DERIVE_KEY_ZEROS_SIZE); + p_temp += ATCA_DERIVE_KEY_ZEROS_SIZE; + + // (8) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // Calculate SHA256 to get the derived key. + atcac_sw_sha2_256(temporary, ATCA_MSG_SIZE_DERIVE_KEY, param->target_key); + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} +#endif /* ATCAH_DERIVE_KEY */ + +/** \brief This function calculates the input MAC for a DeriveKey command. + + The DeriveKey command will need an input MAC if SlotConfig[TargetKey].Bit15 is set. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_DERIVE_KEY_MAC +ATCA_STATUS atcah_derive_key_mac(struct atca_derive_key_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_DERIVE_KEY_MAC]; + uint8_t *p_temp; + + // Check parameters + if (!param->parent_key || !param->mac || (param->mode & ~DERIVE_KEY_RANDOM_FLAG) + || (param->target_key_id > ATCA_KEY_ID_MAX)) + { + return ATCA_BAD_PARAM; + } + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes parent key + memcpy(p_temp, param->parent_key, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_DERIVE_KEY; + + // (3) 1 byte Param1 (random) + *p_temp++ = param->mode; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->target_key_id & 0xFF; + *p_temp++ = (param->target_key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // Calculate SHA256 to get the input MAC for DeriveKey command + atcac_sw_sha2_256(temporary, ATCA_MSG_SIZE_DERIVE_KEY_MAC, param->mac); + + return ATCA_SUCCESS; +} +#endif /* ATCAH_DERIVE_KEY_MAC */ + +/** \brief This function decrypts 32-byte encrypted data received with the Read command. + + To use this function, first the nonce must be valid and synchronized between device and application. + The application sends a GenDig command to the Device, using a key specified by SlotConfig.ReadKey. + The device updates its TempKey. + The application then updates its own TempKey using the GenDig calculation function, using the same key. + The application sends a Read command to the device for a user zone configured with EncryptRead. + The device encrypts 32-byte zone content, and outputs it to the host. + The application passes these encrypted data to this decryption function. The function decrypts the data and returns them. + TempKey must be updated by GenDig using a ParentKey as specified by SlotConfig.ReadKey before executing this function. + The decryption function does not check whether the TempKey has been generated by a correct ParentKey for the corresponding zone. + Therefore to get a correct result, the application has to make sure that prior GenDig calculation was done using correct ParentKey. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_DECRYPT +ATCA_STATUS atcah_decrypt(struct atca_decrypt_in_out *param) +{ + uint8_t i; + + // Check parameters + if (!param->crypto_data || !param->temp_key) + { + return ATCA_BAD_PARAM; + } + + // Check TempKey fields validity + // Note that if temp_key.key_id is not checked, + // we cannot make sure if the key used in previous GenDig IS equal to + // the key pointed by SlotConfig.ReadKey in the device. + if ( // TempKey.CheckFlag must be 0 + param->temp_key->no_mac_flag + // TempKey.Valid must be 1 + || (param->temp_key->valid != 1) + // TempKey.GenData must be 1 + || (param->temp_key->gen_dig_data != 1) + // TempKey.SourceFlag must be 0 (random) + || param->temp_key->source_flag + ) + { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Decrypt by XOR-ing Data with the TempKey + for (i = 0; i < ATCA_KEY_SIZE; i++) + { + param->crypto_data[i] ^= param->temp_key->value[i]; + } + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} +#endif /* ATCAH_DECRYPT */ + +/** \brief This function creates a SHA256 digest on a little-endian system. + * + * \param[in] len byte length of message + * \param[in] message pointer to message + * \param[out] digest SHA256 of message + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_SHA256 +ATCA_STATUS atcah_sha256(int32_t len, const uint8_t *message, uint8_t *digest) +{ + return (ATCA_STATUS)atcac_sw_sha2_256(message, len, digest); +} +#endif /* ATCAH_SHA256 */ + +/** \brief Calculate the PubKey digest created by GenKey and saved to TempKey. + * + * \param[in,out] param GenKey parameters required to calculate the PubKey + * digest. Digest is return in the temp_key parameter. + * + \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_GEN_KEY_MSG +ATCA_STATUS atcah_gen_key_msg(struct atca_gen_key_in_out *param) +{ + uint8_t msg[128]; + + if (param == NULL || param->public_key == NULL || param->sn == NULL || param->temp_key == NULL) + { + return ATCA_BAD_PARAM; + } + if (param->public_key_size == 0 || param->public_key_size > 88) + { + return ATCA_BAD_PARAM; + } + + memset(msg, 0, sizeof(msg)); + memcpy(&msg[0], param->temp_key->value, 32); + msg[32] = ATCA_GENKEY; + + if (param->mode & GENKEY_MODE_PUBKEY_DIGEST) + { + // Calculate PubKey digest of stored public key, takes priority over other bits + if (param->other_data == NULL) + { + return ATCA_BAD_PARAM; + } + memcpy(&msg[33], param->other_data, 3); // OtherData replaces mode and key_id in message + } + else if (param->mode & GENKEY_MODE_DIGEST) + { + msg[33] = param->mode; + msg[34] = (uint8_t)(param->key_id >> 0); + msg[35] = (uint8_t)(param->key_id >> 8); + } + else + { + // Mode indicates no PubKey digest was requested. + // No change to TempKey. + return ATCA_SUCCESS; + } + + msg[36] = param->sn[8]; + memcpy(&msg[37], ¶m->sn[0], 2); + + // Copy public key into end of message + memcpy(&msg[sizeof(msg) - param->public_key_size], param->public_key, param->public_key_size); + + atcac_sw_sha2_256(msg, sizeof(msg), param->temp_key->value); + param->temp_key->gen_dig_data = 0; + param->temp_key->gen_key_data = 1; + param->temp_key->key_id = param->key_id; + + return ATCA_SUCCESS; +} +#endif /* ATCAH_GEN_KEY_MSG */ + +/** \brief Populate the slot_config, key_config, and is_slot_locked fields in + * the atca_sign_internal_in_out structure from the provided config + * zone. + * + * The atca_sign_internal_in_out structure has a number of fields + * (slot_config, key_config, is_slot_locked) that can be determined + * automatically from the current state of TempKey and the full config + * zone. + * + * \param[in,out] param Sign(Internal) parameters to be filled out. Only + * slot_config, key_config, and is_slot_locked will be + * set. + * \param[in] device_type The type of the device. + * \param[in] config Full 128 byte config zone for the device. + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_CONFIG_TO_SIGN_INTERNAL +ATCA_STATUS atcah_config_to_sign_internal(ATCADeviceType device_type, struct atca_sign_internal_in_out *param, const uint8_t* config) +{ + const uint8_t* value = NULL; + uint16_t slot_locked = 0; + + if (param == NULL || config == NULL || param->temp_key == NULL) + { + return ATCA_BAD_PARAM; + } + + // SlotConfig[TempKeyFlags.keyId] + value = &config[20 + param->temp_key->key_id * 2]; + param->slot_config = (uint16_t)value[0] | ((uint16_t)value[1] << 8); + + // KeyConfig[TempKeyFlags.keyId] + value = &config[96 + param->temp_key->key_id * 2]; + param->key_config = (uint16_t)value[0] | ((uint16_t)value[1] << 8); + + if (device_type == ATECC108A && param->temp_key->key_id < 8) + { + value = &config[52 + param->temp_key->key_id * 2]; + param->use_flag = value[0]; + param->update_count = value[1]; + } + else + { + param->use_flag = 0x00; + param->update_count = 0x00; + } + + //SlotLocked:TempKeyFlags.keyId + slot_locked = (uint16_t)config[88] | ((uint16_t)config[89] << 8); + param->is_slot_locked = (slot_locked & (1 << param->temp_key->key_id)) ? false : true; + + return ATCA_SUCCESS; +} +#endif /* ATCAH_CONFIG_TO_SIGN_INTERNAL */ + +/** \brief Builds the full message that would be signed by the Sign(Internal) + * command. + * + * Additionally, the function will optionally output the OtherData data + * required by the Verify(In/Validate) command as well as the SHA256 digest of + * the full message. + * + * \param[out] device_type Device type to perform the calculation for. + * \param[out] param Input data and output buffers required. + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_SIGN_INTERNAL_MSG +ATCA_STATUS atcah_sign_internal_msg(ATCADeviceType device_type, struct atca_sign_internal_in_out *param) +{ + uint8_t msg[55]; + + if (param == NULL || param->temp_key == NULL || param->sn == NULL) + { + return ATCA_BAD_PARAM; + } + + memset(msg, 0, sizeof(msg)); + memcpy(&msg[0], param->temp_key->value, 32); + msg[32] = ATCA_SIGN; // Sign OpCode + msg[33] = param->mode; // Sign Mode + msg[34] = (uint8_t)(param->key_id >> 0); // Sign KeyID + msg[35] = (uint8_t)(param->key_id >> 8); + msg[36] = (uint8_t)(param->slot_config >> 0); // SlotConfig[TempKeyFlags.keyId] + msg[37] = (uint8_t)(param->slot_config >> 8); + msg[38] = (uint8_t)(param->key_config >> 0); // KeyConfig[TempKeyFlags.keyId] + msg[39] = (uint8_t)(param->key_config >> 8); + + //TempKeyFlags (b0-3: keyId, b4: sourceFlag, b5: GenDigData, b6: GenKeyData, b7: NoMacFlag) + msg[40] |= ((param->temp_key->key_id & 0x0F) << 0); + msg[40] |= ((param->temp_key->source_flag & 0x01) << 4); + msg[40] |= ((param->temp_key->gen_dig_data & 0x01) << 5); + msg[40] |= ((param->temp_key->gen_key_data & 0x01) << 6); + msg[40] |= ((param->temp_key->no_mac_flag & 0x01) << 7); + + if (device_type == ATECC108A && param->temp_key->key_id < 8) + { + msg[41] = param->use_flag; // UseFlag[TempKeyFlags.keyId] + msg[42] = param->update_count; // UpdateCount[TempKeyFlags.keyId] + } + else + { + msg[41] = 0x00; + msg[42] = 0x00; + } + + // Serial Number + msg[43] = param->sn[8]; + memcpy(&msg[48], ¶m->sn[0], 2); + if (param->mode & SIGN_MODE_INCLUDE_SN) + { + memcpy(&msg[44], ¶m->sn[4], 4); + memcpy(&msg[50], ¶m->sn[2], 2); + } + + // The bit within the SlotLocked field corresponding to the last key used in the TempKey computation is in the LSB + msg[52] = param->is_slot_locked ? 0x00 : 0x01; + + // If the slot contains a public key corresponding to a supported curve, and if PubInfo indicates this key must be + // validated before being used by Verify, and if the validity bits have a value of 0x05, then the PubKey Valid byte + // will be 0x01. In all other cases, it will be 0. + msg[53] = param->for_invalidate ? 0x01 : 0x00; + + msg[54] = 0x00; + + if (param->message) + { + memcpy(param->message, msg, sizeof(msg)); + } + if (param->verify_other_data) + { + memcpy(¶m->verify_other_data[0], &msg[33], 10); + memcpy(¶m->verify_other_data[10], &msg[44], 4); + memcpy(¶m->verify_other_data[14], &msg[50], 5); + } + if (param->digest) + { + return (ATCA_STATUS)atcac_sw_sha2_256(msg, sizeof(msg), param->digest); + } + else + { + return ATCA_SUCCESS; + } +} +#endif /* ATCAH_SIGN_INTERNAL_MSG */ + +/** \brief Builds the counter match value that needs to be stored in a slot. + * + * \param[in] counter_value Counter value to be used for the counter + * match. This must be a multiple of 32. + * \param[out] counter_match_value Data to be stored in the beginning of a + * counter match slot will be returned here + * (8 bytes). + * + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_ENCODE_COUNTER_MATCH +ATCA_STATUS atcah_encode_counter_match(uint32_t counter_value, uint8_t * counter_match_value) +{ + if ((counter_value > COUNTER_MAX_VALUE) || (counter_value % 32 != 0) || (counter_match_value == NULL)) + { + return ATCA_BAD_PARAM; + } + + // Counter match value is stored in little-endian unsigned format + counter_match_value[0] = (uint8_t)((counter_value >> 0) & 0xFF); + counter_match_value[1] = (uint8_t)((counter_value >> 8) & 0xFF); + counter_match_value[2] = (uint8_t)((counter_value >> 16) & 0xFF); + counter_match_value[3] = (uint8_t)((counter_value >> 24) & 0xFF); + + // Counter match value should be repeated in the next 4 bytes + memcpy(counter_match_value + 4, counter_match_value, 4); + + return ATCA_SUCCESS; +} +#endif /* ATCAH_ENCODE_COUNTER_MATCAH */ + +/** \brief This function calculates the input MAC for the ECC204 Write command. + + The Write command will need an input MAC if SlotConfig3.bit0 is set. + + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_WRITE_AUTH_MAC +ATCA_STATUS atcah_ecc204_write_auth_mac(struct atca_write_mac_in_out *param) +{ + uint8_t mac_input[ATCA_MSG_SIZE_ENCRYPT_MAC]; + uint8_t i; + uint8_t *p_temp; + + // Check parameters + if ((NULL == param->input_data) || (NULL == param->temp_key)) + { + return ATCA_BAD_PARAM; + } + + // Encrypt by XOR-ing Data with the session key + for (i = 0; i < 32; i++) + { + param->encrypted_data[i] = param->input_data[i] ^ param->temp_key->value[i]; + } + + // If the pointer *mac is provided by the caller then calculate input MAC + if (param->auth_mac) + { + // Start calculation + p_temp = mac_input; + + // (1) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_WRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = (param->key_id >> 8) & 0xFF; + *p_temp++ = param->key_id & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_WRITE_MAC_ZEROS_SIZE); + p_temp += ATCA_WRITE_MAC_ZEROS_SIZE; + + // (8) 32 bytes PlainText + memcpy(p_temp, param->input_data, ATCA_KEY_SIZE); + + // Calculate SHA256 to get MAC + atcac_sw_sha2_256(mac_input, sizeof(mac_input), param->auth_mac); + } + + return ATCA_SUCCESS; +} +#endif /* ATCAH_WRITE_AUTH_MAC */ + +/** \brief This function calculates the session key for the ECC204. + * + * \param[in,out] param pointer to parameter structure + * \return ATCA_SUCCESS on success, otherwise an error code. + */ +#if ATCAH_GEN_SESSION_KEY +ATCA_STATUS atcah_gen_session_key(struct atca_session_key_in_out *param) +{ + uint8_t session_key_input[ATCA_MSG_SIZE_SESSION_KEY]; + uint8_t *p_temp; + + if ((NULL == param->transport_key) || (NULL == param->nonce) || (NULL == param->session_key)) + { + return ATCA_BAD_PARAM; + } + + p_temp = session_key_input; + + // (1) 32 bytes of transport key + memcpy(p_temp, param->transport_key, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 0x15 + *p_temp++ = 0x15; + + // (3) 0x00 + *p_temp++ = 0x00; + + // (4) 2bytes of transport key id + *p_temp++ = param->transport_key_id & 0xFF; + *p_temp++ = (param->transport_key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] + *p_temp++ = param->sn[8]; + + // (6) 2 bytes SN[0:1] + *p_temp++ = param->sn[0]; + *p_temp++ = param->sn[1]; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_WRITE_MAC_ZEROS_SIZE); + p_temp += ATCA_WRITE_MAC_ZEROS_SIZE; + + // (8) 32 bytes nonce + memcpy(p_temp, param->nonce, 32); + + // Calculate SHA256 to get MAC + atcac_sw_sha2_256(session_key_input, sizeof(session_key_input), param->session_key); + + return ATCA_SUCCESS; +} +#endif /* ATCAH_GEN_SESSION_KEY */ + +#endif \ No newline at end of file diff --git a/drivers/ecc108a/micropython.cmake b/drivers/ecc108a/micropython.cmake index 316bf39..dcbc38a 100644 --- a/drivers/ecc108a/micropython.cmake +++ b/drivers/ecc108a/micropython.cmake @@ -12,6 +12,7 @@ target_sources(usermod_ecc108a INTERFACE ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_iface.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/atca_utils_sizes.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/cryptoauthlib.h + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/host/atca_host.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_hmac.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_lock.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_secureboot.c @@ -26,7 +27,7 @@ target_sources(usermod_ecc108a INTERFACE ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_derivekey.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_genkey.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_execution.c -# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_verify.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_verify.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_sign.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_helpers.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_counter.c @@ -34,7 +35,7 @@ target_sources(usermod_ecc108a INTERFACE ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_basic.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_random.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_command.c -# ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_sha.c + ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_sha.c ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_privwrite.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_kdf.c # ${CMAKE_CURRENT_LIST_DIR}/cryptoauthlib/calib/calib_aes.c diff --git a/drivers/tidal_usb/tidal_usb_console.c b/drivers/tidal_usb/tidal_usb_console.c index 41cb237..aaad04e 100644 --- a/drivers/tidal_usb/tidal_usb_console.c +++ b/drivers/tidal_usb/tidal_usb_console.c @@ -4,7 +4,7 @@ #include "tusb_console.h" #include "tidal_usb_console.h" -#if CONFIG_USB_CDC_ENABLED +#if CONFIG_TINYUSB_CDC_ENABLED #include "tusb_cdc_acm.h" // USB serial read callbacks from mp diff --git a/drivers/tidal_usb/tidal_usb_hid.c b/drivers/tidal_usb/tidal_usb_hid.c index 3108827..df92908 100644 --- a/drivers/tidal_usb/tidal_usb_hid.c +++ b/drivers/tidal_usb/tidal_usb_hid.c @@ -26,7 +26,10 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep void tud_hid_report_complete_cb(uint8_t itf, uint8_t const *report, uint8_t len) { ESP_LOGW(TAG, "HID report complete"); - pop_and_send_report(); + #if CFG_TUD_U2FHID + // Also send any pending U2F reports + pop_and_send_report(); + #endif } // Send up to 6 keyboard scancodes diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index 8955116..fc82bd7 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -6,7 +6,7 @@ #include "u2f_crypto.h" #include -#if CFG_TUD_U2FHID +#if CONFIG_TINYUSB_U2FHID_ENABLED static const char *TAG = "tidalU2F"; @@ -171,10 +171,13 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body ESP_LOGI(TAG, "Allocating container"); arbitrary_size_container response_data = { .size=0, - .data=malloc(512) + .data=malloc(1024) }; + memset(response_data.data, 0x00, 1024); size_t write_head = 0; uint8_t handle = allocate_handle(); + uint8_t signature_input[131] = { 0 }; + // Set reserved byte ESP_LOGI(TAG, "Setting header"); @@ -190,10 +193,11 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body response_data.data[write_head++] = 0x01; response_data.data[write_head++] = handle; + // Attestation certificate ESP_LOGI(TAG, "Setting cert"); // Get the certificate from the secure elefment - arbitrary_size_container cert = get_der_certificate(1); + arbitrary_size_container cert = get_attestation_certificate(); // Copy it into the current data stream memcpy(response_data.data + write_head, cert.data, cert.size); write_head += cert.size; @@ -202,12 +206,11 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body // Create the signature out of 0x00, the register request, key handle and pubkey ESP_LOGI(TAG, "Setting signature"); - uint8_t signature_input[131] = { 0 }; signature_input[0] = 0x00; memcpy(signature_input + 1, register_params, 65); signature_input[66] = handle; memcpy(signature_input + 67, response_data.data + 1, 64); - arbitrary_size_container signature = get_signature(signature_input); + arbitrary_size_container signature = get_signature(1, signature_input); memcpy(response_data.data + write_head, signature.data, signature.size); write_head += signature.size; // Free the intermediate copy @@ -218,7 +221,7 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; ESP_LOGI(TAG, "Built %d byte register response", write_head); response_data.size = write_head; - realloc(response_data.data, write_head); + //realloc(response_data.data, write_head); printf("RAW data:"); for (int i=0;iapplication_param, 32); memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - arbitrary_size_container signature = get_signature(signature_input); + arbitrary_size_container signature = get_signature(6, signature_input); memcpy(response_data.data + write_head, signature.data, signature.size); write_head += signature.size; // Free the intermediate copy diff --git a/drivers/tidal_usb/tidal_usb_u2f.h b/drivers/tidal_usb/tidal_usb_u2f.h index 009c277..7168b23 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.h +++ b/drivers/tidal_usb/tidal_usb_u2f.h @@ -44,7 +44,7 @@ typedef struct u2f_raw_authenticate_request_body { // U2F HIF support -#define REPORT_RING_SIZE 10 +#define REPORT_RING_SIZE 16 typedef struct u2f_hid_msg { uint32_t CID; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 4f91ceb..e239d93 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -1,46 +1,101 @@ #include "u2f_crypto.h" #include "esp_log.h" +#include "atca_iface.h" +#include "atca_basic.h" #include #include #include static const char *TAG = "tidalU2F"; -arbitrary_size_container get_der_certificate(uint8_t handle) { - uint8_t cert[] = { - 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x56, 0xfc, 0xfd, 0xe4, 0x9c, 0x47, 0x59, 0xce, 0xd2, - 0x0e, 0xb3, 0xbf, 0xd4, 0x42, 0x75, 0x0b, 0x8d, 0x97, 0x15, 0xc6, 0x50, 0xfd, 0xb9, 0xd1, 0xd8, - 0x6a, 0xb0, 0x71, 0xa2, 0x90, 0xe0, 0xeb, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, - 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x6f, 0x76, 0x9d, 0x62, 0xb7, 0x00, 0xbc, - 0x0c, 0x58, 0x99, 0x76, 0x82, 0x95, 0x80, 0xdd, 0xc6, 0xb1, 0x2e, 0x26, 0x02, 0x43, 0xdf, 0xe1, - 0xe6, 0x72, 0x7b, 0xa1, 0xe9, 0xdc, 0xe1, 0xae, 0x26, 0x8a, 0x23, 0x45, 0xb0, 0xbb, 0x0f, 0x4f, - 0x3e, 0x73, 0xa1, 0x01, 0x09, 0xfb, 0xbe, 0x04, 0xf0, 0x91, 0xd5, 0xa7, 0xd9, 0xe6, 0x77, 0x26, - 0x01, 0xaf, 0xfb, 0xbc, 0x21, 0x20, 0x79, 0x7b, 0xcc + +arbitrary_size_container get_attestation_certificate() { + unsigned char attestation_der[] = { + 0x30, 0x82, 0x02, 0x4a, 0x30, 0x82, 0x01, 0xef, 0x02, 0x14, 0x11, 0xca, + 0xcc, 0x12, 0x88, 0x94, 0x28, 0x5c, 0xa8, 0x14, 0xc5, 0xd7, 0x9b, 0xb6, + 0x6f, 0x29, 0xb4, 0x73, 0xb8, 0xdd, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0xa5, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x4c, 0x6f, 0x6e, + 0x64, 0x6f, 0x6e, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x06, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x31, 0x22, 0x30, 0x20, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x19, 0x45, 0x6c, 0x65, 0x63, 0x74, + 0x72, 0x6f, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x09, 0x42, 0x61, 0x64, 0x67, 0x65, + 0x54, 0x65, 0x61, 0x6d, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x11, 0x54, 0x69, 0x44, 0x41, 0x4c, 0x20, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x20, 0x30, 0x1e, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, + 0x11, 0x62, 0x61, 0x64, 0x67, 0x65, 0x40, 0x65, 0x6d, 0x66, 0x63, 0x61, + 0x6d, 0x70, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, + 0x31, 0x30, 0x33, 0x30, 0x31, 0x37, 0x34, 0x32, 0x34, 0x34, 0x5a, 0x18, + 0x0f, 0x32, 0x30, 0x35, 0x37, 0x31, 0x30, 0x33, 0x30, 0x31, 0x37, 0x34, + 0x32, 0x34, 0x34, 0x5a, 0x30, 0x81, 0xa5, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x0f, 0x30, 0x0d, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, + 0x6e, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x06, + 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x19, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, + 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x09, 0x42, 0x61, 0x64, 0x67, 0x65, 0x54, 0x65, + 0x61, 0x6d, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x11, 0x54, 0x69, 0x44, 0x41, 0x4c, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x62, + 0x61, 0x64, 0x67, 0x65, 0x40, 0x65, 0x6d, 0x66, 0x63, 0x61, 0x6d, 0x70, + 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x70, 0x33, 0xf2, 0x6e, 0x2d, + 0xc2, 0xc0, 0xd1, 0xf8, 0xa7, 0x03, 0x3e, 0xa6, 0x4e, 0x47, 0x1a, 0xe1, + 0x02, 0xfe, 0xf3, 0xdb, 0xc9, 0xbd, 0xb7, 0x3e, 0x69, 0x59, 0xa1, 0xa5, + 0x49, 0x8b, 0x8e, 0x9a, 0x2a, 0xbd, 0xb2, 0xf5, 0xa8, 0xcb, 0xa0, 0x4a, + 0xb4, 0x6a, 0x84, 0x32, 0x09, 0x80, 0x95, 0x21, 0x99, 0x3d, 0x29, 0xe1, + 0xe0, 0xc2, 0xdf, 0xbd, 0xd5, 0x08, 0x22, 0x7a, 0xd8, 0x2d, 0xe2, 0x30, + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, + 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xd6, 0x6b, 0x12, 0x6c, 0xa9, + 0xf4, 0x56, 0x80, 0xf5, 0x58, 0xb9, 0xc3, 0xdf, 0xd5, 0xb2, 0xdf, 0x49, + 0x25, 0x44, 0x55, 0x81, 0xa8, 0x96, 0x88, 0x6b, 0x49, 0x03, 0x0b, 0xdb, + 0xa6, 0x75, 0x7f, 0x02, 0x21, 0x00, 0xa2, 0x46, 0x8d, 0xbd, 0x42, 0xda, + 0x2d, 0xda, 0x09, 0x0d, 0x68, 0xd8, 0x1b, 0x9f, 0x00, 0xea, 0xef, 0xfa, + 0x2f, 0x77, 0x1b, 0xc7, 0xe2, 0x36, 0x8c, 0x0b, 0xae, 0x34, 0x6b, 0x8c, + 0x4d, 0xc5 }; - ESP_LOGI(TAG, "Allocating %d bytes", sizeof(cert)); + unsigned int attestation_der_len = 590; + + ESP_LOGI(TAG, "Allocating %d bytes", attestation_der_len); arbitrary_size_container response_data = { - .size=sizeof(cert), - .data=malloc(sizeof(cert)), + .size=attestation_der_len, + .data=malloc(attestation_der_len), }; - memcpy(response_data.data, cert, sizeof(cert)); + memcpy(response_data.data, &attestation_der, attestation_der_len); return response_data; } -arbitrary_size_container get_signature(uint8_t signature_input[]) { +arbitrary_size_container get_signature(uint8_t handle, uint8_t signature_input[]) { + uint8_t digest[32] = { 0 }; + ESP_LOGI(TAG, "Calculating digest"); + atcab_hw_sha2_256(signature_input, sizeof(signature_input), digest); ESP_LOGI(TAG, "Allocating %d bytes", 73); arbitrary_size_container response_data = { - .size=73, - .data=malloc(73), + .size=64, + .data=malloc(64), }; - memset(response_data.data, 0xF0, 73); + ESP_LOGI(TAG, "Signing data"); + atcab_sign(handle, &digest, response_data.data); + //memset(response_data.data, 0xF0, 73); return response_data; } -void *set_pubkey(uint8_t handle, uint8_t *target) { - memset(target, 0xC0, 65); - return; +void set_counter(uint8_t handle, uint32_t *target) { + //atcab_counter_increment(handle, target); +} + +void set_pubkey(uint8_t handle, uint8_t *target) { + atcab_genkey(handle, target); } uint8_t allocate_handle() { - return 1; + return 6; } \ No newline at end of file diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h index 5d0ab83..fe63cd2 100644 --- a/drivers/tidal_usb/u2f_crypto.h +++ b/drivers/tidal_usb/u2f_crypto.h @@ -6,7 +6,8 @@ typedef struct arbitrary_size_container { uint8_t *data; } arbitrary_size_container; -arbitrary_size_container get_der_certificate(uint8_t handle); -arbitrary_size_container get_signature(uint8_t signature_input[]); -void *set_pubkey(uint8_t handle, uint8_t *target); +arbitrary_size_container get_attestation_certificate(); +arbitrary_size_container get_signature(uint8_t handle, uint8_t signature_input[]); +void set_counter(uint8_t handle, uint32_t *target); +void set_pubkey(uint8_t handle, uint8_t *target); uint8_t allocate_handle(); \ No newline at end of file diff --git a/esp-iot-solution.diff b/esp-iot-solution.diff index 83f959c..15f3547 100644 --- a/esp-iot-solution.diff +++ b/esp-iot-solution.diff @@ -38,8 +38,8 @@ index 2b6e48c..c4ca8c5 100644 #define CFG_TUD_CDC CONFIG_TINYUSB_CDC_PORT_NUM #define CFG_TUD_MSC CONFIG_TINYUSB_MSC_ENABLED -#define CFG_TUD_HID CONFIG_TINYUSB_HID_ENABLED -+#define CFG_TUD_HID_KBD 1 -+#define CFG_TUD_U2FHID false ++#define CFG_TUD_HID_KBD false ++#define CFG_TUD_U2FHID 1 +#define CFG_TUD_HID 1 #define CFG_TUD_MIDI CONFIG_TINYUSB_MIDI_ENABLED #define CFG_TUD_CUSTOM_CLASS CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED diff --git a/keys/attestation.crt b/keys/attestation.crt new file mode 100644 index 0000000..3d80394 --- /dev/null +++ b/keys/attestation.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSjCCAe8CFBHKzBKIlChcqBTF15u2bym0c7jdMAoGCCqGSM49BAMCMIGlMQsw +CQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xIjAg +BgNVBAoMGUVsZWN0cm9tYWduZXRpYyBGaWVsZCBMdGQxEjAQBgNVBAsMCUJhZGdl +VGVhbTEaMBgGA1UEAwwRVGlEQUwgQXR0ZXN0YXRpb24xIDAeBgkqhkiG9w0BCQEW +EWJhZGdlQGVtZmNhbXAub3JnMCAXDTIyMTAzMDE3NDI0NFoYDzIwNTcxMDMwMTc0 +MjQ0WjCBpTELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwG +TG9uZG9uMSIwIAYDVQQKDBlFbGVjdHJvbWFnbmV0aWMgRmllbGQgTHRkMRIwEAYD +VQQLDAlCYWRnZVRlYW0xGjAYBgNVBAMMEVRpREFMIEF0dGVzdGF0aW9uMSAwHgYJ +KoZIhvcNAQkBFhFiYWRnZUBlbWZjYW1wLm9yZzBZMBMGByqGSM49AgEGCCqGSM49 +AwEHA0IABHAz8m4twsDR+KcDPqZORxrhAv7z28m9tz5pWaGlSYuOmiq9svWoy6BK +tGqEMgmAlSGZPSnh4MLfvdUIInrYLeIwCgYIKoZIzj0EAwIDSQAwRgIhANZrEmyp +9FaA9Vi5w9/Vst9JJURVgaiWiGtJAwvbpnV/AiEAokaNvULaLdoJDWjYG58A6u/6 +L3cbx+I2jAuuNGuMTcU= +-----END CERTIFICATE----- diff --git a/keys/attestation.csr b/keys/attestation.csr new file mode 100644 index 0000000..6846993 --- /dev/null +++ b/keys/attestation.csr @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBYjCCAQgCAQAwgaUxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzAN +BgNVBAcMBkxvbmRvbjEiMCAGA1UECgwZRWxlY3Ryb21hZ25ldGljIEZpZWxkIEx0 +ZDESMBAGA1UECwwJQmFkZ2VUZWFtMRowGAYDVQQDDBFUaURBTCBBdHRlc3RhdGlv +bjEgMB4GCSqGSIb3DQEJARYRYmFkZ2VAZW1mY2FtcC5vcmcwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAARwM/JuLcLA0finAz6mTkca4QL+89vJvbc+aVmhpUmLjpoq +vbL1qMugSrRqhDIJgJUhmT0p4eDC373VCCJ62C3ioAAwCgYIKoZIzj0EAwIDSAAw +RQIgdBVG25oY7umbvnhQxlXSAKWgAUWspzSNziQYrTbYugACIQCVI+P3E5QPAlLy +AQau36WadR9IA7RLqtXfYxvcbbbWpg== +-----END CERTIFICATE REQUEST----- diff --git a/keys/attestation.der b/keys/attestation.der new file mode 100644 index 0000000000000000000000000000000000000000..5b83728709001c407b71e03a0468b085ab0aa4d6 GIT binary patch literal 590 zcmXqLV)8O*VtmgeB6#YIP{$OFm=z*Nug~6=ueqgo$6W(1HV&;ek8`#x%uEK2OAWaV zIN6v(S=fY`+?@>h4R}Eu4jwk2{JfO>JeUAGTtLY{0i=S9N76MXHMyiHKQ}QwFSR5y zS-~wcH77;ErzFKt$Up$3hMR}eDKRBIH6%4L*HFqp0wl)FBN&qD;^?E`SW=Q&T#{Il z3A9APK#q+Q=%%*syo{WTVuDE^T@I`hoyhcWb2F3=4<|alaCQ%an zMh2$lNCHE~Cy@riZ0z9hXJUj#1T!N$vl9bLf$^t2-9ra1{#edzx6IF7>LJs=&$mzR z-ENl|xp1jxci$|ny_>$SIK9AYOIC{!XTwy*nYNk_9~`>B_bP`{)eYT8$Pvrz$zb5d zq{whBTPSDcm#~Jf5jzjxzq;wZr>aY6)q>gOZOHhZ^jMj Y`3$e#|I#m)KK{t8hkKn#c8~8-01&mba{vGU literal 0 HcmV?d00001 diff --git a/keys/attestation.h b/keys/attestation.h new file mode 100644 index 0000000..9f6b833 --- /dev/null +++ b/keys/attestation.h @@ -0,0 +1,53 @@ +unsigned char attestation_der[] = { + 0x30, 0x82, 0x02, 0x4a, 0x30, 0x82, 0x01, 0xef, 0x02, 0x14, 0x11, 0xca, + 0xcc, 0x12, 0x88, 0x94, 0x28, 0x5c, 0xa8, 0x14, 0xc5, 0xd7, 0x9b, 0xb6, + 0x6f, 0x29, 0xb4, 0x73, 0xb8, 0xdd, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0xa5, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x4c, 0x6f, 0x6e, + 0x64, 0x6f, 0x6e, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x06, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x31, 0x22, 0x30, 0x20, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x19, 0x45, 0x6c, 0x65, 0x63, 0x74, + 0x72, 0x6f, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x09, 0x42, 0x61, 0x64, 0x67, 0x65, + 0x54, 0x65, 0x61, 0x6d, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x11, 0x54, 0x69, 0x44, 0x41, 0x4c, 0x20, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x20, 0x30, 0x1e, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, + 0x11, 0x62, 0x61, 0x64, 0x67, 0x65, 0x40, 0x65, 0x6d, 0x66, 0x63, 0x61, + 0x6d, 0x70, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, + 0x31, 0x30, 0x33, 0x30, 0x31, 0x37, 0x34, 0x32, 0x34, 0x34, 0x5a, 0x18, + 0x0f, 0x32, 0x30, 0x35, 0x37, 0x31, 0x30, 0x33, 0x30, 0x31, 0x37, 0x34, + 0x32, 0x34, 0x34, 0x5a, 0x30, 0x81, 0xa5, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x0f, 0x30, 0x0d, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, + 0x6e, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x06, + 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x19, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, + 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x09, 0x42, 0x61, 0x64, 0x67, 0x65, 0x54, 0x65, + 0x61, 0x6d, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x11, 0x54, 0x69, 0x44, 0x41, 0x4c, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x62, + 0x61, 0x64, 0x67, 0x65, 0x40, 0x65, 0x6d, 0x66, 0x63, 0x61, 0x6d, 0x70, + 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x70, 0x33, 0xf2, 0x6e, 0x2d, + 0xc2, 0xc0, 0xd1, 0xf8, 0xa7, 0x03, 0x3e, 0xa6, 0x4e, 0x47, 0x1a, 0xe1, + 0x02, 0xfe, 0xf3, 0xdb, 0xc9, 0xbd, 0xb7, 0x3e, 0x69, 0x59, 0xa1, 0xa5, + 0x49, 0x8b, 0x8e, 0x9a, 0x2a, 0xbd, 0xb2, 0xf5, 0xa8, 0xcb, 0xa0, 0x4a, + 0xb4, 0x6a, 0x84, 0x32, 0x09, 0x80, 0x95, 0x21, 0x99, 0x3d, 0x29, 0xe1, + 0xe0, 0xc2, 0xdf, 0xbd, 0xd5, 0x08, 0x22, 0x7a, 0xd8, 0x2d, 0xe2, 0x30, + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, + 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xd6, 0x6b, 0x12, 0x6c, 0xa9, + 0xf4, 0x56, 0x80, 0xf5, 0x58, 0xb9, 0xc3, 0xdf, 0xd5, 0xb2, 0xdf, 0x49, + 0x25, 0x44, 0x55, 0x81, 0xa8, 0x96, 0x88, 0x6b, 0x49, 0x03, 0x0b, 0xdb, + 0xa6, 0x75, 0x7f, 0x02, 0x21, 0x00, 0xa2, 0x46, 0x8d, 0xbd, 0x42, 0xda, + 0x2d, 0xda, 0x09, 0x0d, 0x68, 0xd8, 0x1b, 0x9f, 0x00, 0xea, 0xef, 0xfa, + 0x2f, 0x77, 0x1b, 0xc7, 0xe2, 0x36, 0x8c, 0x0b, 0xae, 0x34, 0x6b, 0x8c, + 0x4d, 0xc5 +}; +unsigned int attestation_der_len = 590; diff --git a/keys/private.pem b/keys/private.pem new file mode 100644 index 0000000..fd4cbf9 --- /dev/null +++ b/keys/private.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDOln7OQO6fHoGDxGW7nQH5DzlnkxxGCfSgeJFb9w7LjoAoGCCqGSM49 +AwEHoUQDQgAEcDPybi3CwNH4pwM+pk5HGuEC/vPbyb23PmlZoaVJi46aKr2y9ajL +oEq0aoQyCYCVIZk9KeHgwt+91Qgietgt4g== +-----END EC PRIVATE KEY----- diff --git a/keys/public.pem b/keys/public.pem new file mode 100644 index 0000000..5fde78d --- /dev/null +++ b/keys/public.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcDPybi3CwNH4pwM+pk5HGuEC/vPb +yb23PmlZoaVJi46aKr2y9ajLoEq0aoQyCYCVIZk9KeHgwt+91Qgietgt4g== +-----END PUBLIC KEY----- diff --git a/modules/boot.py b/modules/boot.py index 589110e..960699e 100644 --- a/modules/boot.py +++ b/modules/boot.py @@ -2,6 +2,7 @@ import tidal import tidal_helpers +import ecc108a from esp32 import Partition # sleep_sel just gets in the way of using lightsleep @@ -10,6 +11,7 @@ # Initialize USB early on tidal.usb.initialize() tidal.init_lcd() +ecc108a.init() if tidal.BUTTON_FRONT.value() == 0: # Boot to the recovery menu diff --git a/tildamk6/sdkconfig.board b/tildamk6/sdkconfig.board index f963518..d28ac50 100644 --- a/tildamk6/sdkconfig.board +++ b/tildamk6/sdkconfig.board @@ -26,10 +26,11 @@ CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID= CONFIG_TINYUSB_DESC_USE_DEFAULT_PID= # USB feature flags +CONFIG_USB_CDC_ENABLED=y CONFIG_TINYUSB_CDC_ENABLED=y CONFIG_TINYUSB_HID_ENABLED=y -CONFIG_TINYUSB_HIDKEYBOARD_ENABLED=y -CONFIG_TINYUSB_U2FHID_ENABLED=n +CONFIG_TINYUSB_HIDKEYBOARD_ENABLED=n +CONFIG_TINYUSB_U2FHID_ENABLED=y CONFIG_TINYUSB_MSC_ENABLED=n CONFIG_TINYUSB_MIDI_ENABLED=n CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED=n From 91e249c47bb22d0f72353192af922360a7929e5f Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 27 Nov 2022 15:24:12 +0000 Subject: [PATCH 12/32] Use DER format for signature return --- drivers/tidal_usb/u2f_crypto.c | 35 ++++++++++++++++++++++++++++------ drivers/tidal_usb/u2f_crypto.h | 3 ++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index e239d93..67990fc 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -75,16 +75,39 @@ arbitrary_size_container get_attestation_certificate() { arbitrary_size_container get_signature(uint8_t handle, uint8_t signature_input[]) { uint8_t digest[32] = { 0 }; + + uint8_t signature[64]; + ESP_LOGI(TAG, "Calculating digest"); atcab_hw_sha2_256(signature_input, sizeof(signature_input), digest); - ESP_LOGI(TAG, "Allocating %d bytes", 73); - arbitrary_size_container response_data = { - .size=64, - .data=malloc(64), - }; ESP_LOGI(TAG, "Signing data"); - atcab_sign(handle, &digest, response_data.data); + atcab_sign(handle, &digest, &signature); //memset(response_data.data, 0xF0, 73); + return der_encode_signature(&signature); +} + + +arbitrary_size_container der_encode_signature(uint8_t *signature) { + arbitrary_size_container response_data = { + .size=70, + .data=malloc(70), + }; + // Compound structure + response_data.data[0] = 0x30; + + // Length + response_data.data[1] = (32 + 2) * 2; + + // r + response_data.data[2] = 0x02; + response_data.data[3] = 32; + memcpy(response_data.data + 4, signature, 32); + + // s + response_data.data[36] = 0x02; + response_data.data[37] = 32; + memcpy(response_data.data + 38, signature + 32, 32); + return response_data; } diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h index fe63cd2..1ee2f61 100644 --- a/drivers/tidal_usb/u2f_crypto.h +++ b/drivers/tidal_usb/u2f_crypto.h @@ -10,4 +10,5 @@ arbitrary_size_container get_attestation_certificate(); arbitrary_size_container get_signature(uint8_t handle, uint8_t signature_input[]); void set_counter(uint8_t handle, uint32_t *target); void set_pubkey(uint8_t handle, uint8_t *target); -uint8_t allocate_handle(); \ No newline at end of file +uint8_t allocate_handle(); +arbitrary_size_container der_encode_signature(uint8_t *signature); \ No newline at end of file From e26308f09c63cee2ec60f6a7dd7c97e1b88ec2f8 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 27 Nov 2022 15:46:50 +0000 Subject: [PATCH 13/32] Send pubkey in uncompressed format --- drivers/tidal_usb/u2f_crypto.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 67990fc..2ea3dd3 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -111,12 +111,16 @@ arbitrary_size_container der_encode_signature(uint8_t *signature) { return response_data; } + + void set_counter(uint8_t handle, uint32_t *target) { //atcab_counter_increment(handle, target); } void set_pubkey(uint8_t handle, uint8_t *target) { - atcab_genkey(handle, target); + // This is an uncompressed key - in DER format?s + target[0] = 0x04; + atcab_genkey(handle, target + 1); } uint8_t allocate_handle() { From 2a66ea5797717d9d9d1f4a3887ec36f716a0da3c Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 28 Nov 2022 13:56:31 +0000 Subject: [PATCH 14/32] Fix alignment of continuation packets and simplify signature scheme. --- drivers/tidal_usb/tidal_usb_u2f.c | 21 ++++++++------------ drivers/tidal_usb/u2f_crypto.c | 32 ++++++++++++++----------------- drivers/tidal_usb/u2f_crypto.h | 4 ++-- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index fc82bd7..d80aabe 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -78,11 +78,12 @@ bool handle_message_fragment(uint8_t *buffer) { } else { // This is the first fragment, set up a big enough buffer ESP_LOGI(TAG, "Allocating larger buffer"); - in_progress_packet = malloc(msg_size); - expected_size = msg_size; + // The expected size is the reported data size plus the header on the initial packet + expected_size = msg_size + 7; + in_progress_packet = malloc(expected_size); // Copy the entire message, including the header uint16_t bytes_to_copy = HID_RPT_SIZE; - memcpy(in_progress_packet + current_index, buffer, bytes_to_copy); + memcpy(in_progress_packet, buffer, bytes_to_copy); current_index = bytes_to_copy; packet_needs_free = true; return false; @@ -210,11 +211,8 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body memcpy(signature_input + 1, register_params, 65); signature_input[66] = handle; memcpy(signature_input + 67, response_data.data + 1, 64); - arbitrary_size_container signature = get_signature(1, signature_input); - memcpy(response_data.data + write_head, signature.data, signature.size); - write_head += signature.size; - // Free the intermediate copy - free(signature.data); + arbitrary_size_container signature; + write_head += get_signature(1, signature_input, response_data.data + write_head); // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; @@ -273,11 +271,8 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a memcpy(signature_input + 0, authenticate_params->application_param, 32); memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - arbitrary_size_container signature = get_signature(6, signature_input); - memcpy(response_data.data + write_head, signature.data, signature.size); - write_head += signature.size; - // Free the intermediate copy - free(signature.data); + arbitrary_size_container signature; + write_head += get_signature(6, &signature_input, response_data.data + write_head); // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 2ea3dd3..d371c74 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -73,42 +73,38 @@ arbitrary_size_container get_attestation_certificate() { return response_data; } -arbitrary_size_container get_signature(uint8_t handle, uint8_t signature_input[]) { +size_t get_signature(uint8_t handle, uint8_t *signature_input, uint8_t *target) { uint8_t digest[32] = { 0 }; uint8_t signature[64]; ESP_LOGI(TAG, "Calculating digest"); - atcab_hw_sha2_256(signature_input, sizeof(signature_input), digest); + atcab_hw_sha2_256(signature_input, 69, digest); + ESP_LOGI(TAG, "Signing data"); atcab_sign(handle, &digest, &signature); - //memset(response_data.data, 0xF0, 73); - return der_encode_signature(&signature); + return der_encode_signature(&signature, target); } -arbitrary_size_container der_encode_signature(uint8_t *signature) { - arbitrary_size_container response_data = { - .size=70, - .data=malloc(70), - }; +size_t der_encode_signature(uint8_t *signature, uint8_t *target) { // Compound structure - response_data.data[0] = 0x30; + target[0] = 0x30; // Length - response_data.data[1] = (32 + 2) * 2; + target[1] = (32 + 2) * 2; // r - response_data.data[2] = 0x02; - response_data.data[3] = 32; - memcpy(response_data.data + 4, signature, 32); + target[2] = 0x02; + target[3] = 32; + memcpy(target + 4, signature, 32); // s - response_data.data[36] = 0x02; - response_data.data[37] = 32; - memcpy(response_data.data + 38, signature + 32, 32); + target[36] = 0x02; + target[37] = 32; + memcpy(target + 38, signature + 32, 32); - return response_data; + return 70; } diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h index 1ee2f61..8c89fd5 100644 --- a/drivers/tidal_usb/u2f_crypto.h +++ b/drivers/tidal_usb/u2f_crypto.h @@ -7,8 +7,8 @@ typedef struct arbitrary_size_container { } arbitrary_size_container; arbitrary_size_container get_attestation_certificate(); -arbitrary_size_container get_signature(uint8_t handle, uint8_t signature_input[]); +size_t get_signature(uint8_t handle, uint8_t *signature_input, uint8_t *target); void set_counter(uint8_t handle, uint32_t *target); void set_pubkey(uint8_t handle, uint8_t *target); uint8_t allocate_handle(); -arbitrary_size_container der_encode_signature(uint8_t *signature); \ No newline at end of file +size_t der_encode_signature(uint8_t *signature, uint8_t *target); \ No newline at end of file From 64564fd89b983d8210e9f98974d8f27ab1cf7cb4 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sat, 10 Feb 2024 19:32:00 +0000 Subject: [PATCH 15/32] Helper functions for debugging. Return data as bytes rather than a number. --- drivers/ecc108a/ecc108a.c | 48 ++++++++++++++++++++++--------- drivers/tidal_usb/tidal_usb_u2f.c | 2 +- drivers/tidal_usb/u2f_crypto.c | 3 +- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 48ce386..d1eefae 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -126,10 +126,8 @@ STATIC mp_obj_t ecc108a_genkey(mp_obj_t slot_id) { // Return X, Y tuple mp_obj_t tuple[2]; - uint32_t x = (pubkey[0] << 0*8) | (pubkey[1] << 1*8) | (pubkey[2] << 2*8) | (pubkey[3] << 3*8); - uint32_t y = (pubkey[4] << 0*8) | (pubkey[5] << 1*8) | (pubkey[6] << 2*8) | (pubkey[7] << 3*8); - tuple[0] = mp_obj_new_int_from_ull(x); - tuple[1] = mp_obj_new_int_from_ull(y); + tuple[0] = mp_obj_new_bytes(pubkey, 32); + tuple[1] = mp_obj_new_bytes(pubkey+32, 32); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(ecc108a_genkey_obj, ecc108a_genkey); @@ -144,10 +142,8 @@ STATIC mp_obj_t ecc108a_get_pubkey(mp_obj_t slot_id) { // Return X, Y tuple mp_obj_t tuple[2]; - uint32_t x = (pubkey[0] << 0*8) | (pubkey[1] << 1*8) | (pubkey[2] << 2*8) | (pubkey[3] << 3*8); - uint32_t y = (pubkey[4] << 0*8) | (pubkey[5] << 1*8) | (pubkey[6] << 2*8) | (pubkey[7] << 3*8); - tuple[0] = mp_obj_new_int_from_ull(x); - tuple[1] = mp_obj_new_int_from_ull(y); + tuple[0] = mp_obj_new_bytes(pubkey, 32); + tuple[1] = mp_obj_new_bytes(pubkey+32, 32); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(ecc108a_get_pubkey_obj, ecc108a_get_pubkey); @@ -165,15 +161,40 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { // Return R, S tuple mp_obj_t tuple[2]; - uint32_t r = (signature[0] << 0*8) | (signature[1] << 1*8) | (signature[2] << 2*8) | (signature[3] << 3*8); - uint32_t s = (signature[4] << 0*8) | (signature[5] << 1*8) | (signature[6] << 2*8) | (signature[7] << 3*8); - tuple[0] = mp_obj_new_int_from_ull(r); - tuple[1] = mp_obj_new_int_from_ull(s); + tuple[0] = mp_obj_new_bytes(signature, 32); + tuple[1] = mp_obj_new_bytes(signature+32, 32); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(ecc108a_sign_obj, ecc108a_sign); +STATIC mp_obj_t ecc108a_verify(mp_obj_t message, mp_obj_t signature, mp_obj_t public_key) { + + mp_obj_tuple_t *public_key_tuple = MP_OBJ_TO_PTR(public_key); + const char *x = mp_obj_str_get_data(public_key_tuple->items[0], 32); + const char *y = mp_obj_str_get_data(public_key_tuple->items[1], 32); + uint8_t key[64]; + memcpy(&key[0], x, 32); + memcpy(&key[32], y, 32); + + mp_obj_tuple_t *signature_tuple = MP_OBJ_TO_PTR(public_key); + const char *r = mp_obj_str_get_data(signature_tuple->items[0], 32); + const char *s = mp_obj_str_get_data(signature_tuple->items[1], 32); + uint8_t sig[64]; + memcpy(&sig[0], r, 32); + memcpy(&sig[32], s, 32); + + const char *message_data = mp_obj_str_get_data(message, 32); + + bool verified; + atcab_verify_extern((const uint8_t*) message_data, &sig, &key, &verified); + if (verified) + return mp_const_true; + else + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(ecc108a_verify_obj, ecc108a_verify); + STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ecc108a) }, @@ -186,7 +207,8 @@ STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&ecc108a_get_serial_number_obj) }, { MP_ROM_QSTR(MP_QSTR_genkey), MP_ROM_PTR(&ecc108a_genkey_obj) }, { MP_ROM_QSTR(MP_QSTR_get_pubkey), MP_ROM_PTR(&ecc108a_get_pubkey_obj) }, - { MP_ROM_QSTR(MP_QSTR_ecc108a_sign), MP_ROM_PTR(&ecc108a_sign_obj) }, + { MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&ecc108a_sign_obj) }, + { MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&ecc108a_verify_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ecc108a_module_globals, ecc108a_module_globals_table); diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index d80aabe..cb2a951 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -255,7 +255,7 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a .data=malloc(85) }; size_t write_head = 0; - + // Set reserved byte ESP_LOGI(TAG, "Setting presence bit"); response_data.data[write_head++] = 0x01; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index d371c74..9b27f76 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -116,7 +116,8 @@ void set_counter(uint8_t handle, uint32_t *target) { void set_pubkey(uint8_t handle, uint8_t *target) { // This is an uncompressed key - in DER format?s target[0] = 0x04; - atcab_genkey(handle, target + 1); + atcab_get_pubkey(handle, target+1); + //atcab_genkey(handle, target + 1); } uint8_t allocate_handle() { From 237bf9b2b2ba5ee3df13949d51e93f3210495a5f Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Wed, 3 Apr 2024 19:30:19 +0100 Subject: [PATCH 16/32] Improve verify helper to fix mp API problem. Now returns ATCA error.@ --- drivers/ecc108a/ecc108a.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index d1eefae..440b9eb 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -169,25 +169,31 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(ecc108a_sign_obj, ecc108a_sign); STATIC mp_obj_t ecc108a_verify(mp_obj_t message, mp_obj_t signature, mp_obj_t public_key) { + // All the strings are length 32, but we need to pass a *pointer* to a size t. + const size_t thirtytwo = 32; + // Extract the pubkey mp_obj_tuple_t *public_key_tuple = MP_OBJ_TO_PTR(public_key); - const char *x = mp_obj_str_get_data(public_key_tuple->items[0], 32); - const char *y = mp_obj_str_get_data(public_key_tuple->items[1], 32); + const char *x = mp_obj_str_get_data(public_key_tuple->items[0], &thirtytwo); + const char *y = mp_obj_str_get_data(public_key_tuple->items[1], &thirtytwo); uint8_t key[64]; memcpy(&key[0], x, 32); memcpy(&key[32], y, 32); - mp_obj_tuple_t *signature_tuple = MP_OBJ_TO_PTR(public_key); - const char *r = mp_obj_str_get_data(signature_tuple->items[0], 32); - const char *s = mp_obj_str_get_data(signature_tuple->items[1], 32); + // Extract the signature + mp_obj_tuple_t *signature_tuple = MP_OBJ_TO_PTR(signature); + const char *r = mp_obj_str_get_data(signature_tuple->items[0], &thirtytwo); + const char *s = mp_obj_str_get_data(signature_tuple->items[1], &thirtytwo); uint8_t sig[64]; memcpy(&sig[0], r, 32); memcpy(&sig[32], s, 32); - const char *message_data = mp_obj_str_get_data(message, 32); - + // Extract the message (this is a SHA256 of the user-facing 'message') + const char *message_data = mp_obj_str_get_data(message, &thirtytwo); + + // Verify on-chip bool verified; - atcab_verify_extern((const uint8_t*) message_data, &sig, &key, &verified); + assert_ATCA_SUCCESS(atcab_verify_extern((const uint8_t*) message_data, &sig, &key, &verified)); if (verified) return mp_const_true; else From eaba9eee9bc791e3a85352e94e45e7529a960e9d Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Wed, 3 Apr 2024 22:18:56 +0100 Subject: [PATCH 17/32] Update github build script with user components --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e9da91d..74e74ee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,8 +48,8 @@ jobs: source esp-idf/export.sh ln -sfn $GITHUB_WORKSPACE/tildamk6 micropython/ports/esp32/boards/tildamk6 cd micropython/ports/esp32 - make submodules BOARD=tildamk6 USER_C_MODULES=$GITHUB_WORKSPACE/drivers/micropython.cmake IOT_SOLUTION_PATH=$GITHUB_WORKSPACE/esp-iot-solution TARGET=esp32s3 - make BOARD=tildamk6 USER_C_MODULES=$GITHUB_WORKSPACE/drivers/micropython.cmake $@ IOT_SOLUTION_PATH=$GITHUB_WORKSPACE/esp-iot-solution TARGET=esp32s3 + make submodules BOARD=tildamk6 USER_C_MODULES=$GITHUB_WORKSPACE/drivers/micropython.cmake USER_COMPONENTS=$GITHUB_WORKSPACE/components/tinyusb IOT_SOLUTION_PATH=$GITHUB_WORKSPACE/esp-iot-solution TARGET=esp32s3 + make BOARD=tildamk6 USER_C_MODULES=$GITHUB_WORKSPACE/drivers/micropython.cmake USER_COMPONENTS=$GITHUB_WORKSPACE/components/tinyusb $@ IOT_SOLUTION_PATH=$GITHUB_WORKSPACE/esp-iot-solution TARGET=esp32s3 cd ../../.. echo "{\"build\":\"$(git describe --tags --always)\", \"name\":\"$(git describe --tags --always)\"}" > micropython/ports/esp32/build-tildamk6/tidal.txt - name: Archive firmware From 99487acafdb072f5897b3b0c5b9a7131b1d0f2da Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Thu, 4 Apr 2024 12:53:18 +0100 Subject: [PATCH 18/32] Fix signature size, allowing authentication to work (!) Co-authored-by: Skyler Mansfield --- drivers/tidal_usb/tidal_usb_u2f.c | 4 ++-- drivers/tidal_usb/u2f_crypto.c | 5 ++--- drivers/tidal_usb/u2f_crypto.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index cb2a951..de91882 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -212,7 +212,7 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body signature_input[66] = handle; memcpy(signature_input + 67, response_data.data + 1, 64); arbitrary_size_container signature; - write_head += get_signature(1, signature_input, response_data.data + write_head); + write_head += get_signature(1, 131, signature_input, response_data.data + write_head); // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; @@ -272,7 +272,7 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); arbitrary_size_container signature; - write_head += get_signature(6, &signature_input, response_data.data + write_head); + write_head += get_signature(6, 69, &signature_input, response_data.data + write_head); // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 9b27f76..2fdfaff 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -73,14 +73,13 @@ arbitrary_size_container get_attestation_certificate() { return response_data; } -size_t get_signature(uint8_t handle, uint8_t *signature_input, uint8_t *target) { +size_t get_signature(uint8_t handle, size_t signature_length, uint8_t *signature_input, uint8_t *target) { uint8_t digest[32] = { 0 }; uint8_t signature[64]; ESP_LOGI(TAG, "Calculating digest"); - atcab_hw_sha2_256(signature_input, 69, digest); - + atcab_hw_sha2_256(signature_input, signature_length, digest); ESP_LOGI(TAG, "Signing data"); atcab_sign(handle, &digest, &signature); return der_encode_signature(&signature, target); diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h index 8c89fd5..c00e750 100644 --- a/drivers/tidal_usb/u2f_crypto.h +++ b/drivers/tidal_usb/u2f_crypto.h @@ -7,7 +7,7 @@ typedef struct arbitrary_size_container { } arbitrary_size_container; arbitrary_size_container get_attestation_certificate(); -size_t get_signature(uint8_t handle, uint8_t *signature_input, uint8_t *target); +size_t get_signature(uint8_t handle, size_t signature_length, uint8_t *signature_input, uint8_t *target); void set_counter(uint8_t handle, uint32_t *target); void set_pubkey(uint8_t handle, uint8_t *target); uint8_t allocate_handle(); From 44df071a4b75225180a11eb94c35154b31aeace8 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 15 Apr 2024 16:44:25 +0100 Subject: [PATCH 19/32] Basic GUI for authenticator support --- drivers/tidal_helpers/tidal_helpers.c | 57 +++++++++ drivers/tidal_usb/micropython.cmake | 1 + drivers/tidal_usb/tidal_usb_u2f.c | 111 ++++++++++++++---- drivers/tidal_usb/tidal_usb_u2f.h | 1 + .../tidal_usb_u2f_shared_variables.c | 7 ++ .../tidal_usb_u2f_shared_variables.h | 15 +++ drivers/tidal_usb/u2f_crypto.c | 20 ++-- modules/app.py | 4 +- modules/app_launcher/__init__.py | 2 + modules/authenticator/__init__.py | 104 ++++++++++++++++ modules/boot.py | 1 + modules/scheduler.py | 6 + modules/settings_app/__init__.py | 1 + 13 files changed, 294 insertions(+), 36 deletions(-) create mode 100644 drivers/tidal_usb/tidal_usb_u2f_shared_variables.c create mode 100644 drivers/tidal_usb/tidal_usb_u2f_shared_variables.h create mode 100644 modules/authenticator/__init__.py diff --git a/drivers/tidal_helpers/tidal_helpers.c b/drivers/tidal_helpers/tidal_helpers.c index a45807b..b83acca 100644 --- a/drivers/tidal_helpers/tidal_helpers.c +++ b/drivers/tidal_helpers/tidal_helpers.c @@ -13,6 +13,7 @@ #include "esp32s2/rom/usb/usb_persist.h" #include "esp_wpa2.h" #include "driver/ledc.h" +#include "tidal_usb_u2f_shared_variables.h" // static const char *TAG = "tidal_helpers"; @@ -22,6 +23,58 @@ typedef struct _machine_pin_obj_t { gpio_num_t id; } machine_pin_obj_t; +STATIC mp_obj_t tidal_helper_authentication_requested() { + mp_obj_t response[3]; + response[0] = mp_const_none; + response[1] = mp_const_none; + response[2] = mp_const_none; + + if (authentication_operation == AUTHENTICATE_REQUEST || authentication_operation == REGISTER_REQUEST) { + response[0] = mp_const_true; + if (authentication_operation_slot == 99) + response[1] = mp_const_none; + else + response[1] = mp_obj_new_int(authentication_operation_slot); + response[2] = mp_obj_new_bytes(authentication_application_parameter, 32); + } else { + response[0] = mp_const_false; + } + return mp_obj_new_tuple(3, response); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_helper_authentication_requested_obj, tidal_helper_authentication_requested); + +STATIC mp_obj_t tidal_helper_authentication_mismatch() { + authentication_operation = KEY_MISMATCH; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_helper_authentication_mismatch_obj, tidal_helper_authentication_mismatch); + +STATIC mp_obj_t tidal_helper_authentication_approve(mp_obj_t state) { + if (state == mp_const_true) { + if (authentication_operation == AUTHENTICATE_REQUEST) + authentication_operation = AUTHENTICATE_APPROVED; + if (authentication_operation == REGISTER_REQUEST) + authentication_operation = REGISTER_APPROVED; + } + if (state == mp_const_false) + authentication_operation = USER_REFUSED; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_helper_authentication_approve_obj, tidal_helper_authentication_approve); + + +STATIC mp_obj_t tidal_helper_authentication_slot(mp_obj_t slot) { + if (mp_obj_is_int(slot)) { + authentication_operation = mp_obj_get_int(slot); + return slot; + } else { + mp_raise_ValueError(slot); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_helper_authentication_slot_obj, tidal_helper_authentication_slot); + + STATIC gpio_num_t get_pin(mp_obj_t pin_obj) { if (mp_obj_is_int(pin_obj)) { return (gpio_num_t)mp_obj_get_int(pin_obj); @@ -387,6 +440,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(tidal_set_backlight_pwm_obj, tidal_set_backligh STATIC const mp_rom_map_elem_t tidal_helpers_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ota) }, + { MP_ROM_QSTR(MP_QSTR_set_authentication_approval), MP_ROM_PTR(&tidal_helper_authentication_approve_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_authentication_requested), MP_ROM_PTR(&tidal_helper_authentication_requested_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_authentication_mismatch), MP_ROM_PTR(&tidal_helper_authentication_mismatch_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_authentication_slot), MP_ROM_PTR(&tidal_helper_authentication_slot_obj) }, { MP_ROM_QSTR(MP_QSTR_get_variant), MP_ROM_PTR(&tidal_helper_get_variant_obj) }, { MP_ROM_QSTR(MP_QSTR_usb_connected), MP_ROM_PTR(&tidal_helper_usb_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_usb_suspended), MP_ROM_PTR(&tidal_helper_usb_suspended_obj) }, diff --git a/drivers/tidal_usb/micropython.cmake b/drivers/tidal_usb/micropython.cmake index 78afd80..ef65966 100644 --- a/drivers/tidal_usb/micropython.cmake +++ b/drivers/tidal_usb/micropython.cmake @@ -7,6 +7,7 @@ target_sources(usermod_tidal_usb INTERFACE ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_hid.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_console.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_u2f.c + ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_u2f_shared_variables.c ${CMAKE_CURRENT_LIST_DIR}/u2f_crypto.c ) diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index de91882..d4dae91 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -5,6 +5,9 @@ #include "esp_log.h" #include "u2f_crypto.h" #include +#include "py/builtin.h" + +#include "tidal_usb_console.h" #if CONFIG_TINYUSB_U2FHID_ENABLED static const char *TAG = "tidalU2F"; @@ -14,9 +17,8 @@ uint8_t *in_progress_packet = NULL; bool packet_needs_free = false; uint16_t expected_size = 0; uint16_t current_index = 0; -bool had_user_interaction = false; -u2f_hid_msg upcoming_report_ring[REPORT_RING_SIZE] = { NULL }; +u2f_hid_msg upcoming_report_ring[REPORT_RING_SIZE] = { 0 }; bool upcoming_report_ring_waiting[REPORT_RING_SIZE] = { false }; uint8_t write_head = 0; uint8_t read_head = 0; @@ -35,7 +37,7 @@ void push_report(u2f_hid_msg *msg) { void pop_and_send_report() { if (!upcoming_report_ring_waiting[read_head]) { - // There's already a report waiting to be picked up. This is a fatal error. + // There's no report waiting to be picked up. This is a fatal error. ESP_LOGW(TAG, "U2F outbound report buffer empty"); return; } @@ -47,7 +49,7 @@ void pop_and_send_report() { } -bool handle_message_fragment(uint8_t *buffer) { +bool handle_message_fragment(const uint8_t *buffer) { const u2f_hid_msg *msg = (u2f_hid_msg *) buffer; if (in_progress_packet != NULL) { // This is a continuation packet @@ -135,7 +137,8 @@ void handle_report_u2f(uint8_t itf, uint8_t report_id, hid_report_type_t report_ free(in_progress_packet); packet_needs_free = false; } - in_progress_packet = expected_size = current_index = NULL; + in_progress_packet = NULL; + expected_size = current_index = 0; } @@ -197,7 +200,7 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body // Attestation certificate ESP_LOGI(TAG, "Setting cert"); - // Get the certificate from the secure elefment + // Get the certificate from the secure element arbitrary_size_container cert = get_attestation_certificate(); // Copy it into the current data stream memcpy(response_data.data + write_head, cert.data, cert.size); @@ -251,19 +254,22 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a ESP_LOGI(TAG, "Allocating container"); arbitrary_size_container response_data = { - .size=85, - .data=malloc(85) + .size=0, + .data=malloc(256) }; + memset(response_data.data, 0x00, 185); size_t write_head = 0; // Set reserved byte ESP_LOGI(TAG, "Setting presence bit"); response_data.data[write_head++] = 0x01; - // The next 4 bytes are a counter - response_data.data[write_head++] = 0x00; - response_data.data[write_head++] = 0x00; - response_data.data[write_head++] = 0x00; - response_data.data[write_head++] = 0x01; + // The next 4 bytes are a counter, increment it for this handle and return + uint32_t counter_value = 0; + set_counter(authenticate_params->key_handle[0], &counter_value); + response_data.data[write_head++] = (counter_value >> 24) && 0xFF; + response_data.data[write_head++] = (counter_value >> 16) && 0xFF; + response_data.data[write_head++] = (counter_value >> 8) && 0xFF; + response_data.data[write_head++] = (counter_value >> 0) && 0xFF; // Create the signature out of the application parameter, the user presence byte, the counter then the challenge param ESP_LOGI(TAG, "Setting signature"); @@ -271,15 +277,15 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a memcpy(signature_input + 0, authenticate_params->application_param, 32); memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - arbitrary_size_container signature; - write_head += get_signature(6, 69, &signature_input, response_data.data + write_head); - + memset(&response_data.data[write_head], 0xF0, 70); + /*write_head += *///get_signature(6, 69, signature_input, response_data.data + write_head); + write_head += 70; // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; ESP_LOGI(TAG, "Built %d byte authenticate response", write_head); response_data.size = write_head; - realloc(response_data.data, write_head); + //realloc(response_data.data, write_head); /*printf("RAW data:"); @@ -340,10 +346,14 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { ESP_LOGI(TAG, "Will process U2F_REGISTER raw message (Instruction %x)", raw_message->INS); u2f_raw_register_request_body *register_params = (u2f_raw_register_request_body *) raw_message->extended_form.data; - if (!had_user_interaction) { + if (authentication_operation == NO_OPERATION || authentication_operation == REGISTER_REQUEST) { + // Set shared variables with micropython + authentication_operation = REGISTER_REQUEST; + authentication_operation_slot = 99; + memcpy(authentication_application_parameter, register_params->application_param, 32); + // The user needs to allow this, send back the conditions // not satisfied status as the only body - ESP_LOGI(TAG, "Awaiting user interaction, reporting conditions not satisfied"); u2f_hid_msg response = { .CID = TIDAL_CHANNEL, @@ -355,22 +365,71 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { (U2F_SW_CONDITIONS_NOT_SATISFIED & 0xff) } }; - had_user_interaction = true; u2f_report(&response); - } else { + } else if (authentication_operation == REGISTER_APPROVED) { // Reset the interaction flag - had_user_interaction = false; arbitrary_size_container response_data = process_register_command(register_params); send_multipart_response(&response_data); + authentication_operation = NO_OPERATION; free(response_data.data); } } else if (raw_message->INS == U2F_AUTHENTICATE) { + +/* arbitrary_size_container response_data = { + .size=185, + .data=malloc(185) + }; + size_t write_head = 0; + + memcpy(response_data.data, raw_message->extended_form.data, 70); + response_data.size = 70; + realloc(response_data.data, 70); + */ + ESP_LOGI(TAG, "Will process U2F_AUTHENTICATE raw message (Instruction %x)", raw_message->INS); u2f_raw_authenticate_request_body *authenticate_params = (u2f_raw_authenticate_request_body *) raw_message->extended_form.data; - - arbitrary_size_container response_data = process_authenticate_command(raw_message->P1, authenticate_params); - send_multipart_response(&response_data); - free(response_data.data); + + if (authentication_operation == KEY_MISMATCH) { + u2f_hid_msg response = { + .CID = TIDAL_CHANNEL, + .init.CMD = U2FHID_MSG, + .init.BCNTH = 0, + .init.BCNTL = 0x02, + .init.data = { + (U2F_SW_WRONG_DATA >> 8), + (U2F_SW_WRONG_DATA & 0xff) + } + }; + u2f_report(&response); + authentication_operation = NO_OPERATION; + } else if (authentication_operation == AUTHENTICATE_APPROVED) { + arbitrary_size_container response_data = process_authenticate_command(raw_message->P1, authenticate_params); + send_multipart_response(&response_data); + free(response_data.data); + authentication_operation = NO_OPERATION; + } + else { + // The user needs to allow this, send back the conditions + // not satisfied status as the only body + + // Set shared variables with micropython + authentication_operation = AUTHENTICATE_REQUEST; + authentication_operation_slot = authenticate_params->key_handle[0]; + memcpy(authentication_application_parameter, authenticate_params->application_param, 32); + + ESP_LOGI(TAG, "Awaiting user interaction, reporting conditions not satisfied"); + u2f_hid_msg response = { + .CID = TIDAL_CHANNEL, + .init.CMD = U2FHID_MSG, + .init.BCNTH = 0, + .init.BCNTL = 0x02, + .init.data = { + (U2F_SW_CONDITIONS_NOT_SATISFIED >> 8), + (U2F_SW_CONDITIONS_NOT_SATISFIED & 0xff) + } + }; + u2f_report(&response); + } } else { ESP_LOGE(TAG, "Got U2F raw message, but instruction %x is not known", raw_message->INS); } diff --git a/drivers/tidal_usb/tidal_usb_u2f.h b/drivers/tidal_usb/tidal_usb_u2f.h index 7168b23..a29f9b2 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.h +++ b/drivers/tidal_usb/tidal_usb_u2f.h @@ -1,4 +1,5 @@ #include "u2f_hid.h" +#include "tidal_usb_u2f_shared_variables.h" #define min(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c new file mode 100644 index 0000000..33f4b20 --- /dev/null +++ b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c @@ -0,0 +1,7 @@ +#include +#include +#include "tidal_usb_u2f_shared_variables.h" + +enum authentication_state authentication_operation = NO_OPERATION; +uint8_t authentication_operation_slot = 99; +uint8_t authentication_application_parameter[32] = { 0 }; \ No newline at end of file diff --git a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h new file mode 100644 index 0000000..63bf922 --- /dev/null +++ b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h @@ -0,0 +1,15 @@ +#include +#include + +enum authentication_state { + NO_OPERATION, + REGISTER_REQUEST, + REGISTER_APPROVED, + AUTHENTICATE_REQUEST, + AUTHENTICATE_APPROVED, + USER_REFUSED, + KEY_MISMATCH, +}; +enum authentication_state authentication_operation; +uint8_t authentication_operation_slot; +uint8_t authentication_application_parameter[32]; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 2fdfaff..74e6648 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -5,6 +5,7 @@ #include #include #include +#include "tidal_usb_u2f_shared_variables.h" static const char *TAG = "tidalU2F"; @@ -76,17 +77,19 @@ arbitrary_size_container get_attestation_certificate() { size_t get_signature(uint8_t handle, size_t signature_length, uint8_t *signature_input, uint8_t *target) { uint8_t digest[32] = { 0 }; - uint8_t signature[64]; + uint8_t signature[64] = { 0 }; ESP_LOGI(TAG, "Calculating digest"); + atcab_wakeup(); atcab_hw_sha2_256(signature_input, signature_length, digest); ESP_LOGI(TAG, "Signing data"); - atcab_sign(handle, &digest, &signature); - return der_encode_signature(&signature, target); + atcab_sign(handle, digest, signature); + atcab_sleep(); + return der_encode_signature(signature, target); } -size_t der_encode_signature(uint8_t *signature, uint8_t *target) { +size_t der_encode_signature(uint8_t signature[64], uint8_t target[70]) { // Compound structure target[0] = 0x30; @@ -96,19 +99,20 @@ size_t der_encode_signature(uint8_t *signature, uint8_t *target) { // r target[2] = 0x02; target[3] = 32; - memcpy(target + 4, signature, 32); + memcpy(&target[4], &signature[0], 32); // s target[36] = 0x02; target[37] = 32; - memcpy(target + 38, signature + 32, 32); + memcpy(&target[38], &signature[32], 32); - return 70; + return target[1] + 2; } void set_counter(uint8_t handle, uint32_t *target) { + return 1; //atcab_counter_increment(handle, target); } @@ -120,5 +124,5 @@ void set_pubkey(uint8_t handle, uint8_t *target) { } uint8_t allocate_handle() { - return 6; + return authentication_operation_slot; } \ No newline at end of file diff --git a/modules/app.py b/modules/app.py index 3ef2981..9d0a2f1 100644 --- a/modules/app.py +++ b/modules/app.py @@ -121,7 +121,7 @@ def completion(val): self.present_window(keyboard) # Doesn't return until all finished return result[0] - def yes_no_prompt(self, title, yes_prompt=None, no_prompt=None): + def yes_no_prompt(self, title, yes_prompt=None, no_prompt=None, font=None): """Returns True or False, or None if the user dismissed the dialog with the back button""" win = self.window result = [None] @@ -137,7 +137,7 @@ def no(): (yes_prompt or "Yes", yes), (no_prompt or "No", no), ) - menu = DialogWindow(win.fg, win.bg, None, None, title, choices, None, buttons) + menu = DialogWindow(win.fg, win.bg, None, None, title, choices, font, buttons) self.present_window(menu) return result[0] diff --git a/modules/app_launcher/__init__.py b/modules/app_launcher/__init__.py index 6e61727..b0c26fb 100644 --- a/modules/app_launcher/__init__.py +++ b/modules/app_launcher/__init__.py @@ -11,6 +11,7 @@ import os import functools import settings +import authenticator def path_isfile(path): # Wow totally an elegant way to do os.path.isfile... @@ -82,6 +83,7 @@ def list_core_apps(self): core_app_info = [ ("App store", "app_store", "Store"), ("USB Keyboard", "hid", "USBKeyboard"), + ("Authenticator", "authenticator", "Authenticator"), ("Name Badge", "hello", "Hello"), ("Torch", "torch", "Torch"), ("Logo", "emflogo", "EMFLogo"), diff --git a/modules/authenticator/__init__.py b/modules/authenticator/__init__.py new file mode 100644 index 0000000..daa024a --- /dev/null +++ b/modules/authenticator/__init__.py @@ -0,0 +1,104 @@ +from app import MenuApp, Menu +from buttons import Buttons +from textwindow import TextWindow, DialogWindow +from scheduler import get_scheduler +import time +import settings +import tidal +import orientation +import _thread +import vga2_bold_16x32 +import tidal_helpers +import binascii +import machine + + +class PromptPermission(DialogWindow): + + def __init__(self, slot_id=None, *args, **kwargs): + self.slot_id = slot_id + return super(*args, **kwargs) + + def redraw(self): + self.cls() + self.println("Press the joystick to approve") + + + +class Authenticator(MenuApp): + APP_ID = "authenticator" + TITLE = "Authenticator" + + @property + def CHOICES(self): + # The crypto chip has 16 slots + choices = [self.make_slot_select(slot_id) for slot_id in range(16)] + print(choices) + return choices + + def make_slot_select(self, slot_id): + name = settings.get(f"auth_slot_{slot_id}_name", None) + if name and len(name) > 5: + name = name[:5] + if not name: + name = f"Unused slot {slot_id}" + registered_date = settings.get(f"auth_slot_{slot_id}_registered", "") + return (name + " " + registered_date, print) + + +def cycle_leds(): + tidal.led_power_on() + tidal.led[0] = (tidal.led[0][2], ) + tidal.led[0][0:2] + tidal.led.write() + + +def trigger_wink(slot_id=None): + from app_launcher import Launcher + launcher = Launcher._singleton + authenticator_app = launcher._apps.get('authenticator.Authenticator') + if authenticator_app is None: + authenticator_app = launcher._apps['authenticator.Authenticator'] = Authenticator() + schedule = get_scheduler() + schedule.switch_app(authenticator_app) + tidal.led_power_on(True) + tidal.led[0] = (255, 255, 0) + flasher = authenticator_app.periodic(250, cycle_leds) + okay = authenticator_app.yes_no_prompt("Sign?", font=vga2_bold_16x32) + tidal.led[0] = (0, 0, 0) + tidal.led.write() + tidal.led_power_on(False) + flasher.cancel() + return okay + +prompting = False +def allow_interrupt_when_authenticating(): + def check_for_wink(): + global prompting + requested, slot_id, application_param = tidal_helpers.get_authentication_requested() + if requested == False: # Slot 0 might be requested, which is falsey + return + elif prompting: + # An earlier periodic invocation is asking + return + else: + prompting = True + if slot_id is None: + for i in range(16): + if not settings.get(f"auth_slot_{i}_name", ""): + slot_id = i + break + if slot_id is None: + # No slots available + tidal_helpers.set_authentication_approval(False) + return + response = trigger_wink(slot_id) + if response: + name = binascii.hexlify(application_param).decode('latin-1') + settings.set(f"auth_slot_{slot_id}_name", f"{name}") + settings.set(f"auth_slot_{slot_id}_registered", "%04d-%02d-%02d" % (machine.RTC().datetime()[:3])) + settings.save() + tidal_helpers.set_authentication_slot(slot_id) + tidal_helpers.set_authentication_approval(response) + prompting = False + scheduler = get_scheduler() + scheduler.periodic(5000, check_for_wink) \ No newline at end of file diff --git a/modules/boot.py b/modules/boot.py index 960699e..c99aabc 100644 --- a/modules/boot.py +++ b/modules/boot.py @@ -25,6 +25,7 @@ from app_launcher import Launcher menu = Launcher() + Launcher._singleton = menu try: os.mkdir("/apps") diff --git a/modules/scheduler.py b/modules/scheduler.py index 336f743..e5100f3 100644 --- a/modules/scheduler.py +++ b/modules/scheduler.py @@ -98,6 +98,12 @@ def enter(self): enter_level = self._level deactivated_app = None while True: + if first_time: + if settings.get("enable_u2f", True): + # Add the U2F periodic task + import authenticator + authenticator.allow_interrupt_when_authenticating() + while self.check_for_interrupts() or first_time: first_time = False uasyncio.run_until_complete() diff --git a/modules/settings_app/__init__.py b/modules/settings_app/__init__.py index 00e7e2f..6066045 100644 --- a/modules/settings_app/__init__.py +++ b/modules/settings_app/__init__.py @@ -151,6 +151,7 @@ def refresh(self): (5, 15, 30, 60, 5*60, 10*60, 30*60, 60*60, 8*60*60)), self.make_choice("USB sleep delay", None, "usb_nosleep_time", 15, fmt_time, (15, 30, 60)), self.make_choice("UART menu app", None, "uart_menu_app", True, fmt_on_off, (True, False)), + self.make_choice("MFA mode", None, "enable_u2f", True, fmt_on_off, (True, False)), self.make_nvs_choice("REPL on SDA/SCL", None, "uart_sdascl", 0, fmt_on_off, (1, 0)), ) From 3a347cc9cc7265dcb8476c4f955fd2812c77c035 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 15 Apr 2024 22:34:16 +0100 Subject: [PATCH 20/32] Allow user driven switching of U2F and HID modes --- .../include_private/descriptors_control.h | 18 ++--- .../additions/src/descriptors_control.c | 69 ++++++++++++++++--- drivers/ecc108a/ecc108a.c | 10 ++- drivers/tidal_helpers/tidal_helpers.c | 22 ++++-- drivers/tidal_usb/tidal_usb_hid.c | 2 +- drivers/tidal_usb/tidal_usb_u2f.c | 20 +++--- drivers/tidal_usb/u2f_crypto.c | 6 +- modules/authenticator/__init__.py | 54 +++++++++++---- modules/scheduler.py | 7 +- modules/settings.py | 7 ++ modules/settings_app/__init__.py | 2 +- tildamk6/sdkconfig.board | 2 +- 12 files changed, 162 insertions(+), 57 deletions(-) diff --git a/components/tinyusb/additions/include_private/descriptors_control.h b/components/tinyusb/additions/include_private/descriptors_control.h index e77569a..370eb55 100644 --- a/components/tinyusb/additions/include_private/descriptors_control.h +++ b/components/tinyusb/additions/include_private/descriptors_control.h @@ -29,6 +29,9 @@ extern "C" { #endif +int32_t hid_mode; + + //------------- EndPoint Descriptor -------------// enum { EPNUM_DEFAULT = 0, @@ -54,13 +57,9 @@ enum { # if CFG_TUD_HID_KBD EPNUM_HID_DATA, # endif - -# if CFG_TUD_U2FHID - EPNUM_HID_DATA_2, -# endif }; -#if ((CFG_TUD_BTH * 2) + (CFG_TUD_NET * 2) + (CFG_TUD_CDC * 2) + CFG_TUD_MSC + CFG_TUD_HID + CFG_TUD_U2FHID) > 4 +#if ((CFG_TUD_BTH * 2) + (CFG_TUD_NET * 2) + (CFG_TUD_CDC * 2) + CFG_TUD_MSC + CFG_TUD_HID) > 4 #error "USB endpoint number not be more than 5" #endif @@ -93,14 +92,10 @@ enum { ITF_NUM_MSC, # endif -# if CFG_TUD_HID_KBD +# if CFG_TUD_HID ITF_NUM_HID, # endif -# if CFG_TUD_U2FHID - ITF_NUM_HID_2, -# endif - # if CFG_TUD_DFU ITF_NUM_DFU, # endif @@ -145,8 +140,7 @@ enum { TUD_CDC_DESC_LEN * CFG_TUD_CDC + TUD_RNDIS_DESC_LEN * CFG_TUD_NET + TUD_MSC_DESC_LEN * CFG_TUD_MSC + - TUD_HID_DESC_LEN * CFG_TUD_HID_KBD + - TUD_HID_DESC_LEN * CFG_TUD_U2FHID + + TUD_HID_DESC_LEN * (CFG_TUD_HID_KBD | CFG_TUD_U2FHID) + TUD_BTH_DESC_LEN * CFG_TUD_BTH, ALT_CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + diff --git a/components/tinyusb/additions/src/descriptors_control.c b/components/tinyusb/additions/src/descriptors_control.c index a9f9a12..5b7b04c 100644 --- a/components/tinyusb/additions/src/descriptors_control.c +++ b/components/tinyusb/additions/src/descriptors_control.c @@ -16,6 +16,7 @@ #include "descriptors_control.h" #include "dfu_device.h" #include "u2f_hid.h" +#include "nvs.h" #define TILDA_REPORT_DESC_U2F(...) \ @@ -59,6 +60,8 @@ uint8_t const desc_hid_report[] = { #define FUNC_ATTRS (DFU_ATTR_CAN_UPLOAD | DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) +int32_t hid_mode = 0; + uint8_t const desc_configuration[] = { #if CONFIG_TINYUSB_NET_ECM // Config number, interface count, string index, total length, attribute, power in mA @@ -93,8 +96,47 @@ uint8_t const desc_configuration[] = { // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval TUD_HID_DESCRIPTOR(ITF_NUM_HID, STRID_HID_INTERFACE, HID_PROTOCOL_KEYBOARD, sizeof(desc_hid_report), (0x80 | EPNUM_HID_DATA), 8, 10), #endif + +#if CFG_TUD_DFU + // Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size + TUD_DFU_DESCRIPTOR(ITF_NUM_DFU, DFU_ALT_COUNT, STRID_DFU_INTERFACE, FUNC_ATTRS, 1000, CFG_TUD_DFU_XFER_BUFSIZE), +#endif + +}; + + +uint8_t const desc_configuration_2[] = { +#if CONFIG_TINYUSB_NET_ECM + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100), +#else + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, 0, 500), +#endif +#if CFG_TUD_BTH + // BT Primary controller descriptor + // Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes + TUD_BTH_DESCRIPTOR(ITF_NUM_BTH, 0 /* STRID_BTH_INTERFACE */, (0x80 | EPNUM_BT_EVT), 16, 1, (0x80 | EPNUM_BT_BULK_OUT), EPNUM_BT_BULK_OUT, 64, 0, 9, 17, 25, 33, 49), +#endif +#if CFG_TUD_NET +#if CONFIG_TINYUSB_NET_ECM + // Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size. + TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_NET, STRID_NET_INTERFACE, STRID_MAC, (0x80 | EPNUM_NET_NOTIF), 64, EPNUM_NET_DATA, (0x80 | EPNUM_NET_DATA), CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU), +#elif CONFIG_TINYUSB_NET_RNDIS + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_RNDIS_DESCRIPTOR(ITF_NUM_NET, STRID_NET_INTERFACE, (0x80 | EPNUM_NET_NOTIF), 8, EPNUM_NET_DATA, (0x80 | EPNUM_NET_DATA), CFG_TUD_NET_ENDPOINT_SIZE), +#endif +#endif +#if CFG_TUD_CDC + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, STRID_CDC_INTERFACE, (0x80 | EPNUM_CDC_NOTIF), 8, EPNUM_CDC_DATA, (0x80 | EPNUM_CDC_DATA), 64), +#endif +#if CFG_TUD_MSC + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, STRID_MSC_INTERFACE, EPNUM_MSC_DATA, (0x80 | EPNUM_MSC_DATA), 64), // highspeed 512 +#endif #if CFG_TUD_U2FHID - TUD_HID_DESCRIPTOR(ITF_NUM_HID_2, STRID_HID_INTERFACE_2, HID_PROTOCOL_NONE, sizeof(desc_hid_report_2), (0x80 | EPNUM_HID_DATA_2), 8, 10), + TUD_HID_DESCRIPTOR(ITF_NUM_HID, STRID_HID_INTERFACE, HID_PROTOCOL_NONE, sizeof(desc_hid_report_2), (0x80 | EPNUM_HID_DATA), 8, 10), #endif #if CFG_TUD_DFU @@ -104,6 +146,7 @@ uint8_t const desc_configuration[] = { }; + // ============================================================================= // CALLBACKS // ============================================================================= @@ -197,12 +240,12 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) { ESP_LOGW(TAG, "Getting descriptor for interface %d", itf); #if CFG_TUD_HID_KBD - if (itf == 0) { + if (hid_mode == 0) { return desc_hid_report; } #endif #if CFG_TUD_U2FHID - if (itf == 0+(CFG_TUD_HID_KBD)) { + if (hid_mode == 1) { return desc_hid_report_2; } #endif @@ -260,13 +303,23 @@ void tusb_set_descriptor(tusb_desc_device_t *dev_desc, const char **str_desc) void tusb_set_config_descriptor(const uint8_t *config_desc) { size_t length = 0; - const uint8_t *config_descriptor = NULL; - if (config_desc == NULL) { + const uint8_t *config_descriptor = NULL; + + nvs_handle_t h = 0; + esp_err_t err = nvs_open("tidal", NVS_READONLY, &h); + hid_mode = 1; + err = nvs_get_i32(h, "enable_u2f", &hid_mode); + nvs_close(h); + if (err != ESP_OK) { + hid_mode = 1; + } + + if (hid_mode == 0) { config_descriptor = desc_configuration; - ESP_LOGI(TAG, "using default config desc"); + ESP_LOGI(TAG, "using keyboard descriptors"); } else { - config_descriptor = config_desc; - ESP_LOGI(TAG, "using custom config desc"); + config_descriptor = desc_configuration_2; + ESP_LOGI(TAG, "using u2fhid descriptors"); } length = (config_descriptor[3]<<8) + config_descriptor[2]; ESP_LOGI(TAG, "config desc size=%d", length); diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 440b9eb..472ad54 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -62,7 +62,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_get_serial_number_obj, ecc108a_get_seri STATIC mp_obj_t ecc108a_provision_slot() { - // Retrieve the current configuration zone + // Retrieve the current configuration zone and patch it + /* + Desired state from ecc108a_tools.run() + Key n: + SlotLocked: 1 (unlocked) + SlotConfig: 6083 + KeyConfig: 0033 + UseFlag: 0xff + */ uint8_t buf[128] = {0}; assert_ATCA_SUCCESS(atcab_read_config_zone(&buf)); diff --git a/drivers/tidal_helpers/tidal_helpers.c b/drivers/tidal_helpers/tidal_helpers.c index b83acca..ade93ac 100644 --- a/drivers/tidal_helpers/tidal_helpers.c +++ b/drivers/tidal_helpers/tidal_helpers.c @@ -23,22 +23,31 @@ typedef struct _machine_pin_obj_t { gpio_num_t id; } machine_pin_obj_t; +STATIC mp_obj_t tidal_helper_authentication_operation() { + return mp_obj_new_int(authentication_operation); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_helper_authentication_operation_obj, tidal_helper_authentication_operation); + STATIC mp_obj_t tidal_helper_authentication_requested() { mp_obj_t response[3]; response[0] = mp_const_none; response[1] = mp_const_none; response[2] = mp_const_none; + // Is the current operation a request? if (authentication_operation == AUTHENTICATE_REQUEST || authentication_operation == REGISTER_REQUEST) { response[0] = mp_const_true; - if (authentication_operation_slot == 99) - response[1] = mp_const_none; - else - response[1] = mp_obj_new_int(authentication_operation_slot); - response[2] = mp_obj_new_bytes(authentication_application_parameter, 32); } else { response[0] = mp_const_false; } + // What slot is in use + if (authentication_operation_slot == 99) { + response[1] = mp_const_none; + } else { + response[1] = mp_obj_new_int(authentication_operation_slot); + } + // What's the application parameter + response[2] = mp_obj_new_bytes(authentication_application_parameter, 32); return mp_obj_new_tuple(3, response); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_helper_authentication_requested_obj, tidal_helper_authentication_requested); @@ -65,7 +74,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_helper_authentication_approve_obj, tidal_ STATIC mp_obj_t tidal_helper_authentication_slot(mp_obj_t slot) { if (mp_obj_is_int(slot)) { - authentication_operation = mp_obj_get_int(slot); + authentication_operation_slot = mp_obj_get_int(slot); return slot; } else { mp_raise_ValueError(slot); @@ -440,6 +449,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(tidal_set_backlight_pwm_obj, tidal_set_backligh STATIC const mp_rom_map_elem_t tidal_helpers_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ota) }, + { MP_ROM_QSTR(MP_QSTR_get_authentication_operation), MP_ROM_PTR(&tidal_helper_authentication_operation_obj) }, { MP_ROM_QSTR(MP_QSTR_set_authentication_approval), MP_ROM_PTR(&tidal_helper_authentication_approve_obj) }, { MP_ROM_QSTR(MP_QSTR_get_authentication_requested), MP_ROM_PTR(&tidal_helper_authentication_requested_obj) }, { MP_ROM_QSTR(MP_QSTR_set_authentication_mismatch), MP_ROM_PTR(&tidal_helper_authentication_mismatch_obj) }, diff --git a/drivers/tidal_usb/tidal_usb_hid.c b/drivers/tidal_usb/tidal_usb_hid.c index df92908..c957271 100644 --- a/drivers/tidal_usb/tidal_usb_hid.c +++ b/drivers/tidal_usb/tidal_usb_hid.c @@ -14,7 +14,7 @@ static const char *TAG = "tidalHID"; void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { printf("REPORT: %d %d %d\n", itf, report_id, report_type); #if CFG_TUD_U2FHID - if (itf == 0+(CFG_TUD_HID_KBD)) { + if (hid_mode == 1) { // This is the U2F device handle_report_u2f(itf, report_id, report_type, buffer, bufsize); } diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index d4dae91..970fe50 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -255,7 +255,7 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a ESP_LOGI(TAG, "Allocating container"); arbitrary_size_container response_data = { .size=0, - .data=malloc(256) + .data=malloc(185) }; memset(response_data.data, 0x00, 185); size_t write_head = 0; @@ -264,12 +264,12 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a ESP_LOGI(TAG, "Setting presence bit"); response_data.data[write_head++] = 0x01; // The next 4 bytes are a counter, increment it for this handle and return - uint32_t counter_value = 0; + uint32_t counter_value = 1; set_counter(authenticate_params->key_handle[0], &counter_value); - response_data.data[write_head++] = (counter_value >> 24) && 0xFF; - response_data.data[write_head++] = (counter_value >> 16) && 0xFF; - response_data.data[write_head++] = (counter_value >> 8) && 0xFF; - response_data.data[write_head++] = (counter_value >> 0) && 0xFF; + response_data.data[write_head++] = 0x00;//(counter_value >> 24) && 0xFF; + response_data.data[write_head++] = 0x00;//(counter_value >> 16) && 0xFF; + response_data.data[write_head++] = 0x00;//(counter_value >> 8) && 0xFF; + response_data.data[write_head++] = 0x00;//(counter_value >> 0) && 0xFF; // Create the signature out of the application parameter, the user presence byte, the counter then the challenge param ESP_LOGI(TAG, "Setting signature"); @@ -277,9 +277,8 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a memcpy(signature_input + 0, authenticate_params->application_param, 32); memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - memset(&response_data.data[write_head], 0xF0, 70); - /*write_head += *///get_signature(6, 69, signature_input, response_data.data + write_head); - write_head += 70; + write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); + // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; @@ -349,7 +348,6 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { if (authentication_operation == NO_OPERATION || authentication_operation == REGISTER_REQUEST) { // Set shared variables with micropython authentication_operation = REGISTER_REQUEST; - authentication_operation_slot = 99; memcpy(authentication_application_parameter, register_params->application_param, 32); // The user needs to allow this, send back the conditions @@ -371,6 +369,7 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { arbitrary_size_container response_data = process_register_command(register_params); send_multipart_response(&response_data); authentication_operation = NO_OPERATION; + authentication_operation_slot = 99; free(response_data.data); } } else if (raw_message->INS == U2F_AUTHENTICATE) { @@ -407,6 +406,7 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { send_multipart_response(&response_data); free(response_data.data); authentication_operation = NO_OPERATION; + authentication_operation_slot = 99; } else { // The user needs to allow this, send back the conditions diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 74e6648..f71b35f 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -112,15 +112,15 @@ size_t der_encode_signature(uint8_t signature[64], uint8_t target[70]) { void set_counter(uint8_t handle, uint32_t *target) { - return 1; + *target = 1; //atcab_counter_increment(handle, target); } void set_pubkey(uint8_t handle, uint8_t *target) { // This is an uncompressed key - in DER format?s target[0] = 0x04; - atcab_get_pubkey(handle, target+1); - //atcab_genkey(handle, target + 1); + //atcab_get_pubkey(handle, target+1); + atcab_genkey(handle, target + 1); } uint8_t allocate_handle() { diff --git a/modules/authenticator/__init__.py b/modules/authenticator/__init__.py index daa024a..0c637d0 100644 --- a/modules/authenticator/__init__.py +++ b/modules/authenticator/__init__.py @@ -45,6 +45,10 @@ def make_slot_select(self, slot_id): registered_date = settings.get(f"auth_slot_{slot_id}_registered", "") return (name + " " + registered_date, print) + def reallocate_slot(self, slot_id): + settings.delete(f"auth_slot_{slot_id}_name") + settings.delete(f"auth_slot_{slot_id}_registered") + settings.save() def cycle_leds(): tidal.led_power_on() @@ -63,7 +67,7 @@ def trigger_wink(slot_id=None): tidal.led_power_on(True) tidal.led[0] = (255, 255, 0) flasher = authenticator_app.periodic(250, cycle_leds) - okay = authenticator_app.yes_no_prompt("Sign?", font=vga2_bold_16x32) + okay = authenticator_app.yes_no_prompt("Sign %d?" % slot_id, font=vga2_bold_16x32) tidal.led[0] = (0, 0, 0) tidal.led.write() tidal.led_power_on(False) @@ -75,25 +79,49 @@ def allow_interrupt_when_authenticating(): def check_for_wink(): global prompting requested, slot_id, application_param = tidal_helpers.get_authentication_requested() - if requested == False: # Slot 0 might be requested, which is falsey + operation = tidal_helpers.get_authentication_operation() + if requested == False: return elif prompting: # An earlier periodic invocation is asking return else: prompting = True - if slot_id is None: - for i in range(16): - if not settings.get(f"auth_slot_{i}_name", ""): - slot_id = i - break - if slot_id is None: - # No slots available - tidal_helpers.set_authentication_approval(False) - return + name = binascii.hexlify(application_param).decode('latin-1') + + if operation == 1: # Registration request + # Re-use an old slot for this application, if possible + if slot_id is None: + for i in range(16): + if settings.get(f"auth_slot_{i}_name", "") == name: + slot_id = i + break + + # If not, find an unused slot + if slot_id is None: + for i in range(16): + if not settings.get(f"auth_slot_{i}_name", ""): + slot_id = i + break + + # No slots available, cancel the approval + if slot_id is None: + tidal_helpers.set_authentication_approval(False) + prompting = False + return + elif operation == 3: # Authenticate request + if slot_id: + # Check the application parameter matches + expected_name = settings.get(f"auth_slot_{slot_id}_name", "") + if name != expected_name: + tidal_helpers.set_authentication_mismatch() + prompting = False + return + + # Prompt the user for permission response = trigger_wink(slot_id) if response: - name = binascii.hexlify(application_param).decode('latin-1') + # If approved, save the metadata settings.set(f"auth_slot_{slot_id}_name", f"{name}") settings.set(f"auth_slot_{slot_id}_registered", "%04d-%02d-%02d" % (machine.RTC().datetime()[:3])) settings.save() @@ -101,4 +129,4 @@ def check_for_wink(): tidal_helpers.set_authentication_approval(response) prompting = False scheduler = get_scheduler() - scheduler.periodic(5000, check_for_wink) \ No newline at end of file + scheduler.periodic(2500, check_for_wink) \ No newline at end of file diff --git a/modules/scheduler.py b/modules/scheduler.py index e5100f3..49329ea 100644 --- a/modules/scheduler.py +++ b/modules/scheduler.py @@ -4,6 +4,7 @@ import time import uasyncio import wifi +import esp32 _scheduler = None @@ -99,7 +100,11 @@ def enter(self): deactivated_app = None while True: if first_time: - if settings.get("enable_u2f", True): + try: + hid_mode = esp32.NVS("tidal").get_i32("enable_u2f") + except OSError: + hid_mode = 0 + if hid_mode == 1: # Add the U2F periodic task import authenticator authenticator.allow_interrupt_when_authenticating() diff --git a/modules/settings.py b/modules/settings.py index f486087..3836c28 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -25,6 +25,13 @@ def set(k, v): _settings[k] = v _modified = True +def delete(k): + global _modified + if _settings is None: + load() + del _settings[k] + _modified = True + def save(): global _settings, _modified if _settings is None: diff --git a/modules/settings_app/__init__.py b/modules/settings_app/__init__.py index 6066045..1f9dd24 100644 --- a/modules/settings_app/__init__.py +++ b/modules/settings_app/__init__.py @@ -151,7 +151,7 @@ def refresh(self): (5, 15, 30, 60, 5*60, 10*60, 30*60, 60*60, 8*60*60)), self.make_choice("USB sleep delay", None, "usb_nosleep_time", 15, fmt_time, (15, 30, 60)), self.make_choice("UART menu app", None, "uart_menu_app", True, fmt_on_off, (True, False)), - self.make_choice("MFA mode", None, "enable_u2f", True, fmt_on_off, (True, False)), + self.make_nvs_choice("MFA mode", None, "enable_u2f", True, fmt_on_off, (True, False)), self.make_nvs_choice("REPL on SDA/SCL", None, "uart_sdascl", 0, fmt_on_off, (1, 0)), ) diff --git a/tildamk6/sdkconfig.board b/tildamk6/sdkconfig.board index d28ac50..9c6c018 100644 --- a/tildamk6/sdkconfig.board +++ b/tildamk6/sdkconfig.board @@ -29,7 +29,7 @@ CONFIG_TINYUSB_DESC_USE_DEFAULT_PID= CONFIG_USB_CDC_ENABLED=y CONFIG_TINYUSB_CDC_ENABLED=y CONFIG_TINYUSB_HID_ENABLED=y -CONFIG_TINYUSB_HIDKEYBOARD_ENABLED=n +CONFIG_TINYUSB_HIDKEYBOARD_ENABLED=y CONFIG_TINYUSB_U2FHID_ENABLED=y CONFIG_TINYUSB_MSC_ENABLED=n CONFIG_TINYUSB_MIDI_ENABLED=n From fb4a4f228b5b9ce082e7c6f71759a7951e1f91e4 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 15 Apr 2024 22:44:06 +0100 Subject: [PATCH 21/32] Set the target env variable at workflow module scope --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74e74ee..d1c0f76 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,8 @@ on: push: tags: - "v*" +env: + TARGET: esp32s3 jobs: Build-Firmware: runs-on: ubuntu-latest From 020440b185dc1a672cae1fc41765e15abb52d40c Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 15 Apr 2024 22:56:40 +0100 Subject: [PATCH 22/32] Force idf target in the tinyusb component --- components/tinyusb/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/tinyusb/CMakeLists.txt b/components/tinyusb/CMakeLists.txt index a796321..23a5532 100644 --- a/components/tinyusb/CMakeLists.txt +++ b/components/tinyusb/CMakeLists.txt @@ -1,3 +1,4 @@ +set(IDF_TARGET esp32s3) idf_build_get_property(target IDF_TARGET) set(srcs) From 818d729c27d5b268d6c899494cba6c7063b5cda9 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 15 Apr 2024 23:12:53 +0100 Subject: [PATCH 23/32] Another attempt to sort target for github builds --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1c0f76..642d380 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,6 +7,7 @@ on: - "v*" env: TARGET: esp32s3 + IDF_TARGET: esp32s3 jobs: Build-Firmware: runs-on: ubuntu-latest From b440c3cb68f9801a600f1d3ea12733b7f822033b Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 15 Apr 2024 23:28:19 +0100 Subject: [PATCH 24/32] Use IDF 4.4.1 in github --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 642d380..2cf829f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v2 with: repository: espressif/esp-idf - ref: release/v4.4 + ref: v4.4.1 path: esp-idf submodules: true - name: Install SDK From 7e94e9d2476924fe6a440660ca6464dcf203b386 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 21 Apr 2024 16:40:22 +0100 Subject: [PATCH 25/32] Move cryptographic operation calls into MicroPython to improve reliability --- drivers/ecc108a/ecc108a.c | 32 +++++++-- drivers/tidal_usb/micropython.cmake | 1 + drivers/tidal_usb/tidal_usb_u2f.c | 72 ++++++++++++++----- .../tidal_usb_u2f_shared_variables.c | 6 +- .../tidal_usb_u2f_shared_variables.h | 4 ++ drivers/tidal_usb/u2f_crypto.c | 8 ++- drivers/tidal_usb/u2f_crypto.h | 3 +- modules/authenticator/__init__.py | 38 ++++++++-- 8 files changed, 130 insertions(+), 34 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 472ad54..8a343b7 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -35,7 +35,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_init_obj, ecc108a_init); STATIC mp_obj_t ecc108a_read_config() { - assert_ATCA_SUCCESS(atcab_wakeup()); + atcab_wakeup(); uint8_t buf[128] = {0}; assert_ATCA_SUCCESS(atcab_read_config_zone(&buf)); return mp_obj_new_bytearray(sizeof(buf), buf); @@ -47,7 +47,7 @@ STATIC mp_obj_t ecc108a_get_serial_number() { uint8_t serial[9] = { 0 }; char serial_str[27] = ""; - assert_ATCA_SUCCESS(atcab_wakeup()); + atcab_wakeup(); assert_ATCA_SUCCESS(atcab_read_serial_number(&serial)); sprintf(&serial_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", @@ -129,7 +129,7 @@ STATIC mp_obj_t ecc108a_genkey(mp_obj_t slot_id) { uint8_t pubkey[64] = { 0 }; uint8_t slot = mp_obj_get_int(slot_id); - //assert_ATCA_SUCCESS(atcab_wakeup()); + atcab_wakeup(); assert_ATCA_SUCCESS(atcab_genkey(slot, &pubkey)); // Return X, Y tuple @@ -145,7 +145,7 @@ STATIC mp_obj_t ecc108a_get_pubkey(mp_obj_t slot_id) { uint8_t pubkey[64] = { 0 }; uint8_t slot = mp_obj_get_int(slot_id); - //assert_ATCA_SUCCESS(atcab_wakeup()); + atcab_wakeup(); assert_ATCA_SUCCESS(atcab_get_pubkey(slot, &pubkey)); // Return X, Y tuple @@ -164,7 +164,7 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { mp_check_self(mp_obj_is_str_or_bytes(message)); GET_STR_DATA_LEN(message, msg, str_len); - //assert_ATCA_SUCCESS(atcab_wakeup()); + atcab_wakeup(); assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); // Return R, S tuple @@ -175,6 +175,27 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(ecc108a_sign_obj, ecc108a_sign); +STATIC mp_obj_t ecc108a_full_sign(mp_obj_t slot_id, mp_obj_t message) { + uint8_t digest[32] = { 0 }; + uint8_t signature[64] = { 0 }; + uint8_t slot = mp_obj_get_int(slot_id); + + mp_check_self(mp_obj_is_str_or_bytes(message)); + GET_STR_DATA_LEN(message, msg, msg_len); + + atcab_wakeup(); + atcab_hw_sha2_256(msg, msg_len, digest); + assert_ATCA_SUCCESS(atcab_sign(slot, digest, signature)); + atcab_sleep(); + + // Return R, S tuple + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_bytes(signature, 32); + tuple[1] = mp_obj_new_bytes(signature+32, 32); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(ecc108a_full_sign_obj, ecc108a_full_sign); + STATIC mp_obj_t ecc108a_verify(mp_obj_t message, mp_obj_t signature, mp_obj_t public_key) { // All the strings are length 32, but we need to pass a *pointer* to a size t. @@ -222,6 +243,7 @@ STATIC const mp_rom_map_elem_t ecc108a_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_genkey), MP_ROM_PTR(&ecc108a_genkey_obj) }, { MP_ROM_QSTR(MP_QSTR_get_pubkey), MP_ROM_PTR(&ecc108a_get_pubkey_obj) }, { MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&ecc108a_sign_obj) }, + { MP_ROM_QSTR(MP_QSTR_full_sign), MP_ROM_PTR(&ecc108a_full_sign_obj) }, { MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&ecc108a_verify_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ecc108a_module_globals, ecc108a_module_globals_table); diff --git a/drivers/tidal_usb/micropython.cmake b/drivers/tidal_usb/micropython.cmake index ef65966..f0dbe57 100644 --- a/drivers/tidal_usb/micropython.cmake +++ b/drivers/tidal_usb/micropython.cmake @@ -3,6 +3,7 @@ add_library(usermod_tidal_usb INTERFACE) # Add our source files to the lib target_sources(usermod_tidal_usb INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/tidal_authentication.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_hid.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_console.c diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index 970fe50..485e451 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -179,7 +179,6 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body }; memset(response_data.data, 0x00, 1024); size_t write_head = 0; - uint8_t handle = allocate_handle(); uint8_t signature_input[131] = { 0 }; @@ -189,13 +188,15 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body // The next 65 bytes are the pubkey ESP_LOGI(TAG, "Setting pubkey"); - set_pubkey(handle, response_data.data + write_head); - write_head += 65; + //set_pubkey(authentication_operation_slot, response_data.data + write_head, false); + response_data.data[write_head++] = 0x04; + memcpy(response_data.data + write_head, authentication_pubkey, 64); + write_head += 64; // Then handle length followed by handle ESP_LOGI(TAG, "Setting handle"); response_data.data[write_head++] = 0x01; - response_data.data[write_head++] = handle; + response_data.data[write_head++] = authentication_operation_slot; // Attestation certificate @@ -210,12 +211,15 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body // Create the signature out of 0x00, the register request, key handle and pubkey ESP_LOGI(TAG, "Setting signature"); - signature_input[0] = 0x00; + /*signature_input[0] = 0x00; memcpy(signature_input + 1, register_params, 65); signature_input[66] = handle; memcpy(signature_input + 67, response_data.data + 1, 64); arbitrary_size_container signature; - write_head += get_signature(1, 131, signature_input, response_data.data + write_head); + //write_head += get_signature(1, 131, signature_input, response_data.data + write_head); + */ + memcpy(response_data.data + write_head, authentication_signature, 64); + write_head += 64; // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; @@ -223,7 +227,7 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body ESP_LOGI(TAG, "Built %d byte register response", write_head); response_data.size = write_head; //realloc(response_data.data, write_head); - + /* printf("RAW data:"); for (int i=0;ikey_handle[0], &counter_value); + //uint32_t counter_value = 1; + //set_counter(authenticate_params->key_handle[0], &counter_value); response_data.data[write_head++] = 0x00;//(counter_value >> 24) && 0xFF; response_data.data[write_head++] = 0x00;//(counter_value >> 16) && 0xFF; response_data.data[write_head++] = 0x00;//(counter_value >> 8) && 0xFF; - response_data.data[write_head++] = 0x00;//(counter_value >> 0) && 0xFF; + response_data.data[write_head++] = 0x01;//(counter_value >> 0) && 0xFF; // Create the signature out of the application parameter, the user presence byte, the counter then the challenge param ESP_LOGI(TAG, "Setting signature"); @@ -277,13 +281,27 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a memcpy(signature_input + 0, authenticate_params->application_param, 32); memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); + + // Ensure the signature material didn't change while we computed it + if (memcmp(signature_input, authentication_value_to_sign, authentication_length_to_sign) == 0) { + write_head += der_encode_signature(authentication_signature, response_data.data + write_head); + //write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); + response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; + response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; + ESP_LOGI(TAG, "Built %d byte authenticate response", write_head); + response_data.size = write_head; + } else { + response_data.data[0] = U2F_SW_CONDITIONS_NOT_SATISFIED >> 8; + response_data.data[1] = U2F_SW_CONDITIONS_NOT_SATISFIED & 0xFF; + response_data.size = 2; + } + + //write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); + ///uint8_t fakesig[64] = { 0x11, 0xce, 0x96, 0x46, 0xf3, 0xc6, 0xa0, 0xc9, 0x84, 0x3c, 0x89, 0xa8, 0xd7, 0xb0, 0xab, 0x48, 0xf1, 0xba, 0xab, 0xa9, 0x9e, 0x65, 0x1c, 0x7e, 0x67, 0x3a, 0x1d, 0xba, 0x99, 0xa4, 0xb9, 0x16, 0x61, 0x53, 0x32, 0x66, 0x31, 0x65, 0xbb, 0xb3, 0x20, 0x94, 0xa3, 0xd1, 0x9d, 0xeb, 0xcd, 0xa3, 0xac, 0x73, 0x71, 0x9e, 0x3d, 0xec, 0x54, 0x0d, 0xe7, 0xf1, 0x9a, 0xd5, 0x05, 0xd2, 0xf2, 0xb9 }; + //memcpy(response_data.data + write_head+3, authentication_signature, 64); + //write_head += 70; // Set the status epilogue - response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; - response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; - ESP_LOGI(TAG, "Built %d byte authenticate response", write_head); - response_data.size = write_head; //realloc(response_data.data, write_head); @@ -349,6 +367,9 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { // Set shared variables with micropython authentication_operation = REGISTER_REQUEST; memcpy(authentication_application_parameter, register_params->application_param, 32); + authentication_length_to_sign = 131; + authentication_value_to_sign[0] = 0; + memcpy(authentication_value_to_sign, register_params, 65); // The user needs to allow this, send back the conditions // not satisfied status as the only body @@ -413,9 +434,26 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { // not satisfied status as the only body // Set shared variables with micropython - authentication_operation = AUTHENTICATE_REQUEST; authentication_operation_slot = authenticate_params->key_handle[0]; memcpy(authentication_application_parameter, authenticate_params->application_param, 32); + + authentication_length_to_sign = 69; + memcpy(authentication_value_to_sign, authenticate_params->application_param, 32); + authentication_value_to_sign[32] = 0x01; + authentication_value_to_sign[33] = 0x00; + authentication_value_to_sign[34] = 0x00; + authentication_value_to_sign[35] = 0x00; + authentication_value_to_sign[36] = 0x01; + memcpy(authentication_value_to_sign + 37, authenticate_params->challenge_param, 32); + + authentication_operation = AUTHENTICATE_REQUEST; + + /*uint8_t signature_input[69] = { 0 }; + memcpy(signature_input + 0, authenticate_params->application_param, 32); + memcpy(signature_input + 32, response_data.data, 5); + memcpy(signature_input + 37, authenticate_params->challenge_param, 32); + //write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); +*/ ESP_LOGI(TAG, "Awaiting user interaction, reporting conditions not satisfied"); u2f_hid_msg response = { diff --git a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c index 33f4b20..406a59a 100644 --- a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c +++ b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c @@ -1,7 +1,11 @@ +#include #include #include #include "tidal_usb_u2f_shared_variables.h" enum authentication_state authentication_operation = NO_OPERATION; uint8_t authentication_operation_slot = 99; -uint8_t authentication_application_parameter[32] = { 0 }; \ No newline at end of file +uint8_t authentication_application_parameter[32] = { 0 }; +size_t authentication_length_to_sign = 0; +uint8_t authentication_value_to_sign[256] = { 0 }; +uint8_t authentication_signature[64] = { 0 }; \ No newline at end of file diff --git a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h index 63bf922..a9255b3 100644 --- a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h +++ b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h @@ -13,3 +13,7 @@ enum authentication_state { enum authentication_state authentication_operation; uint8_t authentication_operation_slot; uint8_t authentication_application_parameter[32]; +size_t authentication_length_to_sign; +uint8_t authentication_value_to_sign[256]; +uint8_t authentication_signature[64]; +uint8_t authentication_pubkey[64]; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index f71b35f..57c382a 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -116,11 +116,13 @@ void set_counter(uint8_t handle, uint32_t *target) { //atcab_counter_increment(handle, target); } -void set_pubkey(uint8_t handle, uint8_t *target) { +void set_pubkey(uint8_t handle, uint8_t *target, bool regenerate) { // This is an uncompressed key - in DER format?s target[0] = 0x04; - //atcab_get_pubkey(handle, target+1); - atcab_genkey(handle, target + 1); + if (regenerate) + atcab_genkey(handle, target + 1); + else + atcab_get_pubkey(handle, target + 1); } uint8_t allocate_handle() { diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h index c00e750..5585ded 100644 --- a/drivers/tidal_usb/u2f_crypto.h +++ b/drivers/tidal_usb/u2f_crypto.h @@ -1,5 +1,6 @@ #include #include +#include typedef struct arbitrary_size_container { size_t size; @@ -9,6 +10,6 @@ typedef struct arbitrary_size_container { arbitrary_size_container get_attestation_certificate(); size_t get_signature(uint8_t handle, size_t signature_length, uint8_t *signature_input, uint8_t *target); void set_counter(uint8_t handle, uint32_t *target); -void set_pubkey(uint8_t handle, uint8_t *target); +void set_pubkey(uint8_t handle, uint8_t *target, bool regenerate); uint8_t allocate_handle(); size_t der_encode_signature(uint8_t *signature, uint8_t *target); \ No newline at end of file diff --git a/modules/authenticator/__init__.py b/modules/authenticator/__init__.py index 0c637d0..a8835cd 100644 --- a/modules/authenticator/__init__.py +++ b/modules/authenticator/__init__.py @@ -8,9 +8,11 @@ import orientation import _thread import vga2_bold_16x32 -import tidal_helpers +import tidal_authentication import binascii import machine +import ecc108a +import hashlib class PromptPermission(DialogWindow): @@ -78,8 +80,8 @@ def trigger_wink(slot_id=None): def allow_interrupt_when_authenticating(): def check_for_wink(): global prompting - requested, slot_id, application_param = tidal_helpers.get_authentication_requested() - operation = tidal_helpers.get_authentication_operation() + requested, slot_id, application_param = tidal_authentication.get_authentication_requested() + operation = tidal_authentication.get_authentication_operation() if requested == False: return elif prompting: @@ -106,15 +108,17 @@ def check_for_wink(): # No slots available, cancel the approval if slot_id is None: - tidal_helpers.set_authentication_approval(False) + tidal_authentication.set_authentication_approval(False) prompting = False return + else: + tidal_authentication.set_authentication_slot(slot_id) elif operation == 3: # Authenticate request if slot_id: # Check the application parameter matches expected_name = settings.get(f"auth_slot_{slot_id}_name", "") if name != expected_name: - tidal_helpers.set_authentication_mismatch() + tidal_authentication.set_authentication_mismatch() prompting = False return @@ -125,8 +129,28 @@ def check_for_wink(): settings.set(f"auth_slot_{slot_id}_name", f"{name}") settings.set(f"auth_slot_{slot_id}_registered", "%04d-%02d-%02d" % (machine.RTC().datetime()[:3])) settings.save() - tidal_helpers.set_authentication_slot(slot_id) - tidal_helpers.set_authentication_approval(response) + + try: + to_sign = tidal_authentication.get_to_sign() + if tidal_authentication.get_authentication_operation() == 1: + # This is a register request, overwrite the handle at byte 66 + to_sign = bytearray(to_sign) + to_sign[66] = slot_id + to_sign = bytes(to_sign) + # This is registration, so generate a key + ecc108a.genkey(slot_id) + print("material", to_sign) + print("slot", slot_id) + pubkey = ecc108a.get_pubkey(slot_id) + tidal_authentication.set_pubkey(pubkey) + print("pubkey", pubkey) + signature = ecc108a.full_sign(slot_id, to_sign) + print("sig", signature) + tidal_authentication.set_signature(signature) + tidal_authentication.set_authentication_approval(response) + except OSError: + # Retry + pass prompting = False scheduler = get_scheduler() scheduler.periodic(2500, check_for_wink) \ No newline at end of file From be695b20151ca8ef96c283c219c5c2bb1987dabc Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 7 Jul 2024 17:24:56 +0100 Subject: [PATCH 26/32] Improvements to u2f --- drivers/ecc108a/ecc108a.c | 19 +++++++++++++++++-- drivers/tidal_usb/tidal_usb_u2f.c | 2 +- drivers/tidal_usb/u2f_crypto.c | 2 ++ modules/authenticator/__init__.py | 7 ++++++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 8a343b7..4bbf08e 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -162,10 +162,11 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { uint8_t slot = mp_obj_get_int(slot_id); mp_check_self(mp_obj_is_str_or_bytes(message)); - GET_STR_DATA_LEN(message, msg, str_len); + GET_STR_DATA_LEN(message, digest, digest_len); atcab_wakeup(); - assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); + assert_ATCA_SUCCESS(atcab_sign(slot, digest, signature)); + atcab_sleep(); // Return R, S tuple mp_obj_t tuple[2]; @@ -196,6 +197,20 @@ STATIC mp_obj_t ecc108a_full_sign(mp_obj_t slot_id, mp_obj_t message) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(ecc108a_full_sign_obj, ecc108a_full_sign); +/* +import ecc108a, hashlib +slot = 6 +key = ecc108a.get_pubkey(slot) +message = "This is a test message" +hash = hashlib.sha256(message).digest() +sig = ecc108a.sign(slot, hash) +ecc108a.verify(hash, sig, key) + +*/ +//msg = b'a'*32 ; ecc108a.verify(msg, (msg, msg), (msg, msg)) +// ecc108a.verify(msg, (b'\xfd\x0c \xc4\xe0\x1c\x1d\xd8H\xf6\xb5?12\xc2\x1e>k\xc8\xb3\xc4=\x0e\xdb#v\xba\xffn\x94<\x7f', b'\xcb~\xe0`\t\xc9Yf\xfd\xdbc2\xe7\xf4\x81\xf0\x13\xc8\xb90\xd7\xa3~XI\xb4c\xa9H\x00Wu'), (b'\xe4`\xb2\x93\xc9\x9bj\x9f\xfbD\x94\x1di\x9b\x96\xc7\x91F\x1c\xcf\x7f\xe4\xbe\x8d4%P\xe3\xbb\x18;\xa0', b'\x0b\x9e\xe8\xf1\x9cB\x06\xb1\x93\xd2&\x7f\xdb\x03\x17\xa82\x99\x18\x1f\t\x1cz\xe5H\xb2\xb3}fM\xabe')) + + STATIC mp_obj_t ecc108a_verify(mp_obj_t message, mp_obj_t signature, mp_obj_t public_key) { // All the strings are length 32, but we need to pass a *pointer* to a size t. diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index 485e451..a362278 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -155,7 +155,7 @@ void handle_u2f_init(u2fhid_init_request const* init_request) { .DEVICE_VER_MAJOR = 0x03, .DEVICE_VER_MINOR = 0x04, .DEVICE_VER_BUILD = 0x05, - .CAPABILITIES = CAPFLAG_WINK + .CAPABILITIES = 0 //CAPFLAG_WINK }; // Allocate a response report diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 57c382a..32f0b9a 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -83,6 +83,8 @@ size_t get_signature(uint8_t handle, size_t signature_length, uint8_t *signature atcab_wakeup(); atcab_hw_sha2_256(signature_input, signature_length, digest); ESP_LOGI(TAG, "Signing data"); + atcab_sleep(); + atcab_wakeup(); atcab_sign(handle, digest, signature); atcab_sleep(); return der_encode_signature(signature, target); diff --git a/modules/authenticator/__init__.py b/modules/authenticator/__init__.py index a8835cd..c954952 100644 --- a/modules/authenticator/__init__.py +++ b/modules/authenticator/__init__.py @@ -91,6 +91,8 @@ def check_for_wink(): prompting = True name = binascii.hexlify(application_param).decode('latin-1') + #slot_id = 6 + if operation == 1: # Registration request # Re-use an old slot for this application, if possible if slot_id is None: @@ -144,7 +146,10 @@ def check_for_wink(): pubkey = ecc108a.get_pubkey(slot_id) tidal_authentication.set_pubkey(pubkey) print("pubkey", pubkey) - signature = ecc108a.full_sign(slot_id, to_sign) + ecc108a.init() + ecc108a.read_config() + sig = hashlib.sha256(to_sign).digest() + signature = ecc108a.sign(slot_id, sig) print("sig", signature) tidal_authentication.set_signature(signature) tidal_authentication.set_authentication_approval(response) From 56fd3ace3523dfb47a4bbc631d196dd0ec8e4dc6 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Sun, 7 Jul 2024 17:40:26 +0100 Subject: [PATCH 27/32] Add missing usb driver files??? --- drivers/tidal_usb/cryptoauthlib | 1 + drivers/tidal_usb/micropython.cmake | 1 - drivers/tidal_usb/tidal_authentication.c | 176 ++++++++++++++++++ drivers/tidal_usb/tidal_usb_u2f.c | 72 ++----- .../tidal_usb_u2f_shared_variables.c | 6 +- .../tidal_usb_u2f_shared_variables.h | 4 - drivers/tidal_usb/u2f_crypto.c | 8 +- drivers/tidal_usb/u2f_crypto.h | 3 +- 8 files changed, 199 insertions(+), 72 deletions(-) create mode 160000 drivers/tidal_usb/cryptoauthlib create mode 100644 drivers/tidal_usb/tidal_authentication.c diff --git a/drivers/tidal_usb/cryptoauthlib b/drivers/tidal_usb/cryptoauthlib new file mode 160000 index 0000000..9a37b8d --- /dev/null +++ b/drivers/tidal_usb/cryptoauthlib @@ -0,0 +1 @@ +Subproject commit 9a37b8d685c351faed720d18d9610345bdaf20b0 diff --git a/drivers/tidal_usb/micropython.cmake b/drivers/tidal_usb/micropython.cmake index f0dbe57..ef65966 100644 --- a/drivers/tidal_usb/micropython.cmake +++ b/drivers/tidal_usb/micropython.cmake @@ -3,7 +3,6 @@ add_library(usermod_tidal_usb INTERFACE) # Add our source files to the lib target_sources(usermod_tidal_usb INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/tidal_authentication.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_hid.c ${CMAKE_CURRENT_LIST_DIR}/tidal_usb_console.c diff --git a/drivers/tidal_usb/tidal_authentication.c b/drivers/tidal_usb/tidal_authentication.c new file mode 100644 index 0000000..273e480 --- /dev/null +++ b/drivers/tidal_usb/tidal_authentication.c @@ -0,0 +1,176 @@ +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/objtuple.h" +#include "esp_log.h" +#include "sdkconfig.h" +#include "mphalport.h" +#include "modmachine.h" // for machine_pin_type +#include "esp_sleep.h" +#include "esp_wifi.h" +#include "device/usbd.h" +#include "rom/uart.h" +#include "soc/rtc_cntl_reg.h" +#include "esp32s2/rom/usb/usb_dc.h" +#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h" +#include "esp32s2/rom/usb/usb_persist.h" +#include "esp_wpa2.h" +#include "driver/ledc.h" +#include "tidal_usb_u2f_shared_variables.h" + + +STATIC mp_obj_t tidal_authentication_authentication_operation() { + return mp_obj_new_int(authentication_operation); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_authentication_authentication_operation_obj, tidal_authentication_authentication_operation); + +STATIC mp_obj_t tidal_authentication_authentication_requested() { + mp_obj_t response[3]; + response[0] = mp_const_none; + response[1] = mp_const_none; + response[2] = mp_const_none; + + // Is the current operation a request? + if (authentication_operation == AUTHENTICATE_REQUEST || authentication_operation == REGISTER_REQUEST) { + response[0] = mp_const_true; + } else { + response[0] = mp_const_false; + } + // What slot is in use + if (authentication_operation_slot == 99) { + response[1] = mp_const_none; + } else { + response[1] = mp_obj_new_int(authentication_operation_slot); + } + // What's the application parameter + response[2] = mp_obj_new_bytes(authentication_application_parameter, 32); + return mp_obj_new_tuple(3, response); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_authentication_authentication_requested_obj, tidal_authentication_authentication_requested); + +STATIC mp_obj_t tidal_authentication_authentication_mismatch() { + authentication_operation = KEY_MISMATCH; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_authentication_authentication_mismatch_obj, tidal_authentication_authentication_mismatch); + +STATIC mp_obj_t tidal_authentication_authentication_approve(mp_obj_t state) { + if (state == mp_const_true) { + if (authentication_operation == AUTHENTICATE_REQUEST) + authentication_operation = AUTHENTICATE_APPROVED; + if (authentication_operation == REGISTER_REQUEST) + authentication_operation = REGISTER_APPROVED; + } + if (state == mp_const_false) + authentication_operation = USER_REFUSED; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_authentication_authentication_approve_obj, tidal_authentication_authentication_approve); + + +STATIC mp_obj_t tidal_authentication_authentication_slot(mp_obj_t slot) { + if (mp_obj_is_int(slot)) { + authentication_operation_slot = mp_obj_get_int(slot); + return slot; + } else { + mp_raise_ValueError(slot); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_authentication_authentication_slot_obj, tidal_authentication_authentication_slot); + + +STATIC mp_obj_t tidal_authentication_to_sign() { + mp_obj_t response; + response = mp_obj_new_bytearray_by_ref(authentication_length_to_sign, authentication_value_to_sign); + return response; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_authentication_to_sign_obj, tidal_authentication_to_sign); + + + + +STATIC mp_obj_t tidal_authentication_last_signature() { + mp_obj_t response; + response = mp_obj_new_bytearray_by_ref(64, authentication_signature); + return response; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(tidal_authentication_last_signature_obj, tidal_authentication_last_signature); + + + +STATIC mp_obj_t tidal_authentication_set_signature(mp_obj_t signature_in) { + mp_obj_t *tuple_data = NULL; + size_t tuple_len; + memset(&authentication_signature, 0x00, 64); + + mp_obj_tuple_get(signature_in, &tuple_len, &tuple_data); + if (tuple_len == 2) { + for (size_t i=0; i<2; i++) { + if (mp_obj_is_str_or_bytes(tuple_data[i])) { + GET_STR_DATA_LEN(tuple_data[i], sig, sig_len); + if (sig_len == 32) { + memcpy((char *)authentication_signature + (i*32), (char *) sig, 32); + } else { + return mp_const_false; + } + } else { + return mp_const_false; + } + } + } else { + return mp_const_false; + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_authentication_set_signature_obj, tidal_authentication_set_signature); + + +STATIC mp_obj_t tidal_authentication_set_pubkey(mp_obj_t pubkey_in) { + mp_obj_t *tuple_data = NULL; + size_t tuple_len; + + mp_obj_tuple_get(pubkey_in, &tuple_len, &tuple_data); + if (tuple_len == 2) { + for (size_t i=0; i<2; i++) { + if (mp_obj_is_str_or_bytes(tuple_data[i])) { + GET_STR_DATA_LEN(tuple_data[i], pk, pk_len); + if (pk_len == 32) { + memcpy((char *)authentication_pubkey + (i*32), (char *) pk, 32); + } else { + return mp_const_false; + } + } else { + return mp_const_false; + } + } + } else { + return mp_const_false; + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(tidal_authentication_set_pubkey_obj, tidal_authentication_set_pubkey); + + + +STATIC const mp_rom_map_elem_t tidal_authentication_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_tidal_authentication) }, + { MP_ROM_QSTR(MP_QSTR_get_authentication_operation), MP_ROM_PTR(&tidal_authentication_authentication_operation_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_authentication_approval), MP_ROM_PTR(&tidal_authentication_authentication_approve_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_authentication_requested), MP_ROM_PTR(&tidal_authentication_authentication_requested_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_authentication_mismatch), MP_ROM_PTR(&tidal_authentication_authentication_mismatch_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_authentication_slot), MP_ROM_PTR(&tidal_authentication_authentication_slot_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_to_sign), MP_ROM_PTR(&tidal_authentication_to_sign_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_signature), MP_ROM_PTR(&tidal_authentication_set_signature_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_pubkey), MP_ROM_PTR(&tidal_authentication_set_pubkey_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_last_signature), MP_ROM_PTR(&tidal_authentication_last_signature_obj) }, + + +}; +STATIC MP_DEFINE_CONST_DICT(tidal_authentication_module_globals, tidal_authentication_module_globals_table); + +const mp_obj_module_t tidal_authentication_user_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&tidal_authentication_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_tidal_authentication, tidal_authentication_user_module, 1); diff --git a/drivers/tidal_usb/tidal_usb_u2f.c b/drivers/tidal_usb/tidal_usb_u2f.c index a362278..f425858 100644 --- a/drivers/tidal_usb/tidal_usb_u2f.c +++ b/drivers/tidal_usb/tidal_usb_u2f.c @@ -179,6 +179,7 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body }; memset(response_data.data, 0x00, 1024); size_t write_head = 0; + uint8_t handle = allocate_handle(); uint8_t signature_input[131] = { 0 }; @@ -188,15 +189,13 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body // The next 65 bytes are the pubkey ESP_LOGI(TAG, "Setting pubkey"); - //set_pubkey(authentication_operation_slot, response_data.data + write_head, false); - response_data.data[write_head++] = 0x04; - memcpy(response_data.data + write_head, authentication_pubkey, 64); - write_head += 64; + set_pubkey(handle, response_data.data + write_head); + write_head += 65; // Then handle length followed by handle ESP_LOGI(TAG, "Setting handle"); response_data.data[write_head++] = 0x01; - response_data.data[write_head++] = authentication_operation_slot; + response_data.data[write_head++] = handle; // Attestation certificate @@ -211,15 +210,12 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body // Create the signature out of 0x00, the register request, key handle and pubkey ESP_LOGI(TAG, "Setting signature"); - /*signature_input[0] = 0x00; + signature_input[0] = 0x00; memcpy(signature_input + 1, register_params, 65); signature_input[66] = handle; memcpy(signature_input + 67, response_data.data + 1, 64); arbitrary_size_container signature; - //write_head += get_signature(1, 131, signature_input, response_data.data + write_head); - */ - memcpy(response_data.data + write_head, authentication_signature, 64); - write_head += 64; + write_head += get_signature(1, 131, signature_input, response_data.data + write_head); // Set the status epilogue response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; @@ -227,7 +223,7 @@ arbitrary_size_container process_register_command(u2f_raw_register_request_body ESP_LOGI(TAG, "Built %d byte register response", write_head); response_data.size = write_head; //realloc(response_data.data, write_head); - /* + printf("RAW data:"); for (int i=0;ikey_handle[0], &counter_value); + uint32_t counter_value = 1; + set_counter(authenticate_params->key_handle[0], &counter_value); response_data.data[write_head++] = 0x00;//(counter_value >> 24) && 0xFF; response_data.data[write_head++] = 0x00;//(counter_value >> 16) && 0xFF; response_data.data[write_head++] = 0x00;//(counter_value >> 8) && 0xFF; - response_data.data[write_head++] = 0x01;//(counter_value >> 0) && 0xFF; + response_data.data[write_head++] = 0x00;//(counter_value >> 0) && 0xFF; // Create the signature out of the application parameter, the user presence byte, the counter then the challenge param ESP_LOGI(TAG, "Setting signature"); @@ -281,27 +277,13 @@ arbitrary_size_container process_authenticate_command(uint8_t control, u2f_raw_a memcpy(signature_input + 0, authenticate_params->application_param, 32); memcpy(signature_input + 32, response_data.data, 5); memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - - // Ensure the signature material didn't change while we computed it - if (memcmp(signature_input, authentication_value_to_sign, authentication_length_to_sign) == 0) { - write_head += der_encode_signature(authentication_signature, response_data.data + write_head); - //write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); - response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; - response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; - ESP_LOGI(TAG, "Built %d byte authenticate response", write_head); - response_data.size = write_head; - } else { - response_data.data[0] = U2F_SW_CONDITIONS_NOT_SATISFIED >> 8; - response_data.data[1] = U2F_SW_CONDITIONS_NOT_SATISFIED & 0xFF; - response_data.size = 2; - } - - //write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); + write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); - ///uint8_t fakesig[64] = { 0x11, 0xce, 0x96, 0x46, 0xf3, 0xc6, 0xa0, 0xc9, 0x84, 0x3c, 0x89, 0xa8, 0xd7, 0xb0, 0xab, 0x48, 0xf1, 0xba, 0xab, 0xa9, 0x9e, 0x65, 0x1c, 0x7e, 0x67, 0x3a, 0x1d, 0xba, 0x99, 0xa4, 0xb9, 0x16, 0x61, 0x53, 0x32, 0x66, 0x31, 0x65, 0xbb, 0xb3, 0x20, 0x94, 0xa3, 0xd1, 0x9d, 0xeb, 0xcd, 0xa3, 0xac, 0x73, 0x71, 0x9e, 0x3d, 0xec, 0x54, 0x0d, 0xe7, 0xf1, 0x9a, 0xd5, 0x05, 0xd2, 0xf2, 0xb9 }; - //memcpy(response_data.data + write_head+3, authentication_signature, 64); - //write_head += 70; // Set the status epilogue + response_data.data[write_head++] = U2F_SW_NO_ERROR >> 8; + response_data.data[write_head++] = U2F_SW_NO_ERROR & 0xFF; + ESP_LOGI(TAG, "Built %d byte authenticate response", write_head); + response_data.size = write_head; //realloc(response_data.data, write_head); @@ -367,9 +349,6 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { // Set shared variables with micropython authentication_operation = REGISTER_REQUEST; memcpy(authentication_application_parameter, register_params->application_param, 32); - authentication_length_to_sign = 131; - authentication_value_to_sign[0] = 0; - memcpy(authentication_value_to_sign, register_params, 65); // The user needs to allow this, send back the conditions // not satisfied status as the only body @@ -434,26 +413,9 @@ void handle_u2f_msg(uint8_t *buffer, uint16_t bufsize) { // not satisfied status as the only body // Set shared variables with micropython + authentication_operation = AUTHENTICATE_REQUEST; authentication_operation_slot = authenticate_params->key_handle[0]; memcpy(authentication_application_parameter, authenticate_params->application_param, 32); - - authentication_length_to_sign = 69; - memcpy(authentication_value_to_sign, authenticate_params->application_param, 32); - authentication_value_to_sign[32] = 0x01; - authentication_value_to_sign[33] = 0x00; - authentication_value_to_sign[34] = 0x00; - authentication_value_to_sign[35] = 0x00; - authentication_value_to_sign[36] = 0x01; - memcpy(authentication_value_to_sign + 37, authenticate_params->challenge_param, 32); - - authentication_operation = AUTHENTICATE_REQUEST; - - /*uint8_t signature_input[69] = { 0 }; - memcpy(signature_input + 0, authenticate_params->application_param, 32); - memcpy(signature_input + 32, response_data.data, 5); - memcpy(signature_input + 37, authenticate_params->challenge_param, 32); - //write_head += get_signature(authenticate_params->key_handle[0], 69, signature_input, response_data.data + write_head); -*/ ESP_LOGI(TAG, "Awaiting user interaction, reporting conditions not satisfied"); u2f_hid_msg response = { diff --git a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c index 406a59a..33f4b20 100644 --- a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c +++ b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.c @@ -1,11 +1,7 @@ -#include #include #include #include "tidal_usb_u2f_shared_variables.h" enum authentication_state authentication_operation = NO_OPERATION; uint8_t authentication_operation_slot = 99; -uint8_t authentication_application_parameter[32] = { 0 }; -size_t authentication_length_to_sign = 0; -uint8_t authentication_value_to_sign[256] = { 0 }; -uint8_t authentication_signature[64] = { 0 }; \ No newline at end of file +uint8_t authentication_application_parameter[32] = { 0 }; \ No newline at end of file diff --git a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h index a9255b3..63bf922 100644 --- a/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h +++ b/drivers/tidal_usb/tidal_usb_u2f_shared_variables.h @@ -13,7 +13,3 @@ enum authentication_state { enum authentication_state authentication_operation; uint8_t authentication_operation_slot; uint8_t authentication_application_parameter[32]; -size_t authentication_length_to_sign; -uint8_t authentication_value_to_sign[256]; -uint8_t authentication_signature[64]; -uint8_t authentication_pubkey[64]; diff --git a/drivers/tidal_usb/u2f_crypto.c b/drivers/tidal_usb/u2f_crypto.c index 32f0b9a..50d6760 100644 --- a/drivers/tidal_usb/u2f_crypto.c +++ b/drivers/tidal_usb/u2f_crypto.c @@ -118,13 +118,11 @@ void set_counter(uint8_t handle, uint32_t *target) { //atcab_counter_increment(handle, target); } -void set_pubkey(uint8_t handle, uint8_t *target, bool regenerate) { +void set_pubkey(uint8_t handle, uint8_t *target) { // This is an uncompressed key - in DER format?s target[0] = 0x04; - if (regenerate) - atcab_genkey(handle, target + 1); - else - atcab_get_pubkey(handle, target + 1); + //atcab_get_pubkey(handle, target+1); + atcab_genkey(handle, target + 1); } uint8_t allocate_handle() { diff --git a/drivers/tidal_usb/u2f_crypto.h b/drivers/tidal_usb/u2f_crypto.h index 5585ded..c00e750 100644 --- a/drivers/tidal_usb/u2f_crypto.h +++ b/drivers/tidal_usb/u2f_crypto.h @@ -1,6 +1,5 @@ #include #include -#include typedef struct arbitrary_size_container { size_t size; @@ -10,6 +9,6 @@ typedef struct arbitrary_size_container { arbitrary_size_container get_attestation_certificate(); size_t get_signature(uint8_t handle, size_t signature_length, uint8_t *signature_input, uint8_t *target); void set_counter(uint8_t handle, uint32_t *target); -void set_pubkey(uint8_t handle, uint8_t *target, bool regenerate); +void set_pubkey(uint8_t handle, uint8_t *target); uint8_t allocate_handle(); size_t der_encode_signature(uint8_t *signature, uint8_t *target); \ No newline at end of file From 6e36a4f258ed2674018e42b0fa10ce0e778f136c Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 27 Jan 2025 21:22:15 +0000 Subject: [PATCH 28/32] Missed changes, to be checked --- drivers/ecc108a/ecc108a.c | 16 ++++++++++++---- modules/authenticator/__init__.py | 14 ++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 4bbf08e..9e48c1f 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -35,7 +35,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(ecc108a_init_obj, ecc108a_init); STATIC mp_obj_t ecc108a_read_config() { - atcab_wakeup(); + assert_ATCA_SUCCESS(atcab_wakeup()); uint8_t buf[128] = {0}; assert_ATCA_SUCCESS(atcab_read_config_zone(&buf)); return mp_obj_new_bytearray(sizeof(buf), buf); @@ -47,7 +47,7 @@ STATIC mp_obj_t ecc108a_get_serial_number() { uint8_t serial[9] = { 0 }; char serial_str[27] = ""; - atcab_wakeup(); + assert_ATCA_SUCCESS(atcab_wakeup()); assert_ATCA_SUCCESS(atcab_read_serial_number(&serial)); sprintf(&serial_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", @@ -129,7 +129,7 @@ STATIC mp_obj_t ecc108a_genkey(mp_obj_t slot_id) { uint8_t pubkey[64] = { 0 }; uint8_t slot = mp_obj_get_int(slot_id); - atcab_wakeup(); + //assert_ATCA_SUCCESS(atcab_wakeup()); assert_ATCA_SUCCESS(atcab_genkey(slot, &pubkey)); // Return X, Y tuple @@ -145,7 +145,7 @@ STATIC mp_obj_t ecc108a_get_pubkey(mp_obj_t slot_id) { uint8_t pubkey[64] = { 0 }; uint8_t slot = mp_obj_get_int(slot_id); - atcab_wakeup(); + //assert_ATCA_SUCCESS(atcab_wakeup()); assert_ATCA_SUCCESS(atcab_get_pubkey(slot, &pubkey)); // Return X, Y tuple @@ -164,9 +164,17 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { mp_check_self(mp_obj_is_str_or_bytes(message)); GET_STR_DATA_LEN(message, digest, digest_len); +<<<<<<< HEAD + //assert_ATCA_SUCCESS(atcab_wakeup()); + assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); +||||||| parent of be695b2... Improvements to u2f + atcab_wakeup(); + assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); +======= atcab_wakeup(); assert_ATCA_SUCCESS(atcab_sign(slot, digest, signature)); atcab_sleep(); +>>>>>>> be695b2... Improvements to u2f // Return R, S tuple mp_obj_t tuple[2]; diff --git a/modules/authenticator/__init__.py b/modules/authenticator/__init__.py index c954952..fe54535 100644 --- a/modules/authenticator/__init__.py +++ b/modules/authenticator/__init__.py @@ -8,11 +8,11 @@ import orientation import _thread import vga2_bold_16x32 -import tidal_authentication +import tidal_helpers import binascii import machine import ecc108a -import hashlib +import tidal_authentication class PromptPermission(DialogWindow): @@ -80,8 +80,8 @@ def trigger_wink(slot_id=None): def allow_interrupt_when_authenticating(): def check_for_wink(): global prompting - requested, slot_id, application_param = tidal_authentication.get_authentication_requested() - operation = tidal_authentication.get_authentication_operation() + requested, slot_id, application_param = tidal_helpers.get_authentication_requested() + operation = tidal_helpers.get_authentication_operation() if requested == False: return elif prompting: @@ -110,17 +110,15 @@ def check_for_wink(): # No slots available, cancel the approval if slot_id is None: - tidal_authentication.set_authentication_approval(False) + tidal_helpers.set_authentication_approval(False) prompting = False return - else: - tidal_authentication.set_authentication_slot(slot_id) elif operation == 3: # Authenticate request if slot_id: # Check the application parameter matches expected_name = settings.get(f"auth_slot_{slot_id}_name", "") if name != expected_name: - tidal_authentication.set_authentication_mismatch() + tidal_helpers.set_authentication_mismatch() prompting = False return From 38f689ee8000d2d283cf78bb300919210ef5d96d Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 27 Jan 2025 21:51:52 +0000 Subject: [PATCH 29/32] Remove unused submodule --- drivers/tidal_usb/cryptoauthlib | 1 - 1 file changed, 1 deletion(-) delete mode 160000 drivers/tidal_usb/cryptoauthlib diff --git a/drivers/tidal_usb/cryptoauthlib b/drivers/tidal_usb/cryptoauthlib deleted file mode 160000 index 9a37b8d..0000000 --- a/drivers/tidal_usb/cryptoauthlib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9a37b8d685c351faed720d18d9610345bdaf20b0 From 3abce0decb2a1336312128ebe13d952421601568 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 27 Jan 2025 22:04:32 +0000 Subject: [PATCH 30/32] Try an older runner --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cf829f..5f0b9aa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ env: IDF_TARGET: esp32s3 jobs: Build-Firmware: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Install dependencies run: | From 04cedf63a8a10b5b544650c5210e31ca42fb1772 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 27 Jan 2025 22:14:00 +0000 Subject: [PATCH 31/32] Fix conflict marker --- drivers/ecc108a/ecc108a.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index 9e48c1f..c4d0089 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -164,17 +164,8 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { mp_check_self(mp_obj_is_str_or_bytes(message)); GET_STR_DATA_LEN(message, digest, digest_len); -<<<<<<< HEAD - //assert_ATCA_SUCCESS(atcab_wakeup()); - assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); -||||||| parent of be695b2... Improvements to u2f - atcab_wakeup(); + assert_ATCA_SUCCESS(atcab_wakeup()); assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); -======= - atcab_wakeup(); - assert_ATCA_SUCCESS(atcab_sign(slot, digest, signature)); - atcab_sleep(); ->>>>>>> be695b2... Improvements to u2f // Return R, S tuple mp_obj_t tuple[2]; From 94ddce52264fcc9a7520cd180c69cdfc71d31fe3 Mon Sep 17 00:00:00 2001 From: Matthew Wilkes Date: Mon, 27 Jan 2025 22:33:57 +0000 Subject: [PATCH 32/32] Fix sign call --- drivers/ecc108a/ecc108a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ecc108a/ecc108a.c b/drivers/ecc108a/ecc108a.c index c4d0089..60f9f3b 100644 --- a/drivers/ecc108a/ecc108a.c +++ b/drivers/ecc108a/ecc108a.c @@ -165,7 +165,8 @@ STATIC mp_obj_t ecc108a_sign(mp_obj_t slot_id, mp_obj_t message) { GET_STR_DATA_LEN(message, digest, digest_len); assert_ATCA_SUCCESS(atcab_wakeup()); - assert_ATCA_SUCCESS(atcab_sign(slot, &msg, &signature)); + assert_ATCA_SUCCESS(atcab_sign(slot, digest, signature)); + atcab_sleep(); // Return R, S tuple mp_obj_t tuple[2];