Search code examples
c++encryptionmicrochip

Cryptoauthlib - An anonymous union can only have non-static data members - segmentation fault


I am trying to compile a c++ program with the cryptoauthlib and I get this (An anonymous union can only have non-static data members) error in the atca_iface.h. I think this is a c11 feature, which is not compatible with c++:

All named structs in the unnamed union throw the error. I removed the names of the structs in the following:

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;

I changed these structs to unnamed structs and it compiles, but I unfortunately get a segmentation fault when calling the init function ATCA_STATUS atinit(ATCAIface ca_iface);... I do not call this function directly. I call atcab_init(&cfg_ateccx08a_i2c_default);

Is there a way to use this without modifying the interface like I did and why do I get the Segmentation fault?

My hardwaresetup is a CM3 with a ATECC608a connected to I2C 1. The interface is up and I can query it. Do I need to modify the default interface to the correct device type and the correct I2C interface? When I do so I get the same segmentation fault.

EDIT:

Example code

#include <iostream>
#include "cryptoauthlib.h"


int main(int argc, char *argv[])
{

    uint8_t random_number;
    atcab_init(&cfg_ateccx08a_i2c_default);
    ATCA_STATUS status = atcab_random(&random_number);

    std::cout << "status: " << (int)status << std::endl;

    return 0;
}

EDIT2:

Someone on github told me that I have to use -DATCA_HAL_I2C as C compiler flag. But I now get undefined reference to hal_i2c_init errors

EDIT3:

The problem seems to be with the cmake configuration of the cryptoauthlib, because I am crosscompiling on windows for armhf.

Looking into the cmake configurations

EDIT4:

To reproduce the latest errors:

get cryptoauthlib from here get VisualGDB from here Install VS 2017 Install VisualGDB Make a new Project with VisualGDB -> CMAKE Project Download the latest toolchain from here Use it from within VisualGDB Add cryptoauthlib as a reference to the project Add the following CMAKE commands after project() in the CMakeLists.txt of the project:

unset(WIN32)
unset(APPLE)
set(UNIX)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fms-extensions -std=c11 -DATCA_HAL_I2C=on -DATCAPRINTF=on")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -DATCA_HAL_I2C=on -DATCAPRINTF=on")

build.

EDIT5:

Found that I had to do set(ATCA_HAL_I2C TRUE) explicitly in my CMAKE project ... as an option it did not work for me, unfortunately.

Now I get a segmentation fault again here:

ATCA_STATUS atcab_random(uint8_t *rand_out)
{
    ...
    ATCACommand ca_cmd = _gDevice->mCommands;

    ...
}

I opened this as an issue on github.


Solution

  • I found the error. The Hardware Abstraction Layer could not connect because the default setting of the bus for the i2c bus .atcai2c.bus was set to 2 and it needs to be 1 otherwise it won't find the i2c device.

    ATCAIfaceCfg cfg_ateccx08a_i2c_default = {
        .iface_type             = ATCA_I2C_IFACE,
        .devtype                = ATECC608A,
        .atcai2c.slave_address  = 0xC0,
        .atcai2c.bus            = 1,
        .atcai2c.baud           = 400000,
        //.atcai2c.baud = 100000,
        .wake_delay             = 1500,
        .rx_retries             = 20
    };
    

    I can now get the revision, the serial and random numbers from the chip with the following:

    #include <iostream>
    #include "cryptoauthlib.h"
    
    
    int main(int argc, char *argv[])
    {
    
        ATCAIfaceCfg *atca_cfg;
        atca_cfg = &cfg_ateccx08a_i2c_default;
    
        ATCA_STATUS status = atcab_init(atca_cfg);
    
        std::cout << "status: " << (int)status << std::endl;
    
        uint8_t revision[4];
        status = atcab_info(revision);
        if (status != ATCA_SUCCESS)
        {
            return -1;
        }
        std::cout << "revision: " << (int)revision << std::endl;
    
        uint8_t serial[ATCA_SERIAL_NUM_SIZE];
        status = atcab_read_serial_number(serial);
        if (status != ATCA_SUCCESS)
        {
            return - 1;
        }
        std::cout << "serial: " << (int)serial << std::endl;
    
        uint8_t num[32];
        status = atcab_random(num);
        if (status != ATCA_SUCCESS)
        {
            return - 1;
        }
        std::cout << "random: " << (int)num << std::endl;
        return 0;
    }
    

    I will continue this on github.