core/cmd_interface/session_manager.h (114 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #ifndef SESSION_MANAGER_H_ #define SESSION_MANAGER_H_ #include <stdbool.h> #include <stdint.h> #include "cerberus_protocol.h" #include "crypto/aes_gcm.h" #include "crypto/hash.h" #include "crypto/rng.h" #include "keystore/keystore.h" #include "riot/riot_key_manager.h" #include "status/rot_status.h" #define SESSION_MANAGER_ENTRY_MAGIC 0xAA92D810 #define SESSION_MANAGER_NONCE_LEN 32 #define SESSION_MANAGER_HMAC_KEY_LEN 32 #define SESSION_MANAGER_TRAILER_LEN \ (CERBERUS_PROTOCOL_AES_GCM_TAG_LEN + CERBERUS_PROTOCOL_AES_IV_LEN) #define SESSION_MANAGER_PAIRING_KEY_LEN 32 enum { SESSION_STATE_UNUSED = 0, /**< Session slot not used currently */ SESSION_STATE_SETUP, /**< Session currently being established */ SESSION_STATE_ESTABLISHED, /**< Session successfully established */ SESSION_STATE_PAIRED, /**< Pairing flow completed in established session */ }; enum { SESSION_PAIRING_STATE_NOT_SUPPORTED = 0, /**< Pairing with device not supported */ SESSION_PAIRING_STATE_NOT_INITIALIZED, /**< Device supports pairing but has not been paired yet */ SESSION_PAIRING_STATE_NOT_PAIRED, /**< Device paired but current session not setup with pairing yet */ SESSION_PAIRING_STATE_PAIRED, /**< Pairing completed with device successfully */ }; /* Forward declare the message structure needed for session manager API. */ struct cmd_interface_msg; /** * Entry in table holding session information and cached keys. */ struct session_manager_entry { uint8_t session_key[AES_GCM_256_KEY_LENGTH]; /**< AES session key */ uint8_t hmac_key[SESSION_MANAGER_HMAC_KEY_LEN]; /**< HMAC key */ uint8_t device_nonce[SESSION_MANAGER_NONCE_LEN]; /**< Nonce generated by device to use during session establishment */ uint8_t cerberus_nonce[SESSION_MANAGER_NONCE_LEN]; /**< Nonce generated by Cerberus to use during session establishment */ uint8_t eid; /**< EID of other device participating in session */ uint8_t session_state; /**< Current session state */ enum hmac_hash hmac_hash_type; /**< HMAC hash type to utilize */ uint8_t aes_init_vector[CERBERUS_PROTOCOL_AES_IV_LEN]; /**< AES Initialization vector used in encryption */ }; /** * Module which holds engines needed for session manager operation and caches session keys. Each * instance is intended to be dedicated to a single command interface. */ struct session_manager { /** * Use provided nonces to either create or restart session with device specified using EID. * * @param session Session manager instance to utilize. * @param eid Device EID. * @param device_nonce 32 byte random nonce generated by device used for AES key generation. * @param cerberus_nonce 32 byte random nonce generated by Cerberus used for AES key generation. * * @return Completion status, 0 if success or an error code. */ int (*add_session) (struct session_manager *session, uint8_t eid, const uint8_t *device_nonce, const uint8_t *cerberus_nonce); /** * Establish session for a device and generate AES session key. * * @param session Session manager instance to utilize. * @param request Request to utilize for setting up the session, expected to hold a key exchange * type 0 request. * * @return Completion status, 0 if success or an error code. */ int (*establish_session) (struct session_manager *session, struct cmd_interface_msg *request); /** * Check if device EID is on an established session. * * @param session Session manager instance to utilize. * @param eid Device EID. * * @return 1 if established, 0 if not or an error code. */ int (*is_session_established) (struct session_manager *session, uint8_t eid); /** * Check pairing state of session with device. * * @param session Session manager instance to utilize. * @param eid Device EID. * * @return Pairing state or an error code. */ int (*get_pairing_state) (struct session_manager *session, uint8_t eid); /** * Decrypt message using AES session key generated for session with device with requested EID. * * @param session Session manager instance to utilize. * @param request Request to decrypt. * * @return Completion status, 0 if success or an error code. */ int (*decrypt_message) (struct session_manager *session, struct cmd_interface_msg *request); /** * Encrypt message using AES session key generated for session with device with requested EID. * Output will contain encrypted message followed by the AES GCM tag and AES initialization * vector generated and used. * * @param session Session manager instance to utilize. * @param request Request to encrypt. * * @return Completion status, 0 if success or an error code. */ int (*encrypt_message) (struct session_manager *session, struct cmd_interface_msg *request); /** * Terminate and reset session. * * @param session Session manager instance to utilize. * @param eid Device EID. * @param hmac Optional HMAC provided by device. Set to NULL if not used. * @param hmac_len HMAC length. * * @return Completion status, 0 if success or an error code. */ int (*reset_session) (struct session_manager *session, uint8_t eid, uint8_t *hmac, size_t hmac_len); /** * Setup device binding in an established encrypted session. * * @param session Session manager instance to utilize. * @param eid Device EID. * @param pairing_key_len Length of the pairing key. * @param pairing_key_hmac Buffer containing HMAC generated by device for pairing key. * @param pairing_key_hmac_len Length of the pairing key HMAC. * * @return Completion status, 0 if success or an error code. */ int (*setup_paired_session) (struct session_manager *session, uint8_t eid, size_t pairing_key_len, uint8_t *pairing_key_hmac, size_t pairing_key_hmac_len); /** * Get session sync HMAC. * * @param session Session manager instance to utilize. * @param eid Device EID. * @param rn_req Random number provided by device. * @param hmac Buffer to hold generated HMAC. * @param hmac_len Size of provided HMAC buffer. * * @return Size of generated HMAC or an error code. */ int (*session_sync) (struct session_manager *session, uint8_t eid, uint32_t rn_req, uint8_t *hmac, size_t hmac_len); const struct aes_gcm_engine *aes; /**< AES engine used to encrypt/decrypt session data */ const struct hash_engine *hash; /**< Hashing engine used to generate AES shared key */ const struct rng_engine *rng; /**< RNG engine used to generate IV buffers */ const struct riot_key_manager *riot; /**< RIoT key manager containing alias key */ size_t num_sessions; /**< Total number of supported sessions */ struct session_manager_entry *sessions_table; /**< Table of supported device sessions */ size_t num_pairing_eids; /**< Total number of supported devices for pairing mode */ const uint8_t *pairing_eids; /**< List of supported devices for pairing mode */ bool sessions_table_preallocated; /**< Flag indicating if session tables were provided by caller */ const struct keystore *store; /**< Keystore used to persist pairing keys */ }; /* Internal functions for use by derived types. */ int session_manager_init (struct session_manager *session, const struct aes_gcm_engine *aes, const struct hash_engine *hash, const struct riot_key_manager *riot, struct session_manager_entry *sessions_table, size_t num_sessions, const uint8_t *pairing_eids, size_t num_pairing_eids, const struct keystore *store); void session_manager_release (struct session_manager *session); int session_manager_add_session (struct session_manager *session, uint8_t eid, const uint8_t *device_nonce, const uint8_t *cerberus_nonce); int session_manager_decrypt_message (struct session_manager *session, struct cmd_interface_msg *request); int session_manager_encrypt_message (struct session_manager *session, struct cmd_interface_msg *request); int session_manager_is_session_established (struct session_manager *session, uint8_t eid); int session_manager_get_pairing_state (struct session_manager *session, uint8_t eid); int session_manager_reset_session (struct session_manager *session, uint8_t eid, uint8_t *hmac, size_t hmac_len); int session_manager_setup_paired_session (struct session_manager *session, uint8_t eid, size_t pairing_key_len, uint8_t *pairing_key_hmac, size_t pairing_key_hmac_len); int session_manager_generate_keys_digest (struct session_manager *session, const uint8_t *device_key, size_t device_key_len, const uint8_t *session_pub_key, size_t session_pub_key_len); int session_manager_session_sync (struct session_manager *session, uint8_t eid, uint32_t rn_req, uint8_t *hmac, size_t hmac_len); struct session_manager_entry* session_manager_get_session (struct session_manager *session, uint8_t eid); #define SESSION_MANAGER_ERROR(code) ROT_ERROR (ROT_MODULE_SESSION_MANAGER, code) /** * Error codes that can be generated by the session manager. */ enum { SESSION_MANAGER_INVALID_ARGUMENT = SESSION_MANAGER_ERROR (0x00), /**< Input parameter is null or not valid. */ SESSION_MANAGER_NO_MEMORY = SESSION_MANAGER_ERROR (0x01), /**< Memory allocation failed. */ SESSION_MANAGER_UNEXPECTED_EID = SESSION_MANAGER_ERROR (0x02), /**< Device EID unexpected. */ SESSION_MANAGER_SESSION_NOT_ESTABLISHED = SESSION_MANAGER_ERROR (0x03), /**< Operation can't be completed without establishing session. */ SESSION_MANAGER_INVALID_ORDER = SESSION_MANAGER_ERROR (0x04), /**< Invalid order attempted for session establishment. */ SESSION_MANAGER_FULL = SESSION_MANAGER_ERROR (0x05), /**< Session manager at capacity and cannot support more sessions. */ SESSION_MANAGER_MALFORMED_MSG = SESSION_MANAGER_ERROR (0x06), /**< Provided message to decrypt invalid. */ SESSION_MANAGER_BUF_TOO_SMALL = SESSION_MANAGER_ERROR (0x07), /**< Provided output buffer too small for operation. */ SESSION_MANAGER_INVALID_REQUEST = SESSION_MANAGER_ERROR (0x08), /**< Provided session request invalid. */ SESSION_MANAGER_OPERATION_UNSUPPORTED = SESSION_MANAGER_ERROR (0x09), /**< Requested operation not supported. */ SESSION_MANAGER_OPERATION_NOT_PERMITTED = SESSION_MANAGER_ERROR (0x0A), /**< Requested operation not permitted. */ SESSION_MANAGER_PAIRING_NOT_SUPPORTED_WITH_DEVICE = SESSION_MANAGER_ERROR (0x0B), /**< Pairing not supported with device. */ SESSION_MANAGER_ADD_SESSION_FAILED = SESSION_MANAGER_ERROR (0x0C), /**< Failed to add a new session. */ SESSION_MANAGER_ESTABLISH_SESSION_FAILED = SESSION_MANAGER_ERROR (0x0D), /**< Failed to establish the encrypted connection. */ SESSION_MANAGER_SESSION_CHECK_FAILED = SESSION_MANAGER_ERROR (0x0E), /**< Failed to check the session state. */ SESSION_MANAGER_PAIRING_STATE_FAILED = SESSION_MANAGER_ERROR (0x0F), /**< Failed to check the pairing state. */ SESSION_MANAGER_DECRYPT_MSG_FAILED = SESSION_MANAGER_ERROR (0x10), /**< Failed to decrypt a message. */ SESSION_MANAGER_ENCRYPT_MSG_FAILED = SESSION_MANAGER_ERROR (0x11), /**< Failed to encrypt a message. */ SESSION_MANAGER_RESET_SESSION_FAILED = SESSION_MANAGER_ERROR (0x12), /**< Failed to terminate a session. */ SESSION_MANAGER_PAIR_SESSION_FAILED = SESSION_MANAGER_ERROR (0x13), /**< Failed to pair with a device. */ SESSION_MANAGER_SESSION_SYNC_FAILED = SESSION_MANAGER_ERROR (0x14), /**< Failed to sync the current session. */ }; #endif /* SESSION_MANAGER_H_ */