#pragma once #include #include /** * @brief The size of a message authentication code * * The MAC size is determined by the size of the output * of the hash function used. In this case, for SHA256, * the size is 32 bytes (= 256 bit) */ #define SHA256_MAC_SIZE 32 #pragma pack(push, 1) typedef enum { /// @brief The initial message from remote to device to request a challenge. initial = 0, /// @brief The second message in an unlock with the challenge from the device to the remote challenge = 1, /// @brief The third message with the signed challenge from the remote to the device request = 2, /// @brief The final message with the unlock result from the device to the remote response = 3, } MessageType; enum class MessageResult: uint8_t { /// @brief The message was accepted. MessageAccepted = 0, /// @brief The web socket received text while waiting for binary data. TextReceived = 1, /// @brief An unexpected socket event occured while performing the exchange. UnexpectedSocketEvent = 2, /// @brief The received message size is invalid. InvalidMessageSize = 3, /// @brief The message signature was incorrect. MessageAuthenticationFailed = 4, /// @brief The server challenge of the message did not match previous messages ServerChallengeMismatch = 5, /// @brief The client challenge of the message did not match previous messages ClientChallengeInvalid = 6, /// @brief An unexpected or unsupported message type was received InvalidMessageType = 7, /// @brief A message is already being processed TooManyRequests = 8, InvalidUrlParameter = 10, InvalidResponseAuthentication = 11, }; /** * @brief A generic message to exchange during challenge-response authentication. */ typedef struct { /// @brief The type of message being sent. MessageType messageType; /** * @brief The random nonce created by the remote * * This nonce is a random number created by the remote, different for each unlock request. * It is set for all message types. */ uint32_t clientChallenge; /** * @brief A random number to sign by the remote * * This nonce is set by the server after receiving an initial message. * It is set for the message types `challenge`, `request`, and `response`. */ uint32_t serverChallenge; /** * @brief The response status for the previous message. * * It is set only for messages from the server, e.g. the `challenge` and `response` message types. * Must be set to `MessageAccepted` for other messages. */ MessageResult result; } Message; /** * @brief The signed version of a message. * */ typedef struct { /** * @brief The authentication code of the message * * The code is created by performing HMAC-SHA256 * over the bytes of the `Message`. */ uint8_t mac[SHA256_MAC_SIZE]; /// @brief The message Message message; } SignedMessage; constexpr size_t messageCounterSize = sizeof(uint32_t); #pragma pack(pop) constexpr int MESSAGE_CONTENT_SIZE = sizeof(Message); constexpr int SIGNED_MESSAGE_SIZE = sizeof(SignedMessage); /** * @brief A callback for messages received over the socket * * The first parameter is a pointer to the byte buffer. * The second parameter indicates the number of received bytes. */ typedef void (*MessageCallback)(uint8_t* payload, size_t length); /** * @brief A callback for socket errors */ typedef void (*ErrorCallback)(MessageResult event);