You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

333 lines
14 KiB

/**
* @file zigbee.security.h
* @brief Zigbee security header file
* @author Exegin Technologies
* @copyright Copyright [2009 - 2020] Exegin Technologies Limited. All rights reserved.
*/
#ifndef ZIGBEE_SECURITY_H
#define ZIGBEE_SECURITY_H
#include <stdint.h>
#include <stdbool.h>
struct ZigBeeT;
/* Security Install Code Max Length (including CRC) */
#define ZB_SEC_INSTALL_CODE_MAX_LENGTH 18U
/* Key and Cipher strengths used by ZigBee. */
#define ZB_SEC_BLOCKSIZE 16U
#define ZB_SEC_KEYSIZE ZB_SEC_BLOCKSIZE
/* ZB_SEC_KEYSTR_SIZE is a helper to know how much to allocate
* for ascii string buffer. */
#define ZB_SEC_KEYSTR_SIZE ((ZB_SEC_KEYSIZE * 2U) + ZB_SEC_KEYSIZE /* separators */ + 1U /* NULL */)
/*
* +-----------------------------------------------------------------------------+
* | Security Security Security Data Frame Integrity |
* | level Level Sub- Attributes Encryption (length M of MIC, |
* | identifier Field in number of |
* | (Figure 18) octets) |
* +-----------------------------------------------------------------------------+
* | 0x00 000 None OFF NO (M = 0) |
* | 0x01 001 MIC-32 OFF YES (M=4) |
* | 0x02 010 MIC-64 OFF YES (M=8) |
* | 0x03 011 MIC-128 OFF YES (M=16) |
* | 0x04 100 ENC ON NO (M = 0) |
* | 0x05 101 ENC-MIC-32 ON YES (M=4) |
* | 0x06 110 ENC-MIC-64 ON YES (M=8) |
* | 0x07 111 ENC-MIC-128 ON YES (M=16) |
* +-----------------------------------------------------------------------------+
*/
#define ZB_SEC_LEVEL_NONE 0x00U
#define ZB_SEC_LEVEL_MIC32 0x01U
#define ZB_SEC_LEVEL_MIC64 0x02U
#define ZB_SEC_LEVEL_MIC128 0x03U
#define ZB_SEC_LEVEL_ENC 0x04U
#define ZB_SEC_LEVEL_ENC_MIC32 (uint8_t)(ZB_SEC_LEVEL_ENC | ZB_SEC_LEVEL_MIC32)
#define ZB_SEC_LEVEL_ENC_MIC64 (uint8_t)(ZB_SEC_LEVEL_ENC | ZB_SEC_LEVEL_MIC64)
#define ZB_SEC_LEVEL_ENC_MIC128 (uint8_t)(ZB_SEC_LEVEL_ENC | ZB_SEC_LEVEL_MIC128)
/* Macro checks security level if encryption is enabled */
#define ZB_SEC_ENCRYPTED(level) ((level & ZB_SEC_LEVEL_ENC) != 0U)
/* Macro returns the length of the MIC, can be computed
* as 4bytes * Floor((2 ^ (level - 1))), or:
* 4 * 2 ^ (level - 1) rounded down to the nearest 4 bytes.
*
* See right-most column in table above.
*/
#define ZB_SEC_MIC_LENGTH(level) ((2U << ((level) & 0x3U)) & ~0x3U)
#define ZB_SEC_MIC_LENGTH_5 4U
/* The maximum possible MIC length. */
#define ZB_SEC_MAX_MIC_LENGTH 16U
/* The length of the CCM* nonce. */
#define ZB_SEC_NONCE_LENGTH 13U
/* The maximum size of the auxilliary header. */
#define ZB_SEC_MAX_HEADER_SIZE 14U
/* Masks for the Security control header fields. (section 4.5.1)*/
#define ZB_SEC_SECCTRL_MASK_LEVEL (uint8_t)0x07U /* Bits 0-2 */
#define ZB_SEC_SECCTRL_MASK_KEYID (uint8_t)0x18U /* Bits 3-4 */
#define ZB_SEC_SECCTRL_MASK_EXTNONCE (uint8_t)0x20U /* Bits 5 */
#define ZB_SEC_SECCTRL_MASK_RESERVED (uint8_t)0x60U /* Bits 6-7 */
/* Offsets of the Security control header fields. */
#define ZB_SEC_SECCTRL_OFFSET_LEVEL 0U
#define ZB_SEC_SECCTRL_OFFSET_KEYID 3U
#define ZB_SEC_SECCTRL_OFFSET_EXTNONCE 5U
/* Key Ids (Frame Control Field). */
enum ZbSecHdrKeyIdT {
ZB_SEC_KEYID_LINK = 0x00,
ZB_SEC_KEYID_NETWORK = 0x01,
ZB_SEC_KEYID_TRANSPORT = 0x02,
ZB_SEC_KEYID_KEYLOAD = 0x03,
/* Exegin add-on - not for over-the-air */
ZB_SEC_KEYID_BOTH_LINK_NETWORK = 0xfe, /* For Update Device (send two) */
ZB_SEC_KEYID_DEFAULT = 0xff
};
/* Maximum value for a frame counter. */
#define ZB_SEC_MAX_FRAME_COUNTER 0xffffffffU
/* Frame Counter Resets are controlled much like a lollipop counter, and require
* the 'new' value to be near zero to guard against replay attacks. */
#define ZB_FRAME_COUNTER_RESET_MAX 256U
/* Key Type Enumerations (Primitives and over-the-air). */
enum ZbSecKeyTypeT {
/* Reserved -- was Trust-Center master key */
ZB_SEC_KEYTYPE_STANDARD_NWK = 0x01, /* Standard network key */
/* 0x02 -- Reserved -- was Application master key */
ZB_SEC_KEYTYPE_APP_LINK = 0x03, /* Application link key */
ZB_SEC_KEYTYPE_TC_LINK = 0x04 /* Trust-Center link key */
/* 0x05 -- Reserved -- was High security network key */
};
/*---------------------------------------------------------------
* Flags to indicate encryption used. Loosely based on enum ZbSecKeyTypeT.
*---------------------------------------------------------------
*/
#define ZB_SEC_ENCRYPT_TYPE_LINK_FLAG 0x80U
enum ZbSecEncryptT {
/* No encryption used */
ZB_SEC_ENCRYPT_TYPE_NONE = 0x00,
/* Encrypted with standard network key */
ZB_SEC_ENCRYPT_TYPE_STANDARD_NWK = 0x01,
/* Link keys */
/* ZB_SEC_ENCRYPT_TYPE_LINK_FLAG = ZB_SEC_ENCRYPT_TYPE_LINK_FLAG, */
/* Application link key */
ZB_SEC_ENCRYPT_TYPE_APP_LINK = 0x83, /* ZB_SEC_ENCRYPT_TYPE_LINK_FLAG | 0x03U */
/* Trust-Center link key */
ZB_SEC_ENCRYPT_TYPE_TC_LINK = 0x84, /* ZB_SEC_ENCRYPT_TYPE_LINK_FLAG | 0x04U */
/* Preconfigured Global Trust-Center link key */
ZB_SEC_ENCRYPT_TYPE_GLOBAL_TC_LINK = 0x90, /* ZB_SEC_ENCRYPT_TYPE_LINK_FLAG | 0x10U */
/* Distributed Global Trust-Center link key */
ZB_SEC_ENCRYPT_TYPE_DISTRIB_TC_LINK = 0xa0 /* ZB_SEC_ENCRYPT_TYPE_LINK_FLAG | 0x20U */
};
/*---------------------------------------------------------------
* CBKE Certificate Formats
*---------------------------------------------------------------
*/
/* Field sizes for the elliptic curve (NIST-K163, aka SECT-163K1) */
#define CBKE_PRIVATE_KEY_SIZE 21U /* sizeof(2^163) */
#define CBKE_COMPRESSED_PUBLIC_KEY_SIZE (CBKE_PRIVATE_KEY_SIZE + 1U)
#define CBKE_UNCOMPRESSED_PUBLIC_KEY_SIZE (2 * CBKE_PRIVATE_KEY_SIZE + 1U)
#define CBKE_SHARED_SECRET_SIZE CBKE_PRIVATE_KEY_SIZE
/* Field sizes for the elliptic curve (NIST-K283, aka SECT-283K1) */
#define CBKE2_PRIVATE_KEY_SIZE 36U /* sizeof(2^283) */
#define CBKE2_COMPRESSED_PUBLIC_KEY_SIZE (CBKE2_PRIVATE_KEY_SIZE + 1U)
#define CBKE2_UNCOMPRESSED_PUBLIC_KEY_SIZE (2U * CBKE2_PRIVATE_KEY_SIZE + 1U)
#define CBKE2_SHARED_SECRET_SIZE CBKE2_PRIVATE_KEY_SIZE
/* Size and layout of the CBKE certificate. */
#define CBKE_CERT_SUBJECT_OFFSET CBKE_COMPRESSED_PUBLIC_KEY_SIZE
#define CBKE_CERT_SUBJECT_SIZE 8U
#define CBKE_CERT_ISSUER_OFFSET (CBKE_CERT_SUBJECT_OFFSET + CBKE_CERT_SUBJECT_SIZE)
#define CBKE_CERT_ISSUER_SIZE 8U
#define CBKE_CERT_DATA_OFFSET (CBKE_CERT_ISSUER_OFFSET + CBKE_CERT_ISSUER_SIZE)
#define CBKE_CERT_DATA_SIZE 10U
#define CBKE_CERTIFICATE_SIZE (CBKE_CERT_DATA_OFFSET + CBKE_CERT_DATA_SIZE)
/* Size and layout of the CBKE2 certificate. */
#define CBKE2_CERT_TYPE_OFFSET 0U
#define CBKE2_CERT_TYPE_SIZE 1U
#define CBKE2_CERT_TYPE 0x00U
#define CBKE2_CERT_SERIAL_OFFSET (CBKE2_CERT_TYPE_SIZE)
#define CBKE2_CERT_SERIAL_SIZE 8U
#define CBKE2_CERT_CURVE_OFFSET (CBKE2_CERT_SERIAL_OFFSET + CBKE2_CERT_SERIAL_SIZE)
#define CBKE2_CERT_CURVE_SIZE 1U
#define CBKE2_CERT_CURVE CURVE_IDENTIFIER_SECT283K1
#define CBKE2_CERT_HASH_OFFSET (CBKE2_CERT_CURVE_OFFSET + CBKE2_CERT_CURVE_SIZE)
#define CBKE2_CERT_HASH_SIZE 1U
#define CBKE2_CERT_HASH HASH_IDENTIFIER_AES_MMO
#define CBKE2_CERT_ISSUER_OFFSET (CBKE2_CERT_HASH_OFFSET + CBKE2_CERT_HASH_SIZE)
#define CBKE2_CERT_ISSUER_SIZE 8U
#define CBKE2_CERT_VALID_FROM_OFFSET (CBKE2_CERT_ISSUER_OFFSET + CBKE2_CERT_ISSUER_SIZE)
#define CBKE2_CERT_VALID_FROM_SIZE 5U
#define CBKE2_CERT_VALID_TO_OFFSET (CBKE2_CERT_VALID_FROM_OFFSET + CBKE2_CERT_VALID_FROM_SIZE)
#define CBKE2_CERT_VALID_TO_SIZE 4U
#define CBKE2_CERT_SUBJECT_OFFSET (CBKE2_CERT_VALID_TO_OFFSET + CBKE2_CERT_VALID_TO_SIZE)
#define CBKE2_CERT_SUBJECT_SIZE 8U
#define CBKE2_CERT_KEY_USAGE_OFFSET (CBKE2_CERT_SUBJECT_OFFSET + CBKE2_CERT_SUBJECT_SIZE)
#define CBKE2_CERT_KEY_USAGE_SIZE 1U
#define CBKE2_CERT_KEY_USAGE KEY_USAGE_AGREEMENT
#define CBKE2_CERT_PUBLIC_KEY_OFFSET (CBKE2_CERT_KEY_USAGE_OFFSET + CBKE2_CERT_KEY_USAGE_SIZE)
#define CBKE2_CERT_PUBLIC_KEY_SIZE 37U
#define CBKE2_CERTIFICATE_SIZE (CBKE2_CERT_PUBLIC_KEY_OFFSET + CBKE2_CERT_PUBLIC_KEY_SIZE)
struct ZbZclCbkePrivateT {
uint8_t privateKey[CBKE_PRIVATE_KEY_SIZE];
uint8_t publicCaKey[CBKE_COMPRESSED_PUBLIC_KEY_SIZE];
};
struct ZbZclCbkeInfoT {
struct ZbZclCbkePrivateT keys;
uint8_t cert[CBKE_CERTIFICATE_SIZE];
uint8_t ephemeralTime; /* In seconds. If 0, CBKE_V1_EPHEMERAL_DEFAULT_TIME is used */
uint8_t confirmTime; /* In seconds. If 0, CBKE_V1_CONFIRM_DEFAULT_TIME is used */
};
struct ZbZclCbke2PrivateT {
uint8_t privateKey[CBKE2_PRIVATE_KEY_SIZE];
uint8_t publicCaKey[CBKE2_COMPRESSED_PUBLIC_KEY_SIZE];
};
struct ZbZclCbke2InfoT {
struct ZbZclCbke2PrivateT keys;
uint8_t cert[CBKE2_CERTIFICATE_SIZE];
uint8_t ephemeralTime; /* In seconds. If 0, CBKE_V2_EPHEMERAL_DEFAULT_TIME is used */
uint8_t confirmTime; /* In seconds. If 0, CBKE_V2_CONFIRM_DEFAULT_TIME is used */
};
/*---------------------------------------------------------------
* Auxiliary Frame Functions
*---------------------------------------------------------------
*/
/* Security Control Field of the Auxilliary Header */
struct ZbSecAuxHdrCtrlT {
uint8_t secLevel;
enum ZbSecHdrKeyIdT keyId;
bool extNonce;
};
/* Structure containing the fields stored in the Aux Header */
struct ZbSecAuxHdrT {
struct ZbSecAuxHdrCtrlT securityCtrl;
uint32_t frameCounter;
uint64_t srcExtAddr; /* Present if securityCtrl.extNonce */
uint8_t keySeqno; /* Present if securityCtrl.keyId = 1 (Network Key) */
};
/**
* Parses the auxiliary header into the provided structure.
* @param data Packet buffer
* @param dataLen Packet length
* @param auxHdrPtr Pointer to ZbSecAuxHdrT structure to parse data into.
* @return Number of bytes in the header, or <0 on error.
*/
int ZbSecParseAuxHdr(const uint8_t *data, unsigned int dataLen, struct ZbSecAuxHdrT *auxHdrPtr);
/**
* Append an auxillary security header to a packet
* @param data Packet buffer
* @param dataLen Packet length
* @param auxHdrPtr auxillary header struct to use
* @return Number of bytes written, or <0 on error.
*/
int ZbSecAppendAuxHdr(uint8_t *data, unsigned int dataLen, struct ZbSecAuxHdrT *auxHdrPtr);
/**
* Builds the CCM* nonce from the source address, frame counter and security control bits.
* The nonce buffer must be at least ZB_SEC_NONCE_LENGTH in size.
* @param nonce Nonce buffer (output)
* @param extAddr Source extended addres
* @param frameCounter Frame counter
* @param secCtrl Security control field
* @return None
*/
void ZbSecMakeNonce(uint8_t *nonce, uint64_t extAddr, uint32_t frameCounter, uint8_t secCtrl);
/*---------------------------------------------------------------
* Security Transformations
*---------------------------------------------------------------
*/
/**
* Performs an AES MMO hash on the selected data
* @param zb Zigbee stack instance
* @param data data to hash
* @param length length of data to hash
* @param digest hash must be AES_BLOCK_SIZE in size!
* @return
*/
bool ZbAesMmoHash(struct ZigBeeT *zb, uint8_t const *data, const unsigned int length, uint8_t *digest);
/**
* Performs the Keyed Hash function for Message Authentication. The HMAC operation described
* in section B.1.4, and specified by FIPS pub 198. This is used to trasmute the link keys into
* key-load and key-transport keys.
* @param key encryption key to use
* @param input input data
* @param keyOut output buffer
* @return
*/
void ZbSecKeyTransform(uint8_t *key, uint8_t input, uint8_t *keyOut);
/* Add a device-key-pair. NOTE: May not be supported by all platforms. */
uint8_t ZbSecAddDeviceLinkKeyByKey(struct ZigBeeT *zb, uint64_t extAddr, uint8_t *key);
uint8_t ZbSecAddDeviceLinkKeyByKeyStr(struct ZigBeeT *zb, uint64_t extAddr, char *str);
/*---------------------------------------------------------------
* Extras: Install Code Helpers (Optional, may not be included in all builds)
*---------------------------------------------------------------
*/
/* Performs redundancy checks on a ZSE installation code and optionally converts the code
* into an application link key. */
bool ZbSecInstallCodeCheck(struct ZigBeeT *zb, const void *installCode, unsigned int codeLen, void *keyOut);
/* Computes the 2-byte CRC of the input Install Code */
void ZbSecInstallCodeCrc(const uint8_t *ic_in, uint8_t ic_len, uint8_t *crc_out);
/* Add a device-key-pair using an Install Code (includes trailing 2-octet CRC). */
uint8_t ZbSecAddDeviceLinkKeyByInstallCode(struct ZigBeeT *zb, uint64_t extAddr, uint8_t *ic, unsigned int len);
/*---------------------------------------------------------------
* ECDSA Signature Validation
*---------------------------------------------------------------
*/
enum ZbSecEcdsaSigType {
ZB_SEC_ECDSA_SIG_SUITE_1,
ZB_SEC_ECDSA_SIG_SUITE_2
};
#define ZB_SEC_CRYPTO_SUITE_V2_CERT_LEN 74U
#define ZB_SEC_CRYPTO_SUITE_V2_SIG_LEN 80U /* IEEE[8] r[36] s[36] */
/**
* Description
* @param zb
* @param sig_type
* @param ca_pub_key_array
* @param ca_pub_key_len
* @param certificate Length must be ZB_SEC_CRYPTO_SUITE_V2_CERT_LEN (74 bytes)
* @param signature Length must be ZB_SEC_CRYPTO_SUITE_V2_SIG_LEN (80 bytes)
* @param image_digest Length is AES_BLOCK_SIZE (16 bytes)
* @param cert_digest Length is AES_BLOCK_SIZE (16 bytes)
* @return
*/
enum ZbStatusCodeT ZbSecEcdsaValidate(struct ZigBeeT *zb, enum ZbSecEcdsaSigType sig_type,
const uint8_t *ca_pub_key_array, unsigned int ca_pub_key_len,
const uint8_t *certificate, const uint8_t *signature,
const uint8_t *image_digest, const uint8_t *cert_digest);
#endif /* ZIGBEE_SECURITY_H */