Contiki 3.x
noncoresec.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Hasso-Plattner-Institut.
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  * 802.15.4 security implementation, which uses a network-wide key
36  * \author
37  * Konrad Krentz <konrad.krentz@gmail.com>
38  */
39 
40 /**
41  * \addtogroup noncoresec
42  * @{
43  */
44 
46 #include "net/llsec/anti-replay.h"
47 #include "net/llsec/llsec802154.h"
49 #include "net/mac/frame802154.h"
50 #include "net/netstack.h"
51 #include "net/packetbuf.h"
52 #include "net/nbr-table.h"
53 #include "net/linkaddr.h"
54 #include "lib/ccm-star.h"
55 #include <string.h>
56 
57 #ifdef NONCORESEC_CONF_DECORATED_FRAMER
58 #define DECORATED_FRAMER NONCORESEC_CONF_DECORATED_FRAMER
59 #else /* NONCORESEC_CONF_DECORATED_FRAMER */
60 #define DECORATED_FRAMER framer_802154
61 #endif /* NONCORESEC_CONF_DECORATED_FRAMER */
62 
63 extern const struct framer DECORATED_FRAMER;
64 
65 #ifdef NONCORESEC_CONF_SEC_LVL
66 #define SEC_LVL NONCORESEC_CONF_SEC_LVL
67 #else /* NONCORESEC_CONF_SEC_LVL */
68 #define SEC_LVL 2
69 #endif /* NONCORESEC_CONF_SEC_LVL */
70 
71 #define WITH_ENCRYPTION (SEC_LVL & (1 << 2))
72 #define MIC_LEN LLSEC802154_MIC_LEN(SEC_LVL)
73 
74 #ifdef NONCORESEC_CONF_KEY
75 #define NONCORESEC_KEY NONCORESEC_CONF_KEY
76 #else /* NONCORESEC_CONF_KEY */
77 #define NONCORESEC_KEY { 0x00 , 0x01 , 0x02 , 0x03 , \
78  0x04 , 0x05 , 0x06 , 0x07 , \
79  0x08 , 0x09 , 0x0A , 0x0B , \
80  0x0C , 0x0D , 0x0E , 0x0F }
81 #endif /* NONCORESEC_CONF_KEY */
82 
83 #define SECURITY_HEADER_LENGTH 5
84 
85 #define DEBUG 0
86 #if DEBUG
87 #include <stdio.h>
88 #define PRINTF(...) printf(__VA_ARGS__)
89 #else /* DEBUG */
90 #define PRINTF(...)
91 #endif /* DEBUG */
92 
93 #if LLSEC802154_USES_AUX_HEADER && SEC_LVL && LLSEC802154_USES_FRAME_COUNTER
94 
95 /* network-wide CCM* key */
96 static uint8_t key[16] = NONCORESEC_KEY;
97 NBR_TABLE(struct anti_replay_info, anti_replay_table);
98 
99 /*---------------------------------------------------------------------------*/
100 static int
101 aead(uint8_t hdrlen, int forward)
102 {
103  uint8_t totlen;
104  uint8_t nonce[CCM_STAR_NONCE_LENGTH];
105  uint8_t *m;
106  uint8_t m_len;
107  uint8_t *a;
108  uint8_t a_len;
109  uint8_t *result;
110  uint8_t generated_mic[MIC_LEN];
111  uint8_t *mic;
112 
113  ccm_star_packetbuf_set_nonce(nonce, forward);
114  totlen = packetbuf_totlen();
115  a = packetbuf_hdrptr();
116 #if WITH_ENCRYPTION
117  a_len = hdrlen;
118  m = a + a_len;
119  m_len = totlen - hdrlen;
120 #else /* WITH_ENCRYPTION */
121  a_len = totlen;
122  m = NULL;
123  m_len = 0;
124 #endif /* WITH_ENCRYPTION */
125 
126  mic = a + totlen;
127  result = forward ? mic : generated_mic;
128 
129  CCM_STAR.aead(nonce,
130  m, m_len,
131  a, a_len,
132  result, MIC_LEN,
133  forward);
134 
135  if(forward) {
137  return 1;
138  } else {
139  return (memcmp(generated_mic, mic, MIC_LEN) == 0);
140  }
141 }
142 /*---------------------------------------------------------------------------*/
143 static void
144 add_security_header(void)
145 {
146  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
147  packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, SEC_LVL);
148 }
149 /*---------------------------------------------------------------------------*/
150 static void
151 send(mac_callback_t sent, void *ptr)
152 {
153  add_security_header();
155  NETSTACK_MAC.send(sent, ptr);
156 }
157 /*---------------------------------------------------------------------------*/
158 static int
159 create(void)
160 {
161  int result;
162 
163  result = DECORATED_FRAMER.create();
164  if(result == FRAMER_FAILED) {
165  return result;
166  }
167 
168  aead(result, 1);
169 
170  return result;
171 }
172 /*---------------------------------------------------------------------------*/
173 static int
174 parse(void)
175 {
176  int result;
177  const linkaddr_t *sender;
178  struct anti_replay_info* info;
179 
180  result = DECORATED_FRAMER.parse();
181  if(result == FRAMER_FAILED) {
182  return result;
183  }
184 
185  if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != SEC_LVL) {
186  PRINTF("noncoresec: received frame with wrong security level\n");
187  return FRAMER_FAILED;
188  }
189  sender = packetbuf_addr(PACKETBUF_ADDR_SENDER);
190  if(linkaddr_cmp(sender, &linkaddr_node_addr)) {
191  PRINTF("noncoresec: frame from ourselves\n");
192  return FRAMER_FAILED;
193  }
194 
196 
197  if(!aead(result, 0)) {
198  PRINTF("noncoresec: received unauthentic frame %"PRIu32"\n",
200  return FRAMER_FAILED;
201  }
202 
203  info = nbr_table_get_from_lladdr(anti_replay_table, sender);
204  if(!info) {
205  info = nbr_table_add_lladdr(anti_replay_table, sender, NBR_TABLE_REASON_LLSEC, NULL);
206  if(!info) {
207  PRINTF("noncoresec: could not get nbr_table_item\n");
208  return FRAMER_FAILED;
209  }
210 
211  /*
212  * Locking avoids replay attacks due to removed neighbor table items.
213  * Unfortunately, an attacker can mount a memory-based DoS attack
214  * on this by replaying broadcast frames from other network parts.
215  * However, this is not an issue as long as the network size does not
216  * exceed NBR_TABLE_MAX_NEIGHBORS.
217  *
218  * To avoid locking, we could swap anti-replay information
219  * to external flash. Locking is also unnecessary when using
220  * pairwise session keys, as done in coresec.
221  */
222  if(!nbr_table_lock(anti_replay_table, info)) {
223  nbr_table_remove(anti_replay_table, info);
224  PRINTF("noncoresec: could not lock\n");
225  return FRAMER_FAILED;
226  }
227 
228  anti_replay_init_info(info);
229  } else {
230  if(anti_replay_was_replayed(info)) {
231  PRINTF("noncoresec: received replayed frame %"PRIu32"\n",
233  return FRAMER_FAILED;
234  }
235  }
236 
237  return result;
238 }
239 /*---------------------------------------------------------------------------*/
240 static void
241 input(void)
242 {
243  NETSTACK_NETWORK.input();
244 }
245 /*---------------------------------------------------------------------------*/
246 static int
247 length(void)
248 {
249  add_security_header();
250  return DECORATED_FRAMER.length() + MIC_LEN;
251 }
252 /*---------------------------------------------------------------------------*/
253 static void
254 init(void)
255 {
256  CCM_STAR.set_key(key);
257  nbr_table_register(anti_replay_table, NULL);
258 }
259 /*---------------------------------------------------------------------------*/
260 const struct llsec_driver noncoresec_driver = {
261  "noncoresec",
262  init,
263  send,
264  input
265 };
266 /*---------------------------------------------------------------------------*/
267 const struct framer noncoresec_framer = {
268  length,
269  create,
270  parse
271 };
272 /*---------------------------------------------------------------------------*/
273 #endif /* LLSEC802154_USES_AUX_HEADER && SEC_LVL && LLSEC802154_USES_FRAME_COUNTER */
274 
275 /** @} */
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1503
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:182
Common functionality of 802.15.4-compliant llsec_drivers.
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:164
Header file for the Rime buffer (packetbuf) management
uint32_t anti_replay_get_counter(void)
Gets the frame counter from packetbuf.
void(* send)(mac_callback_t sent_callback, void *ptr)
Secures outgoing frames before passing them to NETSTACK_MAC.
Definition: llsec.h:69
Interface to anti-replay mechanisms.
Header file for the Rime address representation
The structure of a link layer security driver.
Definition: llsec.h:62
CCM* header file.
#define NULL
The null pointer.
802.15.4 frame creation and parsing functions
802.15.4 security implementation, which uses a network-wide key
void(* init)(void)
Inits link layer security.
Definition: llsec.h:66
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:151
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:170
void anti_replay_set_counter(void)
Sets the frame counter packetbuf attributes.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
void anti_replay_init_info(struct anti_replay_info *info)
Initializes the anti-replay information about the sender.
CCM* convenience functions for MAC security
int anti_replay_was_replayed(struct anti_replay_info *info)
Checks if received frame was replayed.
Include file for the Contiki low-layer network stack (NETSTACK)