Routines to initiate key establishment, handle key establishment callbacks, and print info about the security keys on the device.

License#

Copyright 2018 Silicon Laboratories Inc. www.silabs.com

The licensor of this software is Silicon Laboratories Inc. Your use of this software is governed by the terms of Silicon Labs Master Software License Agreement (MSLA) available at www.silabs.com/about-us/legal/master-software-license-agreement. This software is distributed to you in Source Code format and is governed by the sections of the MSLA applicable to Source Code.

/***************************************************************************/
#include "app/framework/util/common.h"

#include "app/framework/util/service-discovery.h"

#include "app/util/serial/command-interpreter2.h"
#include "app/framework/cli/security-cli.h"
#include "app/framework/util/af-main.h"

#include "app/framework/security/af-security.h"

#ifdef EZSP_HOST
 #define setTcRejoinsUsingWellKnownKeyAllowed(allow) \
  (void)ezspSetPolicy(EZSP_TC_REJOINS_USING_WELL_KNOWN_KEY_POLICY, (allow))
 #define setTcRejoinsUsingWellKnownKeyTimeout(timeout) \
  (void)ezspSetConfigurationValue(EZSP_CONFIG_TC_REJOINS_USING_WELL_KNOWN_KEY_TIMEOUT_S, (timeout))
 #define getTransientKeyTableEntry ezspGetTransientKeyTableEntry
#else  // SoC
extern uint16_t emAllowTcRejoinsUsingWellKnownKeyTimeoutSec;
 #define setTcRejoinsUsingWellKnownKeyAllowed(allow) \
  emberSetTcRejoinsUsingWellKnownKeyAllowed((allow))
 #define setTcRejoinsUsingWellKnownKeyTimeout(timeout) \
  emAllowTcRejoinsUsingWellKnownKeyTimeoutSec = (timeout)
 #define getTransientKeyTableEntry emberGetTransientKeyTableEntry
#endif

//------------------------------------------------------------------------------
// Globals

EmberKeyData cliPreconfiguredLinkKey = DUMMY_KEY;
EmberKeyData cliNetworkKey           = DUMMY_KEY;

#define EMBER_AF_DOXYGEN_CLI__SECURITY_CHANGEKEY_COMMANDS

#define EMBER_AF_DOXYGEN_CLI__SECURITY_CBKE_COMMANDS

#ifndef EMBER_AF_GENERATE_CLI

EmberCommandEntry changeKeyCommands[] = {
  { "link", changeKeyCommand, "b" },
  { "network", changeKeyCommand, "b" },
  { NULL }
};

#endif // EMBER_AF_GENERATE_CLI

#define EMBER_AF_DOXYGEN_CLI__SECURITY_MFG_TOKEN_COMMANDS

#ifndef EMBER_AF_HAS_SECURITY_PROFILE_NONE
void getSetMfgToken(void);

EmberCommandEntry mfgToken[] = {
  emberCommandEntryAction("get", getSetMfgToken, "",
                          "Print the MFG security config token"),
  emberCommandEntryAction("set", getSetMfgToken, "wv",
                          "Set the MFG Security config token.  CANNOT BE UNSET BY CLI."),
  emberCommandEntryTerminator(),
};

EmberCommandEntry emAfSecurityCommands[] = {
  emberCommandEntrySubMenu("mfg-token", mfgToken,
                           "Get/set the MFG Security config token"),
  emberCommandEntryTerminator(),
};

#endif

//------------------------------------------------------------------------------
// Forward Declarations

uint8_t printKeyTable(bool preconfiguredKey);
uint8_t printTransientKeyTable(void);
uint32_t getOutgoingApsFrameCounter(void);

//------------------------------------------------------------------------------

// ******************************************************
// changekey link    <16 byte key>
// changekey network <16 byte key>
// ******************************************************

// Changes the default link or network key that will be used when
// forming or joining a network.
void changeKeyCommand(void)
{
  if (EMBER_NO_NETWORK != emberNetworkState()) {
    emberAfCorePrintln("%pstack must be down.", "ERROR: ");
  } else {
    emberCopyKeyArgument(0,
                         emberCurrentCommand->name[0] == 'l'
                         ? &cliPreconfiguredLinkKey
                         : &cliNetworkKey);
    emberAfDebugPrintln("set key");
  }
}

// Key Establishment commands (cbke <command>) moved to
//   app/framework/plugin/key-establishment/key-establishment-cli.c

void printKeyInfo(void)
{
  uint8_t entriesUsed;
  EmberKeyStruct nwkKey;

#ifndef EMBER_AF_HAS_SECURITY_PROFILE_NONE
  {
    EmberMfgSecurityStruct config;
    if (EMBER_SUCCESS == emberGetMfgSecurityConfig(&config)) {
      if (!(config.keySettings & EMBER_KEY_PERMISSIONS_READING_ALLOWED)) {
        emberAfCorePrintln("\nWARNING:  READING OF KEY VALUES DISABLED BY MFG TOKEN\n");
        emberAfCoreFlush();
      }
    }
  }
#endif

  if ( EMBER_SUCCESS != emberGetKey(EMBER_CURRENT_NETWORK_KEY,
                                    &nwkKey)) {
    MEMSET((uint8_t*)&nwkKey, 0xFF, sizeof(EmberKeyStruct));
  }
  emberAfCorePrintln("%p out FC: %4x",
                     "NWK Key",
                     nwkKey.outgoingFrameCounter);
  emberAfCorePrintln("%p seq num: 0x%x",
                     "NWK Key",
                     nwkKey.sequenceNumber);
  emberAfCorePrint("%p: ",
                   "NWK Key");
  emberAfPrintZigbeeKey(emberKeyContents(&nwkKey.key));

  emberAfCorePrintln("%p out FC: %4x",
                     "Link Key",
                     getOutgoingApsFrameCounter());

  emberAfCorePrintln("TC %p", "Link Key");
  emberAfCoreFlush();
  printKeyTable(true);

  emberAfCorePrintln("%p Table", "Link Key");
  emberAfCoreFlush();
  entriesUsed = printKeyTable(false);
  UNUSED_VAR(entriesUsed);

  emberAfCorePrintln("%d/%d entries used.",
                     entriesUsed,
                     emberAfGetKeyTableSize());
  emberAfCoreFlush();

  emberAfCorePrintln("%p Table", "Transient Key");
  emberAfCoreFlush();

  entriesUsed = printTransientKeyTable();
  UNUSED_VAR(entriesUsed);

  emberAfCorePrintln("%d entr%s consuming %d packet buffer%s.",
                     entriesUsed,
                     entriesUsed > 1 ? "ies" : "y",
                     entriesUsed,
                     entriesUsed > 1 ? "s" : "");
  emberAfCoreFlush();
}

uint8_t printKeyTable(bool preconfiguredKey)
{
  uint8_t i;
  uint8_t entriesUsed = 0;
  uint8_t loopCount = (preconfiguredKey ? 1 : emberAfGetKeyTableSize());

  emberAfCorePrintln("Index IEEE Address         In FC     Type  Auth  Key");

  for (i = 0; i < loopCount; i++) {
    EmberKeyStruct entry;

    if (preconfiguredKey) {
      i = 0xFE; // last

      // Try to get whatever key type is stored in the pre-configured key slot.
      if (EMBER_SUCCESS
          != emberGetKey(EMBER_TRUST_CENTER_LINK_KEY, &entry) ) {
        continue;
      }
    } else if ( EMBER_SUCCESS != emberGetKeyTableEntry(i, &entry) ) {
      continue;
    } else {
      // MISRA requires ..else if.. to have a terminating else.
    }

    if (!preconfiguredKey) {
      emberAfCorePrint("%d     ", i);
    } else {
      emberAfCorePrint("-     ");
    }
    emberAfCoreDebugExec(emberAfPrintBigEndianEui64(entry.partnerEUI64));
    emberAfCorePrint("  %4x  ", entry.incomingFrameCounter);
    emberAfCorePrint("L     %c     ",
                     (entry.bitmask & EMBER_KEY_IS_AUTHORIZED
                      ? 'y'
                      : 'n'));

    emberAfPrintZigbeeKey(emberKeyContents(&(entry.key)));

    emberAfCoreFlush();
    entriesUsed++;
  }

  return entriesUsed;
}

uint8_t printTransientKeyTable(void)
{
  EmberStatus status;
  EmberTransientKeyData transientKeyData;
  uint8_t index = 0;

  emberAfCorePrintln("Index IEEE Address         NWKIndex  In FC     TTL(s) Flag    Key    ");

  status = getTransientKeyTableEntry(index, &transientKeyData);

  while (status == EMBER_SUCCESS) {
    emberAfCorePrint("%d     ", index);
    emberAfCoreDebugExec(emberAfPrintBigEndianEui64(transientKeyData.eui64));
    emberAfCorePrint("  %d       ", transientKeyData.networkIndex);
    emberAfCorePrint("  %4x  ", transientKeyData.incomingFrameCounter);
    emberAfCorePrint("0x%02X", transientKeyData.remainingTimeSeconds);
    emberAfCorePrint(" 0x%02X  ", transientKeyData.bitmask);
    emberAfPrintZigbeeKey(emberKeyContents(&(transientKeyData.keyData)));
    emberAfCorePrintln("");
    emberAfCoreFlush();

    index += 1;
    status = getTransientKeyTableEntry(index, &transientKeyData);
  }

  return index;
}

uint32_t getOutgoingApsFrameCounter(void)
{
  EmberKeyStruct entry;
  if (emberGetKey(EMBER_TRUST_CENTER_LINK_KEY, &entry) != EMBER_SUCCESS) {
    return 0xFFFFFFFFUL;
  }
  return entry.outgoingFrameCounter;
}

#ifndef EMBER_AF_HAS_SECURITY_PROFILE_NONE
void getSetMfgToken(void)
{
  EmberMfgSecurityStruct config;
  EmberStatus status;

  if (emberCurrentCommand->name[0] == 'g') {
    status = emberGetMfgSecurityConfig(&config);
    if (status == EMBER_SUCCESS) {
      emberAfSecurityPrintln("EmberKeySettings: 0x%2X", config.keySettings);
      emberAfSecurityPrintln("  Permissions: %p",
                             ((config.keySettings & EMBER_KEY_PERMISSIONS_READING_ALLOWED)
                              ? "Reading Allowed"
                              : ((config.keySettings & EMBER_KEY_PERMISSIONS_HASHING_ALLOWED)
                                 ? "Hashing only"
                                 : "NONE")));
    } else {
      emberAfSecurityPrintln("Error: Failed to get config, status: 0x%X", status);
    }
  } else {
    uint32_t magicNumber = emberUnsignedCommandArgument(0);
    config.keySettings = (EmberKeySettings)emberUnsignedCommandArgument(1);
    status = emberSetMfgSecurityConfig(magicNumber, &config);
  }

  if (status != EMBER_SUCCESS) {
    emberAfSecurityPrintln("Failed: 0x%X", status);
  }
}
#endif

void optionSecurityAllowTrustCenterRejoinUsingWellKnownKey(void)
{
  bool allow = (bool)emberUnsignedCommandArgument(0);
  setTcRejoinsUsingWellKnownKeyAllowed(allow);
  emberAfCorePrintln("Trust Center %p allow trust center rejoins using "
                     "well-known key.",
                     allow
                     ? "WILL"
                     : "WILL NOT");
}

void optionSecurityAllowTrustCenterRejoinUsingWellKnownKeyTimeout(void)
{
  uint16_t timeout = (uint16_t)emberUnsignedCommandArgument(0);
  setTcRejoinsUsingWellKnownKeyTimeout(timeout);
  emberAfCorePrintln("Set timeout for Trust Center rejoins using well-known "
                     "link key to %d seconds.",
                     timeout);
}

void optionSecuritySetKeyRequestPolicy(void)
{
#ifdef EZSP_HOST
  uint8_t tcPolicy = (uint8_t)emberUnsignedCommandArgument(0);
  uint8_t appPolicy = (uint8_t)emberUnsignedCommandArgument(1);

  // The EZSP policies are offset by EZSP_DENY_TC_KEY_REQUESTS and
  // EZSP_DENY_APP_KEY_REQUESTS, respectively
  tcPolicy += EZSP_DENY_TC_KEY_REQUESTS;
  appPolicy += EZSP_DENY_APP_KEY_REQUESTS;

  (void)ezspSetPolicy(EZSP_TC_KEY_REQUEST_POLICY, tcPolicy);
  (void)ezspSetPolicy(EZSP_APP_KEY_REQUEST_POLICY, tcPolicy);
#else // EZSP_HOST
  emberTrustCenterLinkKeyRequestPolicy = (uint8_t)emberUnsignedCommandArgument(0);
  emberAppLinkKeyRequestPolicy = (uint8_t)emberUnsignedCommandArgument(1);
#endif // EZSP_HOST
}

Macros#

#define
getTransientKeyTableEntry emberGetTransientKeyTableEntry
#define

Commands used to change the default link or network key that will be used when forming or joining a network.

#define

Command used for key establishment.

#define

Macro Definition Documentation#

setTcRejoinsUsingWellKnownKeyAllowed#

#define setTcRejoinsUsingWellKnownKeyAllowed
Value:
(allow)

Definition at line 37 of file ./app/framework/cli/security-cli.c

setTcRejoinsUsingWellKnownKeyTimeout#

#define setTcRejoinsUsingWellKnownKeyTimeout
Value:
(timeout)

Definition at line 39 of file ./app/framework/cli/security-cli.c

getTransientKeyTableEntry#

#define getTransientKeyTableEntry
Value:
emberGetTransientKeyTableEntry

Definition at line 41 of file ./app/framework/cli/security-cli.c

EMBER_AF_DOXYGEN_CLI__SECURITY_CHANGEKEY_COMMANDS#

#define EMBER_AF_DOXYGEN_CLI__SECURITY_CHANGEKEY_COMMANDS

Commands used to change the default link or network key that will be used when forming or joining a network.

changekey link <key>

  • key - 16 byte array. The Link Key provided as a 16 byte array.

changekey network <key>

  • key - 16 byte array. The Network Key provided as a 16 byte array.


Definition at line 67 of file ./app/framework/cli/security-cli.c

EMBER_AF_DOXYGEN_CLI__SECURITY_CBKE_COMMANDS#

#define EMBER_AF_DOXYGEN_CLI__SECURITY_CBKE_COMMANDS

Command used for key establishment.

   <b>cbke start &lt;new partner id&gt; &lt;destination endpoint&gt;</b>
   - new partner ID - uint16_t. The 2 byte node ID of the partner
     with whom to start cbke.

   <b>cbke interpan &lt;pan id&gt; &lt;eui64&gt;</b>
   - PAN ID - uint16_t. The 2 byte PAN ID that the target is located on.
   - eui64 - EmberEUI64. The 8 byte EUI64 of the target (big endian)

   <b>cbke partner &lt;node id&gt; &lt;endpoint&gt;</b>
   - node ID - uint16_t. The two byte node ID of the device
     with whom to initiate key establishment.
   - endpoint - uint8_t. The endpoint on which to begin
     key establishment.

Definition at line 92 of file ./app/framework/cli/security-cli.c

EMBER_AF_DOXYGEN_CLI__SECURITY_MFG_TOKEN_COMMANDS#

#define EMBER_AF_DOXYGEN_CLI__SECURITY_MFG_TOKEN_COMMANDS

Commands used for security.

security mfg-token getsecurity mfg-token set <Magic number> <EmberKeySettings value>

  • Magic number - uint32_t. The 4-byte magic number EMBER_MFG_SECURITY_CONFIG_MAGIC_NUMBER to prevent accidental execution.

  • EmberKeySettings value - uint16_t. The 2-byte value for EmberKeySettings indicating key permissions.


Definition at line 119 of file ./app/framework/cli/security-cli.c

Variable Documentation#

emAllowTcRejoinsUsingWellKnownKeyTimeoutSec#

uint16_t emAllowTcRejoinsUsingWellKnownKeyTimeoutSec

Definition at line 36 of file ./app/framework/cli/security-cli.c

cliPreconfiguredLinkKey#

EmberKeyData cliPreconfiguredLinkKey

Definition at line 47 of file ./app/framework/cli/security-cli.c

cliNetworkKey#

EmberKeyData cliNetworkKey

Definition at line 48 of file ./app/framework/cli/security-cli.c

changeKeyCommands#

EmberCommandEntry changeKeyCommands[]

Definition at line 97 of file ./app/framework/cli/security-cli.c

mfgToken#

EmberCommandEntry mfgToken[]

Definition at line 125 of file ./app/framework/cli/security-cli.c

emAfSecurityCommands#

EmberCommandEntry emAfSecurityCommands[]

Definition at line 133 of file ./app/framework/cli/security-cli.c

Function Documentation#

getSetMfgToken#

void getSetMfgToken (void )
Parameters
N/A

Definition at line 320 of file ./app/framework/cli/security-cli.c

printKeyTable#

uint8_t printKeyTable (bool preconfiguredKey)
Parameters
N/ApreconfiguredKey

Definition at line 236 of file ./app/framework/cli/security-cli.c

printTransientKeyTable#

uint8_t printTransientKeyTable (void )
Parameters
N/A

Definition at line 282 of file ./app/framework/cli/security-cli.c

getOutgoingApsFrameCounter#

uint32_t getOutgoingApsFrameCounter (void )
Parameters
N/A

Definition at line 310 of file ./app/framework/cli/security-cli.c

changeKeyCommand#

void changeKeyCommand (void )
Parameters
N/A

Definition at line 157 of file ./app/framework/cli/security-cli.c

optionSecurityAllowTrustCenterRejoinUsingWellKnownKey#

void optionSecurityAllowTrustCenterRejoinUsingWellKnownKey (void )
Parameters
N/A

Definition at line 350 of file ./app/framework/cli/security-cli.c

optionSecurityAllowTrustCenterRejoinUsingWellKnownKeyTimeout#

void optionSecurityAllowTrustCenterRejoinUsingWellKnownKeyTimeout (void )
Parameters
N/A

Definition at line 361 of file ./app/framework/cli/security-cli.c

optionSecuritySetKeyRequestPolicy#

void optionSecuritySetKeyRequestPolicy (void )
Parameters
N/A

Definition at line 370 of file ./app/framework/cli/security-cli.c