Contiki-NG
csma-security.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017, RISE SICS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32
33/**
34 * \file
35 * CSMA security
36 * \author
37 * Joakim Eriksson <joakim.eriksson@ri.se>
38 */
39
40/**
41 * \addtogroup csma
42 * @{
43*/
44
45#include "contiki.h"
46#include "net/mac/csma/csma.h"
51#include "net/mac/llsec802154.h"
52#include "net/netstack.h"
53#include "net/packetbuf.h"
54#include "lib/ccm-star.h"
55#include "lib/aes-128.h"
56#include <stdio.h>
57#include <string.h>
58#include "ccm-star-packetbuf.h"
59/* Log configuration */
60#include "sys/log.h"
61#define LOG_MODULE "CSMA"
62#define LOG_LEVEL LOG_LEVEL_MAC
63
64#if LOG_LEVEL == LOG_LEVEL_DBG
65static const char * HEX = "0123456789ABCDEF";
66#endif
67
68#if LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER
69
70#define MIC_LEN(level) LLSEC802154_MIC_LEN(level)
71
72#if LLSEC802154_USES_EXPLICIT_KEYS
73#define LLSEC_KEY_INDEX (FRAME802154_IMPLICIT_KEY == packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE) \
74 ? 0 \
75 : packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX))
76#define LLSEC_KEY_MODE (packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE))
77#else
78#define LLSEC_KEY_INDEX (0)
79#define LLSEC_KEY_MODE (FRAME802154_IMPLICIT_KEY)
80#endif /* LLSEC802154_USES_EXPLICIT_KEYS */
81
82/**
83 * The keys for LLSEC for CSMA
84 */
85typedef struct {
86 uint8_t u8[16];
87} aes_key_t;
88static aes_key_t keys[CSMA_LLSEC_MAXKEYS];
89
90/* assumed to be 16 bytes */
91int
92csma_security_set_key(uint8_t index, const uint8_t *key)
93{
94 if(key != NULL && index < CSMA_LLSEC_MAXKEYS) {
95 memcpy(keys[index].u8, key, 16);
96 return 1;
97 }
98 return 0;
99}
100
101#define N_KEYS (sizeof(keys) / sizeof(aes_key))
102/*---------------------------------------------------------------------------*/
103static int
104aead(uint8_t hdrlen, int forward)
105{
106 uint8_t totlen;
107 uint8_t nonce[CCM_STAR_NONCE_LENGTH];
108 uint8_t *m;
109 uint8_t m_len;
110 uint8_t *a;
111 uint8_t a_len;
112 uint8_t *result;
113 /* Allocate for MAX level */
114 uint8_t generated_mic[MIC_LEN(7)];
115 uint8_t *mic;
116 uint8_t key_index;
117 aes_key_t *key;
118 uint8_t with_encryption;
119
120 key_index = LLSEC_KEY_INDEX;
121 if(key_index >= CSMA_LLSEC_MAXKEYS) {
122 LOG_ERR("Key not available: %u\n", key_index);
123 return 0;
124 }
125
126 key = &keys[key_index];
127
128 ccm_star_packetbuf_set_nonce(nonce, forward);
129 totlen = packetbuf_totlen();
130 a = packetbuf_hdrptr();
131
132 with_encryption =
133 (packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x4) ? 1 : 0;
134
135 if(with_encryption) {
136 a_len = hdrlen;
137 m = a + a_len;
138 m_len = totlen - hdrlen;
139 } else {
140 a_len = totlen;
141 m = NULL;
142 m_len = 0;
143 }
144
145 mic = a + totlen;
146 result = forward ? mic : generated_mic;
147
148 CCM_STAR.set_key(key->u8);
149 CCM_STAR.aead(nonce,
150 m, m_len,
151 a, a_len,
152 result, MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07),
153 forward);
154
155 if(forward) {
156 packetbuf_set_datalen(packetbuf_datalen() + MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07));
157 return 1;
158 } else {
159 return (memcmp(generated_mic, mic, MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) == 0);
160 }
161}
162
163/*---------------------------------------------------------------------------*/
164int
165csma_security_create_frame(void)
166{
167 int hdr_len;
168
169 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
170 if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0 &&
171 LLSEC_KEY_INDEX != 0xffff) {
173 }
174
175 hdr_len = NETSTACK_FRAMER.create();
176 if(hdr_len < 0) {
177 return hdr_len;
178 }
179
180 if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0) {
181#if LOG_LEVEL == LOG_LEVEL_DBG
182 int i = 0;
183 uint8_t *p;
184 LOG_DBG(" Payload before (%d):", packetbuf_totlen());
185 p = packetbuf_hdrptr();
186 for(i = 0; i < packetbuf_totlen(); i++) {
187 LOG_DBG_("%c%c", HEX[(p[i] >> 4) & 0x0f], HEX[p[i] & 0x0f]);
188 }
189 LOG_DBG("\n");
190#endif
191
192 if(!aead(hdr_len, 1)) {
193 LOG_ERR("failed to encrypt packet to ");
194 LOG_ERR_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
195 LOG_ERR_("\n");
196 return FRAMER_FAILED;
197 }
198 LOG_INFO("LLSEC-OUT:");
199 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
200 LOG_INFO_(" ");
201 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
202 LOG_INFO_(" %u (%u) LV:%d, KEY:0x%02x\n", packetbuf_datalen(), packetbuf_totlen(),
203 packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL), LLSEC_KEY_INDEX);
204
205#if LOG_LEVEL == LOG_LEVEL_DBG
206 LOG_DBG(" Payload after: (%d)", packetbuf_totlen());
207 p = packetbuf_hdrptr();
208 for(i = 0; i < packetbuf_totlen(); i++) {
209 LOG_DBG_("%c%c", HEX[(p[i] >> 4) & 0x0f], HEX[p[i] & 0x0f]);
210 }
211 LOG_DBG_("\n");
212#endif
213
214 }
215 return hdr_len;
216}
217
218/*---------------------------------------------------------------------------*/
219int
220csma_security_frame_len(void)
221{
222 if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0 &&
223 LLSEC_KEY_INDEX != 0xffff) {
224 return NETSTACK_FRAMER.length() +
225 MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07);
226 }
227 return NETSTACK_FRAMER.length();
228}
229/*---------------------------------------------------------------------------*/
230int
231csma_security_parse_frame(void)
232{
233 int hdr_len;
234
235 hdr_len = NETSTACK_FRAMER.parse();
236 if(hdr_len < 0) {
237 return hdr_len;
238 }
239
240 if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == 0) {
241 /* From https://github.com/contiki-ng/contiki-ng/issues/1610 */
242 /* This should reject unencrypted packets */
243 #ifdef LLSEC802154_REJECT_INSECURE
244 return FRAMER_FAILED;
245 #else
246 /* No security - no more processing required */
247 return hdr_len;
248 #endif
249 }
250
251 LOG_INFO("LLSEC-IN: ");
252 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
253 LOG_INFO_(" ");
254 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
255 LOG_INFO_(" %d %u (%u) LV:%d KM:%d KEY:0x%02x\n", hdr_len, packetbuf_datalen(),
256 packetbuf_totlen(), packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL),
257 LLSEC_KEY_MODE,
258 LLSEC_KEY_INDEX);
259
260 if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != CSMA_LLSEC_SECURITY_LEVEL) {
261 LOG_INFO("received frame with wrong security level (%u) from ",
262 packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL));
263 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
264 LOG_INFO_("\n");
265 return FRAMER_FAILED;
266 }
267
268 if(LLSEC_KEY_MODE != CSMA_LLSEC_KEY_ID_MODE) {
269 LOG_INFO("received frame with wrong key id mode (%u) from ", LLSEC_KEY_MODE);
270 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
271 LOG_INFO("\n");
272 return FRAMER_FAILED;
273 }
274
275 if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER), &linkaddr_node_addr)) {
276 LOG_INFO("frame from ourselves\n");
277 return FRAMER_FAILED;
278 }
279
280 if(packetbuf_datalen() <= MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) {
281 LOG_ERR("MIC error - too little data in frame!\n");
282 return FRAMER_FAILED;
283 }
284
285 packetbuf_set_datalen(packetbuf_datalen() - MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07));
286 if(!aead(hdr_len, 0)) {
287 LOG_INFO("received unauthentic frame %u from ",
288 (unsigned int) anti_replay_get_counter());
289 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
290 LOG_INFO_("\n");
291 return FRAMER_FAILED;
292 }
293
294 /* TODO anti-reply protection */
295 return hdr_len;
296}
297/*---------------------------------------------------------------------------*/
298#else
299/* The "unsecure" version of the create frame / parse frame */
300int
301csma_security_create_frame(void)
302{
303 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
304 return NETSTACK_FRAMER.create();
305}
306int
307csma_security_parse_frame(void)
308{
309 return NETSTACK_FRAMER.parse();
310}
311
312#endif /* LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER */
313
314/** @} */
AES-128.
Interface to anti-replay mechanisms.
CCM* header file.
LLSEC802154 Security related configuration.
The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
802.15.4 frame creation and parsing functions
A MAC framer for IEEE 802.15.4.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
uint32_t anti_replay_get_counter(void)
Gets the frame counter from packetbuf.
void anti_replay_set_counter(void)
Sets the frame counter packetbuf attributes.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:149
Common functionality of 802.15.4-compliant llsec_drivers.
Header file for the logging system.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.