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
65 static 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  */
85 typedef struct {
86  uint8_t u8[16];
87 } aes_key_t;
88 static aes_key_t keys[CSMA_LLSEC_MAXKEYS];
89 
90 /* assumed to be 16 bytes */
91 int
92 csma_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 /*---------------------------------------------------------------------------*/
103 static int
104 aead(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 /*---------------------------------------------------------------------------*/
164 int
165 csma_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 /*---------------------------------------------------------------------------*/
219 int
220 csma_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 /*---------------------------------------------------------------------------*/
230 int
231 csma_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  /* No security - no more processing required */
242  return hdr_len;
243  }
244 
245  LOG_INFO("LLSEC-IN: ");
246  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
247  LOG_INFO_(" ");
248  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
249  LOG_INFO_(" %d %u (%u) LV:%d KM:%d KEY:0x%02x\n", hdr_len, packetbuf_datalen(),
250  packetbuf_totlen(), packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL),
251  LLSEC_KEY_MODE,
252  LLSEC_KEY_INDEX);
253 
254  if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != CSMA_LLSEC_SECURITY_LEVEL) {
255  LOG_INFO("received frame with wrong security level (%u) from ",
256  packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL));
257  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
258  LOG_INFO_("\n");
259  return FRAMER_FAILED;
260  }
261 
262  if(LLSEC_KEY_MODE != CSMA_LLSEC_KEY_ID_MODE) {
263  LOG_INFO("received frame with wrong key id mode (%u) from ", LLSEC_KEY_MODE);
264  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
265  LOG_INFO("\n");
266  return FRAMER_FAILED;
267  }
268 
269  if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER), &linkaddr_node_addr)) {
270  LOG_INFO("frame from ourselves\n");
271  return FRAMER_FAILED;
272  }
273 
274  if(packetbuf_datalen() <= MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) {
275  LOG_ERR("MIC error - too little data in frame!\n");
276  return FRAMER_FAILED;
277  }
278 
279  packetbuf_set_datalen(packetbuf_datalen() - MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07));
280  if(!aead(hdr_len, 0)) {
281  LOG_INFO("received unauthentic frame %u from ",
282  (unsigned int) anti_replay_get_counter());
283  LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
284  LOG_INFO_("\n");
285  return FRAMER_FAILED;
286  }
287 
288  /* TODO anti-reply protection */
289  return hdr_len;
290 }
291 /*---------------------------------------------------------------------------*/
292 #else
293 /* The "unsecure" version of the create frame / parse frame */
294 int
295 csma_security_create_frame(void)
296 {
297  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
298  return NETSTACK_FRAMER.create();
299 }
300 int
301 csma_security_parse_frame(void)
302 {
303  return NETSTACK_FRAMER.parse();
304 }
305 
306 #endif /* LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER */
307 
308 /** @} */
Interface to anti-replay mechanisms.
The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
LLSEC802154 Security related configuration
Common functionality of 802.15.4-compliant llsec_drivers.
A MAC framer for IEEE 802.15.4
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
CCM* header file.
802.15.4 frame creation and parsing functions
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:149
void anti_replay_set_counter(void)
Sets the frame counter packetbuf attributes.
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
uint32_t anti_replay_get_counter(void)
Gets the frame counter from packetbuf.
Header file for the logging system
AES-128.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:136