Skip to content

Commit dc2427c

Browse files
committed
Add command AT$LOCKKEYS
This AT command can be used to prevent the application from reading LoRaWAN security keys over the AT command interface. After this command has been invoked, any attempt to read LoRaWAN security keys via the ATCI will return an error (-50, access denied). This setting will remain in effect until the next reset to factory defaults. Note: This command provides only minimal accidental protection. If the application has access to USART1, USART2, or SPI ports on the modem, it could simply downgrade the modem's firmware to read the keys, or it could switch into the STM32 bootloader mode to directly read the EEPROM. LoRaWAN security keys are stored in the EEPROM in an unencrypted form. This patch represents the first step towards securing LoRaWAN security keys. Future patches may implement additional protection, e.g., store the security keys in the EEPROM in an encrypted form. Related to #121
1 parent 7e3bfab commit dc2427c

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

src/cmd.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ typedef enum cmd_errno {
4242
ERR_UNSUPPORTED = -17, // Not supported in the current band
4343
ERR_DUTYCYCLE = -18, // Cannot transmit due to duty cycling
4444
ERR_NO_CHANNEL = -19, // Channel unavailable due to LBT or error
45-
ERR_TOO_MANY = -20 // Too many link check requests
45+
ERR_TOO_MANY = -20, // Too many link check requests
46+
ERR_ACCESS_DENIED = -50 // Read access to security keys is denied
4647
} cmd_errno_t;
4748

4849

@@ -413,6 +414,8 @@ static void set_joineui(atci_param_t *param)
413414

414415
static void get_nwkskey(void)
415416
{
417+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
418+
416419
atci_print("+OK=");
417420

418421
// We operate in a backwards-compatible 1.0 mode here and in that mode, the
@@ -464,6 +467,8 @@ static void set_nwkskey(atci_param_t *param)
464467

465468
static void get_appskey(void)
466469
{
470+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
471+
467472
atci_print("+OK=");
468473
atci_print_buffer_as_hex(find_key(APP_S_KEY), SE_KEY_SIZE);
469474
EOL();
@@ -489,6 +494,8 @@ static void set_appskey(atci_param_t *param)
489494

490495
static void get_appkey(void)
491496
{
497+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
498+
492499
atci_print("+OK=");
493500
atci_print_buffer_as_hex(find_key(APP_KEY), SE_KEY_SIZE);
494501
EOL();
@@ -1675,6 +1682,8 @@ static void do_halt(atci_param_t *param)
16751682

16761683
static void get_nwkkey(void)
16771684
{
1685+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
1686+
16781687
atci_print("+OK=");
16791688
atci_print_buffer_as_hex(find_key(NWK_KEY), SE_KEY_SIZE);
16801689
EOL();
@@ -1700,6 +1709,8 @@ static void set_nwkkey(atci_param_t *param)
17001709

17011710
static void get_fnwksintkey(void)
17021711
{
1712+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
1713+
17031714
atci_print("+OK=");
17041715
atci_print_buffer_as_hex(find_key(F_NWK_S_INT_KEY), SE_KEY_SIZE);
17051716
EOL();
@@ -1725,6 +1736,8 @@ static void set_fnwksintkey(atci_param_t *param)
17251736

17261737
static void get_snwksintkey(void)
17271738
{
1739+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
1740+
17281741
atci_print("+OK=");
17291742
atci_print_buffer_as_hex(find_key(S_NWK_S_INT_KEY), SE_KEY_SIZE);
17301743
EOL();
@@ -1750,6 +1763,8 @@ static void set_snwksintkey(atci_param_t *param)
17501763

17511764
static void get_nwksenckey(void)
17521765
{
1766+
if (sysconf.lock_keys) abort(ERR_ACCESS_DENIED);
1767+
17531768
atci_print("+OK=");
17541769
atci_print_buffer_as_hex(find_key(NWK_S_ENC_KEY), SE_KEY_SIZE);
17551770
EOL();
@@ -2083,6 +2098,15 @@ static void nvm_userdata(atci_param_t *param)
20832098
}
20842099

20852100

2101+
static void lock_keys(atci_param_t *param)
2102+
{
2103+
(void)param;
2104+
sysconf.lock_keys = 1;
2105+
sysconf_modified = true;
2106+
OK_();
2107+
}
2108+
2109+
20862110
static const atci_command_t cmds[] = {
20872111
{"+UART", NULL, set_uart, get_uart, NULL, "Configure UART interface"},
20882112
{"+VER", NULL, NULL, get_version_comp, NULL, "Firmware version and build time"},
@@ -2154,6 +2178,7 @@ static const atci_command_t cmds[] = {
21542178
{"$CW", cw, NULL, NULL, NULL, "Start continuous carrier wave transmission"},
21552179
{"$CM", cm, NULL, NULL, NULL, "Start continuous modulated FSK transmission"},
21562180
{"$NVM", nvm_userdata, NULL, NULL, NULL, "Manage data in NVM user registers"},
2181+
{"$LOCKKEYS", lock_keys, NULL, NULL, NULL, "Prevent read access to security keys from ATCI"},
21572182
ATCI_COMMAND_CLAC,
21582183
ATCI_COMMAND_HELP};
21592184

src/nvm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ sysconf_t sysconf = {
8383
.default_port = 2,
8484
.data_format = 0,
8585
.sleep = 1,
86+
.lock_keys = 0,
8687
.device_class = CLASS_A,
8788
.unconfirmed_retransmissions = 1,
8889
.confirmed_retransmissions = 8

src/nvm.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,26 @@ typedef struct sysconf
2929
* indicates that the client submits payloads in binary form. The value 1
3030
* indicates that the client submits payloads in a hex form.
3131
*/
32-
uint8_t data_format;
32+
uint8_t data_format : 1;
3333

3434
/* This parameter controls whether the firmware enters low-power modes when
3535
* idle. Set to 0 to disable all low-power modes, set to 1 to enable
3636
* low-power modes.
3737
*/
38-
uint8_t sleep;
38+
uint8_t sleep : 1;
3939

4040
/* We need to keep LoRa device class here, in addition to the MIB, because
4141
* the MIB variable is reset to class A during Join. Having a separate copy
4242
* here allows us to restore the class after Join.
4343
*/
44-
uint8_t device_class;
44+
uint8_t device_class : 2;
45+
46+
/* When this flag is set to 1, the AT command interface will prevent the
47+
* application from reading the various LoRaWAN security keys. The
48+
* corresponding AT commands will return an error. This flag can be only
49+
* reset back to 0 with a factory reset.
50+
*/
51+
uint8_t lock_keys : 1;
4552

4653
/* The maximum number of retransmissions of unconfirmed uplink messages.
4754
* Receiving a downlink message from the network stops retransmissions.

0 commit comments

Comments
 (0)