mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #15150 from fabian18/ieee802154_security
Initial implementation of IEEE 802.15.4 security
This commit is contained in:
commit
1477a340fe
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
489
sys/include/net/ieee802154_security.h
Normal file
489
sys/include/net/ieee802154_security.h
Normal file
@ -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 <fabian.huessler@ovgu.de>
|
||||
*/
|
||||
|
||||
#ifndef NET_IEEE802154_SECURITY_H
|
||||
#define NET_IEEE802154_SECURITY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#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
|
||||
*
|
||||
* <em>IEEE802154_SCF_SECLEVEL_MIC*</em>:
|
||||
* 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.
|
||||
*
|
||||
* <em>IEEE802154_SCF_SECLEVEL_ENC*</em>:
|
||||
* AES-128 in ECB mode is used to encrypt the payload of a frame to provide
|
||||
* confidentiality.
|
||||
*
|
||||
* <em>IEEE802154_SCF_SECLEVEL_ENC_MIC*</em>:
|
||||
* 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 */
|
||||
/** @} */
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
53
sys/net/gnrc/netif/init_devs/include/init_devs.h
Normal file
53
sys/net/gnrc/netif/init_devs/include/init_devs.h
Normal file
@ -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 <fabian.huessler@ovgu.de>
|
||||
*/
|
||||
|
||||
#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 */
|
||||
/** @} */
|
@ -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
|
||||
|
522
sys/net/link_layer/ieee802154/security.c
Normal file
522
sys/net/link_layer/ieee802154/security.c
Normal file
@ -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 <fabian.huessler@ovgu.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
5
tests/ieee802154_security/Makefile
Normal file
5
tests/ieee802154_security/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
USEMODULE += ieee802154
|
||||
USEMODULE += ieee802154_security
|
||||
USEMODULE += gnrc_netif_ieee802154
|
||||
|
||||
include ../driver_netdev_common/Makefile.netdev.mk
|
21
tests/ieee802154_security/Makefile.ci
Normal file
21
tests/ieee802154_security/Makefile.ci
Normal file
@ -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 \
|
||||
#
|
12
tests/ieee802154_security/README.md
Normal file
12
tests/ieee802154_security/README.md
Normal file
@ -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
|
40
tests/ieee802154_security/main.c
Normal file
40
tests/ieee802154_security/main.c
Normal file
@ -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 <fabian.huessler@ovgu.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user