1 /* packet-rf4ce-secur.c
2 * Security related functions and objects for RF4CE dissector
3 * Copyright (C) Atmosic 2023
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "packet-rf4ce-secur.h"
13 #include "packet-zbee-security.h"
14 #include "packet-ieee802154.h"
15 #include <wsutil/wsgcrypt.h>
16 #include <epan/proto_data.h>
19 void rf4ce_print_arr(const char *str
, uint8_t *ptr
, uint16_t len
);
20 #define RF4CE_PRINT_ARR(s, p, l) rf4ce_print_arr(s, p, l)
22 #define RF4CE_PRINT_ARR(s, p, l)
23 #endif /* RF4CE_DEBUG_EN */
25 static keypair_context_t keypair_context
;
26 static key_exchange_context_t key_exchange_context
;
27 static addr_entry_t addr_table
[RF4CE_ADDR_TABLE_SIZE
];
28 static nwk_key_entry_t nwk_key_storage
[RF4CE_NWK_KEY_STORAGE_SIZE
];
29 static vendor_secret_entry_t vendor_secret_storage
[RF4CE_VENDOR_SECRET_STORAGE_SIZE
];
31 static void keypair_context_calc_key(uint8_t *nwk_key
);
32 static nwk_key_entry_t
*nwk_key_storage_get_entry_by_key(uint8_t *nwk_key
, bool key_from_gui
);
34 static void reverse(uint8_t *dest
, uint8_t *src
, uint16_t size
);
36 /* RF4CE GDP 2.0 spec, part 7.4.1 Key Exchange negotiation
37 * Default secret: This is a 128bit "secret" that is known to all devices that are certified to
38 * conform to this specification. The value shall be set to the following octet string (lowest order
40 * Note that this value should be expected to be widely known and the overall link security
41 * should not depend on this value remaining a secret.
43 uint8_t DEFAULT_SECRET
[SEC_STR_LEN
] =
44 {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
45 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
47 void keypair_context_init(const uint8_t *controller_ieee
, const uint8_t *target_ieee
, uint8_t expected_transfer_count
)
49 if ((controller_ieee
== NULL
) || (target_ieee
== NULL
))
53 memset(&keypair_context
, 0, sizeof(keypair_context_t
));
55 memcpy(keypair_context
.controller_addr
, controller_ieee
, RF4CE_IEEE_ADDR_LEN
);
56 memcpy(keypair_context
.target_addr
, target_ieee
, RF4CE_IEEE_ADDR_LEN
);
58 keypair_context
.nwk_key_exchange_transfer_expected
= expected_transfer_count
;
61 static void keypair_context_calc_key(uint8_t *nwk_key
)
63 for (int i
= 0; i
< keypair_context
.nwk_key_exchange_transfer_received
; i
++)
65 for (int j
= 0; j
< KEY_LEN
; j
++)
67 keypair_context
.nwk_key_seed
[(i
+ 1) * KEY_LEN
+ j
] ^= keypair_context
.nwk_key_seed
[i
* KEY_LEN
+ j
];
71 memcpy(nwk_key
, &keypair_context
.nwk_key_seed
[RF4CE_NWK_KEY_SEED_DATA_LENGTH
- KEY_LEN
], KEY_LEN
);
74 void keypair_context_update_seed(uint8_t *seed
, uint8_t seed_seqn
)
76 bool is_retransmit
= (seed_seqn
== keypair_context
.nwk_key_exchange_transfer_received
- 1);
77 bool is_latest_seed
= (seed_seqn
+ 1 == keypair_context
.nwk_key_exchange_transfer_expected
);
79 /* retransmitt of the latest key seed - we must to re-calculate a NWK key */
80 if (is_retransmit
&& is_latest_seed
)
82 memcpy(keypair_context
.nwk_key_seed
, keypair_context
.nwk_key_seed_prev
, RF4CE_NWK_KEY_SEED_DATA_LENGTH
);
87 memcpy(keypair_context
.nwk_key_seed_latest
, seed
, RF4CE_NWK_KEY_SEED_DATA_LENGTH
);
88 keypair_context
.nwk_key_exchange_transfer_received
= 1;
92 /* Retransmit of the previous key seed. Should take this one */
95 /* save this one as a candidate */
96 memcpy(keypair_context
.nwk_key_seed_latest
, seed
, RF4CE_NWK_KEY_SEED_DATA_LENGTH
);
98 /* move on if it's the latest seed to re-calculate a NWK key */
105 if (seed_seqn
== keypair_context
.nwk_key_exchange_transfer_received
)
107 /* Apply previous key seed, it has been accepted since we received the next one */
108 for (int i
= 0; i
< RF4CE_NWK_KEY_SEED_DATA_LENGTH
; i
++)
110 keypair_context
.nwk_key_seed
[i
] ^= keypair_context
.nwk_key_seed_latest
[i
];
113 /* save this one as a candidate */
114 memcpy(keypair_context
.nwk_key_seed_latest
, seed
, RF4CE_NWK_KEY_SEED_DATA_LENGTH
);
115 keypair_context
.nwk_key_exchange_transfer_received
+= 1;
120 uint8_t nwk_key
[KEY_LEN
] = {0};
121 addr_entry_t
*controller_addr_ent
= rf4ce_addr_table_get_addr_entry_by_ieee(keypair_context
.controller_addr
);
122 addr_entry_t
*target_addr_ent
= rf4ce_addr_table_get_addr_entry_by_ieee(keypair_context
.target_addr
);
124 /* save the current key seed to avoid retransmitts of the latest one in future */
125 memcpy(keypair_context
.nwk_key_seed_prev
, keypair_context
.nwk_key_seed
, RF4CE_NWK_KEY_SEED_DATA_LENGTH
);
127 for (int i
= 0; i
< RF4CE_NWK_KEY_SEED_DATA_LENGTH
; i
++)
129 keypair_context
.nwk_key_seed
[i
] ^= keypair_context
.nwk_key_seed_latest
[i
];
132 keypair_context_calc_key(nwk_key
);
134 nwk_key_storage_add_entry(
138 false, /* key from commissioning session */
139 true); /* is_pairing_key */
143 static nwk_key_entry_t
*nwk_key_storage_get_entry_by_key(uint8_t *nwk_key
, bool key_from_gui
)
145 nwk_key_entry_t
*entry
= NULL
;
148 while (idx
< RF4CE_NWK_KEY_STORAGE_SIZE
)
150 if (nwk_key_storage
[idx
].is_used
&& (nwk_key_storage
[idx
].key_from_gui
== key_from_gui
) && (memcmp(nwk_key_storage
[idx
].nwk_key
, nwk_key
, KEY_LEN
) == 0))
152 entry
= nwk_key_storage
+ idx
;
162 void nwk_key_storage_add_entry(uint8_t *nwk_key
, addr_entry_t
*controller_addr_ent
, addr_entry_t
*target_addr_ent
, bool key_from_gui
, bool is_pairing_key
)
164 /* find an existing entry so as not to add duplicates */
165 nwk_key_entry_t
*nwk_key_entry
= nwk_key_storage_get_entry_by_key(nwk_key
, key_from_gui
);
167 if (nwk_key_entry
== NULL
)
171 while (idx
< RF4CE_NWK_KEY_STORAGE_SIZE
)
173 if (!nwk_key_storage
[idx
].is_used
)
175 memcpy(nwk_key_storage
[idx
].nwk_key
, nwk_key
, KEY_LEN
);
176 nwk_key_storage
[idx
].controller_addr_ent
= controller_addr_ent
;
177 nwk_key_storage
[idx
].target_addr_ent
= target_addr_ent
;
178 nwk_key_storage
[idx
].key_from_gui
= key_from_gui
;
179 nwk_key_storage
[idx
].is_used
= true;
180 nwk_key_storage
[idx
].is_pairing_key
= is_pairing_key
;
189 void nwk_key_storage_release_entry(uint8_t *nwk_key
, bool key_from_gui
)
191 nwk_key_entry_t
*nwk_key_entry
= nwk_key_storage_get_entry_by_key(nwk_key
, key_from_gui
);
193 if (nwk_key_entry
!= NULL
)
195 nwk_key_entry
->is_used
= false;
199 void rf4ce_addr_table_add_addrs(const void *ieee_addr
, uint16_t short_addr
)
203 if (ieee_addr
== NULL
)
208 /* search for addresses so as not to add duplicates */
209 while (idx
< RF4CE_ADDR_TABLE_SIZE
)
211 if (addr_table
[idx
].is_used
&& (memcmp(addr_table
[idx
].ieee_addr
, ieee_addr
, RF4CE_IEEE_ADDR_LEN
) == 0) && addr_table
[idx
].short_addr
== short_addr
)
219 /* no duplicates found, search for a free slot */
221 while (idx
< RF4CE_ADDR_TABLE_SIZE
&& addr_table
[idx
].is_used
)
226 if (idx
< RF4CE_ADDR_TABLE_SIZE
)
228 memcpy(addr_table
[idx
].ieee_addr
, ieee_addr
, RF4CE_IEEE_ADDR_LEN
);
229 addr_table
[idx
].short_addr
= short_addr
;
230 addr_table
[idx
].is_used
= true;
234 bool rf4ce_addr_table_get_ieee_addr(uint8_t *ieee_addr
, packet_info
*pinfo
, bool is_src
)
236 bool addr_found
= false;
237 address_type addr_type
;
238 ieee802154_hints_t
*hints
;
239 const void *p_addr
= NULL
;
240 uint16_t short_addr
= 0xffff;
243 if ((ieee_addr
== NULL
) || (pinfo
== NULL
))
249 addr_type
= pinfo
->dl_src
.type
;
250 p_addr
= pinfo
->dl_src
.data
;
254 addr_type
= pinfo
->dl_dst
.type
;
255 p_addr
= pinfo
->dl_dst
.data
;
257 if (addr_type
== AT_EUI64
)
267 hints
= (ieee802154_hints_t
*)p_get_proto_data(wmem_file_scope(),
269 proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN
),
276 short_addr
= (is_src
) ? hints
->src16
: hints
->dst16
;
278 /* Search address in address table */
279 for (unsigned idx
= 0; idx
< RF4CE_ADDR_TABLE_SIZE
; idx
++)
281 if (addr_table
[idx
].is_used
)
283 if (addr_type
== AT_EUI64
)
285 if (memcmp(addr_table
[idx
].ieee_addr
, p_addr
, RF4CE_IEEE_ADDR_LEN
) == 0) {
291 if (addr_table
[idx
].short_addr
== short_addr
) {
297 memcpy(ieee_addr
, addr_table
[idx
].ieee_addr
, RF4CE_IEEE_ADDR_LEN
);
305 addr_entry_t
*rf4ce_addr_table_get_addr_entry_by_ieee(uint8_t *ieee_addr
)
307 addr_entry_t
*entry
= NULL
;
310 while (ieee_addr
!= NULL
&& idx
< RF4CE_ADDR_TABLE_SIZE
)
312 if (addr_table
[idx
].is_used
&& memcmp(addr_table
[idx
].ieee_addr
, ieee_addr
, RF4CE_IEEE_ADDR_LEN
) == 0)
314 entry
= addr_table
+ idx
;
324 void key_exchange_context_init(void)
326 memset(&key_exchange_context
.rand_a
, 0, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
);
327 memset(&key_exchange_context
.rand_b
, 0, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
);
328 memset(&key_exchange_context
.mac_a
, 0, RF4CE_IEEE_ADDR_LEN
);
329 memset(&key_exchange_context
.mac_b
, 0, RF4CE_IEEE_ADDR_LEN
);
332 void key_exchange_context_start_procedure(void)
334 if (!key_exchange_context
.is_proc_started
)
336 key_exchange_context
.is_proc_started
= true;
340 void key_exchange_context_stop_procedure(void)
342 if (key_exchange_context
.is_proc_started
)
344 key_exchange_context
.is_proc_started
= false;
348 bool key_exchange_context_is_procedure_started(void)
350 return key_exchange_context
.is_proc_started
;
353 void key_exchange_context_set_rand_a(uint8_t *rand_a
)
357 memcpy(key_exchange_context
.rand_a
, rand_a
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
);
361 void key_exchange_context_set_rand_b(uint8_t *rand_b
)
365 memcpy(key_exchange_context
.rand_b
, rand_b
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
);
369 void key_exchange_context_set_mac_a(uint8_t *mac_a
)
373 memcpy(key_exchange_context
.mac_a
, mac_a
, RF4CE_IEEE_ADDR_LEN
);
377 void key_exchange_context_set_mac_b(uint8_t *mac_b
)
381 memcpy(key_exchange_context
.mac_b
, mac_b
, RF4CE_IEEE_ADDR_LEN
);
385 #ifdef RF4CE_DEBUG_EN
386 void rf4ce_print_arr(const char *str
, uint8_t *ptr
, uint16_t len
)
388 g_print("%s: ", str
);
389 for (uint16_t i
= 0; i
< len
-1; i
++)
391 g_print("%02x:", *(ptr
+i
));
393 g_print("%02x\n", *(ptr
+len
-1));
395 #endif /* RF4CE_DEBUG_EN */
397 static bool calc_key_cmac(uint8_t *secret
, uint8_t *nwk_key
, uint32_t tag_b_pack
, uint8_t *key_out
)
399 uint8_t mac_a
[RF4CE_IEEE_ADDR_LEN
];
400 uint8_t mac_b
[RF4CE_IEEE_ADDR_LEN
];
402 uint8_t *rand_a
= key_exchange_context
.rand_a
;
403 uint8_t *rand_b
= key_exchange_context
.rand_b
;
405 uint8_t k_dk_data
[RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
+
406 RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
];
407 uint8_t k_dk_data_reversed
[RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
+
408 RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
];
410 uint8_t context_data
[CONTEXT_STR_LEN
+ RF4CE_IEEE_ADDR_LEN
+
411 RF4CE_IEEE_ADDR_LEN
+ KEY_LEN
];
413 uint8_t k_dk_key
[KEY_LEN
];
414 uint8_t new_key
[KEY_LEN
];
416 uint8_t dummy
[KEY_LEN
];
421 reverse(mac_a
, key_exchange_context
.mac_a
, RF4CE_IEEE_ADDR_LEN
);
422 reverse(mac_b
, key_exchange_context
.mac_b
, RF4CE_IEEE_ADDR_LEN
);
424 data_ptr
= k_dk_data
;
425 memcpy(data_ptr
, rand_a
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
);
426 data_ptr
+= RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
;
427 memcpy(data_ptr
, rand_b
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
);
429 data_ptr
= k_dk_data_reversed
;
430 memcpy(data_ptr
, rand_b
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
);
431 data_ptr
+= RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_B_LENGTH
;
432 memcpy(data_ptr
, rand_a
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_RAND_A_LENGTH
);
434 data_ptr
= context_data
;
435 memcpy(data_ptr
, CONTEXT_STR
, CONTEXT_STR_LEN
);
436 data_ptr
+= CONTEXT_STR_LEN
;
437 memcpy(data_ptr
, mac_a
, RF4CE_IEEE_ADDR_LEN
);
438 data_ptr
+= RF4CE_IEEE_ADDR_LEN
;
439 memcpy(data_ptr
, mac_b
, RF4CE_IEEE_ADDR_LEN
);
440 data_ptr
+= RF4CE_IEEE_ADDR_LEN
;
441 memcpy(data_ptr
, nwk_key
, KEY_LEN
);
443 /* Generic Device Profile Version 2.0
444 * 7.4.2 Key generation
445 * Calculate derivation key
446 * K_dk = AES-128-CMAC (RAND-A || RAND-B, Shared secret)
448 rf4ce_aes_cmac(secret
, SEC_STR_LEN
, k_dk_data
, k_dk_key
);
450 /* Calculate new link key
451 * Link key = AES-128-CMAC (K_dk, context || label || pairing key)
453 rf4ce_aes_cmac(context_data
, sizeof(context_data
), k_dk_key
, new_key
);
455 /* Calculate TAG-B value
456 * TAG-B = AES-128-CMAC(link key, RAND-B || RAND-A)
458 rf4ce_aes_cmac(k_dk_data_reversed
, sizeof(k_dk_data_reversed
), new_key
, dummy
);
459 memcpy((uint8_t *)&tag_b_calc
, dummy
, RF4CE_PROFILE_CMD_KEY_EXCHANGE_TAG_A_LENGTH
);
461 RF4CE_PRINT_ARR("tag_b_calc", (uint8_t *)&tag_b_calc
, 4);
462 RF4CE_PRINT_ARR(" new_key", new_key
, 16);
464 if (tag_b_pack
== tag_b_calc
)
466 memcpy(key_out
, new_key
, KEY_LEN
);
473 static bool key_exchange_calc_key_cont(uint8_t *secret
, uint32_t tag_b_pack
, bool try_pairing_key
, uint8_t *new_key_out
)
475 bool is_new_key_found
= false;
477 for (unsigned i
= 0; i
< RF4CE_NWK_KEY_STORAGE_SIZE
; i
++)
479 if (nwk_key_storage
[i
].is_used
&& ((try_pairing_key
&& nwk_key_storage
[i
].is_pairing_key
) || (!try_pairing_key
&& nwk_key_storage
[i
].key_from_gui
)))
481 is_new_key_found
= calc_key_cmac(secret
, nwk_key_storage
[i
].nwk_key
, tag_b_pack
, new_key_out
);
483 if (is_new_key_found
)
490 return is_new_key_found
;
493 void key_exchange_calc_key(uint32_t tag_b_pack
)
495 uint8_t *controller_addr
= key_exchange_context
.mac_a
;
496 uint8_t *target_addr
= key_exchange_context
.mac_b
;
498 addr_entry_t
*controller_addr_ent
= rf4ce_addr_table_get_addr_entry_by_ieee(controller_addr
);
499 addr_entry_t
*target_addr_ent
= rf4ce_addr_table_get_addr_entry_by_ieee(target_addr
);
503 uint8_t new_key
[KEY_LEN
];
504 bool is_new_key_found
= false;
506 for (unsigned i
= 0; i
< RF4CE_VENDOR_SECRET_STORAGE_SIZE
; i
++)
508 if (!vendor_secret_storage
[i
].is_used
)
513 secret
= vendor_secret_storage
[i
].secret
;
515 /* try all the pairing keys first */
516 is_new_key_found
= key_exchange_calc_key_cont(secret
, tag_b_pack
, true, new_key
);
519 if (!is_new_key_found
)
521 is_new_key_found
= key_exchange_calc_key_cont(secret
, tag_b_pack
, false, new_key
);
524 if (is_new_key_found
)
526 nwk_key_storage_add_entry(
530 false, /* key from the Key Exchange procedure */
531 false); /* !is_pairing_key */
538 static vendor_secret_entry_t
*vendor_secret_storage_get_entry(uint8_t *secret
)
540 vendor_secret_entry_t
*entry
= NULL
;
543 while (idx
< RF4CE_VENDOR_SECRET_STORAGE_SIZE
)
545 if (vendor_secret_storage
[idx
].is_used
&& (memcmp(vendor_secret_storage
[idx
].secret
, secret
, SEC_STR_LEN
) == 0))
547 entry
= vendor_secret_storage
+ idx
;
557 void vendor_secret_storage_add_entry(uint8_t *secret
)
560 vendor_secret_entry_t
*entry
= vendor_secret_storage_get_entry(secret
);
567 while (idx
< RF4CE_VENDOR_SECRET_STORAGE_SIZE
&& vendor_secret_storage
[idx
].is_used
)
572 if (idx
< RF4CE_VENDOR_SECRET_STORAGE_SIZE
)
574 memcpy(vendor_secret_storage
[idx
].secret
, secret
, SEC_STR_LEN
);
575 vendor_secret_storage
[idx
].is_used
= true;
579 void vendor_secret_storage_release_entry(uint8_t *secret
)
581 vendor_secret_entry_t
*entry
= vendor_secret_storage_get_entry(secret
);
585 entry
->is_used
= false;
589 void rf4ce_secur_cleanup(void)
593 memset(&keypair_context
, 0, sizeof(keypair_context
));
594 memset(addr_table
, 0, sizeof(addr_table
));
596 while (idx
< RF4CE_NWK_KEY_STORAGE_SIZE
)
598 if (nwk_key_storage
[idx
].is_used
&& !nwk_key_storage
[idx
].key_from_gui
)
600 nwk_key_storage
[idx
].is_used
= false;
607 static void reverse(uint8_t *dest
, uint8_t *src
, uint16_t size
)
609 for (int i
= 0; i
< size
; i
++)
611 dest
[size
- i
- 1] = src
[i
];
616 const uint8_t *in
, uint8_t *out
,
617 uint16_t payload_offset
,
619 uint8_t src_ieee
[RF4CE_IEEE_ADDR_LEN
], uint8_t dst_ieee
[RF4CE_IEEE_ADDR_LEN
])
622 uint8_t frame_control
= *in
;
625 if (*len
< RF4CE_MIN_NWK_LENGTH
|| *len
> RF4CE_MAX_NWK_LENGTH
)
630 while (idx
< RF4CE_NWK_KEY_STORAGE_SIZE
)
632 if (nwk_key_storage
[idx
].is_used
)
636 /* Form the nonce (3.5.11.3 Outgoing frame security) */
637 uint8_t nonce
[RF4CE_IEEE_ADDR_LEN
+ 4 + 1];
640 /* Source IEEE address */
641 reverse(data_ptr
, src_ieee
, RF4CE_IEEE_ADDR_LEN
);
642 data_ptr
+= RF4CE_IEEE_ADDR_LEN
;
643 /* Fetch frame counter from the packet (don't check) */
644 memcpy(data_ptr
, in
+ 1, 4);
647 *data_ptr
= RF4CE_SECUR_CONTROL
;
649 /* Form the auth string (3.5.11.3 Outgoing frame security) */
650 uint8_t auth
[1 + 4 + RF4CE_IEEE_ADDR_LEN
];
653 /* Frame control field */
654 *data_ptr
= frame_control
;
656 /* Fetch frame counter from the packet (don't check) */
657 memcpy(data_ptr
, in
+ 1, 4);
659 /* Destination IEEE address */
660 reverse(data_ptr
, dst_ieee
, RF4CE_IEEE_ADDR_LEN
);
662 ret
= zbee_sec_ccm_decrypt(nwk_key_storage
[idx
].nwk_key
,
668 *len
- payload_offset
- RF4CE_CCM_M
,
673 *len
= *len
- payload_offset
- RF4CE_CCM_M
;
684 // Calculate the CMAC
685 void rf4ce_aes_cmac(unsigned char *input
, unsigned long length
, unsigned char *key
, unsigned char *mac_value
)
687 gcry_mac_hd_t mac_hd
;
690 if (gcry_mac_open(&mac_hd
, GCRY_MAC_CMAC_AES
, 0, NULL
))
694 if (gcry_mac_setkey(mac_hd
, key
, KEY_LEN
))
696 gcry_mac_close(mac_hd
);
699 if (gcry_mac_write(mac_hd
, input
, length
))
701 gcry_mac_close(mac_hd
);
704 if (gcry_mac_read(mac_hd
, mac_value
, &l
))
706 gcry_mac_close(mac_hd
);
709 gcry_mac_close(mac_hd
);