Add Atmel CryptoAuthLib to extras
This is Atmel/Microchip's official library for interfacing to the Atmel ATECC508 chip. The submodule points to their repository in GitHub. Additionally, this includes the HAL necessary to use this library in esp_open_rtos using the i2c library in extras/i2c. I have also included a tool I wrote to play with the chip as an example under examples/atcatool. The extras module currently overrides atca_iface.h to fix bug in cryptoauthlib (c11-only feature, which breaks c++ builds that want to use cryptoauthlib)
This commit is contained in:
parent
8f378b41c8
commit
e66e87aa8e
18 changed files with 1466 additions and 0 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -46,3 +46,6 @@
|
|||
[submodule "lvgl/lv_examples"]
|
||||
path = lvgl/lv_examples
|
||||
url = https://github.com/littlevgl/lv_examples.git
|
||||
[submodule "extras/cryptoauthlib/cryptoauthlib"]
|
||||
path = extras/cryptoauthlib/cryptoauthlib
|
||||
url = https://github.com/MicrochipTech/cryptoauthlib.git
|
||||
|
|
12
examples/atcatool/FreeRTOSConfig.h
Normal file
12
examples/atcatool/FreeRTOSConfig.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* Terminal FreeRTOSConfig overrides.
|
||||
|
||||
This is intended as an example of overriding some of the default FreeRTOSConfig settings,
|
||||
which are otherwise found in FreeRTOS/Source/include/FreeRTOSConfig.h
|
||||
*/
|
||||
|
||||
/* The serial driver depends on counting semaphores */
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
|
||||
/* Use the defaults for everything else */
|
||||
#include_next<FreeRTOSConfig.h>
|
||||
|
5
examples/atcatool/Makefile
Normal file
5
examples/atcatool/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
PROGRAM=atcatool
|
||||
EXTRA_COMPONENTS=extras/stdin_uart_interrupt extras/i2c extras/cryptoauthlib
|
||||
EXTRA_CFLAGS += -DATCAPRINTF
|
||||
ATEC_PRINTF_ENABLE = 1
|
||||
include ../../common.mk
|
56
examples/atcatool/cmd_ecdh.c
Normal file
56
examples/atcatool/cmd_ecdh.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
#include "uart_cmds.h"
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
ATCA_STATUS cmd_ecdh(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status;
|
||||
if (argc >= 2) {
|
||||
uint8_t slot_num = atoi(argv[1]);
|
||||
if (slot_num > 0x7){
|
||||
LOG("Invalid slot number %d; must be between 0 and 7 for private keys", slot_num);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
printf("Performing ECDH key exchange in slot %d\n", slot_num);
|
||||
uint8_t pubkeybytes[100];
|
||||
int pubkeylen = sizeof(pubkeybytes);
|
||||
status = read_pubkey_stdin(pubkeybytes, &pubkeylen);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to read public key");
|
||||
}
|
||||
|
||||
LOG("Got valid looking pubkey; does this look correct?");
|
||||
uint8_t *keyptr = pubkeybytes + (pubkeylen - ATCA_PUB_KEY_SIZE);
|
||||
atcab_printbin_label((const uint8_t*)"pubkey ", keyptr, ATCA_PUB_KEY_SIZE);
|
||||
|
||||
if (!prompt_user()) {
|
||||
printf("Aborting\n");
|
||||
}else{
|
||||
printf("Performing ECDH key exchange\n");
|
||||
}
|
||||
|
||||
// Write key to device
|
||||
uint8_t pmk[ATCA_PRIV_KEY_SIZE];
|
||||
status = atcab_ecdh(slot_num, keyptr, pmk);
|
||||
if(status != ATCA_SUCCESS){
|
||||
RETURN(status, "Failed to obtain pre-master key");
|
||||
}
|
||||
atcab_printbin_label((const uint8_t*)"pmk ", pmk, ATCA_PRIV_KEY_SIZE);
|
||||
|
||||
return ATCA_SUCCESS;
|
||||
} else {
|
||||
printf("Error: missing slot number.\n");
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
}
|
91
examples/atcatool/cmd_priv.c
Normal file
91
examples/atcatool/cmd_priv.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
|
||||
#include "uart_cmds.h"
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
// get cert and priv key
|
||||
//> openssl req -new -x509 -nodes -newkey ec:<(openssl ecparam -name secp256r1) -keyout cert.key -out cert.crt -days 3650
|
||||
|
||||
//#define PEM_PRIV_KEY_OFFSET 5
|
||||
#define PEM_PRIV_KEY_OFFSET 7
|
||||
|
||||
ATCA_STATUS cmd_priv(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status;
|
||||
if (argc >= 2) {
|
||||
uint8_t slot_num = atoi(argv[1]);
|
||||
if (slot_num > 0x7){
|
||||
LOG("Invalid slot number %d; must be between 0 and 7 for private keys", slot_num);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
uint8_t write_key_slot = 0;
|
||||
uint8_t *write_key = NULL;
|
||||
uint8_t random_num[RANDOM_NUM_SIZE];
|
||||
if (argc >= 3) {
|
||||
write_key_slot = atoi(argv[2]);
|
||||
if (write_key_slot == slot_num || write_key_slot < 0x0 || write_key_slot > 0xF) {
|
||||
LOG("Invalid slot for write key (%d); trying unencrypted write", (int)write_key_slot);
|
||||
write_key_slot = 0;
|
||||
write_key = NULL;
|
||||
} else {
|
||||
LOG("Writing write key to slot %d", (int)write_key_slot);
|
||||
if((status = atcab_random(random_num)) != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not make random number");
|
||||
}
|
||||
write_key = random_num;
|
||||
if((status = atcab_write_bytes_zone(ATCA_ZONE_DATA, write_key_slot, 0, write_key, RANDOM_NUM_SIZE)) != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not commit write key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Programming private key in slot %d\n", slot_num);
|
||||
uint8_t privkeybytes[200];
|
||||
int privkeylen = sizeof(privkeybytes);
|
||||
status = read_privkey_stdin(privkeybytes, &privkeylen);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to read private key");
|
||||
}
|
||||
|
||||
LOG("Got valid looking private key; does this look correct?");
|
||||
uint8_t *keyptr = privkeybytes + PEM_PRIV_KEY_OFFSET;
|
||||
atcab_printbin_label((const uint8_t*)"privkey ", keyptr, ATCA_PRIV_KEY_SIZE);
|
||||
|
||||
if (!prompt_user()) {
|
||||
printf("Aborting\n");
|
||||
return ATCA_SUCCESS;
|
||||
}else{
|
||||
printf("Writing key\n");
|
||||
}
|
||||
|
||||
// Write key to device
|
||||
uint8_t priv_key[ATCA_PRIV_KEY_SIZE + 4] = {0};
|
||||
memcpy(priv_key + 4, keyptr, ATCA_PRIV_KEY_SIZE);
|
||||
status = atcab_priv_write(slot_num, priv_key, write_key_slot, write_key);
|
||||
if(status != ATCA_SUCCESS){
|
||||
RETURN(status, "Failed to write key to slot");
|
||||
}
|
||||
|
||||
// Read public key
|
||||
uint8_t pub_key[ATCA_PUB_KEY_SIZE] = {0};
|
||||
if((status = atcab_get_pubkey(slot_num, pub_key)) != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not get public key");
|
||||
}
|
||||
atcab_printbin_label((const uint8_t*)"pubkey ", pub_key, sizeof(pub_key));
|
||||
|
||||
return ATCA_SUCCESS;
|
||||
} else {
|
||||
printf("Error: missing slot number.\n");
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
}
|
59
examples/atcatool/cmd_pub.c
Normal file
59
examples/atcatool/cmd_pub.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
#include "uart_cmds.h"
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
// get cert and priv key
|
||||
//> openssl req -new -x509 -nodes -newkey ec:<(openssl ecparam -name secp256r1) -keyout cert.key -out cert.crt -days 3650
|
||||
// get pub key
|
||||
//> openssl x509 -in cert.crt -pubkey -noout > pubkey.pem
|
||||
|
||||
ATCA_STATUS cmd_pub(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status;
|
||||
if (argc >= 2) {
|
||||
uint8_t slot_num = atoi(argv[1]);
|
||||
if (slot_num < 0x8 || slot_num > 0xF){
|
||||
LOG("Invalid slot number %d; must be between 8 and 15 for public keys", slot_num);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
printf("Programming public key in slot %d\n", slot_num);
|
||||
uint8_t pubkeybytes[100];
|
||||
int pubkeylen = sizeof(pubkeybytes);
|
||||
status = read_pubkey_stdin(pubkeybytes, &pubkeylen);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to read public key");
|
||||
}
|
||||
|
||||
LOG("Got valid looking pubkey; does this look correct?");
|
||||
uint8_t *keyptr = pubkeybytes + (pubkeylen - ATCA_PUB_KEY_SIZE);
|
||||
atcab_printbin_label((const uint8_t*)"pubkey ", keyptr, ATCA_PUB_KEY_SIZE);
|
||||
|
||||
if (!prompt_user()) {
|
||||
printf("Aborting\n");
|
||||
}else{
|
||||
printf("Writing key\n");
|
||||
}
|
||||
|
||||
// Write key to device
|
||||
status = atcab_write_pubkey(slot_num, keyptr);
|
||||
if(status != ATCA_SUCCESS){
|
||||
RETURN(status, "Failed to write key to slot");
|
||||
}
|
||||
|
||||
return ATCA_SUCCESS;
|
||||
} else {
|
||||
printf("Error: missing slot number.\n");
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
}
|
97
examples/atcatool/cmd_verify.c
Normal file
97
examples/atcatool/cmd_verify.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
|
||||
#include "uart_cmds.h"
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
// make test hash
|
||||
//> openssl sha -sha256 cmd_pub.c
|
||||
// sign test hash
|
||||
//> openssl sha -sha256 -sign cert.key -hex cmd_pub.c
|
||||
|
||||
void get_line(char *buf, size_t buflen)
|
||||
{
|
||||
char ch;
|
||||
char cmd[200];
|
||||
int i = 0;
|
||||
while(1) {
|
||||
if (read(0, (void*)&ch, 1)) { // 0 is stdin
|
||||
printf("%c", ch);
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
cmd[i] = 0;
|
||||
i = 0;
|
||||
printf("\n");
|
||||
strcpy(buf, cmd);
|
||||
return;
|
||||
} else {
|
||||
if (i < sizeof(cmd)) cmd[i++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ATCA_STATUS cmd_verify(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status;
|
||||
if (argc >= 2) {
|
||||
uint8_t slot_num = atoi(argv[1]);
|
||||
if (slot_num < 0x8 || slot_num > 0xF){
|
||||
LOG("Invalid slot number %d; must be between 8 and 15 for public keys", slot_num);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
printf("Verifying with public key in slot %d\n", slot_num);
|
||||
char hash[100]; uint8_t hashbin[100]; int hashlen = sizeof(hashbin);
|
||||
char sig[200]; uint8_t sigbin[200]; int siglen = sizeof(sigbin);
|
||||
|
||||
printf("Please paste hash in the terminal (hex format)\n");
|
||||
get_line(hash, sizeof(hash));
|
||||
|
||||
status = atcab_hex2bin(hash, strlen(hash), hashbin, &hashlen);
|
||||
if(status != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not parse hash hex");
|
||||
}
|
||||
|
||||
printf("Please paste signature in the terminal (hex format)\n");
|
||||
get_line(sig, sizeof(sig));
|
||||
|
||||
status = atcab_hex2bin(sig, strlen(sig), sigbin, &siglen);
|
||||
if(status != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not parse signature hex");
|
||||
}
|
||||
|
||||
bool isVerified = false;
|
||||
printf("Trying to verify with\n");
|
||||
atcab_printbin_label((const uint8_t*)"hash ", hashbin, hashlen);
|
||||
printf("Len %d\n", hashlen);
|
||||
atcab_printbin_label((const uint8_t*)"sig ", sigbin, siglen);
|
||||
printf("Len %d\n", siglen);
|
||||
|
||||
uint8_t atca_sig[ATCA_SIG_SIZE] = {0};
|
||||
if(!parse_asn1_signature(sigbin, siglen, atca_sig))
|
||||
{
|
||||
RETURN(ATCA_PARSE_ERROR, "Could not parse ASN.1 signature");
|
||||
}
|
||||
|
||||
atcab_printbin_label((const uint8_t*)"atca_sig ", atca_sig, ATCA_SIG_SIZE);
|
||||
printf("Len %d\n", ATCA_SIG_SIZE);
|
||||
|
||||
status = atcab_verify_stored(hashbin, atca_sig, slot_num, &isVerified);
|
||||
if(status != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not verify signature");
|
||||
}
|
||||
|
||||
printf(isVerified ? "Signature is valid\n" : "Signature is invalid\n");
|
||||
RETURN(status, "Done");
|
||||
} else {
|
||||
printf("Error: missing slot number.\n");
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
}
|
168
examples/atcatool/cmdutility.c
Normal file
168
examples/atcatool/cmdutility.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
|
||||
#include "uart_cmds.h"
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#define RETURN_BOOL(result, message) {printf(": " message "\r\n"); return result;}
|
||||
|
||||
ATCA_STATUS read_key_stdin(const char* beginConst, const char* endConst, uint8_t *keyOut, int *len)
|
||||
{
|
||||
printf("Please paste key in the terminal (PEM format)\n");
|
||||
|
||||
char ch;
|
||||
char cmd[81];
|
||||
int i = 0;
|
||||
bool done = false;
|
||||
uint8_t keybuf[1000] = {0}; // max buffer we should need
|
||||
int buf_used = 0;
|
||||
while (!done && buf_used < (sizeof(keybuf) - 1))
|
||||
{
|
||||
if (read(0, (void *)&ch, 1))
|
||||
{ // 0 is stdin
|
||||
printf("%c", ch);
|
||||
if (ch == '\n' || ch == '\r')
|
||||
{
|
||||
cmd[i] = 0;
|
||||
printf("\n");
|
||||
// check for end of public key
|
||||
if (!strcmp(endConst, cmd))
|
||||
{
|
||||
done = true;
|
||||
printf("Got end of public key\n");
|
||||
}
|
||||
else if (strcmp(beginConst, cmd))
|
||||
{
|
||||
// only copy non-marker text
|
||||
strcat((char *)keybuf, cmd);
|
||||
buf_used += i;
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < sizeof(cmd))
|
||||
cmd[i++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to parse
|
||||
uint8_t keybytes[(sizeof(keybuf) * 3) / 4];
|
||||
size_t arrayLen = sizeof(keybytes);
|
||||
ATCA_STATUS status = atcab_base64decode((const char *)keybuf, sizeof(keybuf), keybytes, &arrayLen);
|
||||
if(status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Error decoding base64 public key");
|
||||
}
|
||||
else if (arrayLen > *len)
|
||||
{
|
||||
LOG("Key was the wrong size (%d); expected at most %d", arrayLen, *len);
|
||||
atcab_printbin_label((const uint8_t*)"decoded ", keybytes, arrayLen);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
memcpy(keyOut, keybytes, arrayLen);
|
||||
*len = arrayLen;
|
||||
return ATCA_SUCCESS;
|
||||
}
|
||||
|
||||
ATCA_STATUS read_pubkey_stdin(uint8_t *keyOut, int *len)
|
||||
{
|
||||
return read_key_stdin(BEGIN_PUB_KEY_CONST, END_PUB_KEY_CONST, keyOut, len);
|
||||
}
|
||||
|
||||
ATCA_STATUS read_privkey_stdin(uint8_t *keyOut, int *len)
|
||||
{
|
||||
return read_key_stdin(BEGIN_PRIV_KEY_CONST, END_PRIV_KEY_CONST, keyOut, len);
|
||||
}
|
||||
|
||||
bool prompt_user()
|
||||
{
|
||||
printf("(y/n)\n");
|
||||
char ch = 0;
|
||||
while(ch != 'y' && ch != 'n') {
|
||||
if (read(0, (void*)&ch, 1)) { // 0 is stdin
|
||||
//NOP
|
||||
}
|
||||
}
|
||||
|
||||
return ch == 'y';
|
||||
}
|
||||
|
||||
bool parse_asn1_signature(uint8_t *asn1Sig, size_t asn1SigLen, uint8_t signatureRintSintOUT[ATCA_SIG_SIZE])
|
||||
{
|
||||
if (asn1Sig == NULL || asn1SigLen < sizeof(signatureRintSintOUT)) return false;
|
||||
|
||||
// Parse ASN.1. We expect the following output:
|
||||
// 0x30 0xXX <--0x30 = sequence; 0xXX num bytes in sequence
|
||||
// 0x02 0xYY <--0x02 = integer (R); 0xYY num bytes in R integer (2's complement)
|
||||
// ... ... <-- YY bytes of R integer
|
||||
// 0x02 0xZZ <--0x02 = integer (S); 0xZZ num bytes in S integer (2's complement)
|
||||
// ... ... <-- ZZ bytes of S integer
|
||||
const uint8_t halfSigSize = ATCA_SIG_SIZE / 2;
|
||||
uint8_t *atca_sig_ptr = signatureRintSintOUT;
|
||||
if (asn1Sig[0] != 0x30)
|
||||
{ // sequence
|
||||
RETURN_BOOL(false, "Expected sequence code (0x30) at position 0");
|
||||
}
|
||||
uint8_t seq_len = asn1Sig[1];
|
||||
if (seq_len < ATCA_SIG_SIZE)
|
||||
{ // sanity check
|
||||
RETURN_BOOL(false, "Sequence does not seem to be long enough for a signature");
|
||||
}
|
||||
if (asn1Sig[2] != 0x02)
|
||||
{ // integer
|
||||
RETURN_BOOL(false, "Expected integer code (0x02) at position 2 (R integer)");
|
||||
}
|
||||
// Get R integer
|
||||
uint8_t r_len = asn1Sig[3];
|
||||
uint8_t *int_ptr = &asn1Sig[4];
|
||||
if (r_len < halfSigSize)
|
||||
{
|
||||
atca_sig_ptr += (halfSigSize - r_len);
|
||||
}
|
||||
else if (r_len > halfSigSize)
|
||||
{
|
||||
int_ptr += (r_len - halfSigSize);
|
||||
r_len = halfSigSize;
|
||||
}
|
||||
memcpy(atca_sig_ptr, int_ptr, r_len); // <--insert R integer into output
|
||||
atca_sig_ptr += r_len;
|
||||
int_ptr += r_len;
|
||||
// more checks
|
||||
if (*int_ptr++ != 0x02)
|
||||
{ // integer
|
||||
RETURN_BOOL(false, "Expected integer code (0x02) at next position (S integer)");
|
||||
}
|
||||
// Get S integer
|
||||
uint8_t s_len = *int_ptr++;
|
||||
if (s_len < halfSigSize)
|
||||
{
|
||||
atca_sig_ptr += (halfSigSize - s_len);
|
||||
}
|
||||
else if (s_len > halfSigSize)
|
||||
{
|
||||
int_ptr += (s_len - halfSigSize);
|
||||
s_len = halfSigSize;
|
||||
}
|
||||
memcpy(atca_sig_ptr, int_ptr, s_len); // <--insert S integer into output
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_b64_pubkey(uint8_t pubkey[ATCA_PUB_KEY_SIZE])
|
||||
{
|
||||
char b64pubkey[100] = {0};
|
||||
size_t b64len = sizeof(b64pubkey);
|
||||
atcab_base64encode(pubkey, ATCA_PUB_KEY_SIZE, b64pubkey, &b64len);
|
||||
printf(BEGIN_PUB_KEY_CONST"\r\n");
|
||||
printf(b64pubkey);
|
||||
printf("\r\n"END_PUB_KEY_CONST"\r\n");
|
||||
}
|
245
examples/atcatool/pubkeyprog.c
Normal file
245
examples/atcatool/pubkeyprog.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* pubkeyprog
|
||||
* Program public keys in the ATCA over UART
|
||||
* UART RX is interrupt driven
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "i2c/i2c.h"
|
||||
#include "cryptoauthlib_init.h"
|
||||
#include <cryptoauthlib.h>
|
||||
|
||||
#include "uart_cmds.h"
|
||||
|
||||
static ATCA_STATUS cmd_cfg(uint32_t argc, char *argv[])
|
||||
{
|
||||
uint8_t configData[ATCA_ECC_CONFIG_SIZE];
|
||||
ATCA_STATUS status = atcab_read_config_zone(configData);
|
||||
if(status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to retrieve config data");
|
||||
}
|
||||
|
||||
printf("Got config data:\n");
|
||||
atcab_printbin(configData, sizeof(configData), true);
|
||||
RETURN(status, "Done");
|
||||
}
|
||||
|
||||
static ATCA_STATUS cmd_otp(uint32_t argc, char *argv[])
|
||||
{
|
||||
uint8_t otpData[ATCA_OTP_SIZE];
|
||||
ATCA_STATUS status = atcab_read_bytes_zone(ATCA_ZONE_OTP, 0, 0, otpData, sizeof(otpData));
|
||||
if(status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to retrieve OTP data");
|
||||
}
|
||||
|
||||
printf("Got OTP data:\n");
|
||||
atcab_printbin(otpData, sizeof(otpData), true);
|
||||
RETURN(status, "Done");
|
||||
}
|
||||
|
||||
// Copied from unit tests
|
||||
uint8_t test_ecc_configdata[ATCA_ECC_CONFIG_SIZE] = {
|
||||
0x01, 0x23, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x04, 0x05, 0x06, 0x07, 0xEE, 0x00, 0x01, 0x00,
|
||||
0xC0, 0x00, 0x55, 0x00, 0x8F, 0x2F, 0xC4, 0x44, 0x87, 0x20, 0xC4, 0xF4, 0x8F, 0x0F, 0x8F, 0x8F,
|
||||
0x9F, 0x8F, 0x83, 0x64, 0xC4, 0x44, 0xC4, 0x64, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x33, 0x00, 0x1C, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x33, 0x00,
|
||||
0x1C, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x30, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x32, 0x00, 0x30, 0x00
|
||||
};
|
||||
uint8_t g_otp_data[ATCA_OTP_SIZE] = "This is test data that can be read back out of the chip!huzzah!";
|
||||
|
||||
static ATCA_STATUS cmd_cfgwrite(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status = atcab_write_config_zone(test_ecc_configdata);
|
||||
if(status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to write ECC config data");
|
||||
}
|
||||
|
||||
RETURN(status, "Done");
|
||||
}
|
||||
|
||||
static ATCA_STATUS cmd_otpwrite(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status = atcab_write_bytes_zone(ATCA_ZONE_OTP, 0, 0, g_otp_data, ATCA_OTP_SIZE);
|
||||
if(status != ATCA_SUCCESS)
|
||||
{
|
||||
RETURN(status, "Failed to write OTP data");
|
||||
}
|
||||
|
||||
RETURN(status, "Done");
|
||||
}
|
||||
|
||||
static ATCA_STATUS cmd_cfglock(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status = atcab_lock_config_zone();
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
printf("Failed!\n");
|
||||
}
|
||||
|
||||
printf("Config Locked!\n");
|
||||
RETURN(status, "Done");
|
||||
}
|
||||
|
||||
static ATCA_STATUS cmd_otplock(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status = atcab_lock_data_zone();
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
printf("Failed!\n");
|
||||
}
|
||||
|
||||
printf("OTP Locked!\n");
|
||||
RETURN(status, "Done");
|
||||
}
|
||||
|
||||
static ATCA_STATUS cmd_gen(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status;
|
||||
if (argc >= 2) {
|
||||
uint8_t slot_num = atoi(argv[1]);
|
||||
if (slot_num > 0x7){
|
||||
LOG("Invalid slot number %d; must be between 0 and 7 for private keys", slot_num);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
uint8_t pubkey[ATCA_PUB_KEY_SIZE] = {0};
|
||||
if ((status = atcab_genkey(slot_num, pubkey)) != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not generate private key");
|
||||
}
|
||||
|
||||
atcab_printbin_label("publickey ", pubkey, sizeof(pubkey));
|
||||
print_b64_pubkey(pubkey);
|
||||
RETURN(status, "Done");
|
||||
} else {
|
||||
printf("Error: missing slot number.\n");
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
static ATCA_STATUS cmd_getpub(uint32_t argc, char *argv[])
|
||||
{
|
||||
ATCA_STATUS status;
|
||||
if (argc >= 2) {
|
||||
uint8_t slot_num = atoi(argv[1]);
|
||||
if (slot_num > 0x7){
|
||||
LOG("Invalid slot number %d; must be between 0 and 7 for private keys", slot_num);
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
|
||||
uint8_t pubkey[ATCA_PUB_KEY_SIZE] = {0};
|
||||
if ((status = atcab_get_pubkey(slot_num, pubkey)) != ATCA_SUCCESS){
|
||||
RETURN(status, "Could not read/generate public key");
|
||||
}
|
||||
|
||||
atcab_printbin_label("publickey ", pubkey, sizeof(pubkey));
|
||||
print_b64_pubkey(pubkey);
|
||||
RETURN(status, "Done");
|
||||
} else {
|
||||
printf("Error: missing slot number.\n");
|
||||
return ATCA_BAD_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_help(uint32_t argc, char *argv[])
|
||||
{
|
||||
printf("pub <slot number> Program public key to a slot\n");
|
||||
printf("priv <slot number> [slot number] Program private key to a slot using optional write key\n");
|
||||
printf("cfg Dump config\n");
|
||||
printf("otp Dump OTP zone\n");
|
||||
printf("verify <slot number> Verify signature with public key in slot\n");
|
||||
printf("cfgwrite Write test configuration\n");
|
||||
printf("otpwrite Write test OTP\n");
|
||||
printf("cfglock Lock config zone (not reversible!)\n");
|
||||
printf("otplock Lock OTP zone (not reversible!)\n");
|
||||
printf("gen <slot number> Generate private key in a slot\n");
|
||||
printf("getpub <slot number> Read/gen a public key from a private key slot\n");
|
||||
printf("ecdh <slot number> Perform ECDH key exchange in slot\n");
|
||||
printf("\nExample:\n");
|
||||
printf(" pub 12<enter> initiates public key programming in slot 12\n");
|
||||
}
|
||||
|
||||
static void handle_command(char *cmd)
|
||||
{
|
||||
char *argv[MAX_ARGC];
|
||||
int argc = 1;
|
||||
char *temp, *rover;
|
||||
memset((void*) argv, 0, sizeof(argv));
|
||||
argv[0] = cmd;
|
||||
rover = cmd;
|
||||
// Split string "<command> <argument 1> <argument 2> ... <argument N>"
|
||||
// into argv, argc style
|
||||
while(argc < MAX_ARGC && (temp = strstr(rover, " "))) {
|
||||
rover = &(temp[1]);
|
||||
argv[argc++] = rover;
|
||||
*temp = 0;
|
||||
}
|
||||
|
||||
if (strlen(argv[0]) > 0) {
|
||||
if (strcmp(argv[0], "help") == 0) cmd_help(argc, argv);
|
||||
else if (strcmp(argv[0], "pub") == 0) cmd_pub(argc, argv);
|
||||
else if (strcmp(argv[0], "priv") == 0) cmd_priv(argc, argv);
|
||||
else if (strcmp(argv[0], "cfg") == 0) cmd_cfg(argc, argv);
|
||||
else if (strcmp(argv[0], "otp") == 0) cmd_otp(argc, argv);
|
||||
else if (strcmp(argv[0], "verify") == 0) cmd_verify(argc, argv);
|
||||
else if (strcmp(argv[0], "cfgwrite") == 0) cmd_cfgwrite(argc, argv);
|
||||
else if (strcmp(argv[0], "otpwrite") == 0) cmd_otpwrite(argc, argv);
|
||||
else if (strcmp(argv[0], "cfglock") == 0) cmd_cfglock(argc, argv);
|
||||
else if (strcmp(argv[0], "otplock") == 0) cmd_otplock(argc, argv);
|
||||
else if (strcmp(argv[0], "gen") == 0) cmd_gen(argc, argv);
|
||||
else if (strcmp(argv[0], "getpub") == 0) cmd_getpub(argc, argv);
|
||||
else if (strcmp(argv[0], "ecdh") == 0) cmd_ecdh(argc, argv);
|
||||
else printf("Unknown command %s, try 'help'\n", argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void pubkeyprog_task(void *pvParameters)
|
||||
{
|
||||
char ch;
|
||||
char cmd[81];
|
||||
int i = 0;
|
||||
|
||||
init_cryptoauthlib(0x60);
|
||||
|
||||
printf("\n\n\nWelcome to atcatool. Type 'help<enter>' for, well, help\n");
|
||||
printf("%% ");
|
||||
while(1) {
|
||||
if (read(0, (void*)&ch, 1)) { // 0 is stdin
|
||||
printf("%c", ch);
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
cmd[i] = 0;
|
||||
i = 0;
|
||||
printf("\n");
|
||||
handle_command((char*) cmd);
|
||||
printf("%% ");
|
||||
} else {
|
||||
if (i < sizeof(cmd)) cmd[i++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define I2C_BUS (0)
|
||||
#define SDA_PIN (4)
|
||||
#define SCL_PIN (5)
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_500K);
|
||||
xTaskCreate(&pubkeyprog_task, "pubkeyprog_task", 2048, NULL, 2, NULL);
|
||||
}
|
24
examples/atcatool/uart_cmds.h
Normal file
24
examples/atcatool/uart_cmds.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
#include <cryptoauthlib.h>
|
||||
|
||||
#define MAX_ARGC (10)
|
||||
#define LOG(...) printf(__VA_ARGS__); printf("\r\n");
|
||||
#define LOG_SUCCESSFAIL(name, oper) if((oper) == ATCA_SUCCESS) { LOG("%s succeeded!\n", name); } else { LOG("%s failed!", name); }
|
||||
|
||||
#define BEGIN_PUB_KEY_CONST "-----BEGIN PUBLIC KEY-----"
|
||||
#define END_PUB_KEY_CONST "-----END PUBLIC KEY-----"
|
||||
|
||||
#define BEGIN_PRIV_KEY_CONST "-----BEGIN EC PRIVATE KEY-----"
|
||||
#define END_PRIV_KEY_CONST "-----END EC PRIVATE KEY-----"
|
||||
|
||||
ATCA_STATUS cmd_pub(uint32_t argc, char *argv[]);
|
||||
ATCA_STATUS cmd_priv(uint32_t argc, char *argv[]);
|
||||
ATCA_STATUS cmd_verify(uint32_t argc, char *argv[]);
|
||||
ATCA_STATUS cmd_ecdh(uint32_t argc, char *argv[]);
|
||||
|
||||
// Utility
|
||||
ATCA_STATUS read_pubkey_stdin(uint8_t *keyOut, int *len);
|
||||
ATCA_STATUS read_privkey_stdin(uint8_t *keyOut, int *len);
|
||||
bool prompt_user();
|
||||
bool parse_asn1_signature(uint8_t *asn1Sig, size_t asn1SigLen, uint8_t signatureRintSintOUT[ATCA_SIG_SIZE]);
|
||||
void print_b64_pubkey(uint8_t pubkey[ATCA_PUB_KEY_SIZE]);
|
6
extras/cryptoauthlib/README.md
Normal file
6
extras/cryptoauthlib/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# cryptoauthlib
|
||||
|
||||
Note: The file atca_iface.h is copied from cryptoauthlib/lib/atca_iface.h. The difference is, the anonymous struct names have been commented out, since they are not valid in c++ (only c11). Otherwise this file is exactly the same. Its presence here overrides the
|
||||
one in cryptoauthlib. See <https://github.com/MicrochipTech/cryptoauthlib/issues/43>.
|
||||
|
||||
Also see <https://github.com/Petezah/CryptoAuthLib-Tools> for some tools which aid in generating config data for the ECC module.
|
173
extras/cryptoauthlib/atca_iface.h
Normal file
173
extras/cryptoauthlib/atca_iface.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Microchip Crypto Auth hardware interface object
|
||||
*
|
||||
* \copyright (c) 2015-2018 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
|
||||
|
||||
/** \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 "atca_command.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ATCA_I2C_IFACE,
|
||||
ATCA_SWI_IFACE,
|
||||
ATCA_UART_IFACE,
|
||||
ATCA_SPI_IFACE,
|
||||
ATCA_HID_IFACE,
|
||||
ATCA_CUSTOM_IFACE,
|
||||
// additional physical interface types here
|
||||
ATCA_UNKNOWN_IFACE,
|
||||
} ATCAIfaceType;
|
||||
|
||||
/* ATCAIfaceCfg is a mediator object between a completely abstract notion of a
|
||||
physical interface and an actual physical interface.
|
||||
|
||||
The main purpose of it is to keep hardware specifics from bleeding into the
|
||||
higher levels - hardware specifics could include things like framework
|
||||
specific items (ASF SERCOM) vs a non-Microchip I2C library constant that
|
||||
defines an I2C port. But I2C has roughly the same parameters regardless of
|
||||
architecture and framework.
|
||||
*/
|
||||
|
||||
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 //ATCAI2C
|
||||
{
|
||||
uint8_t slave_address; // 8-bit slave address
|
||||
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 //ATCASWI
|
||||
{
|
||||
uint8_t bus; // logical SWI bus - HAL will map this to a pin or uart port
|
||||
} atcaswi;
|
||||
|
||||
struct //ATCAUART
|
||||
{
|
||||
int port; // logic port number
|
||||
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 //ATCAHID
|
||||
{
|
||||
int idx; // HID enumeration index
|
||||
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
|
||||
uint8_t guid[16]; // The GUID for this HID device
|
||||
} atcahid;
|
||||
|
||||
struct //ATCACUSTOM
|
||||
{
|
||||
ATCA_STATUS (*halinit)(void *hal, void *cfg);
|
||||
ATCA_STATUS (*halpostinit)(void *iface);
|
||||
ATCA_STATUS (*halsend)(void *iface, uint8_t *txdata, int txlength);
|
||||
ATCA_STATUS (*halreceive)(void *iface, 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 atca_iface is the C object backing ATCAIface. See the atca_iface.h file for
|
||||
* details on the ATCAIface methods
|
||||
*/
|
||||
|
||||
struct atca_iface
|
||||
{
|
||||
ATCAIfaceType mType;
|
||||
ATCAIfaceCfg *mIfaceCFG; // points to previous defined/given Cfg object, caller manages this
|
||||
|
||||
ATCA_STATUS (*atinit)(void *hal, ATCAIfaceCfg *);
|
||||
ATCA_STATUS (*atpostinit)(ATCAIface hal);
|
||||
ATCA_STATUS (*atsend)(ATCAIface hal, uint8_t *txdata, int txlength);
|
||||
ATCA_STATUS (*atreceive)(ATCAIface hal, uint8_t *rxdata, uint16_t *rxlength);
|
||||
ATCA_STATUS (*atwake)(ATCAIface hal);
|
||||
ATCA_STATUS (*atidle)(ATCAIface hal);
|
||||
ATCA_STATUS (*atsleep)(ATCAIface hal);
|
||||
|
||||
// treat as private
|
||||
void *hal_data; // generic pointer used by HAL to point to architecture specific structure
|
||||
// no ATCA object should touch this except HAL, HAL manages this pointer and memory it points to
|
||||
};
|
||||
|
||||
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 atpostinit(ATCAIface ca_iface);
|
||||
ATCA_STATUS atsend(ATCAIface ca_iface, uint8_t *txdata, int txlength);
|
||||
ATCA_STATUS atreceive(ATCAIface ca_iface, uint8_t *rxdata, uint16_t *rxlength);
|
||||
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);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/** @} */
|
||||
#endif
|
||||
|
||||
|
||||
|
41
extras/cryptoauthlib/component.mk
Normal file
41
extras/cryptoauthlib/component.mk
Normal file
|
@ -0,0 +1,41 @@
|
|||
#
|
||||
# esp_open_rtos build system component Makefile
|
||||
#
|
||||
|
||||
CRYPTOAUTHLIB_MODULE_DIR = $(cryptoauthlib_ROOT)cryptoauthlib/
|
||||
CRYPTOAUTHLIB_DIR = $(CRYPTOAUTHLIB_MODULE_DIR)lib/
|
||||
INC_DIRS += $(cryptoauthlib_ROOT) $(CRYPTOAUTHLIB_DIR) $(CRYPTOAUTHLIB_DIR)basic $(CRYPTOAUTHLIB_DIR)hal
|
||||
|
||||
# args for passing into compile rule generation
|
||||
cryptoauthlib_INC_DIR = $(CRYPTOAUTHLIB_DIR) $(CRYPTOAUTHLIB_DIR)basic
|
||||
cryptoauthlib_SRC_DIR = \
|
||||
$(cryptoauthlib_ROOT) \
|
||||
$(CRYPTOAUTHLIB_DIR) \
|
||||
$(CRYPTOAUTHLIB_DIR)basic \
|
||||
$(CRYPTOAUTHLIB_DIR)crypto \
|
||||
$(CRYPTOAUTHLIB_DIR)crypto/hashes \
|
||||
$(CRYPTOAUTHLIB_DIR)host
|
||||
|
||||
cryptoauthlib_EXTRA_SRC_FILES = $(CRYPTOAUTHLIB_DIR)hal/atca_hal.c $(cryptoauthlib_ROOT)/hal/atca_hal_espfreertos_i2c.c
|
||||
|
||||
# default define variable values
|
||||
CRYPTOAUTHLIB_ROOT_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||
include $(CRYPTOAUTHLIB_ROOT_DIR)defaults.mk
|
||||
|
||||
ATEC_DEBUG_FLAGS = \
|
||||
-DATEC_HAL_DEBUG=$(ATEC_HAL_DEBUG) \
|
||||
-DATEC_HAL_VERBOSE_DEBUG=$(ATEC_HAL_VERBOSE_DEBUG) \
|
||||
-DATEC_I2C_HAL_DEBUG=$(ATEC_I2C_HAL_DEBUG)
|
||||
|
||||
cryptoauthlib_CFLAGS += -DATCA_HAL_I2C -std=gnu11 $(ATEC_DEBUG_FLAGS)
|
||||
|
||||
ifeq ($(ATEC_PRINTF_ENABLE), 1)
|
||||
cryptoauthlib_CFLAGS += -DATCAPRINTF
|
||||
cryptoauthlib_CXXFLAGS += -DATCAPRINTF
|
||||
endif
|
||||
|
||||
$(eval $(call component_compile_rules,cryptoauthlib))
|
||||
|
||||
# Helpful error if git submodule not initialised
|
||||
$(CRYPTOAUTHLIB_MODULE_DIR):
|
||||
$(error "cryptoauthlib git submodule not installed. Please run 'git submodule update --init'")
|
1
extras/cryptoauthlib/cryptoauthlib
Submodule
1
extras/cryptoauthlib/cryptoauthlib
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit f86b9dbb1e805d85a435456ca03450342dbdc43e
|
83
extras/cryptoauthlib/cryptoauthlib_init.c
Normal file
83
extras/cryptoauthlib/cryptoauthlib_init.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
#include "cryptoauthlib.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define ATEC_DEBUG
|
||||
#ifdef ATEC_DEBUG
|
||||
#define DBG(...) printf("%s:%d ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\r\n");
|
||||
#define DBGX(...) printf(__VA_ARGS__);
|
||||
#else
|
||||
#define DBGV(...) {};
|
||||
#define DBGVX(...) {};
|
||||
#endif
|
||||
|
||||
void init_cryptoauthlib(uint8_t i2c_addr)
|
||||
{
|
||||
uint32_t revision;
|
||||
uint32_t serial[(ATCA_SERIAL_NUM_SIZE + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
|
||||
bool config_is_locked, data_is_locked;
|
||||
ATCA_STATUS status;
|
||||
const ATCAIfaceCfg *atca_cfg;
|
||||
|
||||
/*
|
||||
* Allow for addresses either in 7-bit format (0-7F) or in Atmel 8-bit shifted-by-one format.
|
||||
* If user specifies address > 0x80, it must be already shifted since I2C bus addresses > 0x7f are invalid.
|
||||
*/
|
||||
if (i2c_addr < 0x7f) i2c_addr <<= 1;
|
||||
atca_cfg = &cfg_ateccx08a_i2c_default;
|
||||
if (atca_cfg->atcai2c.slave_address != i2c_addr)
|
||||
{
|
||||
ATCAIfaceCfg *cfg = (ATCAIfaceCfg *) calloc(1, sizeof(*cfg));
|
||||
memcpy(cfg, &cfg_ateccx08a_i2c_default, sizeof(*cfg));
|
||||
cfg->atcai2c.slave_address = i2c_addr;
|
||||
atca_cfg = cfg;
|
||||
}
|
||||
|
||||
status = atcab_init(atca_cfg);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
DBG("ATCA: Library init failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = atcab_info((uint8_t *) &revision);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
DBG("ATCA: Failed to get chip info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = atcab_read_serial_number((uint8_t *) serial);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
DBG("ATCA: Failed to get chip serial number");
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = atcab_is_locked(LOCK_ZONE_CONFIG, &config_is_locked);
|
||||
status = atcab_is_locked(LOCK_ZONE_DATA, &data_is_locked);
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
DBG("ATCA: Failed to get chip zone lock status");
|
||||
goto out;
|
||||
}
|
||||
|
||||
DBG("ATECC508 @ 0x%02x: rev 0x%04x S/N 0x%04x%04x%02x, zone "
|
||||
"lock status: %s, %s",
|
||||
i2c_addr >> 1, htonl(revision), htonl(serial[0]), htonl(serial[1]),
|
||||
*((uint8_t *) &serial[2]), (config_is_locked ? "yes" : "no"),
|
||||
(data_is_locked ? "yes" : "no"));
|
||||
|
||||
out:
|
||||
/*
|
||||
* We do not free atca_cfg in case of an error even if it was allocated
|
||||
* because it is referenced by ATCA basic object.
|
||||
*/
|
||||
if (status != ATCA_SUCCESS)
|
||||
{
|
||||
DBG("ATCA: Chip is not available");
|
||||
/* In most cases the device can still work, so we continue anyway. */
|
||||
}
|
||||
}
|
15
extras/cryptoauthlib/cryptoauthlib_init.h
Normal file
15
extras/cryptoauthlib/cryptoauthlib_init.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
#ifndef CRYPTOAUTHLIB_INIT_H
|
||||
#define CRYPTOAUTHLIB_INIT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void init_cryptoauthlib(uint8_t i2c_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} //extern "C" {
|
||||
#endif
|
||||
|
||||
#endif //CRYPTOAUTHLIB_INIT_H
|
15
extras/cryptoauthlib/defaults.mk
Normal file
15
extras/cryptoauthlib/defaults.mk
Normal file
|
@ -0,0 +1,15 @@
|
|||
#########################################
|
||||
# Default define variables
|
||||
#########################################
|
||||
|
||||
# Enable/disable debug output from HAL
|
||||
ATEC_HAL_DEBUG ?= 0
|
||||
|
||||
# Enable/disable verbose debug output from HAL
|
||||
ATEC_HAL_VERBOSE_DEBUG ?= 0
|
||||
|
||||
# Enable/disable i2c debug output from HAL
|
||||
ATEC_I2C_HAL_DEBUG ?= 0
|
||||
|
||||
# Enable/disable printf from library
|
||||
ATEC_PRINTF_ENABLE ?= 0
|
372
extras/cryptoauthlib/hal/atca_hal_espfreertos_i2c.c
Normal file
372
extras/cryptoauthlib/hal/atca_hal_espfreertos_i2c.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
#include <inttypes.h>
|
||||
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
||||
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
#include "cryptoauthlib.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
// Move to config if ever necessary
|
||||
#define I2C_BUS (0)
|
||||
|
||||
#define vTaskDelayMs(ms) vTaskDelay((ms)/portTICK_PERIOD_MS)
|
||||
|
||||
#if ATEC_HAL_DEBUG || ATEC_HAL_VERBOSE_DEBUG
|
||||
#define DBG(...) printf("%s:%d ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\r\n");
|
||||
#define DBGX(...) printf(__VA_ARGS__);
|
||||
#if ATEC_HAL_VERBOSE_DEBUG
|
||||
#define DEBUG_HAL
|
||||
#define DBGV(...) printf("%s:%d ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\r\n");
|
||||
#define DBGVX(...) printf(__VA_ARGS__);
|
||||
#else
|
||||
#define DBGV(...) {};
|
||||
#define DBGVX(...) {};
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_HAL
|
||||
static void print_array(uint8_t *data, uint32_t data_size)
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
for (n = 0; n < data_size; n++)
|
||||
{
|
||||
printf("%.2x ", data[n]);
|
||||
if (((n + 1) % 16) == 0)
|
||||
{
|
||||
printf("\r\n");
|
||||
if ((n + 1) != data_size)
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
if (data_size % 16 != 0)
|
||||
printf("\r\n");
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define DBG(...) {};
|
||||
#define DBGX(...) {};
|
||||
#define DBGV(...) {};
|
||||
#define DBGVX(...) {};
|
||||
#endif
|
||||
|
||||
#if ATEC_I2C_HAL_DEBUG
|
||||
#define I2C_DBG(...) printf(__VA_ARGS__); printf("\r\n");
|
||||
#else
|
||||
#define I2C_DBG(...) {};
|
||||
#endif
|
||||
|
||||
ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg)
|
||||
{
|
||||
(void)hal;
|
||||
(void)cfg;
|
||||
return ATCA_SUCCESS;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
|
||||
{
|
||||
(void)iface;
|
||||
return ATCA_SUCCESS;
|
||||
}
|
||||
|
||||
static bool hal_internal_i2c_write(ATCAIface iface, uint8_t *txdata, int len)
|
||||
{
|
||||
const ATCAIfaceCfg *cfg = atgetifacecfg(iface);
|
||||
uint8_t slave_addr = (cfg->atcai2c.slave_address >> 1);
|
||||
|
||||
int result = i2c_slave_write(I2C_BUS, slave_addr, NULL, txdata, len);
|
||||
if (result != 0)
|
||||
{
|
||||
I2C_DBG("I2C write Error: %d len data: %d first byte: %x", result, len, len > 0 ? txdata[0] : 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hal_internal_i2c_read(ATCAIface iface, uint8_t *rxdata, int len)
|
||||
{
|
||||
const ATCAIfaceCfg *cfg = atgetifacecfg(iface);
|
||||
uint8_t slave_addr = (cfg->atcai2c.slave_address >> 1);
|
||||
|
||||
int result = i2c_slave_read(I2C_BUS, slave_addr, NULL, rxdata, len);
|
||||
if (result != 0)
|
||||
{
|
||||
I2C_DBG("I2C read Error: %d len data: %d", result, len);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
|
||||
{
|
||||
ATCA_STATUS status = ATCA_TX_TIMEOUT;
|
||||
#ifdef DEBUG_HAL
|
||||
// shamelessly taken from hal_sam4s_i2c_asf.c
|
||||
printf("hal_i2c_send()\r\n");
|
||||
|
||||
printf("\r\nCommand Packet (size:0x%.8x)\r\n", (uint32_t)txlength);
|
||||
printf("Count : %.2x\r\n", txdata[1]);
|
||||
printf("Opcode : %.2x\r\n", txdata[2]);
|
||||
printf("Param1 : %.2x\r\n", txdata[3]);
|
||||
printf("Param2 : "); print_array(&txdata[4], 2);
|
||||
if (txdata[1] > 7) {
|
||||
printf("Data : "); print_array(&txdata[6], txdata[1] - 7);
|
||||
}
|
||||
printf("CRC : "); print_array(&txdata[txdata[1] - 1], 2);
|
||||
printf("\r\n");
|
||||
#endif
|
||||
|
||||
DBG("Send len %d, sending command", txlength);
|
||||
txdata[0] = 0x03; /* Word Address Value = Command */
|
||||
txlength++; /* Include Word Address value in txlength */
|
||||
|
||||
if (hal_internal_i2c_write(iface, txdata, txlength))
|
||||
{
|
||||
DBGV("ATCA_SUCCESS");
|
||||
status = ATCA_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBGV("ATCA_TX_FAIL");
|
||||
status = ATCA_TX_FAIL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
|
||||
{
|
||||
DBGV("hal_i2c_receive()");
|
||||
const ATCAIfaceCfg *cfg = atgetifacecfg(iface);
|
||||
|
||||
ATCA_STATUS status = ATCA_RX_TIMEOUT;
|
||||
|
||||
int retries = cfg->rx_retries;
|
||||
|
||||
while (retries-- > 0)
|
||||
{
|
||||
if (!hal_internal_i2c_read(iface, rxdata, *rxlength))
|
||||
{
|
||||
DBGV("ATCA_RX_FAIL--retry %d", retries);
|
||||
continue;
|
||||
}
|
||||
DBGV("ATCA_SUCCESS");
|
||||
status = ATCA_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HAL
|
||||
printf("\r\nResponse Packet (size:0x%.4x)\r\n", rxlength);
|
||||
printf("Count : %.2x\r\n", rxdata[0]);
|
||||
if (rxdata[0] > 3) {
|
||||
printf("Data : "); print_array(&rxdata[1], rxdata[0] - 3);
|
||||
printf("CRC : "); print_array(&rxdata[rxdata[0] - 2], 2);
|
||||
}
|
||||
printf("\r\n");
|
||||
#endif
|
||||
/*
|
||||
* rxlength is a pointer, which suggests that the actual number of bytes
|
||||
* received should be returned in the value pointed to, but none of the
|
||||
* existing HAL implementations do it.
|
||||
*/
|
||||
return status;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_wake(ATCAIface iface)
|
||||
{
|
||||
const ATCAIfaceCfg *cfg = atgetifacecfg(iface);
|
||||
|
||||
ATCA_STATUS status = ATCA_WAKE_FAILED;
|
||||
|
||||
uint8_t response[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t expected_response[4] = { 0x04, 0x11, 0x33, 0x43 };
|
||||
|
||||
/*
|
||||
* ATCA devices define "wake up" token as START, 80 us of SDA low, STOP.
|
||||
*/
|
||||
DBGV("Sending wake");
|
||||
i2c_start(I2C_BUS);
|
||||
atca_delay_us(80);
|
||||
i2c_stop(I2C_BUS);
|
||||
|
||||
/* After wake signal we need to wait some time for device to init. */
|
||||
atca_delay_us(cfg->wake_delay);
|
||||
|
||||
/* Receive the wake response. */
|
||||
uint16_t len = sizeof(response);
|
||||
status = hal_i2c_receive(iface, response, &len);
|
||||
if (status == ATCA_SUCCESS) {
|
||||
DBGV("Response %x %x %x %x", response[0], response[1], response[2], response[3]);
|
||||
if (memcmp(response, expected_response, 4) != 0) {
|
||||
DBGV("Wake failed");
|
||||
status = ATCA_WAKE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_idle(ATCAIface iface)
|
||||
{
|
||||
uint8_t idle_cmd = 0x02;
|
||||
DBG("Sending idle");
|
||||
return hal_internal_i2c_write(iface, &idle_cmd, 1) ? ATCA_SUCCESS : ATCA_TX_FAIL;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
|
||||
{
|
||||
uint8_t sleep_cmd = 0x01;
|
||||
DBG("Sending sleep");
|
||||
return hal_internal_i2c_write(iface, &sleep_cmd, 1) ? ATCA_SUCCESS : ATCA_TX_FAIL;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_release(void *hal_data)
|
||||
{
|
||||
(void)hal_data;
|
||||
return ATCA_SUCCESS;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses)
|
||||
{
|
||||
i2c_buses[0] = 0; // There is just one bus on our esp8266 i2c implementation
|
||||
return ATCA_SUCCESS;
|
||||
}
|
||||
|
||||
ATCA_STATUS hal_i2c_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found)
|
||||
{
|
||||
ATCAIfaceCfg *head = cfg;
|
||||
uint8_t slaveAddress = 0x01;
|
||||
ATCADevice device;
|
||||
ATCAIface discoverIface;
|
||||
ATCACommand command;
|
||||
ATCAPacket packet;
|
||||
uint16_t rxsize;
|
||||
uint32_t execution_or_wait_time;
|
||||
ATCA_STATUS status;
|
||||
uint8_t revs508[1][4] = { { 0x00, 0x00, 0x50, 0x00 } };
|
||||
uint8_t revs108[1][4] = { { 0x80, 0x00, 0x10, 0x01 } };
|
||||
uint8_t revs204[2][4] = { { 0x00, 0x02, 0x00, 0x08 },
|
||||
{ 0x00, 0x04, 0x05, 0x00 } };
|
||||
int i;
|
||||
|
||||
/** \brief default configuration, to be reused during discovery process */
|
||||
ATCAIfaceCfg discoverCfg;
|
||||
discoverCfg.iface_type = ATCA_I2C_IFACE;
|
||||
discoverCfg.devtype = ATECC508A;
|
||||
discoverCfg.atcai2c.slave_address = 0x07;
|
||||
discoverCfg.atcai2c.bus = busNum;
|
||||
discoverCfg.atcai2c.baud = 400000;
|
||||
//discoverCfg.atcai2c.baud = 100000;
|
||||
discoverCfg.wake_delay = 800;
|
||||
discoverCfg.rx_retries = 3;
|
||||
|
||||
ATCAHAL_t hal;
|
||||
|
||||
hal_i2c_init( &hal, &discoverCfg );
|
||||
device = newATCADevice( &discoverCfg );
|
||||
discoverIface = atGetIFace( device );
|
||||
command = atGetCommands( device );
|
||||
|
||||
// iterate through all addresses on given i2c bus
|
||||
// all valid 7-bit addresses go from 0x07 to 0x78
|
||||
for ( slaveAddress = 0x07; slaveAddress <= 0x78; slaveAddress++ ) {
|
||||
discoverCfg.atcai2c.slave_address = slaveAddress << 1; // turn it into an 8-bit address which is what the rest of the i2c HAL is expecting when a packet is sent
|
||||
|
||||
// wake up device
|
||||
// If it wakes, send it a dev rev command. Based on that response, determine the device type
|
||||
// BTW - this will wake every cryptoauth device living on the same bus (ecc508a, sha204a)
|
||||
|
||||
if ( hal_i2c_wake( discoverIface ) == ATCA_SUCCESS ) {
|
||||
(*found)++;
|
||||
memcpy( (uint8_t*)head, (uint8_t*)&discoverCfg, sizeof(ATCAIfaceCfg));
|
||||
|
||||
memset( packet.data, 0x00, sizeof(packet.data));
|
||||
|
||||
// get devrev info and set device type accordingly
|
||||
atInfo( command, &packet );
|
||||
#ifdef ATCA_NO_POLL
|
||||
if ((status = atGetExecTime(packet->opcode, device->mCommands)) != ATCA_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
execution_or_wait_time = device->mCommands->execution_time_msec;
|
||||
#else
|
||||
execution_or_wait_time = 1;//ATCA_POLLING_INIT_TIME_MSEC;
|
||||
#endif
|
||||
|
||||
// send the command
|
||||
if ( (status = atsend( discoverIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) {
|
||||
printf("packet send error\r\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// delay the appropriate amount of time for command to execute
|
||||
atca_delay_ms(execution_or_wait_time);
|
||||
|
||||
// receive the response
|
||||
if ( (status = atreceive( discoverIface, &(packet.data[0]), &rxsize )) != ATCA_SUCCESS )
|
||||
continue;
|
||||
|
||||
if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) {
|
||||
printf("command response error\r\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine device type from common info and dev rev response byte strings
|
||||
for ( i = 0; i < (int)sizeof(revs508) / 4; i++ ) {
|
||||
if ( memcmp( &packet.data[1], &revs508[i], 4) == 0 ) {
|
||||
discoverCfg.devtype = ATECC508A;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < (int)sizeof(revs204) / 4; i++ ) {
|
||||
if ( memcmp( &packet.data[1], &revs204[i], 4) == 0 ) {
|
||||
discoverCfg.devtype = ATSHA204A;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < (int)sizeof(revs108) / 4; i++ ) {
|
||||
if ( memcmp( &packet.data[1], &revs108[i], 4) == 0 ) {
|
||||
discoverCfg.devtype = ATECC108A;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
atca_delay_ms(15);
|
||||
// now the device type is known, so update the caller's cfg array element with it
|
||||
head->devtype = discoverCfg.devtype;
|
||||
head++;
|
||||
}
|
||||
|
||||
hal_i2c_idle(discoverIface);
|
||||
}
|
||||
|
||||
hal_i2c_release(&hal);
|
||||
|
||||
return ATCA_SUCCESS;
|
||||
}
|
||||
|
||||
void atca_delay_us(uint32_t us)
|
||||
{
|
||||
DBG("atca_delay_us: %d", us);
|
||||
|
||||
/*
|
||||
* configTICK_RATE_HZ is 100, implying 10 ms ticks.
|
||||
* But we run CPU at 160 and tick timer is not updated, hence / 2 below.
|
||||
* https://github.com/espressif/ESP8266_RTOS_SDK/issues/90
|
||||
*/
|
||||
#define USECS_PER_TICK (1000000 / configTICK_RATE_HZ / 2)
|
||||
uint32_t ticks = us / USECS_PER_TICK;
|
||||
us = us % USECS_PER_TICK;
|
||||
if (ticks > 0) vTaskDelay(ticks);
|
||||
sdk_os_delay_us(us);
|
||||
}
|
||||
|
||||
void atca_delay_ms(uint32_t ms)
|
||||
{
|
||||
atca_delay_us(ms * 1000);
|
||||
}
|
Loading…
Reference in a new issue