diff --git a/drivers/at86rf2xx/at86rf2xx.c b/drivers/at86rf2xx/at86rf2xx.c index 9a3d84dd72..2697d07247 100644 --- a/drivers/at86rf2xx/at86rf2xx.c +++ b/drivers/at86rf2xx/at86rf2xx.c @@ -28,14 +28,91 @@ #include "luid.h" #include "byteorder.h" #include "net/ieee802154.h" +#if IS_USED(IEEE802154_SECURITY) +#include "net/ieee802154_security.h" +#endif #include "net/gnrc.h" #include "at86rf2xx_registers.h" #include "at86rf2xx_internal.h" #include "at86rf2xx_netdev.h" +#if IS_USED(MODULE_AT86RF2XX_AES_SPI) +#include "at86rf2xx_aes.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" +#if IS_USED(MODULE_AT86RF2XX_AES_SPI) && \ + IS_USED(MODULE_IEEE802154_SECURITY) +/** + * @brief Pass the 802.15.4 encryption key to the transceiver hardware + * + * @param[in] dev Abstract security device descriptor + * @param[in] key Encryption key to be used + * @param[in] key_size Size of the encryption key in bytes + */ +static void _at86rf2xx_set_key(ieee802154_sec_dev_t *dev, + const uint8_t *key, uint8_t key_size) +{ + (void)key_size; + at86rf2xx_aes_key_write_encrypt((at86rf2xx_t *)dev->ctx, key); +} + +/** + * @brief Compute CBC-MAC from IEEE 802.15.4 security context + * + * @param[in] dev Abstract security device descriptor + * @param[out] cipher Buffer to store cipher blocks + * @param[in] iv Initial vector + * @param[in] plain Input data blocks + * @param[in] nblocks Number of blocks + */ +static void _at86rf2xx_cbc(const ieee802154_sec_dev_t *dev, + uint8_t *cipher, + uint8_t *iv, + const uint8_t *plain, + uint8_t nblocks) +{ + at86rf2xx_aes_cbc_encrypt((at86rf2xx_t *)dev->ctx, + (aes_block_t *)cipher, + NULL, + iv, + (aes_block_t *)plain, + nblocks); +} + +/** + * @brief Perform ECB encryption + * + * @param[in] dev Abstract security device descriptor + * @param[out] cipher Output cipher blocks + * @param[in] plain Plain blocks + * @param[in] nblocks Number of blocks + */ +static void _at86rf2xx_ecb(const ieee802154_sec_dev_t *dev, + uint8_t *cipher, + const uint8_t *plain, + uint8_t nblocks) +{ + at86rf2xx_aes_ecb_encrypt((at86rf2xx_t *)dev->ctx, + (aes_block_t *)cipher, + NULL, + (aes_block_t *)plain, + nblocks); + +} +/** + * @brief Struct that contains IEEE 802.15.4 security operations + * which are implemented, using the transceiver´s hardware + * crypto capabilities + */ +static const ieee802154_radio_cipher_ops_t _at86rf2xx_cipher_ops = { + .set_key = _at86rf2xx_set_key, + .ecb = _at86rf2xx_ecb, + .cbc = _at86rf2xx_cbc +}; +#endif /* IS_USED(MODULE_AT86RF2XX_COMMON_AES_SPI) && \ + IS_USED(MODULE_IEEE802154_SECURITY) */ void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params, uint8_t index) { @@ -152,6 +229,16 @@ void at86rf2xx_reset(at86rf2xx_t *dev) /* clear interrupt flags */ at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS); +#if IS_USED(MODULE_IEEE802154_SECURITY) && \ + IS_USED(MODULE_AT86RF2XX_AES_SPI) + dev->netdev.sec_ctx.dev.cipher_ops = &_at86rf2xx_cipher_ops; + dev->netdev.sec_ctx.dev.ctx = dev; + /* All configurations of the security module, the SRAM content, + and keys are reset during DEEP_SLEEP or RESET state. */ + at86rf2xx_aes_key_write_encrypt(dev, + dev->netdev.sec_ctx.cipher.context.context); +#endif + /* State to return after receiving or transmitting */ dev->idle_state = AT86RF2XX_PHY_STATE_RX; /* go into RX state */ diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c index 4efb9decb7..1def1bbc05 100644 --- a/drivers/at86rf2xx/at86rf2xx_netdev.c +++ b/drivers/at86rf2xx/at86rf2xx_netdev.c @@ -39,6 +39,9 @@ #include "at86rf2xx_netdev.h" #include "at86rf2xx_internal.h" #include "at86rf2xx_registers.h" +#if IS_USED(MODULE_AT86RF2XX_AES_SPI) +#include "at86rf2xx_aes.h" +#endif #define ENABLE_DEBUG 0 #include "debug.h" @@ -665,6 +668,22 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len) #endif /* MODULE_NETDEV_IEEE802154_OQPSK */ +#if IS_USED(MODULE_AT86RF2XX_COMMON_AES_SPI) && \ + IS_USED(MODULE_IEEE802154_SECURITY) + case NETOPT_ENCRYPTION_KEY: + assert(len >= IEEE802154_SEC_KEY_LENGTH); + at86rf2xx_aes_key_write_encrypt(dev, val); + if (memcmp(dev->netdev.sec_ctx.cipher.context.context, val, len)) { + /* If the key changes, the frame conter can be reset to 0*/ + dev->netdev.sec_ctx.frame_counter = 0; + } + memcpy(dev->netdev.sec_ctx.cipher.context.context, val, + IEEE802154_SEC_KEY_LENGTH); + res = IEEE802154_SEC_KEY_LENGTH; + break; +#endif /* IS_USED(MODULE_AT86RF2XX_AES_SPI) && \ + IS_USED(MODULE_IEEE802154_SECURITY) */ + default: break; } diff --git a/drivers/include/net/netdev/ieee802154.h b/drivers/include/net/netdev/ieee802154.h index 131fa981a0..7af8c5dd90 100644 --- a/drivers/include/net/netdev/ieee802154.h +++ b/drivers/include/net/netdev/ieee802154.h @@ -22,6 +22,9 @@ #include "net/eui_provider.h" #include "net/ieee802154.h" +#if IS_USED(MODULE_IEEE802154_SECURITY) +#include "net/ieee802154_security.h" +#endif #include "net/gnrc/nettype.h" #include "net/netopt.h" #include "net/netdev.h" @@ -116,6 +119,9 @@ typedef struct { uint8_t page; /**< channel page */ uint16_t flags; /**< flags as defined above */ int16_t txpower; /**< tx power in dBm */ +#if IS_USED(MODULE_IEEE802154_SECURITY) || defined (Doxygen) + ieee802154_sec_context_t sec_ctx; /**< security context */ +#endif /** @} */ } netdev_ieee802154_t; diff --git a/drivers/netdev/ieee802154.c b/drivers/netdev/ieee802154.c index 1b9793bafc..2296ffa19f 100644 --- a/drivers/netdev/ieee802154.c +++ b/drivers/netdev/ieee802154.c @@ -45,6 +45,12 @@ void netdev_ieee802154_reset(netdev_ieee802154_t *dev) /* Initialize PAN ID and call netdev::set to propagate it */ dev->pan = CONFIG_IEEE802154_DEFAULT_PANID; dev->netdev.driver->set(&dev->netdev, NETOPT_NID, &dev->pan, sizeof(dev->pan)); + +#if IS_USED(MODULE_IEEE802154_SECURITY) + ieee802154_sec_init(&dev->sec_ctx); + const netopt_enable_t e = NETOPT_ENABLE; + netdev_ieee802154_set(dev, NETOPT_ENCRYPTION, &e, sizeof(e)); +#endif } static inline uint16_t _get_ieee802154_pdu(netdev_ieee802154_t *dev) @@ -115,6 +121,18 @@ int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value, *((uint16_t *)value) = (uint16_t)dev->chan; res = sizeof(dev->chan); break; +#if IS_USED(MODULE_IEEE802154_SECURITY) + case NETOPT_ENCRYPTION: + assert(max_len == sizeof(netopt_enable_t)); + if (dev->flags & NETDEV_IEEE802154_SECURITY_EN) { + *((netopt_enable_t *)value) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)value) = NETOPT_DISABLE; + } + res = sizeof(netopt_enable_t); + break; +#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */ case NETOPT_ACK_REQ: assert(max_len == sizeof(netopt_enable_t)); if (dev->flags & NETDEV_IEEE802154_ACK_REQ) { @@ -159,6 +177,9 @@ int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value, *((uint16_t *)value) = (_get_ieee802154_pdu(dev) - IEEE802154_MAX_HDR_LEN) +#if IS_USED(MODULE_IEEE802154_SECURITY) + -IEEE802154_MAX_AUX_HDR_LEN +#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */ - IEEE802154_FCS_LEN; res = sizeof(uint16_t); break; @@ -219,6 +240,28 @@ int netdev_ieee802154_set(netdev_ieee802154_t *dev, netopt_t opt, const void *va dev->pan = *((uint16_t *)value); res = sizeof(dev->pan); break; +#if IS_USED(MODULE_IEEE802154_SECURITY) + case NETOPT_ENCRYPTION: + assert(len == sizeof(netopt_enable_t)); + if ((*(bool *)value)) { + dev->flags |= NETDEV_IEEE802154_SECURITY_EN; + } + else { + dev->flags &= ~NETDEV_IEEE802154_SECURITY_EN; + } + res = sizeof(netopt_enable_t); + break; + case NETOPT_ENCRYPTION_KEY: + assert(len >= IEEE802154_SEC_KEY_LENGTH); + if (memcmp(dev->sec_ctx.cipher.context.context, value, len)) { + /* If the key changes, the frame conter can be reset to 0*/ + dev->sec_ctx.frame_counter = 0; + } + memcpy(dev->sec_ctx.cipher.context.context, value, + IEEE802154_SEC_KEY_LENGTH); + res = IEEE802154_SEC_KEY_LENGTH; + break; +#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */ case NETOPT_ACK_REQ: if ((*(bool *)value)) { dev->flags |= NETDEV_IEEE802154_ACK_REQ; @@ -283,5 +326,4 @@ int netdev_ieee802154_dst_filter(netdev_ieee802154_t *dev, const uint8_t *mhr) return 1; } - /** @} */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index a40e41d80c..12880d8252 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -64,6 +64,7 @@ PSEUDOMODULES += gnrc_txtsnd PSEUDOMODULES += heap_cmd PSEUDOMODULES += i2c_scan PSEUDOMODULES += ieee802154_radio_hal +PSEUDOMODULES += ieee802154_security PSEUDOMODULES += ieee802154_submac PSEUDOMODULES += ina3221_alerts PSEUDOMODULES += l2filter_blacklist diff --git a/sys/Makefile.dep b/sys/Makefile.dep index c2f557cb6b..a4f3c6ac08 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -50,6 +50,12 @@ ifneq (,$(filter sys_bus_%,$(USEMODULE))) USEMODULE += core_msg_bus endif +ifneq (,$(filter ieee802154_security,$(USEMODULE))) + USEMODULE += crypto + USEMODULE += crypto_aes + USEMODULE += cipher_modes +endif + ifneq (,$(filter rtt_cmd,$(USEMODULE))) FEATURES_REQUIRED += periph_rtt endif diff --git a/sys/include/net/ieee802154/radio.h b/sys/include/net/ieee802154/radio.h index 8055ebaaa3..44066927a1 100644 --- a/sys/include/net/ieee802154/radio.h +++ b/sys/include/net/ieee802154/radio.h @@ -716,6 +716,64 @@ struct ieee802154_radio_ops { int (*set_rx_mode)(ieee802154_dev_t *dev, ieee802154_rx_mode_t mode); }; +/** + * @brief Forward declaration of the radio cipher ops structure + */ +typedef struct ieee802154_radio_cipher_ops ieee802154_radio_cipher_ops_t; + +/** + * @brief Forward declaration of the IEEE802.15.4 security device descriptor + */ +typedef struct ieee802154_sec_dev ieee802154_sec_dev_t; + +/** + * @brief IEEE802.15.4 security device descriptor + */ +struct ieee802154_sec_dev { + /** + * @brief Pointer to the operations of the device + */ + const struct ieee802154_radio_cipher_ops *cipher_ops; + /** + * @brief pointer to the context of the device + */ + void *ctx; +}; + +struct ieee802154_radio_cipher_ops { + /** + * @brief Function to set the encryption key for the + * next cipher operation + * + * @param[in] dev Security device descriptor + * @param[in] key Key to be used for the next cipher operation + * @param[in] key_size key size in bytes + */ + void (*set_key)(ieee802154_sec_dev_t *dev, + const uint8_t *key, uint8_t key_size); + /** + * @brief Function to perform ECB encryption + * + * @param[in] dev Security device descriptor + * @param[out] cipher Output cipher blocks + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ + void (*ecb)(const ieee802154_sec_dev_t *dev, uint8_t *cipher, + const uint8_t *plain, uint8_t nblocks); + /** + * @brief Function to compute CBC-MAC + * + * @param[in] dev Security device descriptor + * @param[in] cipher Output cipher blocks + * @param[in, out] iv in: IV; out: computed MIC + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ + void (*cbc)(const ieee802154_sec_dev_t *dev, uint8_t *cipher, + uint8_t *iv, const uint8_t *plain, uint8_t nblocks); +}; + /** * @brief Shortcut to @ref ieee802154_radio_ops::write * @@ -1155,6 +1213,48 @@ static inline int ieee802154_radio_set_rx_mode(ieee802154_dev_t *dev, return dev->driver->set_rx_mode(dev, mode); } +/** + * @brief Shortcut to ieee802154_sec_dev_t::ieee802154_radio_cipher_ops_t::set_key + * + * @param[in] dev IEEE802.15.4 security device descriptor + * @param[in] key Encryption key + * @param[in] key_size Size of the key in bytes + */ +static inline void ieee802154_radio_cipher_set_key(ieee802154_sec_dev_t *dev, + const uint8_t *key, uint8_t key_size) +{ + dev->cipher_ops->set_key(dev->ctx, key, key_size); +} + +/** + * @brief Shortcut to ieee802154_sec_dev_t::ieee802154_radio_cipher_ops_t::ecb + * + * @param[in] dev IEEE802.15.4 security device descriptor + * @param[out] cipher Output cipher blocks + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ +static inline void ieee802154_radio_cipher_ecb(const ieee802154_sec_dev_t *dev, uint8_t *cipher, + const uint8_t *plain, uint8_t nblocks) +{ + dev->cipher_ops->ecb(dev->ctx, cipher, plain, nblocks); +} + +/** + * @brief Shortcut to ieee802154_sec_dev_t::ieee802154_radio_cipher_ops_t::cbc + * + * @param[in] dev IEEE802.15.4 security device descriptor + * @param[out] cipher Output cipher blocks + * @param[in] iv Initial vector to be XOR´ed to the first plain block + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ +static inline void ieee802154_radio_cipher_cbc(const ieee802154_sec_dev_t *dev, uint8_t *cipher, + uint8_t *iv, const uint8_t *plain, uint8_t nblocks) +{ + dev->cipher_ops->cbc(dev->ctx, cipher, iv, plain, nblocks); +} + #ifdef __cplusplus } #endif diff --git a/sys/include/net/ieee802154_security.h b/sys/include/net/ieee802154_security.h new file mode 100644 index 0000000000..777ce2dcc8 --- /dev/null +++ b/sys/include/net/ieee802154_security.h @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2020 Otto-von-Gericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ieee802154_security IEEE 802.15.4 security + * @ingroup net + * @brief IEEE 802.15.4 security header + * @{ + * + * @file + * @brief IEEE 802.15.4 security interface + * + * Specification: IEEE 802.15.4 - 2015 + * https://www.silabs.com/content/usergenerated/asi/cloud/attachments/siliconlabs/en/community/wireless/proprietary/forum/jcr:content/content/primary/qna/802_15_4_promiscuous-tbzR/hivukadin_vukadi-iTXQ/802.15.4-2015.pdf + * + * @author Fabian Hüßler + */ + +#ifndef NET_IEEE802154_SECURITY_H +#define NET_IEEE802154_SECURITY_H + +#include +#include "kernel_defines.h" +#include "ieee802154.h" +#include "crypto/ciphers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IS_USED(MODULE_IEEE802154_RADIO_HAL) +#include "net/ieee802154/radio.h" +#else +/** + * @brief Forward declaration of an IEEE802.15.4 abstract security device + */ +typedef struct ieee802154_sec_dev ieee802154_sec_dev_t; + +/** + * @brief Struct of security operations + */ +typedef struct ieee802154_radio_cipher_ops { + /** + * @brief Function to set the encryption key for the + * next cipher operation + * + * @param[in] dev Will be @ref ieee802154_sec_context_t::ieee802154_sec_dev_t + * @param[in] key Key to be used for the next cipher operation + * @param[in] key_size key size in bytes + */ + void (*set_key)(ieee802154_sec_dev_t *dev, + const uint8_t *key, + uint8_t key_size); + /** + * @brief Function type to compute CBC-MAC + * + * @param[in] dev Will be @ref ieee802154_sec_context_t::ieee802154_sec_dev_t + * @param[in] cipher Output cipher blocks + * @param[in, out] iv in: IV; out: computed MIC + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ + void (*cbc)(const ieee802154_sec_dev_t *dev, + uint8_t *cipher, + uint8_t *iv, + const uint8_t *plain, + uint8_t nblocks); + /** + * @brief Function type to perform ECB encryption + * + * @param[in] dev Will be @ref ieee802154_sec_context_t::ieee802154_sec_dev_t + * @param[out] cipher Output cipher blocks + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ + void (*ecb)(const ieee802154_sec_dev_t *dev, + uint8_t *cipher, + const uint8_t *plain, + uint8_t nblocks); +} ieee802154_radio_cipher_ops_t; + +/** + * @brief IEEE802.15.4 security device descriptor + */ +struct ieee802154_sec_dev { + /** + * @brief Pointer to the operations of the device + */ + const struct ieee802154_radio_cipher_ops *cipher_ops; + /** + * @brief Pointer to the context of the device + */ + void *ctx; +}; +#endif + +#if !defined(IEEE802154_DEFAULT_KEY) || defined(DOXYGEN) +/** + * @brief AES key that is used in the test vectors from the specification + * + * @note Predefine it yourself, + * if you want another key to be set up on initialization + */ +#define IEEE802154_DEFAULT_KEY { 0xc0, 0xc1, 0xc2, 0xc3, \ + 0xc4, 0xc5, 0xc6, 0xc7, \ + 0xc8, 0xc9, 0xca, 0xcb, \ + 0xcc, 0xcd, 0xce, 0xcf } +#endif + +/** + * @brief Length of an AES key in bytes + */ +#define IEEE802154_SEC_KEY_LENGTH (16U) + +/** + * @brief Block size of an encryption block + */ +#define IEEE802154_SEC_BLOCK_SIZE (16U) + +/** + * @brief Maximum length of the security auxiliary header in bytes + */ +#define IEEE802154_MAX_AUX_HDR_LEN (14U) + +/** + * @brief Maximum Size of IEEE 802.15.4 MAC + */ +#define IEEE802154_MAC_SIZE (16U) + +/** + * @brief Mask to get security level bits + */ +#define IEEE802154_SCF_SECLEVEL_MASK (0x07) + +/** + * @brief Number of shifts to set/get security level bits + */ +#define IEEE802154_SCF_SECLEVEL_SHIFT (0) + +/** + * @brief Mask to get key mode bits + */ +#define IEEE802154_SCF_KEYMODE_MASK (0x18) + +/** + * @brief Number of shifts to set/get key mode bits + */ +#define IEEE802154_SCF_KEYMODE_SHIFT (3) + +/** + * @brief Security levels + * + * IEEE802154_SCF_SECLEVEL_MIC*: + * A message integrity code (MIC), also known as MAC, + * is used to prove authentication. The MIC covers the whole frame + * i.e. header, auxiliary header, and frame payload. + * The MIC is always encrypted, thus it must be decrypted by the receiver, + * to be checked. + * + * IEEE802154_SCF_SECLEVEL_ENC*: + * AES-128 in ECB mode is used to encrypt the payload of a frame to provide + * confidentiality. + * + * IEEE802154_SCF_SECLEVEL_ENC_MIC*: + * A combination of the two modes above is used to ensure + * authentication and confidentiality. + */ +typedef enum { + IEEE802154_SCF_SECLEVEL_NONE = 0x00, /**< no security */ + IEEE802154_SCF_SECLEVEL_MIC32 = 0x01, /**< 32 bit MIC */ + IEEE802154_SCF_SECLEVEL_MIC64 = 0x02, /**< 64 bit MIC */ + IEEE802154_SCF_SECLEVEL_MIC128 = 0x03, /**< 128 bit MIC */ + IEEE802154_SCF_SECLEVEL_ENC = 0x04, /**< encryption */ + IEEE802154_SCF_SECLEVEL_ENC_MIC32 = 0x05, /**< enc. + 32 bit MIC */ + IEEE802154_SCF_SECLEVEL_ENC_MIC64 = 0x06, /**< enc. + 64 bit MIC (mandatory) */ + IEEE802154_SCF_SECLEVEL_ENC_MIC128 = 0x07 /**< enc. + 128 bit MIC */ +} ieee802154_scf_seclevel_t; + +/** + * @brief Key identifier modes + * + * The key identifier field in the auxiliary header + * consists of the key source and the key index fields and is only present + * if the key identifier mode is not IEEE802154_SCF_KEYMODE_IMPLICIT. + * (see 9.4.3 in the spec.) + * + * +----------------+-------------+------------------+------------------------------------+ + * | mode | key source | key index | description | + * +----------------+-------------+------------------+------------------------------------+ + * | IMPLICIT | 0 bytes | 0 bytes | The key is implicitly | + * | | | | known to the receiver. | + * +----------------+-------------+------------------+------------------------------------+ + * | INDEX | 0 bytes | 1 byte | The key can be determined | + * | | | | from the key index. | + * +----------------+-------------+------------------+------------------------------------+ + * | SHORT_INDEX | 4 bytes | 1 byte | The key is a group key and can be | + * | | | | determined from the key index and | + * | | | | the source PAN ID and the | + * | | | | short source address | + * | | | | of the originator of the frame. | + * +----------------+-------------+------------------+------------------------------------+ + * | HX_INDEX | 8 bytes | 1 byte | The key can be determined | + * | | | | from the key index and | + * | | | | the long address of the originator | + * | | | | of the frame. | + * +----------------+-------------+------------------+------------------------------------+ + */ +typedef enum { + IEEE802154_SCF_KEYMODE_IMPLICIT = 0x00, /**< Key is determined implicitly */ + IEEE802154_SCF_KEYMODE_INDEX = 0x01, /**< Key is determined from key index */ + IEEE802154_SCF_KEYMODE_SHORT_INDEX = 0x02, /**< Key is determined from 4 byte key source and key index */ + IEEE802154_SCF_KEYMODE_HW_INDEX = 0x03 /**< Key is determined from 8 byte key source and key index */ +} ieee802154_scr_keymode_t; + +/** + * @brief IEEE 802.15.4 security error codes + */ +typedef enum { + IEEE802154_SEC_OK, /**< Everything went fine */ + IEEE802154_SEC_FRAME_COUNTER_OVERFLOW, /**< The requested operation would let the frame counter overflow */ + IEEE802154_SEC_NO_KEY, /**< Could not find the key to perform a requested cipher operation */ + IEEE802154_SEC_MAC_CHECK_FAILURE, /**< The computet MAC did not match */ + IEEE802154_SEC_UNSUPORTED, /**< Unsupported operation */ +} ieee802154_sec_error_t; + +/** + * @brief Struct to hold IEEE 802.15.4 security information + */ +typedef struct ieee802154_sec_context { + /** + * @brief Cipher context with AES128 interface and key storage + */ + cipher_t cipher; + /** + * @brief Security level IEEE802154_SCF_SECLEVEL_* + */ + uint8_t security_level; + /** + * @brief Key mode IEEE802154_SCF_KEYMODE_* + */ + uint8_t key_id_mode; + /** + * @brief Key index + */ + uint8_t key_index; + /** + * @brief Key source + * + * Content depends on key_id_mode + */ + uint8_t key_source[IEEE802154_LONG_ADDRESS_LEN]; + /** + * @brief Own frame counter + */ + uint32_t frame_counter; + /** + * @brief 802.15.4 security dev + */ + ieee802154_sec_dev_t dev; +} ieee802154_sec_context_t; + +/** + * @brief IEEE 802.15.4 auxiliary security header + */ +typedef struct __attribute__((packed)) { + /** + * @brief Security Control field (SCF) + * + * Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 + * +--------+--------+--------+--------+--------+--------+--------+--------+ + * | security level | key id. mode | fc sup.| ASN | r | r | + * +--------+--------+--------+--------+--------+--------+--------+--------+ + * + * security level: + * one of IEEE802154_SCF_SECLEVEL_* + * key identifier mode: + * one of IEEE802154_SCF_KEY_* + * frame counter suppression: + * basically always zero because we do not support TSCH right now + * ASN: + * basically always zero because we do not support TSCG right now + */ + uint8_t scf; + /** + * @brief frame counter + */ + uint32_t fc; + /** + * @brief key identifier (0 - 9 bytes) according to key id. mode + */ + uint8_t key_id[]; +} ieee802154_aux_sec_t; + +/** + * @brief Content of key_source if key mode is IEEE802154_SCF_KEYMODE_INDEX + */ +typedef struct __attribute__((packed)) { + /** + * @brief Key index of key from originator, defined by key source + */ + uint8_t key_index; +} ieee802154_aux_sec_key_identifier_1_t; + +/** + * @brief Content of key_source if key mode is IEEE802154_SCF_KEYMODE_SHORT_INDEX + */ +typedef struct __attribute__((packed)) { + /** + * @brief macPANId concatenated with macShortAddress + */ + uint8_t key_source[4]; + /** + * @brief Key index of key from originator, defined by key source + */ + uint8_t key_index; +} ieee802154_aux_sec_key_identifier_5_t; + +/** + * @brief Content of key_source if key mode is IEEE802154_SCF_KEYMODE_HW_INDEX + */ +typedef struct __attribute__((packed)) { + /** + * @brief macExtendedAddress + */ + uint8_t key_source[IEEE802154_LONG_ADDRESS_LEN]; + /** + * @brief Key index of key from originator, defined by key source + */ + uint8_t key_index; +} ieee802154_aux_sec_key_identifier_9_t; + +/** + * @brief Format of 13 byte nonce + */ +typedef struct __attribute__((packed)) { + /** + * @brief Source long address + */ + uint8_t src_addr[IEEE802154_LONG_ADDRESS_LEN]; + /** + * @brief Frame counter + */ + uint32_t frame_counter; + /** + * @brief One of IEEE802154_SCF_SECLEVEL_* + */ + uint8_t security_level; +} ieee802154_ccm_nonce_t; + +/** + * @brief Format of 16 byte input block of CCM + */ +typedef struct __attribute__((packed)) { + /** + * @brief Flags field + */ + uint8_t flags; + /** + * @brief Nonce (Number that is only used once) + */ + ieee802154_ccm_nonce_t nonce; + /** + * @brief Either the length of the actual message (for CBC-MAC) or + * a block counter (for CTR) + */ + uint16_t counter; +} ieee802154_ccm_block_t; + +/** + * @brief Initialize IEEE 802.15.4 security context with default values + * + * @param[out] ctx security context + */ +void ieee802154_sec_init(ieee802154_sec_context_t *ctx); + +/** + * @brief Encrypt IEEE 802.15.4 frame according to @p ctx + * + * @param[in] ctx IEEE 802.15.4 security context + * @param[in] header Pointer to frame header + * @param[in, out] header_size in: Header size; out: Size of header and auxiliary header + * @param[in,out] payload in: Plain payload; out: Encrypted payload + * @param[in] payload_size Size of payload + * @param[out] mic Buffer to store computed MIC + * @param[out] mic_size Size of MIC + * @param[in] src_address Source address + * + * @pre @p header should be large enough to also store the auxiliary header + * + * @return 0 Success + * @return negative integer on error + */ +int ieee802154_sec_encrypt_frame(ieee802154_sec_context_t *ctx, + const uint8_t *header, uint8_t *header_size, + uint8_t *payload, uint16_t payload_size, + uint8_t *mic, uint8_t *mic_size, + const uint8_t *src_address); + +/** + * @brief Decrypt IEEE 802.15.4 frame according to @p ctx + * + * @param[in] ctx IEEE 802.15.4 security context + * @param[in] frame_size Size of received frame + * @param[in] header Poinzter to header, which is also the frame + * @param[in, out] header_size in: Header size; out: Size of header and auxiliary header + * @param[out] payload Will point to the beginning of the payload + * @param[out] payload_size Pointer to store the payload size + * @param[out] mic Will point to the beginning of the MIC + * @param[out] mic_size Pointer to store the size of the MIC + * @param[in] src_address Pointer to remote long source address + * + * @pre After @p header follows the auxiliary header + * + * @return 0 Success + * @return negative integer on error + */ +int ieee802154_sec_decrypt_frame(ieee802154_sec_context_t *ctx, + uint16_t frame_size, + uint8_t *header, uint8_t *header_size, + uint8_t **payload, uint16_t *payload_size, + uint8_t **mic, uint8_t *mic_size, + const uint8_t *src_address); + +/** + * @brief Set the encryption key to be used for the next cipher operation + * + * This function should be the default callback operation to set the encryption key, + * if a radio does not provide special hardware security features. + * + * @param[in] dev Security device + * @param[in] key Key to be use for the next cipher operation + * @param[in] key_size Key size + */ +void ieee802154_sec_set_key(ieee802154_sec_dev_t *dev, + const uint8_t *key, uint8_t key_size); + +/** + * @brief Perform ECB block cipher for IEEE802154 security layer + * + * This function should be the default callback operation to perform ECB, + * if a radio does not provide special hardware security features. + * + * @param[in] dev Security device + * @param[out] cipher Output cipher blocks + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ +void ieee802154_sec_ecb(const ieee802154_sec_dev_t *dev, + uint8_t *cipher, + const uint8_t *plain, + uint8_t nblocks); + +/** + * @brief Perform CBC block cipher for IEEE802154 security layer + * MIC computation + * + * This function should be the default callback operation to perform CBC, + * if a radio does not provide special hardware security features. + * + * @param[in] dev Security device + * @param[out] cipher Output cipher blocks + * @param[in] iv Initial vector + * @param[in] plain Input plain blocks + * @param[in] nblocks Number of blocks + */ +void ieee802154_sec_cbc(const ieee802154_sec_dev_t *dev, + uint8_t *cipher, + uint8_t *iv, + const uint8_t *plain, + uint8_t nblocks); + +/** + * @brief Implements @ref ieee802154_sec_set_key, + * @ref ieee802154_sec_ecb, + * @ref ieee802154_sec_cbc + */ +extern const ieee802154_radio_cipher_ops_t ieee802154_radio_cipher_ops; + +#ifdef __cplusplus +} +#endif + +#endif /* NET_IEEE802154_SECURITY_H */ +/** @} */ diff --git a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c index 7763d351b1..5fbef5a2b2 100644 --- a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c +++ b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c @@ -137,7 +137,7 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) gnrc_pktsnip_t *ieee802154_hdr, *netif_hdr; gnrc_netif_hdr_t *hdr; size_t mhr_len = ieee802154_get_frame_hdr_len(pkt->data); - + uint8_t *mhr = pkt->data; /* nread was checked for <= 0 before so we can safely cast it to * unsigned */ if ((mhr_len == 0) || ((size_t)nread < mhr_len)) { @@ -145,21 +145,12 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) gnrc_pktbuf_release(pkt); return NULL; } - nread -= mhr_len; - /* mark IEEE 802.15.4 header */ - ieee802154_hdr = gnrc_pktbuf_mark(pkt, mhr_len, GNRC_NETTYPE_UNDEF); - if (ieee802154_hdr == NULL) { - DEBUG("_recv_ieee802154: no space left in packet buffer\n"); - gnrc_pktbuf_release(pkt); - return NULL; - } - netif_hdr = _make_netif_hdr(ieee802154_hdr->data); + netif_hdr = _make_netif_hdr(mhr); if (netif_hdr == NULL) { DEBUG("_recv_ieee802154: no space left in packet buffer\n"); gnrc_pktbuf_release(pkt); return NULL; } - hdr = netif_hdr->data; #ifdef MODULE_L2FILTER @@ -172,7 +163,7 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) } #endif #ifdef MODULE_GNRC_NETIF_DEDUP - if (_already_received(netif, hdr, ieee802154_hdr->data)) { + if (_already_received(netif, hdr, mhr)) { gnrc_pktbuf_release(pkt); gnrc_pktbuf_release(netif_hdr); DEBUG("_recv_ieee802154: packet dropped by deduplication\n"); @@ -181,9 +172,30 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) memcpy(netif->last_pkt.src, gnrc_netif_hdr_get_src_addr(hdr), hdr->src_l2addr_len); netif->last_pkt.src_len = hdr->src_l2addr_len; - netif->last_pkt.seq = ieee802154_get_seq(ieee802154_hdr->data); + netif->last_pkt.seq = ieee802154_get_seq(mhr); #endif /* MODULE_GNRC_NETIF_DEDUP */ - +#if IS_USED(MODULE_IEEE802154_SECURITY) + { + uint8_t *payload = NULL; + uint16_t payload_size = 0; + uint8_t *mic = NULL; + uint8_t mic_size = 0; + if (mhr[0] & NETDEV_IEEE802154_SECURITY_EN) { + if (ieee802154_sec_decrypt_frame(&((netdev_ieee802154_t *)dev)->sec_ctx, + nread, + mhr, (uint8_t *)&mhr_len, + &payload, &payload_size, + &mic, &mic_size, + gnrc_netif_hdr_get_src_addr(hdr)) != 0) { + DEBUG("_recv_ieee802154: packet dropped by security check\n"); + gnrc_pktbuf_release(pkt); + gnrc_pktbuf_release(netif_hdr); + return NULL; + } + } + nread -= mic_size; + } +#endif hdr->lqi = rx_info.lqi; hdr->rssi = rx_info.rssi; gnrc_netif_hdr_set_netif(hdr, netif); @@ -200,11 +212,20 @@ static gnrc_pktsnip_t *_recv(gnrc_netif_t *netif) od_hex_dump(pkt->data, nread, OD_WIDTH_DEFAULT); } } + /* mark IEEE 802.15.4 header */ + ieee802154_hdr = gnrc_pktbuf_mark(pkt, mhr_len, GNRC_NETTYPE_UNDEF); + if (ieee802154_hdr == NULL) { + DEBUG("_recv_ieee802154: no space left in packet buffer\n"); + gnrc_pktbuf_release(pkt); + gnrc_pktbuf_release(netif_hdr); + return NULL; + } + nread -= ieee802154_hdr->size; gnrc_pktbuf_remove_snip(pkt, ieee802154_hdr); pkt = gnrc_pkt_append(pkt, netif_hdr); } - DEBUG("_recv_ieee802154: reallocating.\n"); + DEBUG("_recv_ieee802154: reallocating MAC payload for upper layer.\n"); gnrc_pktbuf_realloc_data(pkt, nread); } else if (bytes_expected > 0) { DEBUG("_recv_ieee802154: received frame is too short\n"); @@ -222,7 +243,12 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) const uint8_t *src, *dst = NULL; int res = 0; size_t src_len, dst_len; + uint8_t mhr_len; +#if IS_USED(MODULE_IEEE802154_SECURITY) + uint8_t mhr[IEEE802154_MAX_HDR_LEN + IEEE802154_MAX_AUX_HDR_LEN]; +#else uint8_t mhr[IEEE802154_MAX_HDR_LEN]; +#endif uint8_t flags = (uint8_t)(state->flags & NETDEV_IEEE802154_SEND_MASK); le_uint16_t dev_pan = byteorder_htols(state->pan); @@ -250,29 +276,95 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) dst = gnrc_netif_hdr_get_dst_addr(netif_hdr); dst_len = netif_hdr->dst_l2addr_len; } - src_len = netif_hdr->src_l2addr_len; - if (src_len > 0) { - src = gnrc_netif_hdr_get_src_addr(netif_hdr); + if (flags & NETDEV_IEEE802154_SECURITY_EN) { + /* need to include long source address because the recipient + will need it to decrypt the frame */ + src_len = IEEE802154_LONG_ADDRESS_LEN; + src = state->long_addr; } else { - src_len = netif->l2addr_len; - src = netif->l2addr; + src_len = netif_hdr->src_l2addr_len; + if (src_len > 0) { + src = gnrc_netif_hdr_get_src_addr(netif_hdr); + } + else { + src_len = netif->l2addr_len; + src = netif->l2addr; + } } /* fill MAC header, seq should be set by device */ if ((res = ieee802154_set_frame_hdr(mhr, src, src_len, dst, dst_len, dev_pan, dev_pan, flags, state->seq++)) == 0) { DEBUG("_send_ieee802154: Error preperaring frame\n"); + gnrc_pktbuf_release(pkt); return -EINVAL; } + mhr_len = res; /* prepare iolist for netdev / mac layer */ - iolist_t iolist = { + iolist_t iolist_header = { .iol_next = (iolist_t *)pkt->next, .iol_base = mhr, - .iol_len = (size_t)res + .iol_len = mhr_len }; +#if IS_USED(MODULE_IEEE802154_SECURITY) + { + /* write protect `pkt` to set `pkt->next` */ + gnrc_pktsnip_t *tmp = gnrc_pktbuf_start_write(pkt); + if (!tmp) { + DEBUG("_send_ieee802154: no write access to pkt"); + gnrc_pktbuf_release(pkt); + return -ENOMEM; + } + pkt = tmp; + tmp = gnrc_pktbuf_start_write(pkt->next); + if (!tmp) { + DEBUG("_send_ieee802154: no write access to pkt->next"); + gnrc_pktbuf_release(pkt); + return -ENOMEM; + } + pkt->next = tmp; + /* merge snippets to store the L2 payload uniformly in one buffer */ + res = gnrc_pktbuf_merge(pkt->next); + if (res < 0) { + DEBUG("_send_ieee802154: failed to merge pktbuf\n"); + gnrc_pktbuf_release(pkt); + return res; + } + + iolist_header.iol_next = (iolist_t *)pkt->next; + + uint8_t mic[IEEE802154_MAC_SIZE]; + uint8_t mic_size = 0; + + if (flags & NETDEV_IEEE802154_SECURITY_EN) { + res = ieee802154_sec_encrypt_frame(&state->sec_ctx, + mhr, &mhr_len, + pkt->next->data, pkt->next->size, + mic, &mic_size, + state->long_addr); + if (res != 0) { + DEBUG("_send_ieee802154: encryption failedf\n"); + gnrc_pktbuf_release(pkt); + return res; + } + } + if (mic_size) { + gnrc_pktsnip_t *pktmic = gnrc_pktbuf_add(pkt->next->next, + mic, mic_size, + GNRC_NETTYPE_UNDEF); + if (!pktmic) { + DEBUG("_send_ieee802154: no space left in pktbuf to allocate MIC\n"); + gnrc_pktbuf_release(pkt); + return -ENOMEM; + } + pkt->next->next = pktmic; + } + iolist_header.iol_len = mhr_len; + } +#endif #ifdef MODULE_NETSTATS_L2 if (netif_hdr->flags & (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) { @@ -284,13 +376,13 @@ static int _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) #endif #ifdef MODULE_GNRC_MAC if (netif->mac.mac_info & GNRC_NETIF_MAC_INFO_CSMA_ENABLED) { - res = csma_sender_csma_ca_send(dev, &iolist, &netif->mac.csma_conf); + res = csma_sender_csma_ca_send(dev, &iolist_header, &netif->mac.csma_conf); } else { - res = dev->driver->send(dev, &iolist); + res = dev->driver->send(dev, &iolist_header); } #else - res = dev->driver->send(dev, &iolist); + res = dev->driver->send(dev, &iolist_header); #endif /* release old data */ diff --git a/sys/net/gnrc/netif/init_devs/auto_init_at86rf215.c b/sys/net/gnrc/netif/init_devs/auto_init_at86rf215.c index 277507941f..8dcf888592 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_at86rf215.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_at86rf215.c @@ -29,6 +29,7 @@ #include "net/gnrc/gomach/gomach.h" #endif #include "net/gnrc.h" +#include "include/init_devs.h" #include "at86rf215.h" #include "at86rf215_params.h" @@ -37,7 +38,7 @@ * @brief Define stack parameters for the MAC layer thread * @{ */ -#define AT86RF215_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define AT86RF215_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #ifndef AT86RF215_MAC_PRIO #define AT86RF215_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/auto_init_at86rf2xx.c b/sys/net/gnrc/netif/init_devs/auto_init_at86rf2xx.c index a108a56838..7398539214 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_at86rf2xx.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_at86rf2xx.c @@ -27,6 +27,7 @@ #include "net/gnrc/gomach/gomach.h" #endif #include "net/gnrc.h" +#include "include/init_devs.h" #include "at86rf2xx.h" #include "at86rf2xx_params.h" @@ -35,7 +36,7 @@ * @brief Define stack parameters for the MAC layer thread * @{ */ -#define AT86RF2XX_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define AT86RF2XX_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #ifndef AT86RF2XX_MAC_PRIO #define AT86RF2XX_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/auto_init_cc2420.c b/sys/net/gnrc/netif/init_devs/auto_init_cc2420.c index 829e13e97e..49b94e008a 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_cc2420.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_cc2420.c @@ -23,6 +23,7 @@ #include "board.h" #include "net/gnrc/netif/ieee802154.h" #include "net/gnrc.h" +#include "include/init_devs.h" #include "cc2420.h" #include "cc2420_params.h" @@ -31,7 +32,7 @@ * @brief MAC layer stack parameters * @{ */ -#define CC2420_MAC_STACKSIZE (THREAD_STACKSIZE_MAIN) +#define CC2420_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #ifndef CC2420_MAC_PRIO #define CC2420_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/auto_init_cc2538_rf.c b/sys/net/gnrc/netif/init_devs/auto_init_cc2538_rf.c index 302cda7e24..eec5a5d539 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_cc2538_rf.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_cc2538_rf.c @@ -19,6 +19,7 @@ #include "log.h" #include "net/gnrc/netif/ieee802154.h" +#include "include/init_devs.h" #include "cc2538_rf.h" @@ -26,7 +27,7 @@ * @brief Define stack parameters for the MAC layer thread * @{ */ -#define CC2538_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define CC2538_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #ifndef CC2538_MAC_PRIO #define CC2538_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/auto_init_kw2xrf.c b/sys/net/gnrc/netif/init_devs/auto_init_kw2xrf.c index cd3818e086..8ec90ef180 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_kw2xrf.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_kw2xrf.c @@ -24,6 +24,7 @@ #include "board.h" #include "net/gnrc/netif/ieee802154.h" #include "net/gnrc.h" +#include "include/init_devs.h" #include "kw2xrf.h" #include "kw2xrf_params.h" @@ -32,7 +33,7 @@ * @brief Define stack parameters for the MAC layer thread * @{ */ -#define KW2XRF_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define KW2XRF_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #ifndef KW2XRF_MAC_PRIO #define KW2XRF_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/auto_init_kw41zrf.c b/sys/net/gnrc/netif/init_devs/auto_init_kw41zrf.c index b9062a6c0b..b3966f352c 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_kw41zrf.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_kw41zrf.c @@ -22,6 +22,7 @@ #include "board.h" #include "net/gnrc.h" #include "net/gnrc/netif/ieee802154.h" +#include "include/init_devs.h" #ifdef MODULE_GNRC_LWMAC #include "net/gnrc/lwmac/lwmac.h" @@ -37,7 +38,7 @@ * @{ */ #ifndef KW41ZRF_NETIF_STACKSIZE -#define KW41ZRF_NETIF_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define KW41ZRF_NETIF_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #endif #ifndef KW41ZRF_NETIF_PRIO #define KW41ZRF_NETIF_PRIO (GNRC_NETIF_PRIO) diff --git a/sys/net/gnrc/netif/init_devs/auto_init_mrf24j40.c b/sys/net/gnrc/netif/init_devs/auto_init_mrf24j40.c index f9f943b0d4..00d9ea921a 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_mrf24j40.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_mrf24j40.c @@ -21,6 +21,7 @@ #include "board.h" #include "net/gnrc/netif/ieee802154.h" #include "net/gnrc.h" +#include "include/init_devs.h" #include "mrf24j40.h" #include "mrf24j40_params.h" @@ -29,7 +30,7 @@ * @brief Define stack parameters for the MAC layer thread * @{ */ -#define MRF24J40_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define MRF24J40_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #ifndef MRF24J40_MAC_PRIO #define MRF24J40_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/auto_init_nrf802154.c b/sys/net/gnrc/netif/init_devs/auto_init_nrf802154.c index 8d49a977b2..1657f825e6 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_nrf802154.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_nrf802154.c @@ -21,13 +21,14 @@ #include "board.h" #include "nrf802154.h" #include "net/gnrc/netif/ieee802154.h" +#include "include/init_devs.h" /** * @brief Define stack parameters for the MAC layer thread * @{ */ #ifndef NRF802154_MAC_STACKSIZE -#define NRF802154_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define NRF802154_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT) #endif #ifndef NRF802154_MAC_PRIO #define NRF802154_MAC_PRIO (GNRC_NETIF_PRIO) diff --git a/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c b/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c index 3218643d8b..b509bb0bdb 100644 --- a/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c +++ b/sys/net/gnrc/netif/init_devs/auto_init_socket_zep.c @@ -21,6 +21,7 @@ #include "socket_zep.h" #include "socket_zep_params.h" #include "net/gnrc/netif/ieee802154.h" +#include "include/init_devs.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -28,7 +29,7 @@ /** * @brief Define stack parameters for the MAC layer thread */ -#define SOCKET_ZEP_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) +#define SOCKET_ZEP_MAC_STACKSIZE (IEEE802154_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE) #ifndef SOCKET_ZEP_MAC_PRIO #define SOCKET_ZEP_MAC_PRIO (GNRC_NETIF_PRIO) #endif diff --git a/sys/net/gnrc/netif/init_devs/include/init_devs.h b/sys/net/gnrc/netif/init_devs/include/init_devs.h new file mode 100644 index 0000000000..41cd2eb3dc --- /dev/null +++ b/sys/net/gnrc/netif/init_devs/include/init_devs.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_auto_init_gnrc_netif + * @{ + * + * @file + * @brief common netif device initialization definitions + * + * @author Fabian Hüßler + */ + +#ifndef INIT_DEVS_H +#define INIT_DEVS_H + +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief extra stack size if ieee802154 security is enabled + * + * You may increase this value if you experience a stack overflow + * with IEEE 802.15.4 security enabled. + */ +#define IEEE802154_SECURITY_EXTRA_STACKSIZE (128) + +#ifndef IEEE802154_STACKSIZE_DEFAULT +#ifdef MODULE_IEEE802154_SECURITY +#define IEEE802154_STACKSIZE_DEFAULT (THREAD_STACKSIZE_DEFAULT + \ + IEEE802154_SECURITY_EXTRA_STACKSIZE) +#else +/** + * @brief stack size of an ieee802154 device + */ +#define IEEE802154_STACKSIZE_DEFAULT (THREAD_STACKSIZE_DEFAULT) +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* INIT_DEVS_H */ +/** @} */ diff --git a/sys/net/link_layer/ieee802154/Makefile b/sys/net/link_layer/ieee802154/Makefile index 75f19ccb7f..d60468641c 100644 --- a/sys/net/link_layer/ieee802154/Makefile +++ b/sys/net/link_layer/ieee802154/Makefile @@ -4,6 +4,10 @@ SRC = \ ieee802154.c \ # +ifneq (,$(filter ieee802154_security,$(USEMODULE))) + SRC += security.c +endif + ifneq (,$(filter ieee802154_submac,$(USEMODULE))) SRC += submac.c endif diff --git a/sys/net/link_layer/ieee802154/security.c b/sys/net/link_layer/ieee802154/security.c new file mode 100644 index 0000000000..3b5d53c43e --- /dev/null +++ b/sys/net/link_layer/ieee802154/security.c @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file + * @author Fabian Hüßler + * @} + */ + +#include +#include +#include + +#include "crypto/ciphers.h" +#include "crypto/modes/ecb.h" +#include "crypto/modes/cbc.h" +#include "net/ieee802154_security.h" + +const ieee802154_radio_cipher_ops_t ieee802154_radio_cipher_ops = { + .set_key = ieee802154_sec_set_key, + .ecb = ieee802154_sec_ecb, + .cbc = ieee802154_sec_cbc +}; + +static inline uint16_t _min(uint16_t a, uint16_t b) +{ + return a < b ? a : b; +} + +/** + * @brief Flag field of CCM input block + * + * Bit 7 Bit6 Bit 5 - Bit 3 Bit2 - Bit 0 + * +--------+-------+-----------------------+-----------------------+ + * | 0 (r) | Adata | M | L | + * +--------+-------+-----------------------+-----------------------+ + * + * r: value reserved + * Adata: 0 if no MIC is present, 1 else + * M: Number of octets in authentication field (M-2)/2 + * L: Number of octets in length field L-1 + * + * L will actually always be 2 because the maximul message length is 127 + * which is expressed as two bytes. + * Valid values for M are 0 (No MIC), 4 (32 bit MIC), 8 (64 bit MIC) + * and 16 (128 bit MIC) + */ +static inline uint8_t _ccm_flag(uint8_t M, uint8_t L) +{ + assert(M == 0 || M == 4 || M == 8 || M == 16); + assert(L == 2); + return (M >= 4 ? ((1 << 6) | (((M) - 2) / 2)) : 0) | ((L) - 1); +} + +static inline uint8_t _get_sec_level(uint8_t scf) +{ + return (scf & IEEE802154_SCF_SECLEVEL_MASK) + >> IEEE802154_SCF_SECLEVEL_SHIFT; +} + +static inline uint8_t _get_key_id_mode(uint8_t scf) +{ + return (scf & IEEE802154_SCF_KEYMODE_MASK) + >> IEEE802154_SCF_KEYMODE_SHIFT; +} + +static inline uint8_t _mac_size(uint8_t sec_level) +{ + switch (sec_level) { + case IEEE802154_SCF_SECLEVEL_MIC32: + case IEEE802154_SCF_SECLEVEL_ENC_MIC32: + return 4; + case IEEE802154_SCF_SECLEVEL_MIC64: + case IEEE802154_SCF_SECLEVEL_ENC_MIC64: + return 8; + case IEEE802154_SCF_SECLEVEL_MIC128: + case IEEE802154_SCF_SECLEVEL_ENC_MIC128: + return 16; + default: + return 0; + } +} + +/* frame is secured with signature */ +static inline bool _req_mac(uint8_t sec_level) +{ + switch (sec_level) { + case IEEE802154_SCF_SECLEVEL_MIC32: + case IEEE802154_SCF_SECLEVEL_MIC64: + case IEEE802154_SCF_SECLEVEL_MIC128: + case IEEE802154_SCF_SECLEVEL_ENC_MIC32: + case IEEE802154_SCF_SECLEVEL_ENC_MIC64: + case IEEE802154_SCF_SECLEVEL_ENC_MIC128: + return true; + default: + return false; + } +} + +/* frame is encrypted */ +static inline bool _req_encryption(uint8_t sec_level) +{ + switch (sec_level) { + case IEEE802154_SCF_SECLEVEL_ENC: + case IEEE802154_SCF_SECLEVEL_ENC_MIC32: + case IEEE802154_SCF_SECLEVEL_ENC_MIC64: + case IEEE802154_SCF_SECLEVEL_ENC_MIC128: + return true; + default: + return false; + } +} + +static inline void _memxor(void *dst, const void* src, size_t size) +{ + while (size--) { + ((uint8_t *)dst)[size] ^= ((uint8_t *)src)[size]; + } +} + +static inline uint8_t _scf(uint8_t sec_level, uint8_t key_mode) +{ + return (sec_level << IEEE802154_SCF_SECLEVEL_SHIFT) | + (key_mode << IEEE802154_SCF_KEYMODE_SHIFT); +} + +static inline uint8_t _get_aux_hdr_size(uint8_t security_level, + uint8_t key_mode) +{ + if (security_level == IEEE802154_SCF_SECLEVEL_NONE) { + return 0; + } + switch (key_mode) { + case IEEE802154_SCF_KEYMODE_IMPLICIT: + return 5; + case IEEE802154_SCF_KEYMODE_INDEX: + return 6; + case IEEE802154_SCF_KEYMODE_SHORT_INDEX: + return 10; + case IEEE802154_SCF_KEYMODE_HW_INDEX: + return 14; + default: + return 0; + } +} + +static uint8_t _set_aux_hdr(const ieee802154_sec_context_t *ctx, + ieee802154_aux_sec_t *ahr) +{ + ahr->scf = _scf(ctx->security_level, ctx->key_id_mode); + /* If you look in the specification: Annex C, + integers values are in little endian */ + ahr->fc = byteorder_btoll(byteorder_htonl(ctx->frame_counter)).u32; + size_t len = 5; + switch (ctx->key_id_mode) { + case IEEE802154_SCF_KEYMODE_IMPLICIT: + break; + case IEEE802154_SCF_KEYMODE_INDEX: + memcpy(ahr->key_id, &ctx->key_index, 1); + len++; + break; + case IEEE802154_SCF_KEYMODE_SHORT_INDEX: + memcpy(ahr->key_id, ctx->key_source, 4); + memcpy(ahr->key_id + 4, &ctx->key_index, 1); + len += 5; + break; + case IEEE802154_SCF_KEYMODE_HW_INDEX: + memcpy(ahr->key_id, ctx->key_source, 8); + memcpy(ahr->key_id + 4, &ctx->key_index, 1); + len += 9; + break; + default: + break; + } + return len; +} + +/** + * @brief Construct the first block A0 for CTR + */ +static inline void _init_ctr_A0(ieee802154_ccm_block_t *A0, + uint32_t frame_counter, + uint8_t security_level, + const uint8_t *src_address) +{ + A0->flags = _ccm_flag(0, 2); + A0->nonce.frame_counter = htonl(frame_counter); + A0->nonce.security_level = security_level; + A0->counter = 0; + memcpy(A0->nonce.src_addr, src_address, IEEE802154_LONG_ADDRESS_LEN); +} + +/** + * @brief In CTR, the blocks Ai differ in a successive counter + */ +static inline void _advance_ctr_Ai(ieee802154_ccm_block_t *Ai) +{ + Ai->counter = htons(ntohs(Ai->counter) + 1); +} + +/** + * @brief Construct the first block B0 for CBC-MAC + */ +static inline void _init_cbc_B0(ieee802154_ccm_block_t *B0, + uint32_t frame_counter, + uint8_t security_level, + uint16_t m_len, + uint8_t mic_size, + const uint8_t *src_address) +{ + B0->flags = _ccm_flag(mic_size, 2); + B0->nonce.frame_counter = htonl(frame_counter), + B0->nonce.security_level = security_level, + B0->counter = htons(m_len); + memcpy(B0->nonce.src_addr, src_address, IEEE802154_LONG_ADDRESS_LEN); +} + +static const uint8_t *_get_encryption_key(const ieee802154_sec_context_t *ctx, + const uint8_t *mhr, uint8_t mhr_len, + const ieee802154_aux_sec_t *ahr) +{ + (void)mhr; + (void)mhr_len; + (void)ahr; + /* For simplicity, assume that everyone has the same key */ + /* Else you´d have to look up the key based on the destination address */ + return ctx->cipher.context.context; +} + +static const uint8_t *_get_decryption_key(const ieee802154_sec_context_t *ctx, + const uint8_t *mhr, uint8_t mhr_len, + const ieee802154_aux_sec_t *ahr) +{ + (void)mhr; + (void)mhr_len; + (void)ahr; + /* For simplicity, assume that everyone has the same key */ + /* Else you´d have to look up the key based on the source address */ + return ctx->cipher.context.context; +} + +/** + * @brief Perform ECB on one block of data and and add padding if necessary + */ +static uint8_t _ecb(ieee802154_sec_context_t *ctx, + uint8_t *tmp1, uint8_t *tmp2, uint8_t *data, + const uint8_t *Ai, uint16_t size) +{ + uint16_t s = _min(IEEE802154_SEC_BLOCK_SIZE, size); + ctx->dev.cipher_ops->ecb(&ctx->dev, tmp2, Ai, 1); + memcpy(tmp1, data, s); + memset(tmp1 + s, 0, IEEE802154_SEC_BLOCK_SIZE - s); + _memxor(tmp1, tmp2, IEEE802154_SEC_BLOCK_SIZE); + memcpy(data, tmp1, s); + return s; +} + +/** + * @brief Perform CBC on one block of data and add padding if necessary + */ +static uint8_t _cbc_next(ieee802154_sec_context_t *ctx, + uint8_t *last, uint8_t *tmp, + const uint8_t *next, uint16_t size) +{ + uint16_t s = _min(IEEE802154_SEC_BLOCK_SIZE, size); + memcpy(tmp, next, s); + memset(tmp + s, 0, IEEE802154_SEC_BLOCK_SIZE - s); + ctx->dev.cipher_ops->cbc(&ctx->dev, last, last, tmp, 1); + return s; +} + +static void _set_key(ieee802154_sec_context_t *ctx, const uint8_t *key) +{ + ctx->dev.cipher_ops->set_key(&ctx->dev, key, IEEE802154_SEC_BLOCK_SIZE); + memcpy(ctx->cipher.context.context, key, IEEE802154_SEC_KEY_LENGTH); +} + +static void _comp_mic(ieee802154_sec_context_t *ctx, + uint8_t mic[IEEE802154_MAC_SIZE], + ieee802154_ccm_block_t *B0, + const void *a, uint16_t a_len, + const void *m, uint16_t m_len) +{ + uint8_t tmp[IEEE802154_SEC_BLOCK_SIZE] = { 0 }; + uint16_t off; + memset(mic, 0, IEEE802154_MAC_SIZE); + _cbc_next(ctx, mic, tmp, (uint8_t *)B0, sizeof(*B0)); + byteorder_htobebufs(tmp, a_len); + off = _min(sizeof(tmp) - sizeof(uint16_t), a_len); + memcpy(tmp + sizeof(uint16_t), a, off); + _cbc_next(ctx, mic, tmp, tmp, sizeof(uint16_t) + off); + for (;off < a_len;) { + off += _cbc_next(ctx, mic, tmp, &(((uint8_t *)a)[off]), a_len - off); + } + for (off = 0; off < m_len;) { + off += _cbc_next(ctx, mic, tmp, &(((uint8_t *)m)[off]), m_len - off); + } +} + +static void _ctr(ieee802154_sec_context_t *ctx, + ieee802154_ccm_block_t *A0, + const void *m, uint16_t m_len) +{ + uint8_t tmp1[IEEE802154_SEC_BLOCK_SIZE] = { 0 }; + uint8_t tmp2[IEEE802154_SEC_BLOCK_SIZE] = { 0 }; + + for (uint16_t off = 0; off < m_len;) { + _advance_ctr_Ai(A0); + off += _ecb(ctx, tmp1, tmp2, + &(((uint8_t *)m)[off]), (uint8_t *)A0, m_len - off); + } +} + +static void _ctr_mic(ieee802154_sec_context_t *ctx, + ieee802154_ccm_block_t *A0, + void *mic, uint8_t mic_size) +{ + uint8_t tmp1[IEEE802154_SEC_BLOCK_SIZE] = { 0 }; + uint8_t tmp2[IEEE802154_SEC_BLOCK_SIZE] = { 0 }; + + _ecb(ctx, tmp1, tmp2, mic, (uint8_t *)A0, mic_size); +} + +void ieee802154_sec_init(ieee802154_sec_context_t *ctx) +{ + /* device driver can override this */ + ctx->dev.cipher_ops = &ieee802154_radio_cipher_ops; + /* device driver can override this */ + ctx->dev.ctx = ctx; + /* MIC64 is the only mandatory security mode */ + ctx->security_level = IEEE802154_SCF_SECLEVEL_ENC_MIC64; + ctx->key_id_mode = IEEE802154_SCF_KEYMODE_IMPLICIT; + memset(ctx->key_source, 0, sizeof(ctx->key_source)); + ctx->key_index = 0; + ctx->frame_counter = 0; + uint8_t key[] = IEEE802154_DEFAULT_KEY; + + assert(CIPHER_MAX_CONTEXT_SIZE >= IEEE802154_SEC_KEY_LENGTH); + cipher_init(&ctx->cipher, CIPHER_AES_128, key, IEEE802154_SEC_KEY_LENGTH); +} + +int ieee802154_sec_encrypt_frame(ieee802154_sec_context_t *ctx, + const uint8_t *header, uint8_t *header_size, + uint8_t *payload, uint16_t payload_size, + uint8_t *mic, uint8_t *mic_size, + const uint8_t *src_address) +{ + /* For non data frames (MAC commands, beacons) a and a_len would be larger. + ACKs are not encrypted. */ + assert((*((uint8_t *)header)) & IEEE802154_FCF_TYPE_DATA); + + if (ctx->security_level == IEEE802154_SCF_SECLEVEL_NONE) { + *mic_size = 0; + return IEEE802154_SEC_OK; + } + if (ctx->frame_counter == 0xFFFFFFFF) { + /* Letting the frame counter overflow is explicitly prohibited by the specification. + (see 9.4.2) */ + return -IEEE802154_SEC_FRAME_COUNTER_OVERFLOW; + } + + /* write the auxiliary header */ + ieee802154_aux_sec_t *aux = (ieee802154_aux_sec_t *)(header + *header_size); + uint8_t aux_size = _get_aux_hdr_size(ctx->security_level, ctx->key_id_mode); + _set_aux_hdr(ctx, aux); + + /* attempt to find the encrypton key */ + const uint8_t *key; + if (!(key = _get_encryption_key(ctx, header, *header_size, aux))) { + return -IEEE802154_SEC_NO_KEY; + } + _set_key(ctx, key); + + *mic_size = _mac_size(ctx->security_level); + const uint8_t *a = header; + uint8_t *m = payload; + uint16_t a_len = *header_size + aux_size; + uint16_t m_len = payload_size; + ieee802154_ccm_block_t ccm; /* Ai or Bi */ + + /* compute MIC */ + if (_req_mac(ctx->security_level)) { + _init_cbc_B0(&ccm, ctx->frame_counter, ctx->security_level, m_len, *mic_size, src_address); + _comp_mic(ctx, mic, &ccm, a, a_len, m, m_len); + + /* encrypt MIC */ + _init_ctr_A0(&ccm, ctx->frame_counter, ctx->security_level, src_address); + _ctr_mic(ctx, &ccm, mic, *mic_size); + } + /* encrypt payload */ + if (_req_encryption(ctx->security_level)) { + _init_ctr_A0(&ccm, ctx->frame_counter, ctx->security_level, src_address); + _ctr(ctx, &ccm, m, m_len); + } + *header_size += aux_size; + ctx->frame_counter++; + return IEEE802154_SEC_OK; +} + +int ieee802154_sec_decrypt_frame(ieee802154_sec_context_t *ctx, + uint16_t frame_size, + uint8_t *header, uint8_t *header_size, + uint8_t **payload, uint16_t *payload_size, + uint8_t **mic, uint8_t *mic_size, + const uint8_t *src_address) +{ + /* For non data frames (MAC commands, beacons) a and a_len would be larger. + ACKs are not encrypted. */ + assert(*header & IEEE802154_FCF_TYPE_DATA); + + /* read the fields of the auxiliary header */ + ieee802154_aux_sec_t *aux = (ieee802154_aux_sec_t *)(header + *header_size); + uint8_t security_level = _get_sec_level(aux->scf); + uint8_t key_mode = _get_key_id_mode(aux->scf); + uint8_t aux_size = _get_aux_hdr_size(security_level, key_mode); + uint8_t mac_size = _mac_size(security_level); + /* remember that the frame counter was stored in little endian */ + uint32_t frame_counter = byteorder_ntohl( + byteorder_ltobl((le_uint32_t){aux->fc})); + + if (security_level == IEEE802154_SCF_SECLEVEL_NONE) { + *payload = header + *header_size; + *payload_size = frame_size - *header_size; + *mic = NULL; + *mic_size = 0; + return IEEE802154_SEC_OK; + } + + *payload_size = frame_size - *header_size - aux_size - mac_size; + *payload = header + *header_size + aux_size; + *mic_size = mac_size; + *mic = header + frame_size - mac_size; + + /* attempt to find the decryption key */ + const uint8_t *key; + if (!(key = _get_decryption_key(ctx, header, *header_size, aux))) { + return -IEEE802154_SEC_NO_KEY; + } + _set_key(ctx, key); + + const uint8_t *a = header; + uint8_t *c = *payload; + uint16_t a_len = *header_size + aux_size; + uint16_t c_len = *payload_size; + uint8_t *mac = *mic; + ieee802154_ccm_block_t ccm; /* Ai or Bi */ + + /* TODO: + A better implementation would check if the received frame counter is + greater then the frame counter that has previously been received from + the other endpoint. This is done to protect against replay attacks. + But we do not store this information because we also do not have + a proper key store, to avoid complexity on embedded devices. */ + + /* decrypt MIC */ + if (mac_size) { + _init_ctr_A0(&ccm, frame_counter, security_level, src_address); + _ctr_mic(ctx, &ccm, mac, mac_size); + } + /* decrypt cipher */ + if (_req_encryption(security_level)) { + _init_ctr_A0(&ccm, frame_counter, security_level, src_address); + _ctr(ctx, &ccm, c, c_len); + } + /* check MIC */ + if (_req_mac(security_level)) { + uint8_t tmp_mic[IEEE802154_MAC_SIZE]; + _init_cbc_B0(&ccm, frame_counter, security_level, c_len, mac_size, src_address); + _comp_mic(ctx, tmp_mic, &ccm, a, a_len, c, c_len); + if (memcmp(tmp_mic, *mic, mac_size)) { + return -IEEE802154_SEC_MAC_CHECK_FAILURE; + } + } + *header_size += aux_size; + return IEEE802154_SEC_OK; +} + +void ieee802154_sec_set_key(ieee802154_sec_dev_t *ctx, + const uint8_t *key, uint8_t key_size) +{ + /* This is a dummy implementation of the set_key callback + in ieee802154_radio_cipher_ops_t. + The copying of the key is done in the static _set_key() function, + which wraps around the set_key callback and then copies. + For the software encryption / decryption, there is + nothing else to do, hence the NOP. For hardware support, + the key must be transferred to the transceiver. */ + (void)ctx; + (void)key; + (void)key_size; +} + +void ieee802154_sec_ecb(const ieee802154_sec_dev_t *ctx, + uint8_t *cipher, + const uint8_t *plain, + uint8_t nblocks) +{ + cipher_encrypt_ecb(&((ieee802154_sec_context_t *)ctx->ctx)->cipher, + plain, + nblocks * IEEE802154_SEC_BLOCK_SIZE, + cipher); +} + +void ieee802154_sec_cbc(const ieee802154_sec_dev_t *ctx, + uint8_t *cipher, + uint8_t *iv, + const uint8_t *plain, + uint8_t nblocks) +{ + cipher_encrypt_cbc(&((ieee802154_sec_context_t *)ctx->ctx)->cipher, + iv, + plain, + nblocks * IEEE802154_SEC_BLOCK_SIZE, + cipher); +} diff --git a/tests/ieee802154_security/Makefile b/tests/ieee802154_security/Makefile new file mode 100644 index 0000000000..aa9cd89cb7 --- /dev/null +++ b/tests/ieee802154_security/Makefile @@ -0,0 +1,5 @@ +USEMODULE += ieee802154 +USEMODULE += ieee802154_security +USEMODULE += gnrc_netif_ieee802154 + +include ../driver_netdev_common/Makefile.netdev.mk diff --git a/tests/ieee802154_security/Makefile.ci b/tests/ieee802154_security/Makefile.ci new file mode 100644 index 0000000000..09b7719b4b --- /dev/null +++ b/tests/ieee802154_security/Makefile.ci @@ -0,0 +1,21 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-mega2560 \ + arduino-nano \ + arduino-uno \ + atmega328p \ + i-nucleo-lrwan1 \ + nucleo-f030r8 \ + nucleo-f031k6 \ + nucleo-f042k6 \ + nucleo-l011k4 \ + nucleo-l031k6 \ + nucleo-l053r8 \ + nucleo-l552ze-q \ + stk3200 \ + stm32f030f4-demo \ + stm32f0discovery \ + stm32l0538-disco \ + waspmote-pro \ + # diff --git a/tests/ieee802154_security/README.md b/tests/ieee802154_security/README.md new file mode 100644 index 0000000000..092213db5a --- /dev/null +++ b/tests/ieee802154_security/README.md @@ -0,0 +1,12 @@ +Tests for module `ieee802154_security` +====================================== + +This is just a dummy test application to integrate the +module in the CI process, to check if it compiles. + +TODO: +Write a proper test application which runs on `native` +and uses `socket_zep`. + + +[#15150]: https://github.com/RIOT-OS/RIOT/pull/15150 diff --git a/tests/ieee802154_security/main.c b/tests/ieee802154_security/main.c new file mode 100644 index 0000000000..8eb383999b --- /dev/null +++ b/tests/ieee802154_security/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for ieee802154_security module + * + * @author Fabian Hüßler + * @} + */ + +#include "thread.h" +#include "shell.h" +#include "shell_commands.h" + +#include "net/gnrc/pktdump.h" +#include "net/gnrc.h" + +int main(void) +{ + /* enable pktdump output */ + gnrc_netreg_entry_t dump = GNRC_NETREG_ENTRY_INIT_PID( + GNRC_NETREG_DEMUX_CTX_ALL, gnrc_pktdump_pid); + + gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &dump); + + /* start the shell */ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +}