Hazelnet 3.0.0
Reference implementation of the CAN Bus Security (CBS) protocol
|
Hazelnet Client public API. More...
#include "hzl.h"
Go to the source code of this file.
Data Structures | |
struct | hzl_ClientConfig |
Hazelnet Client constant configuration. More... | |
struct | hzl_ClientGroupConfig |
Hazelnet Client constant Group configuration. More... | |
struct | hzl_ClientGroupState |
Hazelnet Client variable State. More... | |
struct | hzl_ClientCtx |
Configuration and status of the HazelNet Client library. More... | |
Typedefs | |
typedef struct hzl_ClientConfig | hzl_ClientConfig_t |
Hazelnet Client constant configuration. More... | |
typedef struct hzl_ClientGroupConfig | hzl_ClientGroupConfig_t |
Hazelnet Client constant Group configuration. More... | |
typedef struct hzl_ClientGroupState | hzl_ClientGroupState_t |
Hazelnet Client variable State. More... | |
typedef struct hzl_ClientCtx | hzl_ClientCtx_t |
Configuration and status of the HazelNet Client library. More... | |
Functions | |
_Static_assert (sizeof(hzl_ClientConfig_t)==22, "The size of the Client Config struct must be exactly 22 B") | |
Double-checking the size of the hzl_ClientConfig_t struct to avoid unexpected paddings. More... | |
_Static_assert (sizeof(hzl_ClientGroupConfig_t)==12, "The size of the Client Group Config struct must be exactly 12 B") | |
Double-checking the size of the hzl_ClientGroupConfig_t struct to avoid unexpected paddings. More... | |
_Static_assert (sizeof(hzl_ClientGroupState_t)==64, "The size of the Client Group state struct must be exactly 64 B") | |
Double-checking the size of the hzl_ClientGroupState_t struct to avoid unexpected paddings. More... | |
HZL_API hzl_Err_t | hzl_ClientInit (hzl_ClientCtx_t *ctx) |
Initialisation of the Client. More... | |
HZL_API hzl_Err_t | hzl_ClientDeInit (hzl_ClientCtx_t *ctx) |
Deinitialisation of the Client, securely clearing the state. More... | |
HZL_API hzl_Err_t | hzl_ClientBuildRequest (hzl_CbsPduMsg_t *requestPdu, hzl_ClientCtx_t *ctx, hzl_Gid_t groupId) |
Builds a Request message, asking for the Session information for a specific group, even if the Session is already established, unless a handshake is already ongoing. More... | |
HZL_API hzl_Err_t | hzl_ClientBuildUnsecured (hzl_CbsPduMsg_t *unsecuredPdu, const hzl_ClientCtx_t *ctx, const uint8_t *userData, size_t userDataLen, hzl_Gid_t groupId) |
Builds an unsecured message in plaintext. More... | |
HZL_API hzl_Err_t | hzl_ClientBuildSecuredFd (hzl_CbsPduMsg_t *securedPdu, hzl_ClientCtx_t *ctx, const uint8_t *userData, size_t userDataLen, hzl_Gid_t groupId) |
Builds a secured message, encrypted, authenticated and timely, only for the given group to be able to read. More... | |
HZL_API hzl_Err_t | hzl_ClientProcessReceived (hzl_CbsPduMsg_t *reactionPdu, hzl_RxSduMsg_t *receivedUserData, hzl_ClientCtx_t *ctx, const uint8_t *receivedPdu, size_t receivedPduLen, hzl_CanId_t receivedCanId) |
Validates, unpacks and decrypts (if necessary) any received message, preparing an automatic response when required. More... | |
Hazelnet Client public API.
Hazelnet implements the CAN Bus Security (CBS) protocol, which secures the CAN FD traffic providing encryption, authenticity and freshness of the messages.
The user of the library must handle the physical transmission and reception manually as this library only handles the building of messages to transmit and processing of received messages. The internal library state keeps track of ongoing handshakes, timeouts and other events per each Group.
The intended usage of the library is listed in an example snippet in the readme.
typedef struct hzl_ClientConfig hzl_ClientConfig_t |
Hazelnet Client constant configuration.
Single instance per Client. Initialised by the user, not modified by the Client. Initialised by the user, not modified by the Client.
typedef struct hzl_ClientGroupConfig hzl_ClientGroupConfig_t |
Hazelnet Client constant Group configuration.
Unique per Group, multiple instances per Client. Initialised by the user, not modified by the Client.
typedef struct hzl_ClientGroupState hzl_ClientGroupState_t |
Hazelnet Client variable State.
Single instance per Group, multiple instances per Client. Initialised, modified, managed and cleared fully by the Client: the user MUST NOT touch its contents.
typedef struct hzl_ClientCtx hzl_ClientCtx_t |
Configuration and status of the HazelNet Client library.
Initialised by the user on embedded, loaded from file on an OS.
_Static_assert | ( | sizeof(hzl_ClientConfig_t) | = =22 , |
"The size of the Client Config struct must be exactly 22 B" | |||
) |
Double-checking the size of the hzl_ClientConfig_t struct to avoid unexpected paddings.
_Static_assert | ( | sizeof(hzl_ClientGroupConfig_t) | = =12 , |
"The size of the Client Group Config struct must be exactly 12 B" | |||
) |
Double-checking the size of the hzl_ClientGroupConfig_t struct to avoid unexpected paddings.
_Static_assert | ( | sizeof(hzl_ClientGroupState_t) | = =64 , |
"The size of the Client Group state struct must be exactly 64 B" | |||
) |
Double-checking the size of the hzl_ClientGroupState_t struct to avoid unexpected paddings.
HZL_API hzl_Err_t hzl_ClientInit | ( | hzl_ClientCtx_t * | ctx | ) |
Initialisation of the Client.
To be called once before any other function. Checks the configuration thoroughly, initialises the states.
After initialisation, the Client will not have the Session information required to transmit a new Secured message; a Request message must be transmitted first with the hzl_ClientBuildRequest() function after initialisation and a Response must be received.
[in,out] | ctx | prepared with the proper structs and function pointers by the user before calling this function. Further initialisation performed by this function. See hzl_ClientCtx_t for details. |
HZL_API hzl_Err_t hzl_ClientDeInit | ( | hzl_ClientCtx_t * | ctx | ) |
Deinitialisation of the Client, securely clearing the state.
To be called after the Client is not used anymore or before entering a low-power mode.
Other fields of the context are untouched (configuration and IO functions), so the context may be reused for another hzl_ClientInit call after the deinitialisation.
Clearing the state when not in use forces the Client to start new handshakes after waking up upon transmitting a new Secured message. This can also be done manually with the hzl_ClientBuildRequest() function.
[in,out] | ctx | context with state to clear. Not NULL. |
HZL_OK | on success. |
HZL_ERR_NULL_CTX | |
HZL_ERR_NULL_CONFIG_CLIENT | |
HZL_ERR_NULL_STATES_GROUPS |
HZL_API hzl_Err_t hzl_ClientBuildRequest | ( | hzl_CbsPduMsg_t * | requestPdu, |
hzl_ClientCtx_t * | ctx, | ||
hzl_Gid_t | groupId | ||
) |
Builds a Request message, asking for the Session information for a specific group, even if the Session is already established, unless a handshake is already ongoing.
The transmission of a Request is mandatory before hzl_ClientBuildSecuredFd() can be used. This function is useful to perform the handshake in advance even if there is no Secured Application Data to transmit right now, to spare time later one when there is some to transmit.
[out] | requestPdu | REQ message in packed format, ready to transmit. Not NULL. |
[in,out] | ctx | to access configurations and update the group states. Not NULL. |
[in] | groupId | destination group identifier (the Parties that will be able to decrypt). |
HZL_OK | on success. |
HZL_ERR_HANDSHAKE_ONGOING | if a handshake is already ongoing right now. It should be enough to just wait for the current handshake to complete, no need to build a new Request. |
Same | values as hzl_ClientInit() in case the context has NULL pointers. |
HZL_ERR_NULL_PDU | if requestPdu is NULL. |
HZL_ERR_GID_TOO_LARGE_FOR_CONFIGURED_HEADER_TYPE | when groupId would not fit in the packed CBS header. |
HZL_ERR_UNKNOWN_GROUP | when group is not supported in the context's configuration. |
HZL_ERR_CANNOT_GENERATE_RANDOM | |
HZL_ERR_CANNOT_GENERATE_NON_ZERO_RANDOM | |
HZL_ERR_CANNOT_GET_CURRENT_TIME |
HZL_API hzl_Err_t hzl_ClientBuildUnsecured | ( | hzl_CbsPduMsg_t * | unsecuredPdu, |
const hzl_ClientCtx_t * | ctx, | ||
const uint8_t * | userData, | ||
size_t | userDataLen, | ||
hzl_Gid_t | groupId | ||
) |
Builds an unsecured message in plaintext.
This message may be transmitted at any point in time, as long as the context is initialised. This means even before or during a handshake for the given Group.
The message may be built and transmitted **even if the group
does not exist** in the configuration. This is allowed in order to communicate with some devices that don't have a preconfigured Group in common with this one. No error is raised.
[out] | unsecuredPdu | UAD message in packed format, ready to transmit. Not NULL. |
[in] | ctx | just to access configurations and functions. No change in the state. Not NULL. |
[in] | userData | plaintext data (SDU) to pack not-obfuscated, not-authenticated. Can be NULL only if userDataLen is zero. |
[in] | userDataLen | length of userData in bytes. |
[in] | groupId | destination group identifier (expected receivers). It may also be a GID not listed in the context's configuration. |
HZL_OK | on success. |
Same | values as hzl_ClientInit() in case the context has NULL pointers. |
HZL_ERR_NULL_PDU | if unsecuredPdu is NULL. |
HZL_ERR_NULL_SDU | if userData is NULL and userDataLen is > 0. |
HZL_ERR_TOO_LONG_SDU | if userDataLen is too large for the underlying PDU. |
HZL_ERR_GID_TOO_LARGE_FOR_CONFIGURED_HEADER_TYPE | when groupId would not fit in the packed CBS header. |
HZL_API hzl_Err_t hzl_ClientBuildSecuredFd | ( | hzl_CbsPduMsg_t * | securedPdu, |
hzl_ClientCtx_t * | ctx, | ||
const uint8_t * | userData, | ||
size_t | userDataLen, | ||
hzl_Gid_t | groupId | ||
) |
Builds a secured message, encrypted, authenticated and timely, only for the given group to be able to read.
Before using this function, a Request message must be built with hzl_ClientBuildRequest(), transmitted and a Response must be received and processed with hzl_ClientProcessReceived().
[out] | securedPdu | CBS message in packed format, ready to transmit. Not NULL. |
[in,out] | ctx | to access configurations and update the group states. Not NULL. |
[in] | userData | plaintext data (SDU) to pack encrypted and authenticated. Can be NULL only if userDataLen is zero. |
[in] | userDataLen | length of userData in bytes. |
[in] | groupId | destination group identifier (the Parties that can decrypt). |
HZL_OK | on successful building of the Secured Application Data. |
HZL_ERR_SESSION_NOT_ESTABLISHED | if the message could not be built yet, a Request must be started with a Request message and a Response must be received. Use hzl_ClientBuildRequest() first. |
Same | values as hzl_ClientInit() in case the context has NULL pointers. |
HZL_ERR_NULL_PDU | if securedPdu is NULL. |
HZL_ERR_NULL_SDU | if userData is NULL and userDataLen is > 0. |
HZL_ERR_TOO_LONG_SDU | if userDataLen is too large for the underlying PDU. |
HZL_ERR_GID_TOO_LARGE_FOR_CONFIGURED_HEADER_TYPE | when groupId would not fit in the packed CBS header. |
HZL_ERR_UNKNOWN_GROUP | when group is not supported in the context's configuration. |
HZL_ERR_CANNOT_GENERATE_RANDOM | |
HZL_ERR_CANNOT_GENERATE_NON_ZERO_RANDOM | |
HZL_ERR_CANNOT_GET_CURRENT_TIME |
HZL_API hzl_Err_t hzl_ClientProcessReceived | ( | hzl_CbsPduMsg_t * | reactionPdu, |
hzl_RxSduMsg_t * | receivedUserData, | ||
hzl_ClientCtx_t * | ctx, | ||
const uint8_t * | receivedPdu, | ||
size_t | receivedPduLen, | ||
hzl_CanId_t | receivedCanId | ||
) |
Validates, unpacks and decrypts (if necessary) any received message, preparing an automatic response when required.
Handles automatically messages of different types, making a variety of checks for the correctness, integrity, authenticity of the message (note: the latter is not guaranteed for Unsecured messages). Updates the internal state automatically to keep track of the changing nonces and Session states.
[out] | reactionPdu | CBS message in packed format, ready to transmit, generated as an automatic, internal reaction to the just received message. Not NULL. No need to transmit if hzl_CbsPduMsg_t.dataLen is zero. Not NULL. |
[out] | receivedUserData | plaintext user data extracted out of receivedPdu . If the processed message contained no user data (was an internal message), the field hzl_RxSduMsg_t.isForUser is false. The whole struct is securely cleared (zeroed out) before anything else is attempted; thus it's full of zeros in case of errors. This is done to clear any lingering data if the buffer is reused, to avoid leaking information about previously-decrypted messages. Not NULL. |
[in,out] | ctx | to access configurations and update the group states. Not NULL. |
[in] | receivedPdu | packed CBS message as received from the underlying layer. Not NULL. |
[in] | receivedPduLen | length of receivedPdu in bytes. |
[in] | receivedCanId | identifier of the underlying layer's PDU, passed as-is to receivedUserData . |
HZL_OK | on success. |
HZL_ERR_MSG_IGNORED | when the message has another destination. |
Same | values as hzl_ClientInit() in case the context has NULL pointers. |
HZL_ERR_NULL_PDU | if receivedUserData or receivedPduLen are NULL. |
HZL_ERR_NULL_SDU | if userData is NULL. |
HZL_ERR_TOO_SHORT_PDU_TO_CONTAIN_HEADER | when the canFdMsg->dataLen is too short to even contain a CBS message with the currently configured Header Type in the ctx. |
HZL_ERR_INVALID_PAYLOAD_TYPE | on unsupported PTY field in the CBS Header. |
HZL_ERR_TOO_SHORT_PDU_TO_CONTAIN_SADFD,HZL_ERR_TOO_SHORT_PDU_TO_CONTAIN_RES,HZL_ERR_TOO_SHORT_PDU_TO_CONTAIN_REN | when the received message is too short to contain the data is should as indicated in its header (or also in the payload length field in case of Secured Application Data messages). |
HZL_ERR_TOO_LONG_CIPHERTEXT | if the received Secured Application Data message claims to contain too much data to fit into the underlying layer's message. |
HZL_ERR_SESSION_NOT_ESTABLISHED | when the current state indicates no session key and counter nonce have been established for this group yet. |
HZL_ERR_SECWARN_MESSAGE_FROM_MYSELF | when the received message seems to originate from the receiver itself. |
HZL_ERR_SECWARN_SERVER_ONLY_MESSAGE | when the received message that can only be sent by the server but is has another SID |
HZL_ERR_SECWARN_RECEIVED_OVERFLOWN_NONCE | if the received nonce is overflown |
HZL_ERR_SECWARN_OLD_MESSAGE | if the received nonce is old, indicating a potential replay attack |
HZL_ERR_SECWARN_INVALID_TAG | when the message integrity and authenticity cannot be guaranteed |