/*************************************************************************************************/ /*! * \file * * \brief SMP main module. * * Copyright (c) 2010-2018 Arm Ltd. * * Copyright (c) 2019 Packetcraft, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************************************/ #ifndef SMP_MAIN_H #define SMP_MAIN_H #include "sec_api.h" #include "wsf_timer.h" #include "l2c_api.h" #include "dm_api.h" #include "smp_api.h" #ifdef __cplusplus extern "C" { #endif /************************************************************************************************** Macros **************************************************************************************************/ /* State machine table constants */ #define SMP_SM_POS_EVENT 0 /* Column position for event */ #define SMP_SM_POS_NEXT_STATE 1 /* Column position for next state */ #define SMP_SM_POS_ACTION 2 /* Column position for action */ #define SMP_SM_NUM_COLS 3 /* Number of columns in state table */ #define SMP_STATE_TBL_COMMON_MAX 5 /* Number of entries in common state table */ /* Position of parameters in pairing request/response */ #define SMP_IO_POS 1 #define SMP_OOB_POS 2 #define SMP_AUTHREQ_POS 3 #define SMP_MAXKEY_POS 4 #define SMP_IKEYDIST_POS 5 #define SMP_RKEYDIST_POS 6 /* Position of parameters in public key message */ #define SMP_PUB_KEY_X_POS 1 #define SMP_PUB_KEY_Y_POS 33 /* LESC Authorization Types */ #define SMP_AUTH_TYPE_UNKNOWN 0 #define SMP_AUTH_TYPE_JUST_WORKS 1 #define SMP_AUTH_TYPE_OOB 2 #define SMP_AUTH_TYPE_PASSKEY 3 #define SMP_AUTH_TYPE_NUM_COMP 4 /*! smpi_sm state machine states */ enum { SMPI_SM_ST_IDLE, /*!< Idle */ SMPI_SM_ST_PAIR_RSP, /*!< Wait for pairing response */ SMPI_SM_ST_PIN, /*!< Wait for PIN */ SMPI_SM_ST_CNF_CALC_1, /*!< Wait for confirm calc 1 */ SMPI_SM_ST_CNF_CALC_2, /*!< Wait for confirm calc 2 */ SMPI_SM_ST_PAIR_CNF, /*!< Wait for pairing confirm */ SMPI_SM_ST_PAIR_RAND, /*!< Wait for pairing random */ SMPI_SM_ST_CNF_VER_CALC_1, /*!< Wait for confirm verify calc 1 */ SMPI_SM_ST_CNF_VER_CALC_2, /*!< Wait for confirm verify calc 2 */ SMPI_SM_ST_STK_CALC, /*!< Wait for STK calc */ SMPI_SM_ST_ENCRYPT, /*!< Wait for link encryption */ SMPI_SM_ST_KEY_DIST, /*!< Key distribution */ SMPI_SM_ST_ATTEMPTS, /*!< Repeated attempts */ SMPI_SM_ST_RSP_TO /*!< Response timeout state */ }; /*! smpr_sm state machine states */ enum { SMPR_SM_ST_IDLE, /*!< Idle */ SMPR_SM_ST_API_PAIR_REQ, /*!< Wait for API pairing request */ SMPR_SM_ST_API_PAIR_RSP, /*!< Wait for API pairing response */ SMPR_SM_ST_PIN_PAIR_1, /*!< Wait for PIN or pairing confirm 1 */ SMPR_SM_ST_PIN_PAIR_2, /*!< Wait for PIN or pairing confirm 2 */ SMPR_SM_ST_CNF_CALC_1, /*!< Wait for confirm calc 1 */ SMPR_SM_ST_CNF_CALC_2, /*!< Wait for confirm calc 2 */ SMPR_SM_ST_PAIR_RAND, /*!< Wait for pairing random */ SMPR_SM_ST_CNF_VER_CALC_1, /*!< Wait for confirm verify calc 1 */ SMPR_SM_ST_CNF_VER_CALC_2, /*!< Wait for confirm verify calc 2 */ SMPR_SM_ST_STK_CALC, /*!< Wait for STK calc */ SMPR_SM_ST_ENCRYPT, /*!< Wait for link encryption */ SMPR_SM_ST_KEY_DIST, /*!< Key distribution */ SMPR_SM_ST_ATTEMPTS, /*!< Repeated attempts */ SMPR_SM_ST_RSP_TO /*!< Response timeout state */ }; /*! smpi_sc_sm state machine states */ enum { SMPI_SC_SM_ST_IDLE, /*!< Idle */ SMPI_SC_SM_ST_PAIR_RSP, /*!< Wait for pairing response */ SMPI_SC_SM_ST_MODE_SELECT, /*!< Select the security mode (LESC or Legacy) */ SMPI_SC_SM_ST_LESC_PIN, /*!< Wait for PIN in LESC */ SMPI_SC_SM_ST_PUB_KEY, /*!< Wait for public key from peer */ SMPI_SC_SM_ST_AUTH_SELECT, /*!< Select the type of LESC pairing (Just Works, Passkey, or OOB) */ SMPI_SC_SM_ST_JWNC_WAIT_CNF, /*!< Wait for confirm in Just Works/Numeric Comparison Pairing */ SMPI_SC_SM_ST_JWNC_RAND, /*!< Wait for rand in Just Works/Numeric Comparison Pairing */ SMPI_SC_SM_ST_JWNC_CHECK_1, /*!< Calculate confirm value in Just Works/Numeric Comparison Pairing */ SMPI_SC_SM_ST_JWNC_CHECK_2, /*!< Calculate user validate value in Just Works/Numeric Comparison Pairing */ SMPI_SC_SM_ST_JWNC_WAIT_USER, /* Wait for user to validate the confirm value */ SMPI_SC_SM_ST_PK_KEYPRESS, /*!< Process a keypress command in passkey pairing */ SMPI_SC_SM_ST_PK_CALC, /*!< Calculate the confirm in passkey pairing */ SMPI_SC_SM_ST_PK_CNF, /*!< Wait for confirm in passkey pairing */ SMPI_SC_SM_ST_PK_RAND, /*!< Wait for rand in passkey pairing */ SMPI_SC_SM_ST_PK_CHECK, /*!< Check the conform value in passkey pairing */ SMPI_SC_SM_ST_PK_REPEAT, /*!< Repeat or complete the passkey pairing */ SMPI_SC_SM_ST_OOB_SEND_RAND, /*!< Send the rand in OOB pairing */ SMPI_SC_SM_ST_OOB_WAIT_RAND, /*!< Wait for a rand in OOB pairing */ SMPI_SC_SM_ST_CALC_DHKEY, /*!< Calculate the DHKEY shared secret */ SMPI_SC_SM_ST_CALC_F5_TKEY, /*!< Calculate the DHKEY T Key */ SMPI_SC_SM_ST_CALC_F5_MACKEY, /*!< Calculate the DHKEY MAC Key */ SMPI_SC_SM_ST_CALC_F5_LTK, /*!< Calculate the DHKEY LTK Key */ SMPI_SC_SM_ST_CALC_F6_EA, /*!< Calculate the DHKEY Ea Key */ SMPI_SC_SM_ST_CALC_F6_EB, /*!< Calculate the DHKEY Eb Key */ SMPI_SC_SM_ST_VERIFY_DH_CHECK, /*!< Verify the DHKEY check value */ SMPI_SC_SM_ST_LEGACY_PIN, /*!< Wait for PIN */ SMPI_SC_SM_ST_CNF_CALC_1, /*!< Wait for confirm calc 1 */ SMPI_SC_SM_ST_CNF_CALC_2, /*!< Wait for confirm calc 2 */ SMPI_SC_SM_ST_PAIR_CNF, /*!< Wait for pairing confirm */ SMPI_SC_SM_ST_PAIR_RAND, /*!< Wait for pairing random */ SMPI_SC_SM_ST_CNF_VER_CALC_1, /*!< Wait for confirm verify calc 1 */ SMPI_SC_SM_ST_CNF_VER_CALC_2, /*!< Wait for confirm verify calc 2 */ SMPI_SC_SM_ST_STK_CALC, /*!< Wait for STK calc */ SMPI_SC_SM_ST_ENCRYPT, /*!< Wait for link encryption */ SMPI_SC_SM_ST_KEY_DIST, /*!< Key distribution */ SMPI_SC_SM_ST_ATTEMPTS, /*!< Repeated attempts */ SMPI_SC_SM_ST_RSP_TO /*!< Response timeout state */ }; /*! smpr_sc_sm state machine states */ enum { SMPR_SC_SM_ST_IDLE, /*!< Idle */ SMPR_SC_SM_ST_API_PAIR_REQ, /*!< Wait for API pairing request */ SMPR_SC_SM_ST_API_PAIR_RSP, /*!< Wait for API pairing response */ SMPR_SC_SM_ST_MODE_SELECT, /*!< Select the security mode (LESC or Legacy) */ SMPR_SC_SM_ST_PUB_KEY, /*!< Wait for public key from peer */ SMPR_SC_SM_ST_LESC_PIN, /*!< Wait for pin in LESC */ SMPR_SC_SM_ST_AUTH_SELECT, /*!< Select the type of LESC pairing (Just Works, Passkey, or OOB) */ SMPR_SC_SM_ST_JWNC_SETUP, /*!< Prepare for Just Works/Numeric Comparison Pairing */ SMPR_SC_SM_ST_JWNC_WAIT_RAND, /*!< Wait for Rand in Just Works/Numeric Comparison Pairing */ SMPR_SC_SM_ST_JWNC_CALC_G2, /*!< Calculate the user validate value in Just Works/Numeric Comparison Pairing */ SMPR_SC_SM_ST_JWNC_WAIT_USER, /*!< Wait for user to validate the confirm value */ SMPR_SC_SM_ST_JWNC_WAIT_USER_DH_CHECK_RCVD, /*!< Wait for user to validate the confirm value with a received DH Key Check */ SMPR_SC_SM_ST_PK_KEYPRESS, /*!< Process a keypress command in passkey pairing */ SMPR_SC_SM_ST_PK_WAIT_AUTH, /*!< The confirm was received before the auth from the API, wait for the auth */ SMPR_SC_SM_ST_PK_WAIT_CNF, /*!< Wait for the confirm command in passkey pairing */ SMPR_SC_SM_ST_PK_CALC, /*!< Calculate the confirm in passkey pairing */ SMPR_SC_SM_ST_PK_RAND, /*!< Send the rand command in passkey pairing */ SMPR_SC_SM_ST_PK_CHECK, /*!< Check the confirm in passkey pairing */ SMPR_SC_SM_ST_PK_REPEAT, /*!< Repeat or complete the passkey pairing */ SMPR_SC_SM_ST_OOB_SEND_RAND, /*!< Send the rand in OOB pairing */ SMPR_SC_SM_ST_OOB_WAIT_RAND, /*!< Wait for a rand in OOB pairing */ SMPR_SC_SM_ST_WAIT_DH_CHECK, /*!< Wait for the DH Check command */ SMPR_SC_SM_ST_CALC_DHKEY, /*!< Calculate the DHKEY shared secret */ SMPR_SC_SM_ST_CALC_F5_TKEY, /*!< Calculate the DHKEY T Key */ SMPR_SC_SM_ST_CALC_F5_MACKEY, /*!< Calculate the DHKEY MAC Key */ SMPR_SC_SM_ST_CALC_F5_LTK, /*!< Calculate the DHKEY LTK Key */ SMPR_SC_SM_ST_CALC_F6_EA, /*!< Calculate the DHKEY Ea Key */ SMPR_SC_SM_ST_CALC_F6_EB, /*!< Calculate the DHKEY Eb Key */ SMPR_SC_SM_ST_PIN_PAIR_1, /*!< Wait for PIN or pairing confirm 1 */ SMPR_SC_SM_ST_PIN_PAIR_2, /*!< Wait for PIN or pairing confirm 2 */ SMPR_SC_SM_ST_CNF_CALC_1, /*!< Wait for confirm calc 1 */ SMPR_SC_SM_ST_CNF_CALC_2, /*!< Wait for confirm calc 2 */ SMPR_SC_SM_ST_PAIR_RAND, /*!< Wait for pairing random */ SMPR_SC_SM_ST_CNF_VER_CALC_1, /*!< Wait for confirm verify calc 1 */ SMPR_SC_SM_ST_CNF_VER_CALC_2, /*!< Wait for confirm verify calc 2 */ SMPR_SC_SM_ST_STK_CALC, /*!< Wait for STK calc */ SMPR_SC_SM_ST_ENCRYPT, /*!< Wait for link encryption */ SMPR_SC_SM_ST_KEY_DIST, /*!< Key distribution */ SMPR_SC_SM_ST_ATTEMPTS, /*!< Repeated attempts */ SMPR_SC_SM_ST_RSP_TO /*!< Response timeout state */ }; /************************************************************************************************** Data Types **************************************************************************************************/ /* Data type for state machine table entry */ typedef uint8_t smpTblEntry_t[SMP_SM_NUM_COLS]; /* Pairing request/response parameters */ typedef uint8_t smpPair_t[SMP_PAIR_REQ_LEN]; /* Temporary storage structure for calculations and other data. * Note that keyInd overlaps b1 through b3 so these will be overwritten * when key exchange occurs. * * Notes on usage from start of pairing to encryption with STK: * buf.b1: PIN or OOB data * buf.b2: RAND from peer * buf.b3: pairing cnf received from peer, then STK (if responder) * buf.b4: RAND used in pairing calc * */ typedef union { struct { uint8_t b1[SMP_KEY_LEN]; uint8_t b2[SMP_KEY_LEN]; uint8_t b3[SMP_KEY_LEN]; uint8_t b4[SMP_KEY_LEN]; } buf; dmSecKeyIndEvt_t keyInd; } smpScratch_t; /* SMP message handling function type */ typedef void (*smpMsgHandler_t)(wsfMsgHdr_t *pMsg); /* SMP connection callback type */ typedef void (*smpConnCback_t)(dmEvt_t *pDmEvt); /* SMP data message type */ typedef struct { wsfMsgHdr_t hdr; /* Header structure */ uint8_t *pPacket; /* Pointer to buffer containing L2CAP packet */ } smpDataMsg_t; /* Union of event handler data types */ typedef union { wsfMsgHdr_t hdr; /* Header structure */ smpDmMsg_t dm; /* Union SMP DM message data types */ secAes_t aes; /* AES Security callback parameters structure */ smpDataMsg_t data; /* SMP data message */ } smpMsg_t; /* LE LTK Calc Scratch buffer */ typedef struct { uint8_t mac[SEC_CMAC_KEY_LEN]; /* MAC Key */ uint8_t ltk_t[SEC_CMAC_KEY_LEN]; /* LTK Key or T value of MAC/LTK calculation */ } smpScLtk_t; /* ECC DH Key */ typedef struct { uint8_t pubKeyX[SMP_PUB_KEY_LEN]; /* Public Key X */ uint8_t pubKeyY[SMP_PUB_KEY_LEN]; /* Public Key Y */ } smpScPubKey_t; /* LESC Scratch Buffers */ typedef struct { uint8_t Na_Ea[SMP_RAND_LEN]; /* Initiator Na or Ea */ uint8_t Nb_Eb[SMP_RAND_LEN]; /* Responder Nb or Eb */ uint8_t Ra[SMP_RAND_LEN]; /* Initiator Ra */ uint8_t Rb[SMP_RAND_LEN]; /* Responder Nb */ uint8_t PeerCb[SMP_RAND_LEN]; /* Peer Responder Confirm */ uint8_t PeerCa_Ea[SMP_RAND_LEN]; /* Peer Responder Confirm or DH Key Check */ } smpScScratch_t; /* SMP LESC Control Block */ typedef struct { uint8_t lescEnabled; /* TRUE when LE Secure Connection pairing in use */ uint8_t authType; /* Type of authentication (Just Works, Numeric Comparison, Passkey, or OOB) */ uint8_t kpNotify; /* TRUE when Keypress notification in use */ uint8_t pkPos; /* Current passkey bit position */ bool_t display; /* Passkey display setting */ smpScPubKey_t *pPeerPublicKey; /* Peer device's ECC Key */ smpScPubKey_t *pLocalPublicKey; /* Local device's public ECC Key */ uint8_t *pPrivateKey; /* Local device's private ECC Key */ smpScScratch_t *pScratch; /* Scratch Buffer */ smpScLtk_t *pLtk; /* LTK calculation control */ } smpScCcb_t; /* SMP connection control block */ typedef struct { wsfTimer_t rspTimer; /* Response timer */ wsfTimer_t waitTimer; /* Wait interval timer after max attempts */ smpPair_t pairReq; /* Pair request parameters */ smpPair_t pairRsp; /* Pair response parameters */ smpScratch_t *pScr; /* Pointer to scratchpad buffer */ uint8_t *pQueued; /* Pointer to queued packet buffer */ uint16_t handle; /* Connection handle */ bool_t initiator; /* TRUE if device is initiator */ bool_t secReq; /* TRUE if security request sent or received */ bool_t flowDisabled; /* TRUE if data flow disabled */ dmConnId_t connId; /* DM connection ID */ uint8_t state; /* State machine state */ uint8_t nextCmdCode; /* Command code of next expected packet */ uint8_t auth; /* Resulting authentication and bonding flags */ uint8_t token; /* AES transaction token */ uint8_t attempts; /* Failed pairing attempts */ uint8_t lastSentKey; /* Command code of last sent key */ smpScCcb_t *pScCcb; /* LE Secure Connection control blocks */ } smpCcb_t; /* State machine action function type */ typedef void (*smpAct_t)(smpCcb_t *pCcb, smpMsg_t *pMsg); /* SMP process pairing function */ typedef bool_t smpProcPairing_t(smpCcb_t *pCcb, uint8_t *pOob, uint8_t *pDisplay); /* SMP process pairing function */ typedef void smpProcAuthReq_t(smpCcb_t *pCcb, uint8_t oob, uint8_t display); /* State machine interface type */ typedef struct { smpTblEntry_t const * const *pStateTbl; /* Pointer to state table */ smpAct_t const *pActionTbl; /* Pointer to action table */ smpTblEntry_t const *pCommonTbl; /* Pointer to common action table */ } smpSmIf_t; /* SMP main control block */ typedef struct { smpCcb_t ccb[DM_CONN_MAX]; /* Legacy Connection control blocks */ smpSmIf_t const *pSlave; /* Slave state machine interface */ smpSmIf_t const *pMaster; /* Master state machine interface */ wsfHandlerId_t handlerId; /* WSF handler ID */ smpProcPairing_t *procPairing; /* Pointer to process pairing function */ smpProcAuthReq_t *procAuthReq; /* Pointer to process auth request function */ bool_t lescSupported; /* TRUE if LE Secure Connections is supported */ } smpCb_t; /************************************************************************************************** Global Variables **************************************************************************************************/ /* SMP packet length table */ extern const uint8_t smpPktLenTbl[]; /* Control block */ extern smpCb_t smpCb; /************************************************************************************************** Function Declarations **************************************************************************************************/ /* utility functions from smp main */ smpCcb_t *smpCcbByHandle(uint16_t handle); smpCcb_t *smpCcbByConnId(dmConnId_t connId); void smpCalcC1Part1(smpCcb_t *pCcb, uint8_t *pKey, uint8_t *pRand); void smpCalcC1Part2(smpCcb_t *pCcb, uint8_t *pKey, uint8_t *pPart1); void smpCalcS1(smpCcb_t *pCcb, uint8_t *pKey, uint8_t *pRand1, uint8_t *pRand2); void smpGenerateLtk(smpCcb_t *pCcb); void smpSendPkt(smpCcb_t *pCcb, uint8_t *pPkt); bool_t smpStateIdle(smpCcb_t *pCcb); void *smpMsgAlloc(uint16_t len); uint8_t smpGetScSecLevel(smpCcb_t *pCcb); /* action functions and utility functions from smp act */ void smpStartRspTimer(smpCcb_t *pCcb); void smpActNone(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpCleanup(smpCcb_t *pCcb); void smpActCleanup(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpSendPairingFailed(smpCcb_t *pCcb, uint8_t reason); void smpActPairingFailed(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActPairingCancel(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActStorePin(smpCcb_t *pCcb, smpMsg_t *pMsg); bool_t smpProcPairing(smpCcb_t *pCcb, uint8_t *pOob, uint8_t *pDisplay); void smpAuthReq(smpCcb_t *pCcb, uint8_t oob, uint8_t display); void smpActPairCnfCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActPairCnfCalc2(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActSendPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActPairCnfVerCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActPairCnfVerCalc2(smpCcb_t *pCcb, smpMsg_t *pMsg); bool_t smpSendKey(smpCcb_t *pCcb, uint8_t keyDist); bool_t smpProcRcvKey(smpCcb_t *pCcb, dmSecKeyIndEvt_t *pKeyInd, uint8_t *pBuf, uint8_t keyDist); void smpActMaxAttempts(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActAttemptRcvd(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActCheckAttempts(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActNotifyDmAttemptsFailure(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActNotifyDmRspToFailure(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpActPairingCmpl(smpCcb_t *pCcb, smpMsg_t *pMsg); void smpSmExecute(smpCcb_t *pCcb, smpMsg_t *pMsg); /* diagnostic functions */ uint8_t *smpEventStr(uint8_t eventId); uint8_t *smpStateStr(uint8_t state); /* SMP DB functions */ uint32_t SmpDbMaxAttemptReached(dmConnId_t connId); void SmpDbPairingFailed(dmConnId_t connId); uint32_t SmpDbGetPairingDisabledTime(dmConnId_t connId); void SmpDbService(void); uint8_t SmpDbGetFailureCount(dmConnId_t connId); void SmpDbSetFailureCount(dmConnId_t connId, uint8_t count); #ifdef __cplusplus }; #endif #endif /* SMP_MAIN_H */