initial commit
This commit is contained in:
+874
@@ -0,0 +1,874 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP common utility functions and action functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "dm_api.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
|
||||
#ifndef SMP_EXTRA_TRACE
|
||||
#define SMP_EXTRA_TRACE FALSE
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start SMP response timer.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpStartRspTimer(smpCcb_t *pCcb)
|
||||
{
|
||||
/* start smp response timer */
|
||||
pCcb->rspTimer.msg.event = SMP_MSG_INT_RSP_TIMEOUT;
|
||||
pCcb->rspTimer.msg.status = SMP_ERR_TIMEOUT;
|
||||
WsfTimerStartSec(&pCcb->rspTimer, SMP_TIMEOUT);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief No action.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActNone(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cleanup CCB.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpCleanup(smpCcb_t *pCcb)
|
||||
{
|
||||
/* free scratch buffer */
|
||||
if (pCcb->pScr != NULL)
|
||||
{
|
||||
WsfBufFree(pCcb->pScr);
|
||||
pCcb->pScr = NULL;
|
||||
}
|
||||
|
||||
/* stop response timer */
|
||||
WsfTimerStop(&pCcb->rspTimer);
|
||||
|
||||
/* stop wait interval timer */
|
||||
WsfTimerStop(&pCcb->waitTimer);
|
||||
|
||||
pCcb->secReq = FALSE;
|
||||
pCcb->nextCmdCode = (pCcb->initiator) ? SMP_CMD_SECURITY_REQ : SMP_CMD_PAIR_REQ;
|
||||
pCcb->lastSentKey = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Cleanup CCB.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActCleanup(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smpCleanup(pCcb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a pairing failed packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param reason Failure reason.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpSendPairingFailed(smpCcb_t *pCcb, uint8_t reason)
|
||||
{
|
||||
uint8_t *pPacket;
|
||||
uint8_t *p;
|
||||
|
||||
if ((pPacket = smpMsgAlloc(L2C_PAYLOAD_START + SMP_PAIR_FAIL_LEN)) != NULL)
|
||||
{
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_FAIL);
|
||||
UINT8_TO_BSTREAM(p, reason);
|
||||
|
||||
smpSendPkt(pCcb, pPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pairing failed.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairingFailed(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* clean up */
|
||||
smpCleanup(pCcb);
|
||||
|
||||
/* set connection idle */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_IDLE);
|
||||
|
||||
/* notify DM of pairing failure */
|
||||
pMsg->hdr.event = DM_SEC_PAIR_FAIL_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pairing cancelled by user.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairingCancel(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* send pairing failed packet */
|
||||
smpSendPairingFailed(pCcb, pMsg->hdr.status);
|
||||
|
||||
smpActPairingFailed(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store the authentication data.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActStorePin(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* copy authentication data to scratchpad */
|
||||
memcpy(pCcb->pScr->buf.b1, pMsg->dm.authRsp.authData, pMsg->dm.authRsp.authDataLen);
|
||||
|
||||
/* zero out unused pin data */
|
||||
if (pMsg->dm.authRsp.authDataLen == SMP_PIN_LEN)
|
||||
{
|
||||
memset(&pCcb->pScr->buf.b1[SMP_PIN_LEN], 0, SMP_OOB_LEN - SMP_PIN_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a pairing request and response data.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pOob Return parameter, TRUE if out-of-band data requested.
|
||||
* \param pDisplay Return parameter, TRUE if pin is to be displayed.
|
||||
*
|
||||
* \return TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t smpProcPairing(smpCcb_t *pCcb, uint8_t *pOob, uint8_t *pDisplay)
|
||||
{
|
||||
bool_t justWorks = TRUE;
|
||||
uint8_t localAuth;
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
*pDisplay = FALSE;
|
||||
*pOob = FALSE;
|
||||
|
||||
/* if OOB available use that */
|
||||
if (pCcb->pairReq[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT &&
|
||||
pCcb->pairRsp[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
*pOob = SMP_OOB_DATA_PRESENT;
|
||||
justWorks = FALSE;
|
||||
}
|
||||
/* if either device set mitm flag */
|
||||
else if ((pCcb->pairReq[SMP_AUTHREQ_POS] & SMP_AUTH_MITM_FLAG) ||
|
||||
(pCcb->pairRsp[SMP_AUTHREQ_POS] & SMP_AUTH_MITM_FLAG))
|
||||
{
|
||||
/* check for compatible I/O settings */
|
||||
if ((pCcb->pairReq[SMP_IO_POS] != SMP_IO_NO_IN_NO_OUT) && /* initiator has i/o and */
|
||||
(pCcb->pairRsp[SMP_IO_POS] != SMP_IO_NO_IN_NO_OUT) && /* responder has i/o and */
|
||||
!(((pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_ONLY) || /* both don't have display only */
|
||||
(pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_YES_NO)) &&
|
||||
((pCcb->pairRsp[SMP_IO_POS] == SMP_IO_DISP_ONLY) ||
|
||||
(pCcb->pairRsp[SMP_IO_POS] == SMP_IO_DISP_YES_NO))))
|
||||
{
|
||||
/* use pin */
|
||||
justWorks = FALSE;
|
||||
|
||||
/* check if pin should be displayed (as initiator) */
|
||||
*pDisplay =
|
||||
((pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_ONLY) || /* initiator is display only or */
|
||||
(pCcb->pairReq[SMP_IO_POS] == SMP_IO_DISP_YES_NO) || /* initiator is display y/n or */
|
||||
((pCcb->pairReq[SMP_IO_POS] == SMP_IO_KEY_DISP) && /* initiator is key/display and */
|
||||
(pCcb->pairRsp[SMP_IO_POS] == SMP_IO_KEY_ONLY || /* responder is key only or key/display */
|
||||
pCcb->pairRsp[SMP_IO_POS] == SMP_IO_KEY_DISP)));
|
||||
|
||||
/* invert display setting if we are not initiator and both are not key only */
|
||||
if (!(pCcb->pairRsp[SMP_IO_POS] == SMP_IO_KEY_ONLY &&
|
||||
pCcb->pairReq[SMP_IO_POS] == SMP_IO_KEY_ONLY))
|
||||
{
|
||||
*pDisplay ^= !pCcb->initiator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!justWorks)
|
||||
{
|
||||
/* set auth flags with mitm bit set */
|
||||
pCcb->auth = (pCcb->pairReq[SMP_AUTHREQ_POS] & pCcb->pairRsp[SMP_AUTHREQ_POS]) | SMP_AUTH_MITM_FLAG;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set auth flags with mitm bit cleared */
|
||||
pCcb->auth = pCcb->pairReq[SMP_AUTHREQ_POS] & pCcb->pairRsp[SMP_AUTHREQ_POS] & ~SMP_AUTH_MITM_FLAG;
|
||||
}
|
||||
|
||||
/* if we ended up with 'just works' but the device configuration requires authentication */
|
||||
localAuth = (pCcb->initiator) ? pCcb->pairReq[SMP_AUTHREQ_POS] : pCcb->pairRsp[SMP_AUTHREQ_POS];
|
||||
if (justWorks && (pSmpCfg->auth & localAuth & SMP_AUTH_MITM_FLAG))
|
||||
{
|
||||
/* cancel pairing */
|
||||
hdr.param = pCcb->connId;
|
||||
hdr.status = SMP_ERR_AUTH_REQ;
|
||||
hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* if max encryption key is less than our minimum */
|
||||
if (pCcb->pairReq[SMP_MAXKEY_POS] < pSmpCfg->minKeyLen ||
|
||||
pCcb->pairRsp[SMP_MAXKEY_POS] < pSmpCfg->minKeyLen)
|
||||
{
|
||||
/* cancel pairing */
|
||||
hdr.param = pCcb->connId;
|
||||
hdr.status = SMP_ERR_ENC_KEY_SIZE;
|
||||
hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Request authentication data or send ourselves an authentication response.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param oob Out-of-band data requested.
|
||||
* \param display TRUE if pin is to be displayed.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpAuthReq(smpCcb_t *pCcb, uint8_t oob, uint8_t display)
|
||||
{
|
||||
/* use a union to save a bit of memory on the stack */
|
||||
union
|
||||
{
|
||||
smpDmAuthRsp_t authRsp;
|
||||
dmSecAuthReqIndEvt_t authReq;
|
||||
} buf;
|
||||
|
||||
/* if authenticated pairing */
|
||||
if (pCcb->auth & SMP_AUTH_MITM_FLAG)
|
||||
{
|
||||
/* request pin or oob from user */
|
||||
buf.authReq.hdr.param = pCcb->connId;
|
||||
buf.authReq.hdr.event = DM_SEC_AUTH_REQ_IND;
|
||||
buf.authReq.oob = oob;
|
||||
buf.authReq.display = display;
|
||||
DmSmpCbackExec((dmEvt_t *) &buf.authReq);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else use just works; send ourselves a auth rsp with all zero pin */
|
||||
buf.authRsp.hdr.param = pCcb->connId;
|
||||
buf.authRsp.hdr.event = SMP_MSG_API_AUTH_RSP;
|
||||
buf.authRsp.authData[0] = 0;
|
||||
buf.authRsp.authData[1] = 0;
|
||||
buf.authRsp.authData[2] = 0;
|
||||
buf.authRsp.authDataLen = SMP_PIN_LEN;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &buf.authRsp);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform first part of pairing confirm calculation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairCnfCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* store authentication data */
|
||||
smpActStorePin(pCcb, pMsg);
|
||||
|
||||
/* get random number to scratchpad */
|
||||
SecRand(pCcb->pScr->buf.b4, SMP_RAND_LEN);
|
||||
|
||||
/* execute calculation */
|
||||
smpCalcC1Part1(pCcb, pCcb->pScr->buf.b1, pCcb->pScr->buf.b4);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform second part of pairing confirm calculation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairCnfCalc2(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smpCalcC1Part2(pCcb, pCcb->pScr->buf.b1, pMsg->aes.pCiphertext);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a pairing confirm packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActSendPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* set next expected packet */
|
||||
pCcb->nextCmdCode = (pCcb->initiator) ? SMP_CMD_PAIR_CNF : SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_CNF_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_CNF);
|
||||
memcpy(p, pMsg->aes.pCiphertext, SMP_CONFIRM_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform first part of the pairing confirm verification calculation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairCnfVerCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* go to start of received pairing random packet */
|
||||
p = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* store random value */
|
||||
memcpy(pCcb->pScr->buf.b2, p, SMP_RAND_LEN);
|
||||
|
||||
/* execute calculation */
|
||||
smpCalcC1Part1(pCcb, pCcb->pScr->buf.b1, p);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform first part of the pairing confirm verification calculation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairCnfVerCalc2(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smpCalcC1Part2(pCcb, pCcb->pScr->buf.b1, pMsg->aes.pCiphertext);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a key.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param keyDist Key distribution mask.
|
||||
*
|
||||
* \return TRUE if done sending keys, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t smpSendKey(smpCcb_t *pCcb, uint8_t keyDist)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
wsfMsgHdr_t *pHdr;
|
||||
|
||||
if (smpCb.lescSupported && pCcb->pScCcb->lescEnabled && pCcb->lastSentKey == 0)
|
||||
{
|
||||
dmSecKeyIndEvt_t keyInd;
|
||||
|
||||
/* pass LTK to app via DM */
|
||||
if (DmConnRole(pCcb->connId) == DM_ROLE_MASTER)
|
||||
{
|
||||
keyInd.type = DM_KEY_PEER_LTK;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyInd.type = DM_KEY_LOCAL_LTK;
|
||||
}
|
||||
|
||||
keyInd.hdr.event = DM_SEC_KEY_IND;
|
||||
keyInd.hdr.param = pCcb->connId;
|
||||
keyInd.secLevel = smpGetScSecLevel(pCcb);
|
||||
keyInd.keyData.ltk.ediv = 0;
|
||||
memset(keyInd.keyData.ltk.rand, 0, SMP_RAND8_LEN);
|
||||
Calc128Cpy(keyInd.keyData.ltk.key, pCcb->pScCcb->pLtk->ltk_t);
|
||||
DmSmpCbackExec((dmEvt_t *)&keyInd);
|
||||
|
||||
pCcb->lastSentKey = SMP_CMD_MASTER_ID;
|
||||
}
|
||||
|
||||
/* check if we're done sending keys */
|
||||
if ((keyDist == 0) ||
|
||||
(keyDist == SMP_KEY_DIST_ENC && pCcb->lastSentKey == SMP_CMD_MASTER_ID) ||
|
||||
(keyDist <= (SMP_KEY_DIST_ENC | SMP_KEY_DIST_ID) && pCcb->lastSentKey == SMP_CMD_ID_ADDR_INFO) ||
|
||||
(pCcb->lastSentKey == SMP_CMD_SIGN_INFO))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* if flow disabled return */
|
||||
if (pCcb->flowDisabled)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* allocate packet buffer for largest packet size */
|
||||
if ((pPkt = smpMsgAlloc(SMP_ENC_INFO_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
|
||||
/* determine next key to send */
|
||||
if (pCcb->lastSentKey == 0 && (keyDist & SMP_KEY_DIST_ENC))
|
||||
{
|
||||
/* generate LTK, EDIV, and RAND */
|
||||
smpGenerateLtk(pCcb);
|
||||
|
||||
/* send first part of LTK */
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_ENC_INFO);
|
||||
Calc128Cpy(p, pCcb->pScr->keyInd.keyData.ltk.key);
|
||||
}
|
||||
else if (pCcb->lastSentKey == SMP_CMD_ENC_INFO)
|
||||
{
|
||||
/* send second part of LTK */
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_MASTER_ID);
|
||||
UINT16_TO_BSTREAM(p, pCcb->pScr->keyInd.keyData.ltk.ediv);
|
||||
memcpy(p, pCcb->pScr->keyInd.keyData.ltk.rand, SMP_RAND8_LEN);
|
||||
}
|
||||
else if ((keyDist & SMP_KEY_DIST_ID) &&
|
||||
(pCcb->lastSentKey == 0 || pCcb->lastSentKey == SMP_CMD_MASTER_ID))
|
||||
{
|
||||
/* send first part of IRK */
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_ID_INFO);
|
||||
Calc128Cpy(p, DmSecGetLocalIrk());
|
||||
}
|
||||
else if (pCcb->lastSentKey == SMP_CMD_ID_INFO)
|
||||
{
|
||||
/* send second part of IRK */
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_ID_ADDR_INFO);
|
||||
UINT8_TO_BSTREAM(p, DM_ADDR_PUBLIC);
|
||||
BDA_TO_BSTREAM(p, HciGetBdAddr());
|
||||
|
||||
}
|
||||
else if ((keyDist & SMP_KEY_DIST_SIGN) &&
|
||||
(pCcb->lastSentKey == 0 || pCcb->lastSentKey == SMP_CMD_ID_ADDR_INFO ||
|
||||
pCcb->lastSentKey == SMP_CMD_MASTER_ID))
|
||||
{
|
||||
/* send SRK */
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_SIGN_INFO);
|
||||
Calc128Cpy(p, DmSecGetLocalCsrk());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* should never get here */
|
||||
WsfMsgFree(pPkt);
|
||||
SMP_TRACE_WARN2("smpSendKey unexpected state keyDist:%d lastSentKey:%d", keyDist, pCcb->lastSentKey);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* set last sent key to command code */
|
||||
pCcb->lastSentKey = pPkt[L2C_PAYLOAD_START];
|
||||
|
||||
/* send command packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
|
||||
/* if flow not disabled set up to send next key */
|
||||
if (!pCcb->flowDisabled)
|
||||
{
|
||||
if ((pHdr = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL)
|
||||
{
|
||||
pHdr->event = SMP_MSG_INT_SEND_NEXT_KEY;
|
||||
pHdr->param = pCcb->connId;
|
||||
WsfMsgSend(smpCb.handlerId, pHdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received key packet and pass it to DM if complete.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pKeyInd Key data structure allocated by caller.
|
||||
* \param pBuf Buffer containing packet.
|
||||
* \param keyDist Key distribution mask.
|
||||
*
|
||||
* \return TRUE if done receiving keys, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t smpProcRcvKey(smpCcb_t *pCcb, dmSecKeyIndEvt_t *pKeyInd, uint8_t *pBuf, uint8_t keyDist)
|
||||
{
|
||||
bool_t keyIndReady = FALSE;
|
||||
bool_t done = FALSE;
|
||||
uint8_t cmdCode;
|
||||
|
||||
/* go to start of packet */
|
||||
pBuf += L2C_PAYLOAD_START;
|
||||
cmdCode = *pBuf++;
|
||||
|
||||
if (cmdCode == SMP_CMD_ENC_INFO)
|
||||
{
|
||||
/* parse encryption information packet */
|
||||
Calc128Cpy(pKeyInd->keyData.ltk.key, pBuf);
|
||||
}
|
||||
else if (cmdCode == SMP_CMD_MASTER_ID)
|
||||
{
|
||||
/* parse master identification packet */
|
||||
BSTREAM_TO_UINT16(pKeyInd->keyData.ltk.ediv, pBuf);
|
||||
memcpy(pKeyInd->keyData.ltk.rand, pBuf, SMP_RAND8_LEN);
|
||||
pKeyInd->secLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ? DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC;
|
||||
pKeyInd->type = DM_KEY_PEER_LTK;
|
||||
keyIndReady = TRUE;
|
||||
}
|
||||
else if (cmdCode == SMP_CMD_ID_INFO)
|
||||
{
|
||||
/* parse identity information packet */
|
||||
Calc128Cpy(pKeyInd->keyData.irk.key, pBuf);
|
||||
}
|
||||
else if (cmdCode == SMP_CMD_ID_ADDR_INFO)
|
||||
{
|
||||
/* parse identity address information packet */
|
||||
BSTREAM_TO_UINT8(pKeyInd->keyData.irk.addrType, pBuf);
|
||||
BSTREAM_TO_BDA(pKeyInd->keyData.irk.bdAddr, pBuf);
|
||||
pKeyInd->type = DM_KEY_IRK;
|
||||
keyIndReady = TRUE;
|
||||
}
|
||||
else if (cmdCode == SMP_CMD_SIGN_INFO)
|
||||
{
|
||||
/* parse signing information packet */
|
||||
Calc128Cpy(pKeyInd->keyData.csrk.key, pBuf);
|
||||
pKeyInd->type = DM_KEY_CSRK;
|
||||
keyIndReady = TRUE;
|
||||
}
|
||||
|
||||
/* set up to receive next key */
|
||||
|
||||
/* if just got first part of LTK or IRK */
|
||||
if (pCcb->nextCmdCode == SMP_CMD_ENC_INFO || pCcb->nextCmdCode == SMP_CMD_ID_INFO)
|
||||
{
|
||||
/* wait for second part of LTK or IRK info */
|
||||
pCcb->nextCmdCode++;
|
||||
}
|
||||
/* else if got LTK and need IRK */
|
||||
else if ((keyDist & SMP_KEY_DIST_ID) && (pCcb->nextCmdCode == SMP_CMD_MASTER_ID))
|
||||
{
|
||||
/* wait for first part of IRK */
|
||||
pCcb->nextCmdCode = SMP_CMD_ID_INFO;
|
||||
}
|
||||
/* else if got LTK or IRK and need SRK */
|
||||
else if ((keyDist & SMP_KEY_DIST_SIGN) &&
|
||||
(pCcb->nextCmdCode == SMP_CMD_MASTER_ID || pCcb->nextCmdCode == SMP_CMD_ID_ADDR_INFO))
|
||||
{
|
||||
/* wait for SRK */
|
||||
pCcb->nextCmdCode = SMP_CMD_SIGN_INFO;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* done receiving keys */
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
/* call callback if key ready */
|
||||
if (keyIndReady)
|
||||
{
|
||||
pKeyInd->hdr.event = DM_SEC_KEY_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) pKeyInd);
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Maximum unsuccessful pairing attempts reached.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActMaxAttempts(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint32_t timeout;
|
||||
|
||||
/* send paring failed packet; note this stops the timer so call this first */
|
||||
smpActPairingCancel(pCcb, pMsg);
|
||||
|
||||
/* Check SMP device DB to determine time to wait before pairing can happen again */
|
||||
timeout = SmpDbMaxAttemptReached(pCcb->connId);
|
||||
|
||||
/* start wait interval timer */
|
||||
pCcb->waitTimer.msg.event = SMP_MSG_INT_WI_TIMEOUT;
|
||||
WsfTimerStartMs(&pCcb->waitTimer, timeout);
|
||||
|
||||
/* clear attempts count */
|
||||
pCcb->attempts = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief A pairing attempt was received while in 'repeated attempts' state.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActAttemptRcvd(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* set that attempt was received */
|
||||
pCcb->attempts = 1;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notify DM of a pairing failure due to max attempt failures.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActNotifyDmAttemptsFailure(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* notify DM of pairing failure */
|
||||
pMsg->hdr.status = SMP_ERR_ATTEMPTS;
|
||||
pMsg->hdr.event = DM_SEC_PAIR_FAIL_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notify DM of a pairing failure due to response timeout.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActNotifyDmRspToFailure(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* notify DM of pairing failure */
|
||||
pMsg->hdr.status = SMP_ERR_TIMEOUT;
|
||||
pMsg->hdr.event = DM_SEC_PAIR_FAIL_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if any pairing attempts received when leaving 'repeated attempts' state.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActCheckAttempts(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* check if attempt was received */
|
||||
if (pCcb->attempts)
|
||||
{
|
||||
pCcb->attempts = 0;
|
||||
smpSendPairingFailed(pCcb, SMP_ERR_ATTEMPTS);
|
||||
|
||||
/* notify DM of pairing failure */
|
||||
smpActNotifyDmAttemptsFailure(pCcb, pMsg);
|
||||
|
||||
smpCleanup(pCcb);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Pairing completed successfully.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpActPairingCmpl(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
dmSecPairCmplIndEvt_t pairCmpl;
|
||||
|
||||
smpCleanup(pCcb);
|
||||
|
||||
/* set connection idle */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_IDLE);
|
||||
|
||||
pairCmpl.auth = pCcb->auth;
|
||||
pairCmpl.hdr.param = pCcb->connId;
|
||||
pairCmpl.hdr.event = DM_SEC_PAIR_CMPL_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) &pairCmpl);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Execute the SMP state machine.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpSmExecute(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smpTblEntry_t const *pTblEntry;
|
||||
smpSmIf_t const *pSmIf;
|
||||
|
||||
#if SMP_EXTRA_TRACE == TRUE
|
||||
if (smpCb.lescSupported)
|
||||
SMP_TRACE_INFO2("SMP Exe: evt=%s st=%s", smpEventStr(pMsg->hdr.event), smpStateStr(pCcb->state));
|
||||
else
|
||||
#endif
|
||||
SMP_TRACE_INFO2("smpSmExecute event=%d state=%d", pMsg->hdr.event, pCcb->state);
|
||||
|
||||
/* look up state table for state */
|
||||
pSmIf = DmConnRole(pCcb->connId) == DM_ROLE_SLAVE? smpCb.pSlave : smpCb.pMaster;
|
||||
pTblEntry = pSmIf->pStateTbl[pCcb->state];
|
||||
|
||||
/* run through state machine twice; once with state table for current state
|
||||
* and once with the state table for common events
|
||||
*/
|
||||
for(;;)
|
||||
{
|
||||
/* look for event match and execute action */
|
||||
do
|
||||
{
|
||||
/* if match */
|
||||
if ((*pTblEntry)[SMP_SM_POS_EVENT] == pMsg->hdr.event)
|
||||
{
|
||||
/* set next state */
|
||||
pCcb->state = (*pTblEntry)[SMP_SM_POS_NEXT_STATE];
|
||||
|
||||
/* execute action */
|
||||
(*pSmIf->pActionTbl[(*pTblEntry)[SMP_SM_POS_ACTION]])(pCcb, pMsg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* next entry */
|
||||
pTblEntry++;
|
||||
|
||||
/* while not at end */
|
||||
} while ((*pTblEntry)[SMP_SM_POS_EVENT] != 0);
|
||||
|
||||
/* if we've reached end of the common state table */
|
||||
if (pTblEntry == (pSmIf->pCommonTbl + SMP_STATE_TBL_COMMON_MAX - 1))
|
||||
{
|
||||
/* we're done */
|
||||
break;
|
||||
}
|
||||
/* else we haven't run through common state table yet */
|
||||
else
|
||||
{
|
||||
/* set it up */
|
||||
pTblEntry = pSmIf->pCommonTbl;
|
||||
}
|
||||
}
|
||||
}
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP device database.
|
||||
*
|
||||
* Copyright (c) 2018-2019 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_timer.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Period in ms to service the database. */
|
||||
#define SMP_DB_SRV_MS 1000
|
||||
|
||||
/* Decrement a timer. */
|
||||
#define SMP_DB_DEC_TIMER(a) do { a = a > SMP_DB_SRV_MS ? a - SMP_DB_SRV_MS : 0;} while (0)
|
||||
|
||||
/* Device database indicies. */
|
||||
#define SMP_DB_COMMON_REC 0 /*! Common record used when database is full. */
|
||||
#define SMP_DB_FIRST_REC 1 /*! Index of first device specific record in database. */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bdAddr_t peerAddr; /*! Peer address. */
|
||||
uint8_t addrType; /*! Peer address type. */
|
||||
uint8_t failCount; /*! Prior attempt failure count. */
|
||||
uint16_t attemptMult; /*! Attempts timeout multiplier (0 - record not used). */
|
||||
uint32_t lockMs; /*! Time remaining until device can attempt pairing. */
|
||||
uint32_t expDecrementMs; /*! Time remaining until attempt attemptMult decreases. */
|
||||
uint32_t failCountToMs; /*! Time remaining until failCount is cleared. */
|
||||
} smpDbDevice_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block. */
|
||||
static struct
|
||||
{
|
||||
smpDbDevice_t db[SMP_DB_MAX_DEVICES]; /*! Device database. */
|
||||
wsfTimer_t serviceTimer; /*! Timer to service database. */
|
||||
} smpDbCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Ensure the SMP DB service timer is running.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void smpDbStartServiceTimer(void)
|
||||
{
|
||||
if (smpDbCb.serviceTimer.isStarted == FALSE)
|
||||
{
|
||||
WsfTimerStartMs(&smpDbCb.serviceTimer, SMP_DB_SRV_MS);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if a database record is in use.
|
||||
*
|
||||
* \param pRec Pointer to the record.
|
||||
*
|
||||
* \return TRUE if record in use, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t smpDbRecordInUse(smpDbDevice_t *pRec)
|
||||
{
|
||||
/* When failCount, lockMs, and attemptMult are zero, the record can be used for another device. */
|
||||
if (pRec->failCount > 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pRec->lockMs > 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pRec->attemptMult > 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Add a device to the database.
|
||||
*
|
||||
* \param pAddr Peer BD address.
|
||||
* \param addrType Peer BD address type.
|
||||
*
|
||||
* \return Pointer to DB record or NULL if database full.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static smpDbDevice_t *smpDbAddDevice(uint8_t *pAddr, uint8_t addrType)
|
||||
{
|
||||
smpDbDevice_t *pRec = &smpDbCb.db[SMP_DB_FIRST_REC];
|
||||
uint8_t i;
|
||||
|
||||
SMP_TRACE_INFO0("smpDbAddDevice");
|
||||
|
||||
for (i = SMP_DB_FIRST_REC; i < SMP_DB_MAX_DEVICES; i++, pRec++)
|
||||
{
|
||||
if (smpDbRecordInUse(pRec) == FALSE)
|
||||
{
|
||||
/* Reset record. */
|
||||
memset(pRec, 0, sizeof(smpDbDevice_t));
|
||||
|
||||
pRec->addrType = addrType;
|
||||
BdaCpy(pRec->peerAddr, pAddr);
|
||||
return pRec;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get a record in the database.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return Pointer to the record associated with the connection or the common record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static smpDbDevice_t *smpDbGetRecord(dmConnId_t connId)
|
||||
{
|
||||
smpDbDevice_t *pRec = &smpDbCb.db[SMP_DB_FIRST_REC];
|
||||
uint8_t addrType = DmHostAddrType(DmConnPeerAddrType(connId));
|
||||
uint8_t *pAddr = DmConnPeerAddr(connId);
|
||||
uint8_t i;
|
||||
|
||||
SMP_TRACE_INFO2("smpDbGetRecord: connId: %d type: %d", connId, addrType);
|
||||
|
||||
for (i = SMP_DB_FIRST_REC; i < SMP_DB_MAX_DEVICES; i++, pRec++)
|
||||
{
|
||||
if (smpDbRecordInUse(pRec) && (pRec->addrType == addrType) && BdaCmp(pRec->peerAddr, pAddr))
|
||||
{
|
||||
return pRec;
|
||||
}
|
||||
}
|
||||
|
||||
/* Device is not in the database, add the device. */
|
||||
pRec = smpDbAddDevice(pAddr, addrType);
|
||||
|
||||
if (pRec == NULL)
|
||||
{
|
||||
SMP_TRACE_INFO0("smpDbGetRecord: common record");
|
||||
|
||||
/* Database is full, use the common record. */
|
||||
pRec = &smpDbCb.db[SMP_DB_COMMON_REC];
|
||||
}
|
||||
|
||||
return pRec;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the SMP Database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbInit(void)
|
||||
{
|
||||
/* Stop active service timer. */
|
||||
if (smpDbCb.serviceTimer.isStarted == TRUE)
|
||||
{
|
||||
WsfTimerStop(&smpDbCb.serviceTimer);
|
||||
}
|
||||
|
||||
/* Reset control block. */
|
||||
memset(&smpDbCb, 0, sizeof(smpDbCb));
|
||||
|
||||
/* Setup service timer. */
|
||||
smpDbCb.serviceTimer.handlerId = smpCb.handlerId;
|
||||
smpDbCb.serviceTimer.msg.event = SMP_DB_SERVICE_IND;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the time (msec) that pairing is disabled for a device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return Time pairing is disabled (msec), or zero if pairing isn't disabled.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t SmpDbGetPairingDisabledTime(dmConnId_t connId)
|
||||
{
|
||||
smpDbDevice_t *pRec = smpDbGetRecord(connId);
|
||||
|
||||
SMP_TRACE_INFO3("SmpDbGetPairingDisabledTime: connId: %d period: %d attemptMult: %d",
|
||||
connId, pRec->lockMs, pRec->attemptMult);
|
||||
|
||||
return pRec->lockMs;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the count of prior failures for a device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param count Failure count.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbSetFailureCount(dmConnId_t connId, uint8_t count)
|
||||
{
|
||||
smpDbDevice_t *pRec = smpDbGetRecord(connId);
|
||||
|
||||
SMP_TRACE_INFO2("SmpDbSetFailureCount: connId: %d count: %d", connId, count);
|
||||
|
||||
pRec->failCount = count;
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
pRec->failCountToMs = pSmpCfg->maxAttemptTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the count of prior failures for a device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return The failure count.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t SmpDbGetFailureCount(dmConnId_t connId)
|
||||
{
|
||||
smpDbDevice_t *pRec = smpDbGetRecord(connId);
|
||||
|
||||
SMP_TRACE_INFO2("SmpDbGetFailureCount: connId: %d count: %d", connId, pRec->failCount);
|
||||
|
||||
return pRec->failCount;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to report max pairing attempts was reached for a device.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return Time until device can retry pairing.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint32_t SmpDbMaxAttemptReached(dmConnId_t connId)
|
||||
{
|
||||
smpDbDevice_t *pRec = smpDbGetRecord(connId);
|
||||
uint16_t multiplier;
|
||||
|
||||
SMP_TRACE_INFO1("SmpDbMaxAttemptReached: connId: %d", connId);
|
||||
|
||||
if (pRec->attemptMult == 0)
|
||||
{
|
||||
/* Due to a disconnection, a record exists but the attempt multipier hasn't been set. */
|
||||
multiplier = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
multiplier = (pRec->attemptMult * pSmpCfg->attemptExp);
|
||||
}
|
||||
|
||||
if ((pSmpCfg->attemptTimeout * multiplier) <= pSmpCfg->maxAttemptTimeout)
|
||||
{
|
||||
pRec->lockMs = pSmpCfg->attemptTimeout * multiplier;
|
||||
pRec->attemptMult = multiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Exponential increase is greater than max timeout. */
|
||||
pRec->lockMs = pSmpCfg->maxAttemptTimeout;
|
||||
}
|
||||
|
||||
pRec->expDecrementMs = pSmpCfg->attemptDecTimeout;
|
||||
|
||||
/* Ensure the service timer is running. */
|
||||
smpDbStartServiceTimer();
|
||||
|
||||
return pRec->lockMs;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to report to the SMP DB that a pairing operation failed
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbPairingFailed(dmConnId_t connId)
|
||||
{
|
||||
smpDbDevice_t *pRec = smpDbGetRecord(connId);
|
||||
|
||||
SMP_TRACE_INFO1("SmpDbPairingFailed: connId: %d", connId);
|
||||
|
||||
/* Reset exponent decrement timer. */
|
||||
pRec->expDecrementMs = pSmpCfg->attemptDecTimeout;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Service the device database timers
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbService(void)
|
||||
{
|
||||
uint8_t i;
|
||||
smpDbDevice_t *pRec = smpDbCb.db;
|
||||
|
||||
/* Service device specific records. */
|
||||
for (i = 0; i < SMP_DB_MAX_DEVICES; i++, pRec++)
|
||||
{
|
||||
if (smpDbRecordInUse(pRec))
|
||||
{
|
||||
/* Decrement all time periods. */
|
||||
SMP_DB_DEC_TIMER(pRec->expDecrementMs);
|
||||
SMP_DB_DEC_TIMER(pRec->lockMs);
|
||||
SMP_DB_DEC_TIMER(pRec->failCountToMs);
|
||||
|
||||
/* Process expDecrementMs timeout. */
|
||||
if (pRec->expDecrementMs == 0)
|
||||
{
|
||||
/* Exponential decrease of multiplier. */
|
||||
pRec->attemptMult /= pSmpCfg->attemptExp;
|
||||
|
||||
if (pRec->attemptMult)
|
||||
{
|
||||
pRec->expDecrementMs = pSmpCfg->attemptDecTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process failCountToMs timeout. */
|
||||
if (pRec->failCountToMs == 0)
|
||||
{
|
||||
pRec->failCount = 0;
|
||||
}
|
||||
|
||||
/* If the record is in use, ensure the service timer is running. */
|
||||
if (smpDbRecordInUse(pRec))
|
||||
{
|
||||
smpDbStartServiceTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove all records from the SMP database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbRemoveAllDevices(void)
|
||||
{
|
||||
/* Stop active service timer. */
|
||||
if (smpDbCb.serviceTimer.isStarted == TRUE)
|
||||
{
|
||||
WsfTimerStop(&smpDbCb.serviceTimer);
|
||||
}
|
||||
|
||||
/* Reset database. */
|
||||
memset(&smpDbCb.db, 0, sizeof(smpDbCb.db));
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Remove a device with the given identity from the SMP database.
|
||||
*`
|
||||
* \param pAddr Pointer to BD Address.
|
||||
* \param addrType BD Address type.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDbRemoveDevice(uint8_t *pAddr, uint8_t addrType)
|
||||
{
|
||||
smpDbDevice_t *pRec = &smpDbCb.db[SMP_DB_FIRST_REC];
|
||||
uint8_t peerAddrType = DmHostAddrType(addrType);
|
||||
uint8_t i;
|
||||
|
||||
for (i = SMP_DB_FIRST_REC; i < SMP_DB_MAX_DEVICES; i++, pRec++)
|
||||
{
|
||||
if (smpDbRecordInUse(pRec) && (pRec->addrType == peerAddrType) && BdaCmp(pRec->peerAddr, pAddr))
|
||||
{
|
||||
/* Reset record. */
|
||||
memset(pRec, 0, sizeof(smpDbDevice_t));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
+862
@@ -0,0 +1,862 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_math.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "dm_api.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smp_handler.h"
|
||||
#include "sec_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* SMP packet length table */
|
||||
const uint8_t smpPktLenTbl[] =
|
||||
{
|
||||
0,
|
||||
SMP_PAIR_REQ_LEN,
|
||||
SMP_PAIR_RSP_LEN,
|
||||
SMP_PAIR_CNF_LEN,
|
||||
SMP_PAIR_RAND_LEN,
|
||||
SMP_PAIR_FAIL_LEN,
|
||||
SMP_ENC_INFO_LEN,
|
||||
SMP_MASTER_ID_LEN,
|
||||
SMP_ID_INFO_LEN,
|
||||
SMP_ID_ADDR_INFO_LEN,
|
||||
SMP_SIGN_INFO_LEN,
|
||||
SMP_SECURITY_REQ_LEN,
|
||||
SMP_PUB_KEY_MSG_LEN,
|
||||
SMP_DHKEY_CHECK_MSG_LEN,
|
||||
SMP_KEYPRESS_MSG_LEN
|
||||
};
|
||||
|
||||
/* Control block */
|
||||
smpCb_t smpCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2C data callback for SMP.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void smpL2cDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t cmdCode;
|
||||
smpCcb_t *pCcb;
|
||||
|
||||
/* get connection control block for this handle, ignore packet if not found */
|
||||
if ((pCcb = smpCcbByHandle(handle)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse command code */
|
||||
cmdCode = *(pPacket + L2C_PAYLOAD_START);
|
||||
|
||||
/* verify length and that command is the expected command or pairing failed */
|
||||
if ((cmdCode >= SMP_CMD_PAIR_REQ && cmdCode < SMP_CMD_MAX) &&
|
||||
(len == smpPktLenTbl[cmdCode]) &&
|
||||
((cmdCode == pCcb->nextCmdCode) || (cmdCode == SMP_CMD_PAIR_FAIL)))
|
||||
{
|
||||
smpMsg_t msg;
|
||||
|
||||
/* send to state machine */
|
||||
if (cmdCode == SMP_CMD_PAIR_FAIL)
|
||||
{
|
||||
msg.hdr.event = SMP_MSG_CMD_PAIRING_FAILED;
|
||||
msg.hdr.status = *(pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.hdr.event = SMP_MSG_CMD_PKT;
|
||||
}
|
||||
|
||||
msg.hdr.param = pCcb->connId;
|
||||
msg.data.pPacket = pPacket;
|
||||
smpSmExecute(pCcb, &msg);
|
||||
}
|
||||
/* else ignore it */
|
||||
else
|
||||
{
|
||||
SMP_TRACE_WARN3("unexpected packet cmd:%d len:%d, expected:%d", cmdCode, len, pCcb->nextCmdCode);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2C control callback for SMP.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void smpL2cCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
smpCcb_t *pCcb;
|
||||
uint8_t *pPkt;
|
||||
|
||||
/* get connection control block */
|
||||
pCcb = smpCcbByConnId((dmConnId_t) pMsg->param);
|
||||
|
||||
/* verify connection is open */
|
||||
if (pCcb->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* set flow */
|
||||
pCcb->flowDisabled = (pMsg->event == L2C_CTRL_FLOW_DISABLE_IND);
|
||||
|
||||
/* if data flow enabled */
|
||||
if (!pCcb->flowDisabled)
|
||||
{
|
||||
/* if packet in qeueue */
|
||||
if (pCcb->pQueued != NULL)
|
||||
{
|
||||
/* send queued packet */
|
||||
pPkt = pCcb->pQueued;
|
||||
pCcb->pQueued = NULL;
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
|
||||
/* if SMP state not idle */
|
||||
if (!smpStateIdle(pCcb))
|
||||
{
|
||||
/* trigger send of next key */
|
||||
pMsg->event = SMP_MSG_INT_SEND_NEXT_KEY;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to resume attempts state if a disconnect and reconnect occured while in the
|
||||
* attempts state.
|
||||
*
|
||||
* \param connId Connection ID to prevent pairing.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void smpResumeAttemptsState(dmConnId_t connId)
|
||||
{
|
||||
smpCcb_t *pCcb = smpCcbByConnId(connId);
|
||||
uint32_t timeMs = SmpDbGetPairingDisabledTime(connId);
|
||||
|
||||
if (timeMs)
|
||||
{
|
||||
if (smpCb.lescSupported)
|
||||
{
|
||||
pCcb->state = DmConnRole(connId) == DM_ROLE_SLAVE? SMPR_SC_SM_ST_ATTEMPTS : SMPI_SC_SM_ST_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->state = DmConnRole(connId) == DM_ROLE_SLAVE? SMPR_SM_ST_ATTEMPTS : SMPI_SM_ST_ATTEMPTS;
|
||||
}
|
||||
|
||||
/* Start smp timer indicating the time to prevent pairing in the attempts state */
|
||||
pCcb->waitTimer.msg.event = SMP_MSG_INT_WI_TIMEOUT;
|
||||
WsfTimerStartMs(&pCcb->waitTimer, timeMs);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief DM connection callback for SMP.
|
||||
*
|
||||
* \param pDmEvt DM callback event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void smpDmConnCback(dmEvt_t *pDmEvt)
|
||||
{
|
||||
smpCcb_t *pCcb;
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
pCcb = smpCcbByConnId((dmConnId_t) pDmEvt->hdr.param);
|
||||
|
||||
/* if new connection created */
|
||||
if (pDmEvt->hdr.event == DM_CONN_OPEN_IND)
|
||||
{
|
||||
/* set up state machine for master or slave */
|
||||
if (DmConnRole((dmConnId_t) pDmEvt->hdr.param) == DM_ROLE_MASTER)
|
||||
{
|
||||
pCcb->initiator = TRUE;
|
||||
pCcb->nextCmdCode = SMP_CMD_SECURITY_REQ;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->initiator = FALSE;
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_REQ;
|
||||
}
|
||||
|
||||
/* initialize control block */
|
||||
pCcb->handle = pDmEvt->connOpen.handle;
|
||||
pCcb->connId = (dmConnId_t) pDmEvt->hdr.param;
|
||||
pCcb->secReq = FALSE;
|
||||
pCcb->flowDisabled = FALSE;
|
||||
pCcb->attempts = SmpDbGetFailureCount((dmConnId_t) pDmEvt->hdr.param);
|
||||
pCcb->lastSentKey = 0;
|
||||
pCcb->state = 0;
|
||||
|
||||
/* Resume the attempts state if necessary */
|
||||
smpResumeAttemptsState((dmConnId_t) pDmEvt->hdr.param);
|
||||
}
|
||||
/* else if connection has been opened */
|
||||
else if (pCcb->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* handle close */
|
||||
if (pDmEvt->hdr.event == DM_CONN_CLOSE_IND)
|
||||
{
|
||||
/* store attempts count */
|
||||
SmpDbSetFailureCount((dmConnId_t) pDmEvt->hdr.param, pCcb->attempts);
|
||||
|
||||
/* send to state machine */
|
||||
hdr.param = pDmEvt->hdr.param;
|
||||
hdr.event = SMP_MSG_DM_CONN_CLOSE;
|
||||
hdr.status = pDmEvt->connClose.reason + DM_SEC_HCI_ERR_BASE;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
|
||||
/* clear conn ID after handling event */
|
||||
pCcb->connId = DM_CONN_ID_NONE;
|
||||
|
||||
/* free queued packet buffer */
|
||||
if (pCcb->pQueued != NULL)
|
||||
{
|
||||
WsfMsgFree(pCcb->pQueued);
|
||||
pCcb->pQueued = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the connection control block for the given handle.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
*
|
||||
* \return Pointer to connection control block or NULL if not found.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
smpCcb_t *smpCcbByHandle(uint16_t handle)
|
||||
{
|
||||
dmConnId_t connId;
|
||||
|
||||
if ((connId = DmConnIdByHandle(handle)) != DM_CONN_ID_NONE)
|
||||
{
|
||||
return &smpCb.ccb[connId - 1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the connection control block for the connection ID.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Pointer to connection control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
smpCcb_t *smpCcbByConnId(dmConnId_t connId)
|
||||
{
|
||||
WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX));
|
||||
|
||||
return &smpCb.ccb[connId - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform the first part of SMP calculation C1.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pKey Encryption key parameter 'k'.
|
||||
* \param pRand Random value 'r'.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpCalcC1Part1(smpCcb_t *pCcb, uint8_t *pKey, uint8_t *pRand)
|
||||
{
|
||||
uint8_t buf[HCI_ENCRYPT_DATA_LEN];
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
uint8_t iAddrType;
|
||||
uint8_t rAddrType;
|
||||
|
||||
/* set initiator/responder address types */
|
||||
if (pCcb->initiator)
|
||||
{
|
||||
/* if local device's using RPA */
|
||||
if (!BdaIsZeros(DmConnLocalRpa(pCcb->connId)))
|
||||
{
|
||||
iAddrType = DM_ADDR_RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
iAddrType = DmConnLocalAddrType(pCcb->connId);
|
||||
}
|
||||
|
||||
/* if peer device's using RPA */
|
||||
if (!BdaIsZeros(DmConnPeerRpa(pCcb->connId)))
|
||||
{
|
||||
rAddrType = DM_ADDR_RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
rAddrType = DmConnPeerAddrType(pCcb->connId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if peer device's using RPA */
|
||||
if (!BdaIsZeros(DmConnPeerRpa(pCcb->connId)))
|
||||
{
|
||||
iAddrType = DM_ADDR_RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
iAddrType = DmConnPeerAddrType(pCcb->connId);
|
||||
}
|
||||
|
||||
/* if local device's using RPA */
|
||||
if (!BdaIsZeros(DmConnLocalRpa(pCcb->connId)))
|
||||
{
|
||||
rAddrType = DM_ADDR_RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
rAddrType = DmConnLocalAddrType(pCcb->connId);
|
||||
}
|
||||
}
|
||||
|
||||
/* note all numbers contained in byte arrays are little endian */
|
||||
|
||||
/* create parameter from xor of r and pres, preq, rat, and iat */
|
||||
p = buf;
|
||||
*p++ = iAddrType ^ *pRand++;
|
||||
*p++ = rAddrType ^ *pRand++;
|
||||
for (i = 0; i < SMP_PAIR_REQ_LEN; i++)
|
||||
{
|
||||
*p++ = pCcb->pairReq[i] ^ *pRand++;
|
||||
}
|
||||
for (i = 0; i < SMP_PAIR_RSP_LEN; i++)
|
||||
{
|
||||
*p++ = pCcb->pairRsp[i] ^ *pRand++;
|
||||
}
|
||||
|
||||
/* encrypt */
|
||||
pCcb->token = SecAes(pKey, buf, smpCb.handlerId, pCcb->connId, SMP_MSG_WSF_AES_CMPL);
|
||||
|
||||
if (pCcb->token == SEC_TOKEN_INVALID)
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
/* fail on invalid token */
|
||||
hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform the second part of SMP calculation C1.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pKey Encryption key parameter 'k'.
|
||||
* \param pPart1 Result from part 1.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpCalcC1Part2(smpCcb_t *pCcb, uint8_t *pKey, uint8_t *pPart1)
|
||||
{
|
||||
uint8_t buf[HCI_ENCRYPT_DATA_LEN];
|
||||
uint8_t *p;
|
||||
uint8_t i;
|
||||
uint8_t *pIaddr;
|
||||
uint8_t *pRaddr;
|
||||
|
||||
/* set initiator/responder addresss */
|
||||
if (pCcb->initiator)
|
||||
{
|
||||
/* use local device's RPA */
|
||||
pIaddr = DmConnLocalRpa(pCcb->connId);
|
||||
|
||||
/* if local device's not using RPA */
|
||||
if (BdaIsZeros(pIaddr))
|
||||
{
|
||||
/* use local device's address */
|
||||
pIaddr = DmConnLocalAddr(pCcb->connId);
|
||||
}
|
||||
|
||||
/* use peer device's RPA */
|
||||
pRaddr = DmConnPeerRpa(pCcb->connId);
|
||||
|
||||
/* if peer device's not using RPA */
|
||||
if (BdaIsZeros(pRaddr))
|
||||
{
|
||||
/* use peer device's address */
|
||||
pRaddr = DmConnPeerAddr(pCcb->connId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* use peer device's RPA */
|
||||
pIaddr = DmConnPeerRpa(pCcb->connId);
|
||||
|
||||
/* if peer device's not using RPA */
|
||||
if (BdaIsZeros(pIaddr))
|
||||
{
|
||||
/* use peer device's address */
|
||||
pIaddr = DmConnPeerAddr(pCcb->connId);
|
||||
}
|
||||
|
||||
/* use local device's RPA */
|
||||
pRaddr = DmConnLocalRpa(pCcb->connId);
|
||||
|
||||
/* if local device's not using RPA */
|
||||
if (BdaIsZeros(pRaddr))
|
||||
{
|
||||
/* use local device's address */
|
||||
pRaddr = DmConnLocalAddr(pCcb->connId);
|
||||
}
|
||||
}
|
||||
|
||||
/* note all numbers contained in byte arrays are little endian */
|
||||
|
||||
/* create parameter from xor of part 1 result with ia, ra, and pad */
|
||||
p = buf;
|
||||
for (i = BDA_ADDR_LEN; i > 0; i--)
|
||||
{
|
||||
*p++ = *pRaddr++ ^ *pPart1++;
|
||||
}
|
||||
for (i = BDA_ADDR_LEN; i > 0; i--)
|
||||
{
|
||||
*p++ = *pIaddr++ ^ *pPart1++;
|
||||
}
|
||||
*p++ = *pPart1++;
|
||||
*p++ = *pPart1++;
|
||||
*p++ = *pPart1++;
|
||||
*p++ = *pPart1++;
|
||||
|
||||
/* encrypt */
|
||||
pCcb->token = SecAes(pKey, buf, smpCb.handlerId, pCcb->connId, SMP_MSG_WSF_AES_CMPL);
|
||||
|
||||
if (pCcb->token == SEC_TOKEN_INVALID)
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
/* fail on invalid token */
|
||||
hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform calculation S1.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pKey Encryption key parameter 'k'.
|
||||
* \param pRand1 Random value 1.
|
||||
* \param pRand2 Random value 2.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpCalcS1(smpCcb_t *pCcb, uint8_t *pKey, uint8_t *pRand1, uint8_t *pRand2)
|
||||
{
|
||||
uint8_t buf[HCI_ENCRYPT_DATA_LEN];
|
||||
|
||||
/* note all numbers contained in byte arrays are little endian */
|
||||
|
||||
/* construct parameter r' from r1 and r2 */
|
||||
Calc128Cpy64(buf, pRand2);
|
||||
Calc128Cpy64(&buf[SMP_RAND8_LEN], pRand1);
|
||||
|
||||
/* encrypt */
|
||||
pCcb->token = SecAes(pKey, buf, smpCb.handlerId, pCcb->connId, SMP_MSG_WSF_AES_CMPL);
|
||||
|
||||
if (pCcb->token == SEC_TOKEN_INVALID)
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
/* fail on invalid token */
|
||||
hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate LTK, EDIV, and RAND.
|
||||
*
|
||||
* \param pScr Pointer to scratch buffer containing input and output data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpGenerateLtk(smpCcb_t *pCcb)
|
||||
{
|
||||
uint8_t *p;
|
||||
smpScratch_t *pScr = pCcb->pScr;
|
||||
|
||||
/* generated results are stored in scratch buffer */
|
||||
p = pScr->keyInd.keyData.ltk.key;
|
||||
|
||||
/* generate LTK from random number */
|
||||
SecRand(p, pScr->keyInd.encKeyLen);
|
||||
p += pScr->keyInd.encKeyLen;
|
||||
|
||||
/* set remaining key bytes to zero */
|
||||
memset(p, 0, (SMP_KEY_LEN - pScr->keyInd.encKeyLen));
|
||||
|
||||
/* use existing random number stored in scratch buf b4 for EDIV and RAND */
|
||||
BYTES_TO_UINT16(pScr->keyInd.keyData.ltk.ediv, pScr->buf.b4);
|
||||
memcpy(pScr->keyInd.keyData.ltk.rand, &pScr->buf.b4[2], SMP_RAND8_LEN);
|
||||
|
||||
/* pass key to app via DM */
|
||||
pScr->keyInd.type = DM_KEY_LOCAL_LTK;
|
||||
pScr->keyInd.secLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ? DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC;
|
||||
pScr->keyInd.hdr.event = DM_SEC_KEY_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) &pScr->keyInd);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an SMP command packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pPkt Buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpSendPkt(smpCcb_t *pCcb, uint8_t *pPkt)
|
||||
{
|
||||
/* if flow disabled */
|
||||
if (pCcb->flowDisabled)
|
||||
{
|
||||
/* if packet already queued discard it and replace it with this new packet */
|
||||
if (pCcb->pQueued != NULL)
|
||||
{
|
||||
SMP_TRACE_WARN1("smpSendPkt packet discarded cmd:%d", pCcb->pQueued[L2C_PAYLOAD_START]);
|
||||
WsfMsgFree(pCcb->pQueued);
|
||||
}
|
||||
|
||||
/* queue packet */
|
||||
pCcb->pQueued = pPkt;
|
||||
}
|
||||
/* else send it to L2CAP */
|
||||
else
|
||||
{
|
||||
L2cDataReq(L2C_CID_SMP, pCcb->handle, smpPktLenTbl[pPkt[L2C_PAYLOAD_START]], pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if SMP connection is in idle state.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return TRUE if in idle state, FALSE otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t smpStateIdle(smpCcb_t *pCcb)
|
||||
{
|
||||
return (pCcb->state == 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate an SMP data message buffer to be used for the SMP protocol messages.
|
||||
*
|
||||
* \param len Message length in bytes.
|
||||
*
|
||||
* \return Pointer to data message buffer or NULL if allocation failed.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void *smpMsgAlloc(uint16_t len)
|
||||
{
|
||||
return WsfMsgDataAlloc(len, HCI_TX_DATA_TAILROOM);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by DM to send a message to SMP.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDmMsgSend(smpDmMsg_t *pMsg)
|
||||
{
|
||||
WsfMsgSend(smpCb.handlerId, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by DM to notify SMP of encrypted link status.
|
||||
*
|
||||
* \param pMsg Pointer to HCI message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpDmEncryptInd(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* set event to SMP event type */
|
||||
pMsg->event = (pMsg->status == HCI_SUCCESS) ?
|
||||
SMP_MSG_DM_ENCRYPT_CMPL : SMP_MSG_DM_ENCRYPT_FAILED;
|
||||
|
||||
/* pass event to handler */
|
||||
SmpHandler(0, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate Secure Connections security level.
|
||||
* Note: calculation assumes Secure Connections was used. This function cannot be used to
|
||||
* calculate a legacy pairing's security level.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return Security level.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t smpGetScSecLevel(smpCcb_t *pCcb)
|
||||
{
|
||||
uint8_t secLevel;
|
||||
|
||||
if (pCcb->auth & SMP_AUTH_MITM_FLAG)
|
||||
{
|
||||
if (WSF_MIN(pCcb->pairReq[SMP_MAXKEY_POS], pCcb->pairRsp[SMP_MAXKEY_POS]) == SMP_KEY_SIZE_MAX)
|
||||
{
|
||||
secLevel = DM_SEC_LEVEL_ENC_LESC;
|
||||
}
|
||||
else
|
||||
{
|
||||
secLevel = DM_SEC_LEVEL_ENC_AUTH;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
secLevel = DM_SEC_LEVEL_ENC;
|
||||
}
|
||||
|
||||
return secLevel;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the STK for the given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pSecLevel Returns the security level of pairing when STK was created.
|
||||
*
|
||||
* \return Pointer to STK or NULL if not available.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *SmpDmGetStk(dmConnId_t connId, uint8_t *pSecLevel)
|
||||
{
|
||||
smpCcb_t *pCcb;
|
||||
|
||||
/* get connection control block */
|
||||
pCcb = smpCcbByConnId(connId);
|
||||
|
||||
if (smpCb.lescSupported && pCcb->pScCcb->lescEnabled && (pCcb->pScCcb->pLtk != NULL))
|
||||
{
|
||||
/* set security level */
|
||||
*pSecLevel = smpGetScSecLevel(pCcb);
|
||||
|
||||
/* return buffer containing STK */
|
||||
return pCcb->pScCcb->pLtk->ltk_t;
|
||||
}
|
||||
else if (pCcb->pScr != NULL)
|
||||
{
|
||||
/* set security level */
|
||||
*pSecLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ? DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC;
|
||||
|
||||
/* return buffer containing STK */
|
||||
return pCcb->pScr->buf.b3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return the LTK for the given connection.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return Pointer to STK or NULL if not available.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *SmpDmGetLtk(dmConnId_t connId)
|
||||
{
|
||||
smpCcb_t *pCcb;
|
||||
|
||||
/* get connection control block */
|
||||
pCcb = smpCcbByConnId(connId);
|
||||
|
||||
if (smpCb.lescSupported)
|
||||
{
|
||||
/* return buffer containing STK */
|
||||
return pCcb->pScCcb->pLtk->ltk_t;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief SMP handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID for SMP.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpHandlerInit(wsfHandlerId_t handlerId)
|
||||
{
|
||||
uint8_t i;
|
||||
smpCcb_t *pCcb;
|
||||
|
||||
/* store handler ID */
|
||||
smpCb.handlerId = handlerId;
|
||||
|
||||
/* Initialize the SMP device database */
|
||||
SmpDbInit();
|
||||
|
||||
/* Initialize control block CCBs */
|
||||
for (i = 0, pCcb = smpCb.ccb; i < DM_CONN_MAX; i++, pCcb++)
|
||||
{
|
||||
/* initialize response timer */
|
||||
pCcb->rspTimer.handlerId = handlerId;
|
||||
pCcb->rspTimer.msg.param = i + 1; /* param stores the conn id */
|
||||
|
||||
/* initialize wait interval timer */
|
||||
pCcb->waitTimer.handlerId = handlerId;
|
||||
pCcb->waitTimer.msg.param = i + 1; /* param stores the conn id */
|
||||
}
|
||||
|
||||
/* Register with L2C */
|
||||
L2cRegister(L2C_CID_SMP, smpL2cDataCback, smpL2cCtrlCback);
|
||||
|
||||
/* Register with DM */
|
||||
DmConnRegister(DM_CLIENT_ID_SMP, smpDmConnCback);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
*
|
||||
* \brief WSF event handler for SMP.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
smpCcb_t *pCcb;
|
||||
|
||||
/* Handle message */
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
if (pMsg->event == SMP_DB_SERVICE_IND)
|
||||
{
|
||||
SmpDbService();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pMsg->event == SMP_MSG_WSF_CMAC_CMPL)
|
||||
{
|
||||
secCmacMsg_t *pCmac = (secCmacMsg_t *) pMsg;
|
||||
|
||||
/* Free the plain text buffer that was allocated and passed into SecCmac */
|
||||
if (pCmac->pPlainText)
|
||||
{
|
||||
WsfBufFree(pCmac->pPlainText);
|
||||
}
|
||||
}
|
||||
|
||||
/* get connection control block */
|
||||
pCcb = smpCcbByConnId((dmConnId_t) pMsg->param);
|
||||
|
||||
/* verify connection is open */
|
||||
if (pCcb->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* if AES result verify it is not stale */
|
||||
if (pMsg->event == SMP_MSG_WSF_AES_CMPL && pCcb->token != pMsg->status)
|
||||
{
|
||||
SMP_TRACE_WARN2("AES token mismatch: %d %d", pCcb->token, pMsg->status);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send to state machine */
|
||||
smpSmExecute(pCcb, (smpMsg_t *) pMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Handle events */
|
||||
else if (event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \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 */
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Simple implementation of SMP when not supported.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "l2c_api.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2C control callback for SMP.
|
||||
*
|
||||
* \param pMsg Pointer to message structure.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void smpNonL2cCtrlCback(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief L2CAP data callback for SMP when SMP not supported.
|
||||
*
|
||||
* \param handle The connection handle.
|
||||
* \param len The length of the L2CAP payload data in pPacket.
|
||||
* \param pPacket A buffer containing the packet.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpNonL2cDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
|
||||
{
|
||||
uint8_t *pRsp;
|
||||
uint8_t *p;
|
||||
uint8_t role;
|
||||
dmConnId_t connId;
|
||||
|
||||
if ((connId = DmConnIdByHandle(handle)) == DM_CONN_ID_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
role = DmConnRole(connId);
|
||||
|
||||
p = pPacket + L2C_PAYLOAD_START;
|
||||
|
||||
/* SMP is not supported so fail gracefully */
|
||||
|
||||
/* if slave and pairing request received, or master and security request received */
|
||||
if ((role == DM_ROLE_SLAVE && *p == SMP_CMD_PAIR_REQ) ||
|
||||
(role == DM_ROLE_MASTER && *p == SMP_CMD_SECURITY_REQ))
|
||||
{
|
||||
/* send pairing failed */
|
||||
if ((pRsp = smpMsgAlloc(L2C_PAYLOAD_START + SMP_PAIR_FAIL_LEN)) != NULL)
|
||||
{
|
||||
p = pRsp + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_FAIL);
|
||||
UINT8_TO_BSTREAM(p, SMP_ERR_PAIRING_NOT_SUP);
|
||||
|
||||
L2cDataReq(L2C_CID_SMP, handle, SMP_PAIR_FAIL_LEN, pRsp);
|
||||
}
|
||||
}
|
||||
|
||||
/* all other messages are ignored */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Use this SMP init function when SMP is not supported.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpNonInit(void)
|
||||
{
|
||||
/* Register with L2C */
|
||||
L2cRegister(L2C_CID_SMP, smpNonL2cDataCback, smpNonL2cCtrlCback);
|
||||
}
|
||||
Vendored
+1004
File diff suppressed because it is too large
Load Diff
Vendored
+758
@@ -0,0 +1,758 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP Secure Connections main module and utility functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "sec_api.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
#include "dm_api.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_defs.h"
|
||||
#include "smp_main.h"
|
||||
#include "smp_sc_main.h"
|
||||
#include "smp_handler.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* LE Secure Connections Control Block (TBD: Make these dynamic) */
|
||||
smpScCcb_t SMP_ScCcb[DM_CONN_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate LESC Scratch buffers
|
||||
*
|
||||
* \param pCcb SMP control block.
|
||||
*
|
||||
* \return TRUE if success, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
bool_t SmpScAllocScratchBuffers(smpCcb_t *pCcb)
|
||||
{
|
||||
if (pCcb->pScCcb->pScratch == NULL)
|
||||
{
|
||||
pCcb->pScCcb->pScratch = WsfBufAlloc(sizeof(smpScScratch_t));
|
||||
}
|
||||
|
||||
if (pCcb->pScCcb->pPeerPublicKey == NULL)
|
||||
{
|
||||
pCcb->pScCcb->pPeerPublicKey = WsfBufAlloc(sizeof(smpScPubKey_t));
|
||||
}
|
||||
|
||||
if (pCcb->pScCcb->pLtk == NULL)
|
||||
{
|
||||
pCcb->pScCcb->pLtk = WsfBufAlloc(sizeof(smpScLtk_t));
|
||||
}
|
||||
|
||||
if (pCcb->pScCcb->pLocalPublicKey == NULL)
|
||||
{
|
||||
pCcb->pScCcb->pLocalPublicKey = WsfBufAlloc(sizeof(smpScPubKey_t));
|
||||
}
|
||||
|
||||
if (pCcb->pScCcb->pPrivateKey == NULL)
|
||||
{
|
||||
pCcb->pScCcb->pPrivateKey = WsfBufAlloc(SMP_PRIVATE_KEY_LEN);
|
||||
}
|
||||
|
||||
if (pCcb->pScCcb->pScratch && pCcb->pScCcb->pPeerPublicKey && pCcb->pScCcb->pLtk &&
|
||||
pCcb->pScCcb->pLocalPublicKey && pCcb->pScCcb->pPrivateKey)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free LESC Scratch buffers
|
||||
*
|
||||
* \param pCcb SMP control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScFreeScratchBuffers(smpCcb_t *pCcb)
|
||||
{
|
||||
/* free scratch buffer */
|
||||
if (pCcb->pScCcb->pScratch != NULL)
|
||||
{
|
||||
WsfBufFree(pCcb->pScCcb->pScratch);
|
||||
pCcb->pScCcb->pScratch = NULL;
|
||||
}
|
||||
|
||||
/* free scratch peer public key buffer */
|
||||
if (pCcb->pScCcb->pPeerPublicKey != NULL)
|
||||
{
|
||||
WsfBufFree(pCcb->pScCcb->pPeerPublicKey);
|
||||
pCcb->pScCcb->pPeerPublicKey = NULL;
|
||||
}
|
||||
|
||||
/* free scratch LTK buffer */
|
||||
if (pCcb->pScCcb->pLtk != NULL)
|
||||
{
|
||||
WsfBufFree(pCcb->pScCcb->pLtk);
|
||||
pCcb->pScCcb->pLtk = NULL;
|
||||
}
|
||||
|
||||
/* free scratch local public key buffer */
|
||||
if (pCcb->pScCcb->pLocalPublicKey != NULL)
|
||||
{
|
||||
WsfBufFree(pCcb->pScCcb->pLocalPublicKey);
|
||||
pCcb->pScCcb->pLocalPublicKey = NULL;
|
||||
}
|
||||
|
||||
/* free scratch private key buffer */
|
||||
if (pCcb->pScCcb->pPrivateKey != NULL)
|
||||
{
|
||||
WsfBufFree(pCcb->pScCcb->pPrivateKey);
|
||||
pCcb->pScCcb->pPrivateKey = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform CMAC calculation or send SMP failure
|
||||
*
|
||||
* \param pKey CMAC Key
|
||||
* \param pText Pointer to message text.
|
||||
* \param textLen Length of pText in bytes.
|
||||
* \param pCcb SMP control block.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScCmac(const uint8_t *pKey, uint8_t *pText, uint8_t textLen, smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
if (SecCmac(pKey, pText, textLen, smpCb.handlerId, pCcb->connId, SMP_MSG_WSF_CMAC_CMPL) == FALSE)
|
||||
{
|
||||
WsfBufFree(pText);
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Allocate a buffer or send SMP failure
|
||||
*
|
||||
* \param size Size of buffer to allocate.
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return Allocated buffer.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *SmpScAlloc(uint8_t size, smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pBuf = WsfBufAlloc(size);
|
||||
|
||||
if (pBuf == NULL)
|
||||
{
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Free a buffer allocated with SmpScAlloc.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to free.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScFree(uint8_t *pBuf)
|
||||
{
|
||||
WsfBufFree(pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate cryptographic toolkit function F4.
|
||||
*
|
||||
* \param pCcb SMP control block
|
||||
* \param pMsg WSF message.
|
||||
* \param pU Pointer to U parameter of F4 function.
|
||||
* \param pV Pointer to V parameter of F4 function.
|
||||
* \param z Byte with z parameter of F4 function.
|
||||
* \param pX Pointer to X parameter of F4 function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScCalcF4(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pU, uint8_t *pV, uint8_t z, uint8_t *pX)
|
||||
{
|
||||
uint8_t *pCmacText;
|
||||
|
||||
/* f4(pU, pV, pX, z) where f4(U, V, x, Z) = AES-CMACx (U || V || Z) */
|
||||
if ((pCmacText = SmpScAlloc(SMP_F4_TEXT_LEN, pCcb, pMsg)) != NULL)
|
||||
{
|
||||
uint8_t *pCatBuf = pCmacText;
|
||||
|
||||
/* Concatinate pU, pV, z */
|
||||
pCatBuf = SmpScCat(pCatBuf, pU, SMP_PUB_KEY_LEN);
|
||||
pCatBuf = SmpScCat(pCatBuf, pV, SMP_PUB_KEY_LEN);
|
||||
*pCatBuf = z;
|
||||
|
||||
/* Execute CMAC with Nb as the key */
|
||||
SmpScCmac(pX, pCmacText, SMP_F4_TEXT_LEN, pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP for LESC security.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScInit()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i=0; i<DM_CONN_MAX; i++)
|
||||
{
|
||||
smpCb.ccb[i].pScCcb = &SMP_ScCcb[i];
|
||||
}
|
||||
|
||||
smpCb.procPairing = smpScProcPairing;
|
||||
smpCb.procAuthReq = smpScAuthReq;
|
||||
smpCb.lescSupported = TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Concatinate a buffer and return a pointer to the next byte after concatination.
|
||||
*
|
||||
* \param pDst Pointer to destination.
|
||||
* \param pSrc Pointer to source buffer.
|
||||
* \param len Length of pSrc in bytes.
|
||||
*
|
||||
* \return Pointer to next byte after concatination.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *SmpScCat(uint8_t *pDst, const uint8_t *pSrc, uint8_t len)
|
||||
{
|
||||
memcpy(pDst, pSrc, len);
|
||||
return pDst + len;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Concatinate a 128 bit buffer and return a pointer to the next byte after concatination.
|
||||
*
|
||||
* \param pDst Pointer to destination.
|
||||
* \param pSrc Pointer to source buffer.
|
||||
*
|
||||
* \return Pointer to next byte after concatination.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *SmpScCat128(uint8_t *pDst, uint8_t *pSrc)
|
||||
{
|
||||
Calc128Cpy(pDst, pSrc);
|
||||
return pDst + 16;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send public key to peer.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpScSendPubKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Transmit the public key */
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_BUSY);
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PUB_KEY_MSG_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PUBLIC_KEY);
|
||||
|
||||
/* Store Public Key X data in LSB first format */
|
||||
WStrReverseCpy(p, pCcb->pScCcb->pLocalPublicKey->pubKeyX, SMP_PUB_KEY_LEN);
|
||||
|
||||
/* Store Public Key Y data in LSB first format */
|
||||
WStrReverseCpy(p+SMP_PUB_KEY_LEN, pCcb->pScCcb->pLocalPublicKey->pubKeyY, SMP_PUB_KEY_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the DH Key check command to the peer.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
* \param pCheck Check data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpScSendDHKeyCheck(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pCheck)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_BUSY);
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_DHKEY_CHECK_MSG_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_DHKEY_CHECK);
|
||||
|
||||
/* DH Key Check data is result of last CMAC operation (LSB first) */
|
||||
WStrReverseCpy(p, pCheck, SMP_DHKEY_CHECK_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a Pair Rand command to the peer
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
* \param pRand Pointer to rand data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpScSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pRand)
|
||||
{
|
||||
/* Transmit the Pair Rand */
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_BUSY);
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_RAND_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_RAND);
|
||||
|
||||
/* Store Random data (LSB first) */
|
||||
WStrReverseCpy(p, pRand, SMP_RAND_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a pairing confirm packet to the peer
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
* \param pCnf Point to confirm data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpScSendPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pCnf)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_BUSY);
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_CNF_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_CNF);
|
||||
|
||||
/* Store Confirm data (LSB first) */
|
||||
WStrReverseCpy(p, pCnf, SMP_CONFIRM_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next bit used in Passkey calculations.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t smpGetPkBit(smpCcb_t *pCcb)
|
||||
{
|
||||
smpScCcb_t *pScCb = pCcb->pScCcb;
|
||||
uint8_t indx = (SMP_RAND_LEN - 1) - pScCb->pkPos / 8;
|
||||
uint8_t bit = pScCb->pkPos % 8;
|
||||
|
||||
if (pScCb->pScratch->Ra[indx] & 1<<bit)
|
||||
return 0x81;
|
||||
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get a pointer to the connection's Peer Public Key for LESC pairing
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return Peer public Key.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
smpScPubKey_t *smpGetPeerPublicKey(dmConnId_t connId)
|
||||
{
|
||||
smpCcb_t *pCcb = smpCcbByConnId(connId);
|
||||
|
||||
if (pCcb->pScCcb)
|
||||
{
|
||||
return pCcb->pScCcb->pPeerPublicKey;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the connection's Peer Public Key for LESC pairing
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pKey A Pointer to the peer's public key.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpSetPeerPublicKey(dmConnId_t connId, smpScPubKey_t *pKey)
|
||||
{
|
||||
smpCcb_t *pCcb = smpCcbByConnId(connId);
|
||||
|
||||
if (pCcb->pScCcb)
|
||||
{
|
||||
memcpy(pCcb->pScCcb->pPeerPublicKey, pKey, sizeof(smpScPubKey_t));
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the OOB Confirm value
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pCnf OOB Configuration.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScSetOobCfg(dmConnId_t connId, dmSecLescOobCfg_t *pConfig)
|
||||
{
|
||||
smpCcb_t *pCcb = smpCcbByConnId(connId);
|
||||
|
||||
WSF_ASSERT(pCcb->pScCcb->pScratch);
|
||||
|
||||
SMP_TRACE_128("OOB Peer Confirm", pConfig->peerConfirm);
|
||||
SMP_TRACE_128("OOB Peer Random", pConfig->peerRandom);
|
||||
SMP_TRACE_128("OOB Local Confirm", pConfig->localConfirm);
|
||||
SMP_TRACE_128("OOB Local Random", pConfig->localRandom);
|
||||
|
||||
if (pCcb->initiator)
|
||||
{
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->PeerCa_Ea, pConfig->localConfirm);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, pConfig->localRandom);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->PeerCb, pConfig->peerConfirm);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, pConfig->peerRandom);
|
||||
}
|
||||
else
|
||||
{
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->PeerCb, pConfig->localConfirm);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, pConfig->localRandom);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->PeerCa_Ea, pConfig->peerConfirm);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, pConfig->peerRandom);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Format a cancel message with consideration for the attempts counter
|
||||
*
|
||||
* \param connId Connection Id.
|
||||
* \param pHdr Pointer to header of message to fill.
|
||||
* \param status Status to include.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpScGetCancelMsgWithReattempt(dmConnId_t connId, wsfMsgHdr_t *pHdr, uint8_t status)
|
||||
{
|
||||
smpCcb_t *pCcb = smpCcbByConnId(connId);
|
||||
|
||||
SMP_TRACE_INFO1("SmpScGetCancelMsgWithReattempt: %d", pCcb->attempts);
|
||||
|
||||
/* update repeated attempts count */
|
||||
pCcb->attempts++;
|
||||
|
||||
pHdr->param = connId;
|
||||
pHdr->status = status;
|
||||
|
||||
SmpDbPairingFailed(connId);
|
||||
|
||||
if (pCcb->attempts == pSmpCfg->maxAttempts)
|
||||
{
|
||||
/* max attempts reached */
|
||||
pHdr->event = SMP_MSG_INT_MAX_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else just fail */
|
||||
pHdr->event = SMP_MSG_API_CANCEL_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process failure and check attempt count
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpScFailWithReattempt(smpCcb_t *pCcb)
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
SmpScGetCancelMsgWithReattempt(pCcb->connId, &hdr, SMP_ERR_CONFIRM_VALUE);
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *)&hdr);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Convert event into string for diagnostics.
|
||||
*
|
||||
* \param eventId Event ID
|
||||
*
|
||||
* \return Event string.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *smpEventStr(uint8_t eventId)
|
||||
{
|
||||
switch(eventId)
|
||||
{
|
||||
case SMP_MSG_API_PAIR_REQ: return (uint8_t*) "API_PAIR_REQ";
|
||||
case SMP_MSG_API_PAIR_RSP: return (uint8_t*) "API_PAIR_RSP";
|
||||
case SMP_MSG_API_CANCEL_REQ: return (uint8_t*) "API_CANCEL_REQ";
|
||||
case SMP_MSG_API_AUTH_RSP: return (uint8_t*) "API_AUTH_RSP";
|
||||
case SMP_MSG_API_SECURITY_REQ: return (uint8_t*) "API_SECURITY_REQ";
|
||||
case SMP_MSG_CMD_PKT: return (uint8_t*) "CMD_PKT";
|
||||
case SMP_MSG_CMD_PAIRING_FAILED: return (uint8_t*) "CMD_PAIRING_FAILED";
|
||||
case SMP_MSG_DM_ENCRYPT_CMPL: return (uint8_t*) "DM_ENCRYPT_CMPL";
|
||||
case SMP_MSG_DM_ENCRYPT_FAILED: return (uint8_t*) "DM_ENCRYPT_FAILED";
|
||||
case SMP_MSG_DM_CONN_CLOSE: return (uint8_t*) "DM_CONN_CLOSE";
|
||||
case SMP_MSG_WSF_AES_CMPL: return (uint8_t*) "WSF_AES_CMPL";
|
||||
case SMP_MSG_INT_SEND_NEXT_KEY: return (uint8_t*) "INT_SEND_NEXT_KEY";
|
||||
case SMP_MSG_INT_MAX_ATTEMPTS: return (uint8_t*) "INT_MAX_ATTEMPTS";
|
||||
case SMP_MSG_INT_PAIRING_CMPL: return (uint8_t*) "INT_PAIRING_CMPL";
|
||||
case SMP_MSG_INT_RSP_TIMEOUT: return (uint8_t*) "INT_RSP_TIMEOUT";
|
||||
case SMP_MSG_INT_WI_TIMEOUT: return (uint8_t*) "INT_WI_TIMEOUT";
|
||||
case SMP_MSG_INT_LESC: return (uint8_t*) "INT_LESC";
|
||||
case SMP_MSG_INT_LEGACY: return (uint8_t*) "INT_LEGACY";
|
||||
case SMP_MSG_INT_JW_NC: return (uint8_t*) "INT_JW_NC";
|
||||
case SMP_MSG_INT_PASSKEY: return (uint8_t*) "INT_PASSKEY";
|
||||
case SMP_MSG_INT_OOB: return (uint8_t*) "INT_OOB";
|
||||
case SMP_MSG_API_USER_CONFIRM: return (uint8_t*) "API_USER_CONFIRM";
|
||||
case SMP_MSG_API_USER_KEYPRESS: return (uint8_t*) "API_USER_KEYPRESS";
|
||||
case SMP_MSG_API_KEYPRESS_CMPL: return (uint8_t*) "API_KEYPRESS_CMPL";
|
||||
case SMP_MSG_WSF_ECC_CMPL: return (uint8_t*) "WSF_ECC_CMPL";
|
||||
case SMP_MSG_INT_PK_NEXT: return (uint8_t*) "INT_PK_NEXT";
|
||||
case SMP_MSG_INT_PK_CMPL: return (uint8_t*) "INT_PK_CMPL";
|
||||
case SMP_MSG_WSF_CMAC_CMPL: return (uint8_t*) "WSF_CMAC_CMPL";
|
||||
case SMP_MSG_DH_CHECK_FAILURE: return (uint8_t*) "DH_CHECK_FAILURE";
|
||||
|
||||
default: return (uint8_t*) "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Convert state into string for diagnostics.
|
||||
*
|
||||
* \param state State ID
|
||||
*
|
||||
* \return State string.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *smpStateStr(uint8_t state)
|
||||
{
|
||||
uint8_t initiator = smpCb.ccb[0].initiator;
|
||||
|
||||
if (initiator)
|
||||
{
|
||||
return smpiStateStr(state);
|
||||
}
|
||||
|
||||
return smprStateStr(state);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write an array of bytes to the log.
|
||||
*
|
||||
* \param str Prefix string printed before the byte array
|
||||
* \param pArray Array of bytes
|
||||
* \param len Length of pArray in bytes
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpLogByteArray(char *str, uint8_t *pArray, uint8_t len)
|
||||
{
|
||||
#if WSF_TOKEN_ENABLED == TRUE || WSF_TRACE_ENABLED == TRUE
|
||||
|
||||
char buffer[512];
|
||||
int i, j=0, pos=0;
|
||||
|
||||
SMP_TRACE_INFO0(str);
|
||||
|
||||
while (j < len)
|
||||
{
|
||||
int count = 16;
|
||||
|
||||
if (len-j < count)
|
||||
count = j;
|
||||
|
||||
buffer[pos++] = '[';
|
||||
|
||||
for (i=0; i<count; i++, j++)
|
||||
{
|
||||
uint8_t quad;
|
||||
|
||||
if (i && i % 4 == 0)
|
||||
buffer[pos++] = ' ';
|
||||
|
||||
quad = (pArray[j] >> 4) & 0xf;
|
||||
|
||||
if (quad < 10)
|
||||
buffer[pos++] = '0' + quad;
|
||||
else
|
||||
buffer[pos++] = 'a' + quad - 10;
|
||||
|
||||
quad = pArray[j] & 0xf;
|
||||
|
||||
if (quad < 10)
|
||||
buffer[pos++] = '0' + quad;
|
||||
else
|
||||
buffer[pos++] = 'a' + quad - 10;
|
||||
}
|
||||
|
||||
buffer[pos++] = ']';
|
||||
buffer[pos++] = '\0';
|
||||
SMP_TRACE_INFO0(buffer);
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (pos)
|
||||
{
|
||||
buffer[pos++] = ']';
|
||||
buffer[pos++] = '\0';
|
||||
|
||||
SMP_TRACE_INFO0(buffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Vendored
+151
@@ -0,0 +1,151 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP main module header file.
|
||||
*
|
||||
* 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_SC_MAIN_H
|
||||
#define SMP_SC_MAIN_H
|
||||
|
||||
#include "smp_main.h"
|
||||
#include "smp_defs.h"
|
||||
#include "smp_api.h"
|
||||
#include "wsf_trace.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
#if WSF_TOKEN_ENABLED == TRUE || WSF_TRACE_ENABLED == TRUE
|
||||
#define SMP_TRACE_128(msg, ptr) smpLogByteArray(msg, ptr, 16)
|
||||
#define SMP_TRACE_256(msg, ptr) smpLogByteArray(msg, ptr, 32)
|
||||
#else
|
||||
#define SMP_TRACE_128(msg, ptr)
|
||||
#define SMP_TRACE_256(msg, ptr)
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Constants
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Number of bits in the Passkey */
|
||||
#define SMP_PK_BIT_COUNT 20
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* common state machine action functions */
|
||||
void smpScActCleanup(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActPairingFailed(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActPairingCancel(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActAuthSelect(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActPkSetup(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActJwncCalcF4(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActJwncCalcG2(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActJwncDisplay(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActPkKeypress(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActPkSendKeypress(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActCalcSharedSecret(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActCalcF5TKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActCalcF5MacKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActCalcF5Ltk(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActDHKeyCalcF6Ea(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScActDHKeyCalcF6Eb(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
|
||||
/* initiator state machine action functions */
|
||||
void smpiScActSendPubKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActAuthSelect(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActJwncSetup(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActJwncSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActJwncCalcF4(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActJwncCalcG2(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActPkCalcCa(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActPkCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActPkSendCnf(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActPkSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActPkCheck(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActOobCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActOobSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActOobProcRand(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActDHKeyCheckSend(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiScActDHKeyCheckVerify(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
|
||||
/* responder state machine action functions */
|
||||
void smprScActStoreLescPin(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActSendPubKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActJwncSetup(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActJwncCalcG2(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActJwncDisplay(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActJwncSendCnf(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkStoreCnf(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkStoreCnfAndCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkStorePinAndCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkSendCnf(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkCalcCa(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActPkSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActOobSetup(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActOobCalcCa(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActOobSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActStoreDhCheck(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActWaitDhCheck(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActDHKeyCheckSend(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprScActCalcDHKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
|
||||
/* common functions */
|
||||
bool_t SmpScAllocScratchBuffers(smpCcb_t *pCcb);
|
||||
void SmpScFreeScratchBuffers(smpCcb_t *pCcb);
|
||||
bool_t smpScProcPairing(smpCcb_t *pCcb, uint8_t *pOob, uint8_t *pDisplay);
|
||||
void SmpReverseCpy(uint8_t *pBuf1, uint8_t *pBuf2, uint8_t len);
|
||||
void SmpScCmac(const uint8_t *pKey, uint8_t *pText, uint8_t textLen, smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
uint8_t *SmpScAlloc(uint8_t size, smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void SmpScFree(uint8_t *pBuf);
|
||||
void SmpScCalcF4(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pU, uint8_t *pV, uint8_t z, uint8_t *pX);
|
||||
uint8_t *SmpScCat(uint8_t *pDst, const uint8_t *pSrc, uint8_t len);
|
||||
uint8_t *SmpScCat128(uint8_t *pDst, uint8_t *pSrc);
|
||||
uint8_t smpGetPkBit(smpCcb_t *pCcb);
|
||||
smpScPubKey_t *smpGetPeerPublicKey(dmConnId_t connId);
|
||||
void smpSetPeerPublicKey(dmConnId_t connId, smpScPubKey_t *pKey);
|
||||
void SmpScSetOobCfg(dmConnId_t connId, dmSecLescOobCfg_t *pConfig);
|
||||
void smpScAuthReq(smpCcb_t *pCcb, uint8_t oob, uint8_t display);
|
||||
void smpScFailWithReattempt(smpCcb_t *pCcb);
|
||||
void SmpScInit(void);
|
||||
|
||||
/* common command send functoins */
|
||||
void smpScSendPubKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpScSendDHKeyCheck(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pCheck);
|
||||
void smpScSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pRand);
|
||||
void smpScSendPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg, uint8_t *pCnf);
|
||||
|
||||
/* diagnostics utility functions */
|
||||
void smpLogByteArray(char *str, uint8_t *pArray, uint8_t len);
|
||||
uint8_t *smpiStateStr(uint8_t state);
|
||||
uint8_t *smprStateStr(uint8_t state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SMP_SC_MAIN_H */
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP initiator state machine action functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpi_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initiate a pairing request.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActPairReq(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_BUSY);
|
||||
|
||||
/* set next expected packet */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RSP;
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate scratch buffer */
|
||||
pCcb->pScr = WsfBufAlloc(sizeof(smpScratch_t));
|
||||
/* handle alloc failure */
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_REQ_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_REQ);
|
||||
UINT8_TO_BSTREAM(p, pSmpCfg->ioCap);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.oob);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.auth);
|
||||
UINT8_TO_BSTREAM(p, pSmpCfg->maxKeyLen);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.iKeyDist);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.rKeyDist);
|
||||
|
||||
/* store pair req data */
|
||||
memcpy(pCcb->pairReq, pPkt + L2C_PAYLOAD_START, SMP_PAIR_REQ_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check if a security request has been received when pairing is cancelled.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActCheckSecurityReq(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* if security req received send pairing failed */
|
||||
if (pCcb->secReq)
|
||||
{
|
||||
pCcb->secReq = FALSE;
|
||||
smpSendPairingFailed(pCcb, pMsg->hdr.status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a security request packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActProcSecurityReq(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
dmSecSlaveIndEvt_t slaveInd;
|
||||
|
||||
pCcb->secReq = TRUE;
|
||||
|
||||
/* parse packet */
|
||||
slaveInd.auth = *(pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN);
|
||||
|
||||
/* pass to DM */
|
||||
slaveInd.hdr.param = pCcb->connId;
|
||||
slaveInd.hdr.event = DM_SEC_SLAVE_REQ_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) &slaveInd);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a pairing response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActProcPairRsp(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint8_t oob;
|
||||
uint8_t display;
|
||||
|
||||
/* go to start of packet */
|
||||
p = pMsg->data.pPacket + L2C_PAYLOAD_START;
|
||||
|
||||
/* store packet parameters */
|
||||
memcpy(pCcb->pairRsp, p, SMP_PAIR_RSP_LEN);
|
||||
|
||||
/* verify no new key distribution bits are set */
|
||||
if (((~(pCcb->pairReq[SMP_IKEYDIST_POS]) & p[SMP_IKEYDIST_POS]) != 0) ||
|
||||
((~(pCcb->pairReq[SMP_RKEYDIST_POS]) & p[SMP_RKEYDIST_POS]) != 0))
|
||||
{
|
||||
/* invalid parameters; cancel pairing */
|
||||
pMsg->hdr.status = SMP_ERR_INVALID_PARAM;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* proceed to process pairing */
|
||||
if (smpCb.procPairing(pCcb, &oob, &display))
|
||||
{
|
||||
smpCb.procAuthReq(pCcb, oob, display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a pairing confirm packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActProcPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* go to start of packet */
|
||||
p = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* store confirm value */
|
||||
memcpy(pCcb->pScr->buf.b3, p, SMP_CONFIRM_LEN);
|
||||
|
||||
/* set next expected packet */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer and send pairing random packet */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_RAND_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_RAND);
|
||||
memcpy(p, pCcb->pScr->buf.b4, SMP_RAND_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Verify the calculated confirm value. If ok, proceed with STK calculcation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActCnfVerify(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* compare calculated confirm value with value received earlier */
|
||||
if (memcmp(pMsg->aes.pCiphertext, pCcb->pScr->buf.b3, SMP_CONFIRM_LEN) != 0)
|
||||
{
|
||||
pMsg->hdr.status = SMP_ERR_CONFIRM_VALUE;
|
||||
|
||||
/* confirm values don't match; update repeated attempts count */
|
||||
pCcb->attempts++;
|
||||
SmpDbPairingFailed(pCcb->connId);
|
||||
|
||||
if (pCcb->attempts == pSmpCfg->maxAttempts)
|
||||
{
|
||||
/* max attempts reached */
|
||||
pMsg->hdr.event = SMP_MSG_INT_MAX_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else just fail */
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
}
|
||||
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* do STK calculation: key, responder rand, initiator rand */
|
||||
smpCalcS1(pCcb, pCcb->pScr->buf.b1, pCcb->pScr->buf.b2, pCcb->pScr->buf.b4);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Encrypt link with STK.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActStkEncrypt(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t buf[SMP_KEY_LEN];
|
||||
uint8_t encKeyLen;
|
||||
uint8_t secLevel;
|
||||
|
||||
encKeyLen = (pCcb->pairReq[SMP_MAXKEY_POS] < pCcb->pairRsp[SMP_MAXKEY_POS]) ?
|
||||
pCcb->pairReq[SMP_MAXKEY_POS] : pCcb->pairRsp[SMP_MAXKEY_POS];
|
||||
|
||||
/* adjust key based on max key length */
|
||||
memcpy(buf, pMsg->aes.pCiphertext, encKeyLen);
|
||||
memset((buf + encKeyLen), 0, (SMP_KEY_LEN - encKeyLen));
|
||||
|
||||
secLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ? DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC;
|
||||
DmSmpEncryptReq(pCcb->connId, secLevel, buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set up key distribution.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActSetupKeyDist(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t rKeyDist;
|
||||
|
||||
/* start smp response timer once for entire key distribution phase */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* initialize parameters in key ind struct */
|
||||
pCcb->pScr->keyInd.hdr.param = pCcb->connId;
|
||||
pCcb->pScr->keyInd.secLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ?
|
||||
DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC;
|
||||
pCcb->pScr->keyInd.encKeyLen =
|
||||
(pCcb->pairReq[SMP_MAXKEY_POS] < pCcb->pairRsp[SMP_MAXKEY_POS]) ?
|
||||
pCcb->pairReq[SMP_MAXKEY_POS] : pCcb->pairRsp[SMP_MAXKEY_POS];
|
||||
|
||||
pCcb->nextCmdCode = 0;
|
||||
|
||||
/* get negotiated responder key distribution */
|
||||
rKeyDist = pCcb->pairReq[SMP_RKEYDIST_POS] & pCcb->pairRsp[SMP_RKEYDIST_POS];
|
||||
|
||||
/* set up to receive first key distribution packet */
|
||||
if (rKeyDist & SMP_KEY_DIST_ENC)
|
||||
{
|
||||
if (smpCb.lescSupported && pCcb->pScCcb->lescEnabled)
|
||||
{
|
||||
if (rKeyDist & SMP_KEY_DIST_ID)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_ID_INFO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_ENC_INFO;
|
||||
}
|
||||
}
|
||||
else if (rKeyDist & SMP_KEY_DIST_ID)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_ID_INFO;
|
||||
}
|
||||
else if (rKeyDist & SMP_KEY_DIST_SIGN)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_SIGN_INFO;
|
||||
}
|
||||
|
||||
if (pCcb->nextCmdCode == 0)
|
||||
{
|
||||
/* no responder keys to be distributed; start sending keys */
|
||||
pMsg->hdr.event = SMP_MSG_INT_SEND_NEXT_KEY;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Receive a key.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActRcvKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t keyDist;
|
||||
|
||||
/* get responder key distribution */
|
||||
keyDist = pCcb->pairReq[SMP_RKEYDIST_POS] & pCcb->pairRsp[SMP_RKEYDIST_POS];
|
||||
|
||||
/* process received key */
|
||||
if (smpProcRcvKey(pCcb, &pCcb->pScr->keyInd, pMsg->data.pPacket, keyDist))
|
||||
{
|
||||
/* no responder keys to be distributed; start sending keys */
|
||||
pCcb->nextCmdCode = 0;
|
||||
|
||||
pMsg->hdr.event = SMP_MSG_INT_SEND_NEXT_KEY;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a key.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiActSendKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t keyDist;
|
||||
|
||||
/* get initiator key distribution */
|
||||
keyDist = pCcb->pairReq[SMP_IKEYDIST_POS] & pCcb->pairRsp[SMP_IKEYDIST_POS];
|
||||
|
||||
/* send next key */
|
||||
if ((pCcb->nextCmdCode == 0) && smpSendKey(pCcb, keyDist))
|
||||
{
|
||||
/* done sending keys; send ourselves pairing complete msg */
|
||||
pMsg->hdr.event = SMP_MSG_INT_PAIRING_CMPL;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP initiator 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 SMPI_MAIN_H
|
||||
#define SMPI_MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* state machine interface */
|
||||
extern const smpSmIf_t smpiSmIf;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/* state machine action functions */
|
||||
void smpiActPairReq(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActCheckSecurityReq(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActProcSecurityReq(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActProcPairRsp(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActProcPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActCnfVerify(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActStkEncrypt(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActSetupKeyDist(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActRcvKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smpiActSendKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SMPI_MAIN_H */
|
||||
Vendored
+497
@@ -0,0 +1,497 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP Secure Connections initiator state machine action functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpi_main.h"
|
||||
#include "smp_sc_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a public key and perform common auth select actions
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActAuthSelect(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Execute Common Auth Select actions */
|
||||
smpScActAuthSelect(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send public key to peer.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActSendPubKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Next command is the Public Key from the responder */
|
||||
pCcb->nextCmdCode = SMP_CMD_PUBLIC_KEY;
|
||||
|
||||
/* Send the public key */
|
||||
smpScSendPubKey(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Prepare for the Just Works/Numeric Comparison Use Case
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActJwncSetup(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Select Random Na (128-bits) */
|
||||
SecRand(pCcb->pScCcb->pScratch->Na_Ea, SMP_RAND_LEN);
|
||||
|
||||
SMP_TRACE_128("Rand Na", pCcb->pScCcb->pScratch->Na_Ea);
|
||||
|
||||
/* Set Ra and Rb to sero */
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, (uint8_t*) calc128Zeros);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, (uint8_t*) calc128Zeros);
|
||||
|
||||
/* Next command is a Pair Confirm from Responder */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_CNF;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the rand value to the responder for Just Works use case
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActJwncSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pCb = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Cb from responder is in Confirm from rsponder */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->PeerCb, pCb, SMP_CONFIRM_LEN);
|
||||
|
||||
SMP_TRACE_128("Peer Cb", pCcb->pScCcb->pScratch->PeerCb);
|
||||
|
||||
/* Next command is a Pair Random from Responder */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* Send the Pair Rand */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Na_Ea);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the confirm value for just works use case
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActJwncCalcF4(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pNb = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Nb from responder is in pPacket */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Nb_Eb, pNb, SMP_RAND_LEN);
|
||||
|
||||
smpScActJwncCalcF4(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the verify value for the just works use case
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActJwncCalcG2(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
secCmacMsg_t *pCmac = (secCmacMsg_t *) pMsg;
|
||||
|
||||
SMP_TRACE_128("Local Cb", pCmac->pCiphertext);
|
||||
|
||||
/* Check the result of the F4 confirm calculation */
|
||||
if (memcmp(pCcb->pScCcb->pScratch->PeerCb, pCmac->pCiphertext, SMP_CONFIRM_LEN))
|
||||
{
|
||||
smpScFailWithReattempt(pCcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
smpScActJwncCalcG2(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the Cai for the passkey use case using toolkit function F4
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActPkCalcCa(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Record the passkey on the first confirm */
|
||||
if (pCcb->pScCcb->pkPos == 0)
|
||||
{
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, (uint8_t *)calc128Zeros);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, (uint8_t *)calc128Zeros);
|
||||
|
||||
if (pMsg->dm.authRsp.authDataLen <= 3)
|
||||
{
|
||||
WStrReverseCpy(&pCcb->pScCcb->pScratch->Ra[13], pMsg->dm.authRsp.authData, pMsg->dm.authRsp.authDataLen);
|
||||
WStrReverseCpy(&pCcb->pScCcb->pScratch->Rb[13], pMsg->dm.authRsp.authData, pMsg->dm.authRsp.authDataLen);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get random Nai */
|
||||
SecRand(pCcb->pScCcb->pScratch->Na_Ea, SMP_RAND_LEN);
|
||||
|
||||
SMP_TRACE_128("Rand Na", pCcb->pScCcb->pScratch->Na_Ea);
|
||||
|
||||
/* Ca = f4(PKax, PKbx, Nai, Rai) where f4(U, V, x, Z) = AES-CMACx (U || V || Z) */
|
||||
SmpScCalcF4(pCcb, pMsg,
|
||||
pCcb->pScCcb->pLocalPublicKey->pubKeyX,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
smpGetPkBit(pCcb), pCcb->pScCcb->pScratch->Na_Ea);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the Cbi for the passkey use case using toolkit function F4
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActPkCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pNb = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Record the Nbi */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Nb_Eb, pNb, SMP_RAND_LEN);
|
||||
|
||||
/* Cb = f4(PKbx, PKax, Nbi, Rai) where f4(U, V, x, Z) = AES-CMACx (U || V || Z) */
|
||||
SmpScCalcF4(pCcb, pMsg,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
pCcb->pScCcb->pLocalPublicKey->pubKeyX,
|
||||
smpGetPkBit(pCcb), pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the Cai Confirm for the passkey use case command for passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActPkSendCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("Cai", pMsg->aes.pCiphertext);
|
||||
|
||||
/* Send the Cai to the peer */
|
||||
smpScSendPairCnf(pCcb, pMsg, pMsg->aes.pCiphertext);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the Nai Random command for passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActPkSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pCb = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Record the Cbi from the responder */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->PeerCb, pCb, SMP_CONFIRM_LEN);
|
||||
|
||||
/* Next command is the Pair Random */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* Send the Nai */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Na_Ea);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check the Cbi from the responder against the calculated Cbi for the passkey use case
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActPkCheck(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("Cbi", pMsg->aes.pCiphertext);
|
||||
|
||||
/* Verify the Calculated Cbi to previously received Cbi */
|
||||
if (memcmp(pCcb->pScCcb->pScratch->PeerCb, pMsg->aes.pCiphertext, SMP_RAND_LEN))
|
||||
{
|
||||
smpScFailWithReattempt(pCcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
/* Increment the bit position */
|
||||
if (++pCcb->pScCcb->pkPos >= SMP_PK_BIT_COUNT)
|
||||
{
|
||||
hdr.event = SMP_MSG_INT_PK_CMPL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Next command is the Pair Confirm */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_CNF;
|
||||
|
||||
hdr.event = SMP_MSG_INT_PK_NEXT;
|
||||
}
|
||||
|
||||
/* Post an event to move to the next passkey confirm or complete the process */
|
||||
hdr.param = pCcb->connId;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the Cb to compare against the Cb sent via OOB methods
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActOobCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* If the peer device's OOB data flag does not indicate remote OOB data has been received,
|
||||
clear Ra. */
|
||||
if (pCcb->pairRsp[SMP_OOB_POS] != SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, (uint8_t*) calc128Zeros);
|
||||
}
|
||||
|
||||
/* If we indicated the presence of remote OOB data has been received, calculate Cb. */
|
||||
if (pCcb->pairReq[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
/* Calculate Cb using Toolkit function F4 */
|
||||
SmpScCalcF4(pCcb, pMsg,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
0, pCcb->pScCcb->pScratch->Rb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Simulate the cb calculation is complete and clear rb */
|
||||
secCmacMsg_t msg;
|
||||
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, (uint8_t*)calc128Zeros);
|
||||
|
||||
msg.hdr.param = pCcb->connId;
|
||||
msg.hdr.event = SMP_MSG_WSF_CMAC_CMPL;
|
||||
msg.pPlainText = NULL;
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send random Na to responder in OOB pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActOobSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Only compare Cb if we indicated that we received OOB data. */
|
||||
if (pCcb->pairReq[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
SMP_TRACE_128("Initiator Cb", pMsg->aes.pCiphertext);
|
||||
|
||||
/* Verify the Cb matches the value passed from the responder via OOB methods */
|
||||
if (memcmp(pCcb->pScCcb->pScratch->PeerCb, pMsg->aes.pCiphertext, SMP_CONFIRM_LEN))
|
||||
{
|
||||
smpScFailWithReattempt(pCcb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next command is a Pair Rand from Responder */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* Calculate a the Na */
|
||||
SecRand(pCcb->pScCcb->pScratch->Na_Ea, SMP_RAND_LEN);
|
||||
|
||||
SMP_TRACE_128("Rand Na", pCcb->pScCcb->pScratch->Na_Ea);
|
||||
|
||||
/* Send the Na to the responder */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Na_Ea);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process random Nb from responder in OOB pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActOobProcRand(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pNb = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Copy the Nb from the responder */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Nb_Eb, pNb, SMP_RAND_LEN);
|
||||
|
||||
/* Initiate the DH Check */
|
||||
smpScActCalcSharedSecret(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the DH Key check.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActDHKeyCheckSend(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("DHKey Eb", pMsg->aes.pCiphertext);
|
||||
|
||||
/* Copy Eb from the smpScActDHKeyCalcF6Eb in LSB first format (as it will be received from peer) */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Nb_Eb, pMsg->aes.pCiphertext, SMP_RAND_LEN);
|
||||
|
||||
/* Next cmd message is the DH Key Check from the responder */
|
||||
pCcb->nextCmdCode = SMP_CMD_DHKEY_CHECK;
|
||||
|
||||
/* Send the DH Key check with Ea to the responder */
|
||||
smpScSendDHKeyCheck(pCcb, pMsg, pCcb->pScCcb->pScratch->Na_Ea);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Verify the DH Key Check.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smpiScActDHKeyCheckVerify(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pEbPeer = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;;
|
||||
|
||||
/* Verify the DH Key Check Eb with the value received from the responder */
|
||||
if (memcmp(pEbPeer, pCcb->pScCcb->pScratch->Nb_Eb, SMP_RAND_LEN) == 0)
|
||||
{
|
||||
uint8_t buf[SMP_KEY_LEN];
|
||||
uint8_t encKeyLen;
|
||||
|
||||
encKeyLen = (pCcb->pairReq[SMP_MAXKEY_POS] < pCcb->pairRsp[SMP_MAXKEY_POS]) ?
|
||||
pCcb->pairReq[SMP_MAXKEY_POS] : pCcb->pairRsp[SMP_MAXKEY_POS];
|
||||
|
||||
/* Adjust key based on max key length */
|
||||
memcpy(buf, pCcb->pScCcb->pLtk->ltk_t, encKeyLen);
|
||||
memset((buf + encKeyLen), 0, (SMP_KEY_LEN - encKeyLen));
|
||||
|
||||
/* Initiate encryption */
|
||||
DmSmpEncryptReq(pCcb->connId, smpGetScSecLevel(pCcb), buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* DH Key check failed */
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
hdr.param = pCcb->connId;
|
||||
hdr.status = SMP_ERR_DH_KEY_CHECK;
|
||||
|
||||
/* update repeated attempts count */
|
||||
pCcb->attempts++;
|
||||
SmpDbPairingFailed(pCcb->connId);
|
||||
|
||||
if (pCcb->attempts == pSmpCfg->maxAttempts)
|
||||
{
|
||||
/* max attempts reached */
|
||||
hdr.event = SMP_MSG_INT_MAX_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else just fail */
|
||||
hdr.event = SMP_MSG_DH_CHECK_FAILURE;
|
||||
}
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
Vendored
+643
@@ -0,0 +1,643 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP Secure Connections initiator state machine.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpi_main.h"
|
||||
#include "smp_sc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function enumeration */
|
||||
enum
|
||||
{
|
||||
SMPI_SC_ACT_NONE, /*!< No Action */
|
||||
SMPI_SC_ACT_CLEANUP, /*!< Process Pairing Cleanup */
|
||||
SMPI_SC_ACT_PAIRING_FAILED, /*!< Process Pairing Failed */
|
||||
SMPI_SC_ACT_PAIRING_CANCEL, /*!< Process Pairing Canceled */
|
||||
SMPI_SC_ACT_PAIR_CNF_CALC_1, /*!< Process Confirm Value Calculation 1 */
|
||||
SMPI_SC_ACT_PAIR_CNF_CALC_2, /*!< Process Confirm Value Calculation 2 */
|
||||
SMPI_SC_ACT_SEND_PAIR_CNF, /*!< Process Send Confirm Value */
|
||||
SMPI_SC_ACT_PAIR_CNF_VER_CALC_1, /*!< Process Received Confirm Value Verification Calculation 1 */
|
||||
SMPI_SC_ACT_PAIR_CNF_VER_CALC_2, /*!< Process Received Confirm Value Verification Calculation 2 */
|
||||
SMPI_SC_ACT_MAX_ATTEMPTS, /*!< Process Maximum Attempts */
|
||||
SMPI_SC_ACT_ATTEMPT_RCVD, /*!< Process Attempts Received */
|
||||
SMPI_SC_ACT_CHECK_ATTEMPTS, /*!< Process Check Attempts */
|
||||
SMPI_SC_ACT_NOTIFY_DM_ATTEMPTS, /*!< Process Notify DM of Attempts Failure */
|
||||
SMPI_SC_ACT_NOTIFY_DM_RSP_TO, /*!< Process Notify DM of Response Timeout Failure */
|
||||
SMPI_SC_ACT_PAIRING_CMPL, /*!< Process Pairing Complete */
|
||||
SMPI_SC_ACT_PAIR_REQ, /*!< Process Send Pairing Request */
|
||||
SMPI_SC_ACT_CHECK_SECURITY_REQ, /*!< Process Check Slave Security Request */
|
||||
SMPI_SC_ACT_PROC_SECURITY_REQ, /*!< Process Slave Security Request */
|
||||
SMPI_SC_ACT_PROC_PAIR_RSP, /*!< Process Pairing Response */
|
||||
SMPI_SC_ACT_PROC_PAIR_CNF, /*!< Process Pairing Confirmation */
|
||||
SMPI_SC_ACT_CNF_VERIFY, /*!< Process Verify Received Confirm Value */
|
||||
SMPI_SC_ACT_STK_ENCRYPT, /*!< Process STK Encryption */
|
||||
SMPI_SC_ACT_SETUP_KEY_DIST, /*!< Process Setup Key Distribution */
|
||||
SMPI_SC_ACT_RCV_KEY, /*!< Process Received Key */
|
||||
SMPI_SC_ACT_SEND_KEY, /*!< Process Send Key */
|
||||
|
||||
SMPI_SC_ACT_SEND_PUB_KEY, /*!< Process Send Public Key */
|
||||
SMPI_SC_ACT_SC_AUTH_SELECT, /*!< Process Select Authentication Method */
|
||||
|
||||
SMPI_SC_ACT_JWNC_SETUP, /*!< Process Just Works/Numeric Comparison Setup */
|
||||
SMPI_SC_ACT_JWNC_SEND_RAND, /*!< Process JW/NC Send Random Value */
|
||||
SMPI_SC_ACT_JWNC_CALC_F4, /*!< Process JW/NC Calculate F4 */
|
||||
SMPI_SC_ACT_JWNC_CALC_G2, /*!< Process JW/NC Calculate G2 */
|
||||
SMPI_SC_ACT_JWNC_DISPLAY, /*!< Process Display Numeric Comparison */
|
||||
|
||||
SMPI_SC_ACT_PK_SETUP, /*!< Process Passkey Setup */
|
||||
SMPI_SC_ACT_PK_KEYPRESS, /*!< Process Passkey Keypress */
|
||||
SMPI_SC_ACT_PK_SEND_KEYPRESS, /*!< Process Passkey Send Keypress */
|
||||
SMPI_SC_ACT_PK_CALC_CA, /*!< Process Passkey Calcuate Ca */
|
||||
SMPI_SC_ACT_PK_CALC_CB, /*!< Process Passkey Calculate Cb */
|
||||
SMPI_SC_ACT_PK_SEND_CNF, /*!< Process Passkey Send Confirm Value */
|
||||
SMPI_SC_ACT_PK_SEND_RAND, /*!< Process Passkey Send Random Value */
|
||||
SMPI_SC_ACT_PK_CHECK, /*!< Process Passkey Check Passkey Complete */
|
||||
|
||||
SMPI_SC_ACT_OOB_CALC_CB, /*!< Process OOB Calculate Cb */
|
||||
SMPI_SC_ACT_OOB_SEND_RAND, /*!< Process OOB Send Random Value */
|
||||
SMPI_SC_ACT_OOB_PROC_RAND, /*!< Process OOB Process Received Random Value */
|
||||
|
||||
SMPI_SC_ACT_CALC_DHKEY, /*!< Process DH Key Calculation */
|
||||
SMPI_SC_ACT_CALC_F5_TKEY, /*!< Process Calculate F5 Temporary Key */
|
||||
SMPI_SC_ACT_CALC_F5_MACKEY, /*!< Process Calculate F5 MAC Key */
|
||||
SMPI_SC_ACT_CALC_F5_LTK, /*!< Process Calculate F5 LTK */
|
||||
SMPI_SC_ACT_CALC_F6_EA, /*!< Process Calculate F6 Ea */
|
||||
SMPI_SC_ACT_CALC_F6_EB, /*!< Process Calculate F6 Eb */
|
||||
SMPI_SC_ACT_SEND_DH_CHECK, /*!< Process Send DH Key Check */
|
||||
SMPI_SC_ACT_VERIFY_DH_CHECK, /*!< Process Verify Received DH Key Check */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Static Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function table; order matches action function enumeration */
|
||||
static const smpAct_t smpiScActionTbl[] =
|
||||
{
|
||||
smpActNone,
|
||||
smpScActCleanup,
|
||||
smpScActPairingFailed,
|
||||
smpScActPairingCancel,
|
||||
smpActPairCnfCalc1,
|
||||
smpActPairCnfCalc2,
|
||||
smpActSendPairCnf,
|
||||
smpActPairCnfVerCalc1,
|
||||
smpActPairCnfVerCalc2,
|
||||
smpActMaxAttempts,
|
||||
smpActAttemptRcvd,
|
||||
smpActCheckAttempts,
|
||||
smpActNotifyDmAttemptsFailure,
|
||||
smpActNotifyDmRspToFailure,
|
||||
smpActPairingCmpl,
|
||||
smpiActPairReq,
|
||||
smpiActCheckSecurityReq,
|
||||
smpiActProcSecurityReq,
|
||||
smpiActProcPairRsp,
|
||||
smpiActProcPairCnf,
|
||||
smpiActCnfVerify,
|
||||
smpiActStkEncrypt,
|
||||
smpiActSetupKeyDist,
|
||||
smpiActRcvKey,
|
||||
smpiActSendKey,
|
||||
|
||||
smpiScActSendPubKey,
|
||||
smpiScActAuthSelect,
|
||||
|
||||
smpiScActJwncSetup,
|
||||
smpiScActJwncSendRand,
|
||||
smpiScActJwncCalcF4,
|
||||
smpiScActJwncCalcG2,
|
||||
smpScActJwncDisplay,
|
||||
|
||||
smpScActPkSetup,
|
||||
smpScActPkKeypress,
|
||||
smpScActPkSendKeypress,
|
||||
smpiScActPkCalcCa,
|
||||
smpiScActPkCalcCb,
|
||||
smpiScActPkSendCnf,
|
||||
smpiScActPkSendRand,
|
||||
smpiScActPkCheck,
|
||||
|
||||
smpiScActOobCalcCb,
|
||||
smpiScActOobSendRand,
|
||||
smpiScActOobProcRand,
|
||||
|
||||
smpScActCalcSharedSecret,
|
||||
smpScActCalcF5TKey,
|
||||
smpScActCalcF5MacKey,
|
||||
smpScActCalcF5Ltk,
|
||||
smpScActDHKeyCalcF6Ea,
|
||||
smpScActDHKeyCalcF6Eb,
|
||||
smpiScActDHKeyCheckSend,
|
||||
smpiScActDHKeyCheckVerify,
|
||||
};
|
||||
|
||||
/*! State table for common actions */
|
||||
static const smpTblEntry_t smpiScStateTblCommon[SMP_STATE_TBL_COMMON_MAX] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PAIRING_CANCEL},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SC_SM_ST_RSP_TO, SMPI_SC_ACT_PAIRING_FAILED},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
/*! State table for IDLE */
|
||||
static const smpTblEntry_t smpiScStateTblIdle[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_PAIR_REQ, SMPI_SC_SM_ST_PAIR_RSP, SMPI_SC_ACT_PAIR_REQ},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_CHECK_SECURITY_REQ},
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PROC_SECURITY_REQ},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_NONE},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PAIR_RSP */
|
||||
static const smpTblEntry_t smpiScStateTblPairRsp[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_MODE_SELECT, SMPI_SC_ACT_PROC_PAIR_RSP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_MODE_SELECT */
|
||||
static const smpTblEntry_t smpiScStateTblModeSelect[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_LESC, SMPI_SC_SM_ST_LESC_PIN, SMPI_SC_ACT_NONE},
|
||||
{SMP_MSG_INT_LEGACY, SMPI_SC_SM_ST_LEGACY_PIN, SMPI_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_LESC_PIN */
|
||||
static const smpTblEntry_t smpiScStateTblLescPin[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPI_SC_SM_ST_PUB_KEY, SMPI_SC_ACT_SEND_PUB_KEY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PUB_KEY */
|
||||
static const smpTblEntry_t smpiScStateTblPubKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_AUTH_SELECT, SMPI_SC_ACT_SC_AUTH_SELECT},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_AUTH_SELECT */
|
||||
static const smpTblEntry_t smpiScStateTblAuthSelect[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_JW_NC, SMPI_SC_SM_ST_JWNC_WAIT_CNF, SMPI_SC_ACT_JWNC_SETUP},
|
||||
{SMP_MSG_INT_PASSKEY, SMPI_SC_SM_ST_PK_KEYPRESS, SMPI_SC_ACT_PK_SETUP},
|
||||
{SMP_MSG_INT_OOB, SMPI_SC_SM_ST_OOB_SEND_RAND, SMPI_SC_ACT_OOB_CALC_CB},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_JWNC_WAIT_CNF */
|
||||
static const smpTblEntry_t smpiScStateTblJwNcWaitCnf[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_JWNC_RAND, SMPI_SC_ACT_JWNC_SEND_RAND},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_JWNC_RAND */
|
||||
static const smpTblEntry_t smpiScStateTblJwNcRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_JWNC_CHECK_1, SMPI_SC_ACT_JWNC_CALC_F4},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_JWNC_CHECK_1 */
|
||||
static const smpTblEntry_t smpiScStateTblJwNcCheck1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_JWNC_CHECK_2, SMPI_SC_ACT_JWNC_CALC_G2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_JWNC_CHECK_2 */
|
||||
static const smpTblEntry_t smpiScStateTblJwNcCheck2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_JWNC_WAIT_USER, SMPI_SC_ACT_JWNC_DISPLAY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_JWNC_WAIT_USER */
|
||||
static const smpTblEntry_t smpiScStateTblJwNcWaitUser[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_USER_CONFIRM, SMPI_SC_SM_ST_CALC_DHKEY, SMPI_SC_ACT_CALC_DHKEY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PK_KEYPRESS */
|
||||
static const smpTblEntry_t smprScStateTblPasskeyKeypress[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_PK_KEYPRESS, SMPI_SC_ACT_PK_KEYPRESS},
|
||||
{SMP_MSG_API_USER_KEYPRESS, SMPI_SC_SM_ST_PK_KEYPRESS, SMPI_SC_ACT_PK_SEND_KEYPRESS},
|
||||
{SMP_MSG_API_AUTH_RSP, SMPI_SC_SM_ST_PK_CALC, SMPI_SC_ACT_PK_CALC_CA},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PK_CALC */
|
||||
static const smpTblEntry_t smpiScStateTblPasskeyCalc[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_PK_CNF, SMPI_SC_ACT_PK_SEND_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PK_CNF */
|
||||
static const smpTblEntry_t smpiScStateTblPasskeyCnf[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_PK_RAND, SMPI_SC_ACT_PK_SEND_RAND},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PK_RAND */
|
||||
static const smpTblEntry_t smpiScStateTblPasskeyRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_PK_CHECK, SMPI_SC_ACT_PK_CALC_CB},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PK_CHECK */
|
||||
static const smpTblEntry_t smpiScStateTblPasskeyCheck[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_PK_REPEAT, SMPI_SC_ACT_PK_CHECK},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_PK_REPEAT */
|
||||
static const smpTblEntry_t smpiScStateTblPasskeyRepeat[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_PK_NEXT, SMPI_SC_SM_ST_PK_CALC, SMPI_SC_ACT_PK_CALC_CA},
|
||||
{SMP_MSG_INT_PK_CMPL, SMPI_SC_SM_ST_CALC_DHKEY, SMPI_SC_ACT_CALC_DHKEY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_OOB_SEND_RAND */
|
||||
static const smpTblEntry_t smpiScStateTblOobSendRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_OOB_WAIT_RAND, SMPI_SC_ACT_OOB_SEND_RAND},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_OOB_WAIT_RAND */
|
||||
static const smpTblEntry_t smpiScStateTblOobWaitRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_CALC_DHKEY, SMPI_SC_ACT_OOB_PROC_RAND},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_CALC_DHKEY */
|
||||
static const smpTblEntry_t smpiScStateTblCalcDHKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_ECC_CMPL, SMPI_SC_SM_ST_CALC_F5_TKEY, SMPI_SC_ACT_CALC_F5_TKEY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_CALC_F5_TKEY */
|
||||
static const smpTblEntry_t smpiScStateTblCalcF5TKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_CALC_F5_MACKEY, SMPI_SC_ACT_CALC_F5_MACKEY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_CALC_F5_MACKEY */
|
||||
static const smpTblEntry_t smpiScStateTblCalcF5MacKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_CALC_F5_LTK, SMPI_SC_ACT_CALC_F5_LTK},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_CALC_F5_LTK */
|
||||
static const smpTblEntry_t smpiScStateTblCalcF5LTK[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_CALC_F6_EA, SMPI_SC_ACT_CALC_F6_EA},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_CALC_F6_EA */
|
||||
static const smpTblEntry_t smpiScStateTblDhCalcF6Ea[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_CALC_F6_EB, SMPI_SC_ACT_CALC_F6_EB},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_CALC_F6_EB */
|
||||
static const smpTblEntry_t smpiScStateTblDhCalcF6Eb[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPI_SC_SM_ST_VERIFY_DH_CHECK, SMPI_SC_ACT_SEND_DH_CHECK},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPI_SC_SM_ST_VERIFY_DH_CHECK */
|
||||
static const smpTblEntry_t smpiScStateTblVerifyDHCheck[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_ENCRYPT, SMPI_SC_ACT_VERIFY_DH_CHECK},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy SMPI_SC_SM_ST_LEGACY_PIN */
|
||||
static const smpTblEntry_t smpiScStateTblLegacyPin[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPI_SC_SM_ST_CNF_CALC_1, SMPI_SC_ACT_PAIR_CNF_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_CALC_1 */
|
||||
static const smpTblEntry_t smpiScStateTblCnfCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SC_SM_ST_CNF_CALC_2, SMPI_SC_ACT_PAIR_CNF_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_CALC_2 */
|
||||
static const smpTblEntry_t smpiScStateTblCnfCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SC_SM_ST_PAIR_CNF, SMPI_SC_ACT_SEND_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy PAIR_CNF */
|
||||
static const smpTblEntry_t smpiScStateTblPairCnf[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_PAIR_RAND, SMPI_SC_ACT_PROC_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy PAIR_RAND */
|
||||
static const smpTblEntry_t smpiScStateTblPairRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_CNF_VER_CALC_1, SMPI_SC_ACT_PAIR_CNF_VER_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_VER_CALC_1 */
|
||||
static const smpTblEntry_t smpiScStateTblCnfVerCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SC_SM_ST_CNF_VER_CALC_2, SMPI_SC_ACT_PAIR_CNF_VER_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_VER_CALC_2 */
|
||||
static const smpTblEntry_t smpiScStateTblCnfVerCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SC_SM_ST_STK_CALC, SMPI_SC_ACT_CNF_VERIFY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy STK_CALC */
|
||||
static const smpTblEntry_t smpiScStateTblStkCalc[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SC_SM_ST_ENCRYPT, SMPI_SC_ACT_STK_ENCRYPT},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ENCRYPT */
|
||||
static const smpTblEntry_t smpiScStateTblEncrypt[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_ENCRYPT_CMPL, SMPI_SC_SM_ST_KEY_DIST, SMPI_SC_ACT_SETUP_KEY_DIST},
|
||||
{SMP_MSG_DM_ENCRYPT_FAILED, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SC_SM_ST_ENCRYPT, SMPI_SC_ACT_NONE},
|
||||
{SMP_MSG_DH_CHECK_FAILURE, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PAIRING_CANCEL},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for KEY_DIST */
|
||||
static const smpTblEntry_t smpiScStateTblKeyDist[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_KEY_DIST, SMPI_SC_ACT_RCV_KEY},
|
||||
{SMP_MSG_INT_SEND_NEXT_KEY, SMPI_SC_SM_ST_KEY_DIST, SMPI_SC_ACT_SEND_KEY},
|
||||
{SMP_MSG_INT_PAIRING_CMPL, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_PAIRING_CMPL},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SC_SM_ST_KEY_DIST, SMPI_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ATTEMPTS */
|
||||
static const smpTblEntry_t smpiScStateTblAttempts[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_WI_TIMEOUT, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_CHECK_ATTEMPTS},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SC_SM_ST_RSP_TO, SMPI_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PKT, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_ATTEMPT_RCVD},
|
||||
{SMP_MSG_API_PAIR_REQ, SMPI_SC_SM_ST_PAIR_RSP, SMPI_SC_ACT_NOTIFY_DM_ATTEMPTS},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SC_SM_ST_ATTEMPTS, SMPI_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for RSP_TO */
|
||||
static const smpTblEntry_t smpiScStateTblRspTo[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SC_SM_ST_IDLE, SMPI_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SC_SM_ST_RSP_TO, SMPI_SC_ACT_NONE},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SC_SM_ST_RSP_TO, SMPI_SC_ACT_NONE},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SC_SM_ST_RSP_TO, SMPI_SC_ACT_NONE},
|
||||
{SMP_MSG_API_PAIR_REQ, SMPI_SC_SM_ST_RSP_TO, SMPI_SC_ACT_NOTIFY_DM_RSP_TO},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! Table of individual state tables */
|
||||
static const smpTblEntry_t * const smpiScStateTbl[] =
|
||||
{
|
||||
smpiScStateTblIdle,
|
||||
smpiScStateTblPairRsp,
|
||||
smpiScStateTblModeSelect,
|
||||
smpiScStateTblLescPin,
|
||||
smpiScStateTblPubKey,
|
||||
smpiScStateTblAuthSelect,
|
||||
smpiScStateTblJwNcWaitCnf,
|
||||
smpiScStateTblJwNcRand,
|
||||
smpiScStateTblJwNcCheck1,
|
||||
smpiScStateTblJwNcCheck2,
|
||||
smpiScStateTblJwNcWaitUser,
|
||||
|
||||
smprScStateTblPasskeyKeypress,
|
||||
smpiScStateTblPasskeyCalc,
|
||||
smpiScStateTblPasskeyCnf,
|
||||
smpiScStateTblPasskeyRand,
|
||||
smpiScStateTblPasskeyCheck,
|
||||
smpiScStateTblPasskeyRepeat,
|
||||
|
||||
smpiScStateTblOobSendRand,
|
||||
smpiScStateTblOobWaitRand,
|
||||
|
||||
smpiScStateTblCalcDHKey,
|
||||
smpiScStateTblCalcF5TKey,
|
||||
smpiScStateTblCalcF5MacKey,
|
||||
smpiScStateTblCalcF5LTK,
|
||||
smpiScStateTblDhCalcF6Ea,
|
||||
smpiScStateTblDhCalcF6Eb,
|
||||
smpiScStateTblVerifyDHCheck,
|
||||
|
||||
smpiScStateTblLegacyPin,
|
||||
smpiScStateTblCnfCalc1,
|
||||
smpiScStateTblCnfCalc2,
|
||||
smpiScStateTblPairCnf,
|
||||
smpiScStateTblPairRand,
|
||||
smpiScStateTblCnfVerCalc1,
|
||||
smpiScStateTblCnfVerCalc2,
|
||||
smpiScStateTblStkCalc,
|
||||
smpiScStateTblEncrypt,
|
||||
smpiScStateTblKeyDist,
|
||||
smpiScStateTblAttempts,
|
||||
smpiScStateTblRspTo
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! state machine interface */
|
||||
const smpSmIf_t smpiScSmIf =
|
||||
{
|
||||
smpiScStateTbl,
|
||||
smpiScActionTbl,
|
||||
smpiScStateTblCommon
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP initiator role.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpiScInit(void)
|
||||
{
|
||||
/* set up callback interface */
|
||||
smpCb.pMaster = &smpiScSmIf;
|
||||
|
||||
/* General SMP LESC Initialization */
|
||||
SmpScInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Convert state into string for diagnostics.
|
||||
*
|
||||
* \param state State ID
|
||||
*
|
||||
* \return State string.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *smpiStateStr(uint8_t state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case SMPI_SC_SM_ST_IDLE: return (uint8_t*) "I_IDLE";
|
||||
case SMPI_SC_SM_ST_PAIR_RSP: return (uint8_t*) "I_PAIR_RSP";
|
||||
case SMPI_SC_SM_ST_MODE_SELECT: return (uint8_t*) "I_MODE_SELECT";
|
||||
case SMPI_SC_SM_ST_LESC_PIN: return (uint8_t*) "I_LESC_PIN";
|
||||
case SMPI_SC_SM_ST_PUB_KEY: return (uint8_t*) "I_PUB_KEY";
|
||||
case SMPI_SC_SM_ST_AUTH_SELECT: return (uint8_t*) "I_AUTH_SELECT";
|
||||
case SMPI_SC_SM_ST_JWNC_WAIT_CNF: return (uint8_t*) "I_JWNC_WAIT_CNF";
|
||||
case SMPI_SC_SM_ST_JWNC_RAND: return (uint8_t*) "I_JWNC_RAND";
|
||||
case SMPI_SC_SM_ST_JWNC_CHECK_1: return (uint8_t*) "I_JWNC_CHECK_1";
|
||||
case SMPI_SC_SM_ST_JWNC_CHECK_2: return (uint8_t*) "I_JWNC_CHECK_2";
|
||||
case SMPI_SC_SM_ST_JWNC_WAIT_USER: return (uint8_t*) "I_JWNC_WAIT_USER";
|
||||
case SMPI_SC_SM_ST_PK_KEYPRESS: return (uint8_t*) "I_PK_KEYPRESS";
|
||||
case SMPI_SC_SM_ST_PK_CALC: return (uint8_t*) "I_PK_CALC";
|
||||
case SMPI_SC_SM_ST_PK_CNF: return (uint8_t*) "I_PK_CNF";
|
||||
case SMPI_SC_SM_ST_PK_RAND: return (uint8_t*) "I_PK_RAND";
|
||||
case SMPI_SC_SM_ST_PK_CHECK: return (uint8_t*) "I_PK_CHECK";
|
||||
case SMPI_SC_SM_ST_PK_REPEAT: return (uint8_t*) "I_PK_REPEAT";
|
||||
|
||||
case SMPI_SC_SM_ST_OOB_SEND_RAND: return (uint8_t*) "I_OOB_SEND_RAND";
|
||||
case SMPI_SC_SM_ST_OOB_WAIT_RAND: return (uint8_t*) "I_OOB_WAIT_RAND";
|
||||
|
||||
case SMPI_SC_SM_ST_CALC_DHKEY: return (uint8_t*) "I_CALC_DHKEY";
|
||||
case SMPI_SC_SM_ST_CALC_F5_TKEY: return (uint8_t*) "I_CALC_F5_TKEY";
|
||||
case SMPI_SC_SM_ST_CALC_F5_MACKEY: return (uint8_t*) "I_CALC_F5_MACKEY";
|
||||
case SMPI_SC_SM_ST_CALC_F5_LTK: return (uint8_t*) "I_CALC_F5_LTK";
|
||||
case SMPI_SC_SM_ST_CALC_F6_EA: return (uint8_t*) "I_CALC_F6_EA";
|
||||
case SMPI_SC_SM_ST_CALC_F6_EB: return (uint8_t*) "I_CALC_F6_EB";
|
||||
case SMPI_SC_SM_ST_VERIFY_DH_CHECK: return (uint8_t*) "I_VERIFY_DH_CHECK";
|
||||
|
||||
case SMPI_SC_SM_ST_LEGACY_PIN: return (uint8_t*) "I_LEGACY_PIN";
|
||||
case SMPI_SC_SM_ST_CNF_CALC_1: return (uint8_t*) "I_CNF_CALC_1";
|
||||
case SMPI_SC_SM_ST_CNF_CALC_2: return (uint8_t*) "I_CNF_CALC_2";
|
||||
case SMPI_SC_SM_ST_PAIR_CNF: return (uint8_t*) "I_PAIR_CNF";
|
||||
case SMPI_SC_SM_ST_PAIR_RAND: return (uint8_t*) "I_PAIR_RAND";
|
||||
case SMPI_SC_SM_ST_CNF_VER_CALC_1: return (uint8_t*) "I_CNF_VER_CALC_1";
|
||||
case SMPI_SC_SM_ST_CNF_VER_CALC_2: return (uint8_t*) "I_CNF_VER_CALC_2";
|
||||
case SMPI_SC_SM_ST_STK_CALC: return (uint8_t*) "I_STK_CALC";
|
||||
case SMPI_SC_SM_ST_ENCRYPT: return (uint8_t*) "I_ENCRYPT";
|
||||
case SMPI_SC_SM_ST_KEY_DIST: return (uint8_t*) "I_KEY_DIST";
|
||||
case SMPI_SC_SM_ST_ATTEMPTS: return (uint8_t*) "I_ATTEMPTS";
|
||||
case SMPI_SC_SM_ST_RSP_TO: return (uint8_t*) "I_RSP_TO";
|
||||
|
||||
default: return (uint8_t*) "I_Unknown";
|
||||
}
|
||||
}
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP initiator state machine.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpi_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function enumeration */
|
||||
enum
|
||||
{
|
||||
SMPI_ACT_NONE, /*!< No Action */
|
||||
SMPI_ACT_CLEANUP, /*!< Process Pairing Cleanup */
|
||||
SMPI_ACT_PAIRING_FAILED, /*!< Process Pairing Failed */
|
||||
SMPI_ACT_PAIRING_CANCEL, /*!< Process Pairing Canceled */
|
||||
SMPI_ACT_PAIR_CNF_CALC_1, /*!< Process Confirm Value Calculation 1 */
|
||||
SMPI_ACT_PAIR_CNF_CALC_2, /*!< Process Confirm Value Calculation 2 */
|
||||
SMPI_ACT_SEND_PAIR_CNF, /*!< Process Send Confirm Value */
|
||||
SMPI_ACT_PAIR_CNF_VER_CALC_1, /*!< Process Received Confirm Value Verification Calculation 1 */
|
||||
SMPI_ACT_PAIR_CNF_VER_CALC_2, /*!< Process Received Confirm Value Verification Calculation 2 */
|
||||
SMPI_ACT_MAX_ATTEMPTS, /*!< Process Maximum Attempts */
|
||||
SMPI_ACT_ATTEMPT_RCVD, /*!< Process Attempts Received */
|
||||
SMPI_ACT_CHECK_ATTEMPTS, /*!< Process Check Attempts */
|
||||
SMPI_ACT_NOTIFY_DM_ATTEMPTS, /*!< Process Notify DM of Attempts Failure */
|
||||
SMPI_ACT_NOTIFY_DM_RSP_TO, /*!< Process Notify DM of Response Timeout Failure */
|
||||
SMPI_ACT_PAIRING_CMPL, /*!< Process Pairing Complete */
|
||||
SMPI_ACT_PAIR_REQ, /*!< Process Send Pairing Request */
|
||||
SMPI_ACT_CHECK_SECURITY_REQ, /*!< Process Check Security Request */
|
||||
SMPI_ACT_PROC_SECURITY_REQ, /*!< Process Security Request */
|
||||
SMPI_ACT_PROC_PAIR_RSP, /*!< Process Pairing Response */
|
||||
SMPI_ACT_PROC_PAIR_CNF, /*!< Process Pairing Confirmation */
|
||||
SMPI_ACT_CNF_VERIFY, /*!< Process Verify Received Confirm Value */
|
||||
SMPI_ACT_STK_ENCRYPT, /*!< Process STK Encryption */
|
||||
SMPI_ACT_SETUP_KEY_DIST, /*!< Process Setup Key Distribution */
|
||||
SMPI_ACT_RCV_KEY, /*!< Process Received Key */
|
||||
SMPI_ACT_SEND_KEY /*!< Process Send Key */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Static Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function table; order matches action function enumeration */
|
||||
static const smpAct_t smpiActionTbl[] =
|
||||
{
|
||||
smpActNone,
|
||||
smpActCleanup,
|
||||
smpActPairingFailed,
|
||||
smpActPairingCancel,
|
||||
smpActPairCnfCalc1,
|
||||
smpActPairCnfCalc2,
|
||||
smpActSendPairCnf,
|
||||
smpActPairCnfVerCalc1,
|
||||
smpActPairCnfVerCalc2,
|
||||
smpActMaxAttempts,
|
||||
smpActAttemptRcvd,
|
||||
smpActCheckAttempts,
|
||||
smpActNotifyDmAttemptsFailure,
|
||||
smpActNotifyDmRspToFailure,
|
||||
smpActPairingCmpl,
|
||||
smpiActPairReq,
|
||||
smpiActCheckSecurityReq,
|
||||
smpiActProcSecurityReq,
|
||||
smpiActProcPairRsp,
|
||||
smpiActProcPairCnf,
|
||||
smpiActCnfVerify,
|
||||
smpiActStkEncrypt,
|
||||
smpiActSetupKeyDist,
|
||||
smpiActRcvKey,
|
||||
smpiActSendKey
|
||||
};
|
||||
|
||||
/*! State table for common actions */
|
||||
static const smpTblEntry_t smpiStateTblCommon[SMP_STATE_TBL_COMMON_MAX] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SM_ST_IDLE, SMPI_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SM_ST_IDLE, SMPI_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SM_ST_IDLE, SMPI_ACT_PAIRING_CANCEL},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SM_ST_RSP_TO, SMPI_ACT_PAIRING_FAILED},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
/*! State table for IDLE */
|
||||
static const smpTblEntry_t smpiStateTblIdle[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_PAIR_REQ, SMPI_SM_ST_PAIR_RSP, SMPI_ACT_PAIR_REQ},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SM_ST_IDLE, SMPI_ACT_CLEANUP},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SM_ST_IDLE, SMPI_ACT_CHECK_SECURITY_REQ},
|
||||
{SMP_MSG_CMD_PKT, SMPI_SM_ST_IDLE, SMPI_ACT_PROC_SECURITY_REQ},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SM_ST_IDLE, SMPI_ACT_NONE},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SM_ST_IDLE, SMPI_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PAIR_RSP */
|
||||
static const smpTblEntry_t smpiStateTblPairRsp[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SM_ST_PIN, SMPI_ACT_PROC_PAIR_RSP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PIN */
|
||||
static const smpTblEntry_t smpiStateTblPin[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPI_SM_ST_CNF_CALC_1, SMPI_ACT_PAIR_CNF_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_CALC_1 */
|
||||
static const smpTblEntry_t smpiStateTblCnfCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SM_ST_CNF_CALC_2, SMPI_ACT_PAIR_CNF_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_CALC_2 */
|
||||
static const smpTblEntry_t smpiStateTblCnfCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SM_ST_PAIR_CNF, SMPI_ACT_SEND_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PAIR_CNF */
|
||||
static const smpTblEntry_t smpiStateTblPairCnf[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SM_ST_PAIR_RAND, SMPI_ACT_PROC_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PAIR_RAND */
|
||||
static const smpTblEntry_t smpiStateTblPairRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SM_ST_CNF_VER_CALC_1, SMPI_ACT_PAIR_CNF_VER_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_VER_CALC_1 */
|
||||
static const smpTblEntry_t smpiStateTblCnfVerCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SM_ST_CNF_VER_CALC_2, SMPI_ACT_PAIR_CNF_VER_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_VER_CALC_2 */
|
||||
static const smpTblEntry_t smpiStateTblCnfVerCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SM_ST_STK_CALC, SMPI_ACT_CNF_VERIFY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for STK_CALC */
|
||||
static const smpTblEntry_t smpiStateTblStkCalc[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPI_SM_ST_ENCRYPT, SMPI_ACT_STK_ENCRYPT},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPI_SM_ST_ATTEMPTS, SMPI_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ENCRYPT */
|
||||
static const smpTblEntry_t smpiStateTblEncrypt[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_ENCRYPT_CMPL, SMPI_SM_ST_KEY_DIST, SMPI_ACT_SETUP_KEY_DIST},
|
||||
{SMP_MSG_DM_ENCRYPT_FAILED, SMPI_SM_ST_IDLE, SMPI_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SM_ST_ENCRYPT, SMPI_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for KEY_DIST */
|
||||
static const smpTblEntry_t smpiStateTblKeyDist[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPI_SM_ST_KEY_DIST, SMPI_ACT_RCV_KEY},
|
||||
{SMP_MSG_INT_SEND_NEXT_KEY, SMPI_SM_ST_KEY_DIST, SMPI_ACT_SEND_KEY},
|
||||
{SMP_MSG_INT_PAIRING_CMPL, SMPI_SM_ST_IDLE, SMPI_ACT_PAIRING_CMPL},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SM_ST_KEY_DIST, SMPI_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ATTEMPTS */
|
||||
static const smpTblEntry_t smpiStateTblAttempts[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_WI_TIMEOUT, SMPI_SM_ST_IDLE, SMPI_ACT_CHECK_ATTEMPTS},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SM_ST_RSP_TO, SMPI_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PKT, SMPI_SM_ST_ATTEMPTS, SMPI_ACT_ATTEMPT_RCVD},
|
||||
{SMP_MSG_API_PAIR_REQ, SMPI_SM_ST_PAIR_RSP, SMPI_ACT_NOTIFY_DM_ATTEMPTS},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SM_ST_IDLE, SMPI_ACT_CLEANUP},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SM_ST_IDLE, SMPI_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SM_ST_ATTEMPTS, SMPI_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for RSP_TO */
|
||||
static const smpTblEntry_t smpiStateTblRspTo[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPI_SM_ST_IDLE, SMPI_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPI_SM_ST_RSP_TO, SMPI_ACT_NONE},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPI_SM_ST_RSP_TO, SMPI_ACT_NONE},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPI_SM_ST_RSP_TO, SMPI_ACT_NONE},
|
||||
{SMP_MSG_API_PAIR_REQ, SMPI_SM_ST_RSP_TO, SMPI_ACT_NOTIFY_DM_RSP_TO},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! Table of individual state tables */
|
||||
static const smpTblEntry_t * const smpiStateTbl[] =
|
||||
{
|
||||
smpiStateTblIdle,
|
||||
smpiStateTblPairRsp,
|
||||
smpiStateTblPin,
|
||||
smpiStateTblCnfCalc1,
|
||||
smpiStateTblCnfCalc2,
|
||||
smpiStateTblPairCnf,
|
||||
smpiStateTblPairRand,
|
||||
smpiStateTblCnfVerCalc1,
|
||||
smpiStateTblCnfVerCalc2,
|
||||
smpiStateTblStkCalc,
|
||||
smpiStateTblEncrypt,
|
||||
smpiStateTblKeyDist,
|
||||
smpiStateTblAttempts,
|
||||
smpiStateTblRspTo
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! state machine interface */
|
||||
const smpSmIf_t smpiSmIf =
|
||||
{
|
||||
smpiStateTbl,
|
||||
smpiActionTbl,
|
||||
smpiStateTblCommon
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP initiator role.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmpiInit(void)
|
||||
{
|
||||
/* set up callback interface */
|
||||
smpCb.pMaster = &smpiSmIf;
|
||||
smpCb.procPairing = smpProcPairing;
|
||||
smpCb.procAuthReq = smpAuthReq;
|
||||
}
|
||||
|
||||
+418
@@ -0,0 +1,418 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP responder state machine action functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpr_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a slave security request.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActSendSecurityReq(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_SECURITY_REQ_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_SECURITY_REQ);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.securityReq.auth);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a pairing request packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActProcPairReq(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
dmSecPairIndEvt_t pairInd;
|
||||
uint8_t *p;
|
||||
|
||||
/* allocate scratch buffer */
|
||||
if (pCcb->pScr == NULL)
|
||||
{
|
||||
if ((pCcb->pScr = WsfBufAlloc(sizeof(smpScratch_t))) == NULL)
|
||||
{
|
||||
/* alloc failed; cancel pairing */
|
||||
pMsg->hdr.status = SMP_ERR_UNSPECIFIED;
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* should not happen */
|
||||
SMP_TRACE_ERR0("pScr already allocated");
|
||||
}
|
||||
|
||||
/* set connection busy */
|
||||
DmConnSetIdle(pCcb->connId, DM_IDLE_SMP_PAIR, DM_CONN_BUSY);
|
||||
|
||||
p = pMsg->data.pPacket + L2C_PAYLOAD_START;
|
||||
|
||||
/* store packet for later */
|
||||
memcpy(pCcb->pairReq, p, SMP_PAIR_REQ_LEN);
|
||||
|
||||
/* parse packet to callback event structure */
|
||||
p++; /* skip command code */
|
||||
p++; /* skip IO capabilities */
|
||||
BSTREAM_TO_UINT8(pairInd.oob, p);
|
||||
BSTREAM_TO_UINT8(pairInd.auth, p);
|
||||
p++; /* skip max key len */
|
||||
BSTREAM_TO_UINT8(pairInd.iKeyDist, p);
|
||||
BSTREAM_TO_UINT8(pairInd.rKeyDist, p);
|
||||
|
||||
/* call app callback */
|
||||
pairInd.hdr.param = pCcb->connId;
|
||||
pairInd.hdr.event = DM_SEC_PAIR_IND;
|
||||
DmSmpCbackExec((dmEvt_t *) &pairInd);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a pairing response packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActSendPairRsp(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
uint8_t oob;
|
||||
uint8_t display;
|
||||
|
||||
/* build packet to pairing response buffer in ccb */
|
||||
p = pCcb->pairRsp;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_RSP);
|
||||
UINT8_TO_BSTREAM(p, pSmpCfg->ioCap);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.oob);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.auth);
|
||||
UINT8_TO_BSTREAM(p, pSmpCfg->maxKeyLen);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.iKeyDist);
|
||||
UINT8_TO_BSTREAM(p, pMsg->dm.pair.rKeyDist);
|
||||
|
||||
/* process pairing request and response data */
|
||||
if (smpCb.procPairing(pCcb, &oob, &display))
|
||||
{
|
||||
/* set next expected packet */
|
||||
if ((pCcb->pairReq[SMP_AUTHREQ_POS] & pMsg->dm.pair.auth & SMP_AUTH_SC_FLAG) == SMP_AUTH_SC_FLAG)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_PUBLIC_KEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_CNF;
|
||||
}
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* send pairing response; allocate packet buffer */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_RSP_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet from pairing response buffer */
|
||||
memcpy(pPkt + L2C_PAYLOAD_START, pCcb->pairRsp, SMP_PAIR_RSP_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
|
||||
/* request authentication data */
|
||||
smpCb.procAuthReq(pCcb, oob, display);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store pairing confirm value.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActProcPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* go to start of packet */
|
||||
p = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* store confirm value */
|
||||
memcpy(pCcb->pScr->buf.b3, p, SMP_CONFIRM_LEN);
|
||||
|
||||
/* discard any packets received erroneously at this point */
|
||||
pCcb->nextCmdCode = 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store pairing confirm value and perform first part of pairing confirm calculation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActProcPairCnfCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smprActProcPairCnf(pCcb, pMsg);
|
||||
|
||||
/* get random number to scratchpad */
|
||||
SecRand(pCcb->pScr->buf.b4, SMP_RAND_LEN);
|
||||
|
||||
/* execute calculation */
|
||||
smpCalcC1Part1(pCcb, pCcb->pScr->buf.b1, pCcb->pScr->buf.b4);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Verify the calculated confirm value. If ok, proceed with STK calculcation.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActCnfVerify(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* compare calculated confirm value with value received earlier */
|
||||
if (memcmp(pMsg->aes.pCiphertext, pCcb->pScr->buf.b3, SMP_CONFIRM_LEN) != 0)
|
||||
{
|
||||
/* confirm values don't match; update repeated attempts count */
|
||||
pCcb->attempts++;
|
||||
SmpDbPairingFailed(pCcb->connId);
|
||||
pMsg->hdr.status = SMP_ERR_CONFIRM_VALUE;
|
||||
|
||||
if (pCcb->attempts == pSmpCfg->maxAttempts)
|
||||
{
|
||||
/* max attempts reached */
|
||||
pMsg->hdr.event = SMP_MSG_INT_MAX_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else just fail */
|
||||
pMsg->hdr.event = SMP_MSG_API_CANCEL_REQ;
|
||||
}
|
||||
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* do STK calculation: key, responder rand, initiator rand */
|
||||
smpCalcS1(pCcb, pCcb->pScr->buf.b1, pCcb->pScr->buf.b4, pCcb->pScr->buf.b2);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store STK and then send a pairing random packet.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActSendPairRandom(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pPkt;
|
||||
uint8_t *p;
|
||||
uint8_t encKeyLen;
|
||||
|
||||
/* get max STK length */
|
||||
encKeyLen = (pCcb->pairReq[SMP_MAXKEY_POS] < pCcb->pairRsp[SMP_MAXKEY_POS]) ?
|
||||
pCcb->pairReq[SMP_MAXKEY_POS] : pCcb->pairRsp[SMP_MAXKEY_POS];
|
||||
|
||||
/* store STK and adjust based on max key length */
|
||||
memcpy(pCcb->pScr->buf.b3, pMsg->aes.pCiphertext, encKeyLen);
|
||||
memset((pCcb->pScr->buf.b3 + encKeyLen), 0, (SMP_KEY_LEN - encKeyLen));
|
||||
|
||||
/* start smp response timer */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* allocate packet buffer and send pairing random packet */
|
||||
if ((pPkt = smpMsgAlloc(SMP_PAIR_RAND_LEN + L2C_PAYLOAD_START)) != NULL)
|
||||
{
|
||||
/* build packet */
|
||||
p = pPkt + L2C_PAYLOAD_START;
|
||||
UINT8_TO_BSTREAM(p, SMP_CMD_PAIR_RAND);
|
||||
memcpy(p, pCcb->pScr->buf.b4, SMP_RAND_LEN);
|
||||
|
||||
/* send packet */
|
||||
smpSendPkt(pCcb, pPkt);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set up key distribution.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActSetupKeyDist(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* don't receive anything yet */
|
||||
pCcb->nextCmdCode = 0;
|
||||
|
||||
/* start smp response timer once for entire key distribution phase */
|
||||
smpStartRspTimer(pCcb);
|
||||
|
||||
/* initialize parameters in key ind struct */
|
||||
pCcb->pScr->keyInd.hdr.param = pCcb->connId;
|
||||
pCcb->pScr->keyInd.secLevel = (pCcb->auth & SMP_AUTH_MITM_FLAG) ?
|
||||
DM_SEC_LEVEL_ENC_AUTH : DM_SEC_LEVEL_ENC;
|
||||
pCcb->pScr->keyInd.encKeyLen =
|
||||
(pCcb->pairReq[SMP_MAXKEY_POS] < pCcb->pairRsp[SMP_MAXKEY_POS]) ?
|
||||
pCcb->pairReq[SMP_MAXKEY_POS] : pCcb->pairRsp[SMP_MAXKEY_POS];
|
||||
|
||||
/* start key distribution */
|
||||
smprActSendKey(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a key.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActSendKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t keyDist;
|
||||
|
||||
/* get responder key distribution */
|
||||
keyDist = pCcb->pairReq[SMP_RKEYDIST_POS] & pCcb->pairRsp[SMP_RKEYDIST_POS];
|
||||
|
||||
/* send next key; if done sending keys set up to receive keys */
|
||||
if ((pCcb->nextCmdCode == 0) && smpSendKey(pCcb, keyDist))
|
||||
{
|
||||
pCcb->nextCmdCode = 0;
|
||||
|
||||
/* get initiator key distribution */
|
||||
keyDist = pCcb->pairReq[SMP_IKEYDIST_POS] & pCcb->pairRsp[SMP_IKEYDIST_POS];
|
||||
|
||||
/* set up to receive first key distribution packet */
|
||||
if (keyDist & SMP_KEY_DIST_ENC)
|
||||
{
|
||||
if (smpCb.lescSupported && pCcb->pScCcb->lescEnabled)
|
||||
{
|
||||
if (keyDist & SMP_KEY_DIST_ID)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_ID_INFO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_ENC_INFO;
|
||||
}
|
||||
}
|
||||
else if (keyDist & SMP_KEY_DIST_ID)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_ID_INFO;
|
||||
}
|
||||
else if (keyDist & SMP_KEY_DIST_SIGN)
|
||||
{
|
||||
pCcb->nextCmdCode = SMP_CMD_SIGN_INFO;
|
||||
}
|
||||
|
||||
if (pCcb->nextCmdCode == 0)
|
||||
{
|
||||
/* no keys to receive; send ourselves pairing complete msg */
|
||||
pMsg->hdr.event = SMP_MSG_INT_PAIRING_CMPL;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Receive a key.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprActRcvKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t keyDist;
|
||||
|
||||
/* get initiator key distribution */
|
||||
keyDist = pCcb->pairReq[SMP_IKEYDIST_POS] & pCcb->pairRsp[SMP_IKEYDIST_POS];
|
||||
|
||||
/* process received key */
|
||||
if (smpProcRcvKey(pCcb, &pCcb->pScr->keyInd, pMsg->data.pPacket, keyDist))
|
||||
{
|
||||
/* no more keys to receive; send ourselves pairing complete msg */
|
||||
pMsg->hdr.event = SMP_MSG_INT_PAIRING_CMPL;
|
||||
smpSmExecute(pCcb, pMsg);
|
||||
}
|
||||
}
|
||||
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP responder 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 SMPR_MAIN_H
|
||||
#define SMPR_MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* state machine interface */
|
||||
extern const smpSmIf_t smprSmIf;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
void smprActSendSecurityReq(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActProcPairReq(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActSendPairRsp(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActProcPairCnf(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActProcPairCnfCalc1(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActCnfVerify(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActSendPairRandom(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActSetupKeyDist(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActSendKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
void smprActRcvKey(smpCcb_t *pCcb, smpMsg_t *pMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SMPR_MAIN_H */
|
||||
Vendored
+559
@@ -0,0 +1,559 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP Secure Connections responder state machine action functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "util/calc128.h"
|
||||
#include "util/wstr.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpi_main.h"
|
||||
#include "smp_sc_main.h"
|
||||
#include "dm_api.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store the pin.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActStoreLescPin(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
if (pCcb->pScCcb->authType == SMP_AUTH_TYPE_PASSKEY)
|
||||
{
|
||||
/* Store the pin */
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, (uint8_t *)calc128Zeros);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, (uint8_t *)calc128Zeros);
|
||||
|
||||
if (pMsg->dm.authRsp.authDataLen <= 3)
|
||||
{
|
||||
WStrReverseCpy(&pCcb->pScCcb->pScratch->Ra[13], pMsg->dm.authRsp.authData, pMsg->dm.authRsp.authDataLen);
|
||||
WStrReverseCpy(&pCcb->pScCcb->pScratch->Rb[13], pMsg->dm.authRsp.authData, pMsg->dm.authRsp.authDataLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Responder public key exchange.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActSendPubKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Execute Common Auth Select actions */
|
||||
smpScActAuthSelect(pCcb, pMsg);
|
||||
|
||||
/* Send our public key */
|
||||
smpScSendPubKey(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Prepare for the Just Works/Numeric Comparison Use Case
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActJwncSetup(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Select Random Na (128-bits) */
|
||||
SecRand(pCcb->pScCcb->pScratch->Nb_Eb, SMP_RAND_LEN);
|
||||
|
||||
SMP_TRACE_128("Rand Nb", pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
|
||||
/* Set Ra and Rb to zero */
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, (uint8_t*) calc128Zeros);
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, (uint8_t*) calc128Zeros);
|
||||
|
||||
/* Next command is a Pair Rand from Initiator */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* Perform F4 Calculation of Cb */
|
||||
smpScActJwncCalcF4(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the confirm to the initiator for Just Works/Numeric Comparison pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActJwncSendCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("JWNC Confirm", pMsg->aes.pCiphertext);
|
||||
|
||||
smpScSendPairCnf(pCcb, pMsg, pMsg->aes.pCiphertext);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate Toolkit function G2 for Just Works pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActJwncCalcG2(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pNa = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Na from initiator is in Random Cmd from initiator */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Na_Ea, pNa, SMP_RAND_LEN);
|
||||
|
||||
/* Calculate Vb using G2 */
|
||||
smpScActJwncCalcG2(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notify the application of the verify value calculated with Just Works pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActJwncDisplay(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Next command is a DH Key Check */
|
||||
pCcb->nextCmdCode = SMP_CMD_DHKEY_CHECK;
|
||||
|
||||
/* Send Pair Rand Nb to the Initiator */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
|
||||
/* Send Numeric Comparison to application, if applicable */
|
||||
smpScActJwncDisplay(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store the confirm value from the initiator
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkStoreCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pCa = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Store the Cai from the initiator */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->PeerCa_Ea, pCa, SMP_CONFIRM_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store the Confirm and Calculate the Cbi using toolkit function F4 for passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkStoreCnfAndCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smprScActPkStoreCnf(pCcb, pMsg);
|
||||
smprScActPkCalcCb(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store the Pin and Calculate the Cbi using toolkit function F4 for passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkStorePinAndCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
smprScActStoreLescPin(pCcb, pMsg);
|
||||
smprScActPkCalcCb(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the Cbi using toolkit function F4 for passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkCalcCb(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Get random Nbi */
|
||||
SecRand(pCcb->pScCcb->pScratch->Nb_Eb, SMP_RAND_LEN);
|
||||
|
||||
SMP_TRACE_128("Rand Nb", pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
|
||||
/* Next command is the Pair Random */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
|
||||
/* Cb = f4(PKbx, PKax, Nbi, Rbi) where f4(U, V, x, Z) = AES-CMACx (U || V || Z) */
|
||||
SmpScCalcF4(pCcb, pMsg,
|
||||
pCcb->pScCcb->pLocalPublicKey->pubKeyX,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
smpGetPkBit(pCcb), pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the Cbi to the initiator in a Confirm Command Message in passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkSendCnf(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("Cbi", pMsg->aes.pCiphertext);
|
||||
|
||||
/* Send the Cbi to the peer */
|
||||
smpScSendPairCnf(pCcb, pMsg, pMsg->aes.pCiphertext);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the Cai to be checked against the confirm value from the initiator
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkCalcCa(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pNa = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Copy the Nai from the initiator */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Na_Ea, pNa, SMP_RAND_LEN);
|
||||
|
||||
/* Cai = f4(PKax, PKbx, Nbi, Rbi) where f4(U, V, x, Z) = AES-CMACx (U || V || Z) */
|
||||
SmpScCalcF4(pCcb, pMsg,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
pCcb->pScCcb->pLocalPublicKey->pubKeyX,
|
||||
smpGetPkBit(pCcb), pCcb->pScCcb->pScratch->Na_Ea);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the Nai in a Random Command Message in passkey pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActPkSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("Ca", pMsg->aes.pCiphertext);
|
||||
SMP_TRACE_128("Ca Peer", pCcb->pScCcb->pScratch->PeerCa_Ea);
|
||||
|
||||
/* Verify the Calculated Cai to previously received Cai */
|
||||
if (memcmp(pCcb->pScCcb->pScratch->PeerCa_Ea, pMsg->aes.pCiphertext, SMP_RAND_LEN))
|
||||
{
|
||||
smpScFailWithReattempt(pCcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
/* Increment the bit position */
|
||||
if (++pCcb->pScCcb->pkPos >= SMP_PK_BIT_COUNT)
|
||||
{
|
||||
hdr.event = SMP_MSG_INT_PK_CMPL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Next command is the Pair Confirm */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_CNF;
|
||||
hdr.event = SMP_MSG_INT_PK_NEXT;
|
||||
|
||||
/* Send the Nbi */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
}
|
||||
|
||||
/* Post an event to move to the next passkey confirm or complete the process */
|
||||
hdr.param = pCcb->connId;
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Setup for OOB pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActOobSetup(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* The next command is the Pair Rand from the initiator */
|
||||
pCcb->nextCmdCode = SMP_CMD_PAIR_RAND;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Check the confirm passed via OOB methods
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActOobCalcCa(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pNa = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Copy the Na from the initiator */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->Na_Ea, pNa, SMP_CONFIRM_LEN);
|
||||
|
||||
/* If the peer device's OOB data flag does not indicate remote OOB data has been received,
|
||||
clear Rb. */
|
||||
if (pCcb->pairReq[SMP_OOB_POS] != SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Rb, (uint8_t*) calc128Zeros);
|
||||
}
|
||||
|
||||
/* If we indicated the presence of remote OOB data has been received, calculate Ca. */
|
||||
if (pCcb->pairRsp[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
/* Calculate Ca using Toolkit function F4 */
|
||||
SmpScCalcF4(pCcb, pMsg,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
pCcb->pScCcb->pPeerPublicKey->pubKeyX,
|
||||
0, pCcb->pScCcb->pScratch->Ra);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Simulate the ca calculation is complete and clear ra */
|
||||
secCmacMsg_t msg;
|
||||
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Ra, (uint8_t*)calc128Zeros);
|
||||
|
||||
msg.hdr.param = pCcb->connId;
|
||||
msg.hdr.event = SMP_MSG_WSF_CMAC_CMPL;
|
||||
msg.pPlainText = NULL;
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the random value to the initiator when using OOB pairing
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActOobSendRand(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Only compare Ca if we indicated that we received OOB data. */
|
||||
if (pCcb->pairRsp[SMP_OOB_POS] == SMP_OOB_DATA_PRESENT)
|
||||
{
|
||||
SMP_TRACE_128("Ca", pMsg->aes.pCiphertext);
|
||||
|
||||
/* Check that the Ca value passed via OOB methods match expectations */
|
||||
if (memcmp(pCcb->pScCcb->pScratch->PeerCa_Ea, pMsg->aes.pCiphertext, SMP_CONFIRM_LEN))
|
||||
{
|
||||
smpScFailWithReattempt(pCcb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next command is a DK Key Check from initiator */
|
||||
pCcb->nextCmdCode = SMP_CMD_DHKEY_CHECK;
|
||||
|
||||
/* Get a random Nb */
|
||||
SecRand(pCcb->pScCcb->pScratch->Nb_Eb, SMP_RAND_LEN);
|
||||
|
||||
SMP_TRACE_128("Rand Nb", pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
|
||||
/* Send the rand Nb to the initiator */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Store DH Key Check from Initiator and wait for user input on Numeric Comparison
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActStoreDhCheck(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
uint8_t *pEa = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* Signal that not further commands are expected until Key Distribution phase (if applicable) */
|
||||
pCcb->nextCmdCode = SMP_CMD_MAX;
|
||||
|
||||
/* The Ea from the peer is in the cmd message (copy as MSB First) */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->PeerCa_Ea, pEa, SMP_CONFIRM_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Prepare to wait for the DH Key Check Cmd from the initiator
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActWaitDhCheck(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
/* Next command is a DH Key Check */
|
||||
pCcb->nextCmdCode = SMP_CMD_DHKEY_CHECK;
|
||||
|
||||
if (pCcb->pScCcb->authType == SMP_AUTH_TYPE_PASSKEY)
|
||||
{
|
||||
/* Send the Pair Rand Nb */
|
||||
smpScSendRand(pCcb, pMsg, pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Calculate the DHKey, for Cryptographic Function 5
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActCalcDHKey(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
if (pCcb->nextCmdCode == SMP_CMD_DHKEY_CHECK)
|
||||
{
|
||||
uint8_t *pEa = pMsg->data.pPacket + L2C_PAYLOAD_START + SMP_HDR_LEN;
|
||||
|
||||
/* The Ea from the peer is in the cmd message (copy as MSB First) */
|
||||
WStrReverseCpy(pCcb->pScCcb->pScratch->PeerCa_Ea, pEa, SMP_CONFIRM_LEN);
|
||||
}
|
||||
|
||||
/* Complete the calculation */
|
||||
smpScActCalcSharedSecret(pCcb, pMsg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the DH Key check.
|
||||
*
|
||||
* \param pCcb Connection control block.
|
||||
* \param pMsg State machine message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void smprScActDHKeyCheckSend(smpCcb_t *pCcb, smpMsg_t *pMsg)
|
||||
{
|
||||
SMP_TRACE_128("DHKey Eb", pMsg->aes.pCiphertext);
|
||||
|
||||
/* The Eb from the CMAC calculation */
|
||||
Calc128Cpy(pCcb->pScCcb->pScratch->Nb_Eb, pMsg->aes.pCiphertext);
|
||||
|
||||
/* Verify the DH Key Check Ea with the value received from the initiator */
|
||||
if (memcmp(pCcb->pScCcb->pScratch->PeerCa_Ea, pCcb->pScCcb->pScratch->Na_Ea, SMP_RAND_LEN) == 0)
|
||||
{
|
||||
/* Adjust key based on max key length */
|
||||
uint8_t encKeyLen = (pCcb->pairReq[SMP_MAXKEY_POS] < pCcb->pairRsp[SMP_MAXKEY_POS]) ?
|
||||
pCcb->pairReq[SMP_MAXKEY_POS] : pCcb->pairRsp[SMP_MAXKEY_POS];
|
||||
|
||||
memset((pCcb->pScCcb->pLtk->ltk_t + encKeyLen), 0, (SMP_KEY_LEN - encKeyLen));
|
||||
|
||||
/* Send the DH Key check Eb to the initiator */
|
||||
smpScSendDHKeyCheck(pCcb, pMsg, pCcb->pScCcb->pScratch->Nb_Eb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* DH Key check failed */
|
||||
wsfMsgHdr_t hdr;
|
||||
|
||||
hdr.param = pCcb->connId;
|
||||
hdr.status = SMP_ERR_DH_KEY_CHECK;
|
||||
|
||||
/* update repeated attempts count */
|
||||
pCcb->attempts++;
|
||||
SmpDbPairingFailed(pCcb->connId);
|
||||
|
||||
if (pCcb->attempts == pSmpCfg->maxAttempts)
|
||||
{
|
||||
/* max attempts reached */
|
||||
hdr.event = SMP_MSG_INT_MAX_ATTEMPTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else just fail */
|
||||
hdr.event = SMP_MSG_DH_CHECK_FAILURE;
|
||||
}
|
||||
|
||||
smpSmExecute(pCcb, (smpMsg_t *) &hdr);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+685
@@ -0,0 +1,685 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP Secure Connections initiator state machine.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpr_main.h"
|
||||
#include "smp_sc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function enumeration */
|
||||
enum
|
||||
{
|
||||
SMPR_SC_ACT_NONE, /*!< No Action */
|
||||
SMPR_SC_ACT_CLEANUP, /*!< Process Pairing Cleanup */
|
||||
SMPR_SC_ACT_PAIRING_FAILED, /*!< Process Pairing Failed */
|
||||
SMPR_SC_ACT_PAIRING_CANCEL, /*!< Process Pairing Canceled */
|
||||
SMPR_SC_ACT_SEND_PUB_KEY, /*!< Process Send Public Key */
|
||||
SMPR_SC_ACT_STORE_LEGACY_PIN, /*!< Process Store Legacy Pin */
|
||||
SMPR_SC_ACT_STORE_LESC_PIN, /*!< Process Store LESC Pin */
|
||||
|
||||
SMPR_SC_ACT_PAIR_CNF_CALC_1, /*!< Process Confirm Value Calculation 1 */
|
||||
SMPR_SC_ACT_PAIR_CNF_CALC_2, /*!< Process Confirm Value Calculation 2 */
|
||||
SMPR_SC_ACT_SEND_PAIR_CNF, /*!< Process Send Confirm Value */
|
||||
SMPR_SC_ACT_PAIR_CNF_VER_CALC_1, /*!< Process Received Confirm Value Verification Calculation 1 */
|
||||
SMPR_SC_ACT_PAIR_CNF_VER_CALC_2, /*!< Process Received Confirm Value Verification Calculation 2 */
|
||||
SMPR_SC_ACT_MAX_ATTEMPTS, /*!< Process Maximum Attempts */
|
||||
SMPR_SC_ACT_PAIRING_CMPL, /*!< Process Pairing Complete */
|
||||
SMPR_SC_ACT_CHECK_ATTEMPTS, /*!< Process Check Attempts */
|
||||
SMPR_SC_ACT_NOTIFY_DM_ATTEMPTS, /*!< Process Notify DM of Attempts Failure */
|
||||
SMPR_SC_ACT_NOTIFY_DM_RSP_TO, /*!< Process Notify DM of Response Timeout Failure */
|
||||
SMPR_SC_ACT_ATTEMPT_RCVD, /*!< Process Attempts Received */
|
||||
|
||||
SMPR_SC_ACT_SEND_SECURITY_REQ, /*!< Process Send Slave Security Request */
|
||||
SMPR_SC_ACT_PROC_PAIR_REQ, /*!< Process Pairing Request */
|
||||
SMPR_SC_ACT_SEND_PAIR_RSP, /*!< Process Send Pairing Response */
|
||||
SMPR_SC_ACT_PROC_PAIR_CNF, /*!< Process Received Confirm Value */
|
||||
|
||||
SMPR_SC_ACT_JWNC_SETUP, /*!< Process Just Works/Numeric Comparison Setup */
|
||||
SMPR_SC_ACT_JWNC_SEND_CNF, /*!< Process JW/NC Send Confirm Value */
|
||||
SMPR_SC_ACT_JWNC_CALC_G2, /*!< Process JW/NC Calculate G2 */
|
||||
SMPR_SC_ACT_JWNC_DISPLAY, /*!< Process JW/NC Display Numeric Comparison */
|
||||
|
||||
SMPR_SC_ACT_PK_SETUP, /*!< Process Passkey Setup */
|
||||
SMPR_SC_ACT_PK_KEYPRESS, /*!< Process Passkey Keypress */
|
||||
SMPR_SC_ACT_PK_SEND_KEYPRESS, /*!< Process Passkey Send Keypress */
|
||||
SMPR_SC_ACT_PK_STORE_CNF, /*!< Process Passkey Store Received Confirm Value */
|
||||
SMPR_SC_ACT_PK_STORE_CNF_CALC_CB, /*!< Process Passkey Store Confirm Value Calculation Cb */
|
||||
SMPR_SC_ACT_PK_STORE_PIN_CALC_CB, /*!< Process Passkey Store Pin Value Calculation Cb */
|
||||
SMPR_SC_ACT_PK_CALC_CB, /*!< Process Passkey Calculate Cb */
|
||||
SMPR_SC_ACT_PK_SEND_CNF, /*!< Process Passkey Send Confirm Value */
|
||||
SMPR_SC_ACT_PK_CALC_CA, /*!< Process Passkey Calculate Ca */
|
||||
SMPR_SC_ACT_PK_SEND_RAND, /*!< Process Passkey Send Random Value */
|
||||
|
||||
SMPR_SC_ACT_OOB_SETUP, /*!< Process OOB Setup */
|
||||
SMPR_SC_ACT_OOB_CALC_CA, /*!< Process OOB Calculate Ca */
|
||||
SMPR_SC_ACT_OOB_SEND_RAND, /*!< Process OOB Send Random Value */
|
||||
|
||||
SMPR_SC_ACT_STORE_DH_CHECK, /*!< Process Store DH Key Check */
|
||||
SMPR_SC_ACT_WAIT_DH_CHECK, /*!< Process Wait DH Key Check */
|
||||
SMPR_SC_ACT_CALC_DHKEY, /*!< Process Calculate DH Key Check */
|
||||
SMPR_SC_ACT_CALC_F5_TKEY, /*!< Process Calculate F5 Temporary Key */
|
||||
SMPR_SC_ACT_CALC_F5_MACKEY, /*!< Process Calculate F5 MAC Key */
|
||||
SMPR_SC_ACT_CALC_F5_LTK, /*!< Process Calculate LTK */
|
||||
SMPR_SC_ACT_CALC_F6_EA, /*!< Process Calculate Ea */
|
||||
SMPR_SC_ACT_CALC_F6_EB, /*!< Process Calculate Eb */
|
||||
SMPR_SC_ACT_SEND_DH_CHECK, /*!< Process Send DH Key Check */
|
||||
|
||||
SMPR_SC_ACT_PROC_PAIR_CNF_CALC_1, /*!< Process Confirm Value Calcuation 1 */
|
||||
SMPR_SC_ACT_CNF_VERIFY, /*!< Process Confirm Value Verification */
|
||||
SMPR_SC_ACT_SEND_PAIR_RANDOM, /*!< Process Send Random Value */
|
||||
SMPR_SC_ACT_SETUP_KEY_DIST, /*!< Processs Setup Key Distribution */
|
||||
SMPR_SC_ACT_RCV_KEY, /*!< Process Received Key */
|
||||
SMPR_SC_ACT_SEND_KEY /*!< Process Send Key */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Static Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function table; order matches action function enumeration */
|
||||
static const smpAct_t smprScActionTbl[] =
|
||||
{
|
||||
smpActNone,
|
||||
smpScActCleanup,
|
||||
smpScActPairingFailed,
|
||||
smpScActPairingCancel,
|
||||
smprScActSendPubKey,
|
||||
smpActStorePin,
|
||||
smprScActStoreLescPin,
|
||||
|
||||
smpActPairCnfCalc1,
|
||||
smpActPairCnfCalc2,
|
||||
smpActSendPairCnf,
|
||||
smpActPairCnfVerCalc1,
|
||||
smpActPairCnfVerCalc2,
|
||||
smpActMaxAttempts,
|
||||
smpActPairingCmpl,
|
||||
smpActCheckAttempts,
|
||||
smpActNotifyDmAttemptsFailure,
|
||||
smpActNotifyDmRspToFailure,
|
||||
smpActAttemptRcvd,
|
||||
|
||||
smprActSendSecurityReq,
|
||||
smprActProcPairReq,
|
||||
smprActSendPairRsp,
|
||||
smprActProcPairCnf,
|
||||
|
||||
smprScActJwncSetup,
|
||||
smprScActJwncSendCnf,
|
||||
smprScActJwncCalcG2,
|
||||
smprScActJwncDisplay,
|
||||
|
||||
smpScActPkSetup,
|
||||
smpScActPkKeypress,
|
||||
smpScActPkSendKeypress,
|
||||
smprScActPkStoreCnf,
|
||||
smprScActPkStoreCnfAndCalcCb,
|
||||
smprScActPkStorePinAndCalcCb,
|
||||
smprScActPkCalcCb,
|
||||
smprScActPkSendCnf,
|
||||
smprScActPkCalcCa,
|
||||
smprScActPkSendRand,
|
||||
|
||||
smprScActOobSetup,
|
||||
smprScActOobCalcCa,
|
||||
smprScActOobSendRand,
|
||||
|
||||
smprScActStoreDhCheck,
|
||||
smprScActWaitDhCheck,
|
||||
smprScActCalcDHKey,
|
||||
smpScActCalcF5TKey,
|
||||
smpScActCalcF5MacKey,
|
||||
smpScActCalcF5Ltk,
|
||||
smpScActDHKeyCalcF6Ea,
|
||||
smpScActDHKeyCalcF6Eb,
|
||||
smprScActDHKeyCheckSend,
|
||||
|
||||
smprActProcPairCnfCalc1,
|
||||
smprActCnfVerify,
|
||||
smprActSendPairRandom,
|
||||
smprActSetupKeyDist,
|
||||
smprActRcvKey,
|
||||
smprActSendKey
|
||||
};
|
||||
|
||||
/*! State table for common actions */
|
||||
static const smpTblEntry_t smprScStateTblCommon[SMP_STATE_TBL_COMMON_MAX] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_CANCEL},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SC_SM_ST_RSP_TO, SMPR_SC_ACT_PAIRING_FAILED},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_IDLE */
|
||||
static const smpTblEntry_t smprScStateTblIdle[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_SECURITY_REQ, SMPR_SC_SM_ST_API_PAIR_REQ, SMPR_SC_ACT_SEND_SECURITY_REQ},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_API_PAIR_RSP, SMPR_SC_ACT_PROC_PAIR_REQ},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_API_PAIR_REQ */
|
||||
static const smpTblEntry_t smprScStateTblApiPairReq[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_API_PAIR_RSP, SMPR_SC_ACT_PROC_PAIR_REQ},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_DM_ENCRYPT_CMPL, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_DM_ENCRYPT_FAILED, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_API_PAIR_RSP */
|
||||
static const smpTblEntry_t smprScStateTblApiPairRsp[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_PAIR_RSP, SMPR_SC_SM_ST_MODE_SELECT, SMPR_SC_ACT_SEND_PAIR_RSP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_MODE_SELECT */
|
||||
static const smpTblEntry_t smprScStateTblModeSelect[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_LESC, SMPR_SC_SM_ST_LESC_PIN, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_INT_LEGACY, SMPR_SC_SM_ST_PIN_PAIR_1, SMPR_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for LESC SMPR_SC_SM_ST_LESC_PIN */
|
||||
static const smpTblEntry_t smprScStateTblLescPin[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SC_SM_ST_PUB_KEY, SMPR_SC_ACT_STORE_LESC_PIN},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for LESC SMPR_SC_SM_ST_PUB_KEY */
|
||||
static const smpTblEntry_t smprScStateTblPubKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_AUTH_SELECT, SMPR_SC_ACT_SEND_PUB_KEY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_AUTH_SELECT */
|
||||
static const smpTblEntry_t smprScStateTblAuthSelect[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_JW_NC, SMPR_SC_SM_ST_JWNC_SETUP, SMPR_SC_ACT_JWNC_SETUP},
|
||||
{SMP_MSG_INT_PASSKEY, SMPR_SC_SM_ST_PK_KEYPRESS, SMPR_SC_ACT_PK_SETUP},
|
||||
{SMP_MSG_INT_OOB, SMPR_SC_SM_ST_OOB_WAIT_RAND, SMPR_SC_ACT_OOB_SETUP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_JWNC_SETUP */
|
||||
static const smpTblEntry_t smprScStateTblJwNcSetup[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_JWNC_WAIT_RAND, SMPR_SC_ACT_JWNC_SEND_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_JWNC_WAIT_RAND */
|
||||
static const smpTblEntry_t smprScStateTblJwNcWaitRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_JWNC_CALC_G2, SMPR_SC_ACT_JWNC_CALC_G2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_JWNC_CALC_G2 */
|
||||
static const smpTblEntry_t smprScStateTblJwNcCalcG2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_JWNC_WAIT_USER, SMPR_SC_ACT_JWNC_DISPLAY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_JWNC_WAIT_USER */
|
||||
static const smpTblEntry_t smprScStateTblJwNcWaitUser[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_USER_CONFIRM, SMPR_SC_SM_ST_WAIT_DH_CHECK, SMPR_SC_ACT_WAIT_DH_CHECK},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_JWNC_WAIT_USER_DH_CHECK_RCVD, SMPR_SC_ACT_STORE_DH_CHECK},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_JWNC_WAIT_USER_DH_CHECK_RCVD */
|
||||
static const smpTblEntry_t smprScStateTblJwNcWaitUserDhCheckRcvd[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_USER_CONFIRM, SMPR_SC_SM_ST_CALC_DHKEY, SMPR_SC_ACT_CALC_DHKEY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_KEYPRESS */
|
||||
static const smpTblEntry_t smprScStateTblPassKeyKeypress[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_PK_KEYPRESS, SMPR_SC_ACT_PK_KEYPRESS},
|
||||
{SMP_MSG_EARLY_CNF, SMPR_SC_SM_ST_PK_WAIT_AUTH, SMPR_SC_ACT_PK_STORE_CNF},
|
||||
{SMP_MSG_API_USER_KEYPRESS, SMPR_SC_SM_ST_PK_KEYPRESS, SMPR_SC_ACT_PK_SEND_KEYPRESS},
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SC_SM_ST_PK_WAIT_CNF, SMPR_SC_ACT_STORE_LESC_PIN},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_WAIT_AUTH */
|
||||
static const smpTblEntry_t smprScStateTblPassWaitAuthRsp[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SC_SM_ST_PK_CALC, SMPR_SC_ACT_PK_STORE_PIN_CALC_CB},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_WAIT_CNF */
|
||||
static const smpTblEntry_t smprScStateTblPasskeyWaitCnf[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_PK_CALC, SMPR_SC_ACT_PK_STORE_CNF_CALC_CB},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_CALC */
|
||||
static const smpTblEntry_t smprScStateTblPasskeyCalc[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_PK_RAND, SMPR_SC_ACT_PK_SEND_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_RAND */
|
||||
static const smpTblEntry_t smprScStateTblPasskeyRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_PK_CHECK, SMPR_SC_ACT_PK_CALC_CA},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_CHECK */
|
||||
static const smpTblEntry_t smprScStateTblPasskeyCheck[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_PK_REPEAT, SMPR_SC_ACT_PK_SEND_RAND},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_PK_REPEAT */
|
||||
static const smpTblEntry_t smprScStateTblPasskeyRepeat[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_PK_NEXT, SMPR_SC_SM_ST_PK_WAIT_CNF, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_INT_PK_CMPL, SMPR_SC_SM_ST_WAIT_DH_CHECK, SMPR_SC_ACT_WAIT_DH_CHECK},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_OOB_WAIT_RAND */
|
||||
static const smpTblEntry_t smprScStateTblOobWaitRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_OOB_SEND_RAND, SMPR_SC_ACT_OOB_CALC_CA},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_OOB_SEND_RAND */
|
||||
static const smpTblEntry_t smprScStateTblOobSendRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_WAIT_DH_CHECK, SMPR_SC_ACT_OOB_SEND_RAND},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_WAIT_DH_CHECK */
|
||||
static const smpTblEntry_t smprScStateTblWaitDhCheck[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_CALC_DHKEY, SMPR_SC_ACT_CALC_DHKEY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_CALC_DHKEY */
|
||||
static const smpTblEntry_t smprScStateTblCalcDHKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_ECC_CMPL, SMPR_SC_SM_ST_CALC_F5_TKEY, SMPR_SC_ACT_CALC_F5_TKEY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_CALC_F5_TKEY */
|
||||
static const smpTblEntry_t smprScStateTblCalcF5TKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_CALC_F5_MACKEY, SMPR_SC_ACT_CALC_F5_MACKEY},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_CALC_F5_MACKEY */
|
||||
static const smpTblEntry_t smprScStateTblCalcF5MacKey[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_CALC_F5_LTK, SMPR_SC_ACT_CALC_F5_LTK},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_CALC_F5_LTK */
|
||||
static const smpTblEntry_t smprScStateTblCalcF5LTK[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_CALC_F6_EA, SMPR_SC_ACT_CALC_F6_EA},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_CALC_F6_EA */
|
||||
static const smpTblEntry_t smprScStateTblDhCalcF6Ea[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_CALC_F6_EB, SMPR_SC_ACT_CALC_F6_EB},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for SMPR_SC_SM_ST_CALC_F6_EB */
|
||||
static const smpTblEntry_t smprScStateTblDhCalcF6Eb[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_CMAC_CMPL, SMPR_SC_SM_ST_ENCRYPT, SMPR_SC_ACT_SEND_DH_CHECK},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy PIN_PAIR_1 */
|
||||
static const smpTblEntry_t smprStateTblPinPair1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SC_SM_ST_PIN_PAIR_2, SMPR_SC_ACT_STORE_LEGACY_PIN},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_PIN_PAIR_2, SMPR_SC_ACT_PROC_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy PIN_PAIR_2 */
|
||||
static const smpTblEntry_t smprStateTblPinPair2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SC_SM_ST_CNF_CALC_1, SMPR_SC_ACT_PAIR_CNF_CALC_1},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_CNF_CALC_1, SMPR_SC_ACT_PROC_PAIR_CNF_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_CALC_1 */
|
||||
static const smpTblEntry_t smprStateTblCnfCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SC_SM_ST_CNF_CALC_2, SMPR_SC_ACT_PAIR_CNF_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_CALC_2 */
|
||||
static const smpTblEntry_t smprStateTblCnfCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SC_SM_ST_PAIR_RAND, SMPR_SC_ACT_SEND_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
/*! State table for Legacy PAIR_RAND */
|
||||
static const smpTblEntry_t smprStateTblPairRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_CNF_VER_CALC_1, SMPR_SC_ACT_PAIR_CNF_VER_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_VER_CALC_1 */
|
||||
static const smpTblEntry_t smprStateTblCnfVerCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SC_SM_ST_CNF_VER_CALC_2, SMPR_SC_ACT_PAIR_CNF_VER_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy CNF_VER_CALC_2 */
|
||||
static const smpTblEntry_t smprStateTblCnfVerCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SC_SM_ST_STK_CALC, SMPR_SC_ACT_CNF_VERIFY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for Legacy STK_CALC */
|
||||
static const smpTblEntry_t smprScStateTblStkCalc[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SC_SM_ST_ENCRYPT, SMPR_SC_ACT_SEND_PAIR_RANDOM},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ENCRYPT */
|
||||
static const smpTblEntry_t smprScStateTblEncrypt[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_ENCRYPT_CMPL, SMPR_SC_SM_ST_KEY_DIST, SMPR_SC_ACT_SETUP_KEY_DIST},
|
||||
{SMP_MSG_DM_ENCRYPT_FAILED, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_ENCRYPT, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_DH_CHECK_FAILURE, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_CANCEL},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for KEY_DIST */
|
||||
static const smpTblEntry_t smprScStateTblKeyDist[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_KEY_DIST, SMPR_SC_ACT_RCV_KEY},
|
||||
{SMP_MSG_INT_SEND_NEXT_KEY, SMPR_SC_SM_ST_KEY_DIST, SMPR_SC_ACT_SEND_KEY},
|
||||
{SMP_MSG_INT_PAIRING_CMPL, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_PAIRING_CMPL},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_KEY_DIST, SMPR_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ATTEMPTS */
|
||||
static const smpTblEntry_t smprScStateTblAttempts[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_WI_TIMEOUT, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CHECK_ATTEMPTS},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SC_SM_ST_RSP_TO, SMPR_SC_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_ATTEMPT_RCVD},
|
||||
{SMP_MSG_API_SECURITY_REQ, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_NOTIFY_DM_ATTEMPTS},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SC_SM_ST_ATTEMPTS, SMPR_SC_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for RSP_TO */
|
||||
static const smpTblEntry_t smprScStateTblRspTo[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SC_SM_ST_IDLE, SMPR_SC_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SC_SM_ST_RSP_TO, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SC_SM_ST_RSP_TO, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SC_SM_ST_RSP_TO, SMPR_SC_ACT_NONE},
|
||||
{SMP_MSG_API_SECURITY_REQ, SMPR_SC_SM_ST_RSP_TO, SMPR_SC_ACT_NOTIFY_DM_RSP_TO},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! Table of individual state tables */
|
||||
static const smpTblEntry_t * const smprScStateTbl[] =
|
||||
{
|
||||
smprScStateTblIdle,
|
||||
smprScStateTblApiPairReq,
|
||||
smprScStateTblApiPairRsp,
|
||||
smprScStateTblModeSelect,
|
||||
smprScStateTblPubKey,
|
||||
smprScStateTblLescPin,
|
||||
smprScStateTblAuthSelect,
|
||||
|
||||
smprScStateTblJwNcSetup,
|
||||
smprScStateTblJwNcWaitRand,
|
||||
smprScStateTblJwNcCalcG2,
|
||||
smprScStateTblJwNcWaitUser,
|
||||
smprScStateTblJwNcWaitUserDhCheckRcvd,
|
||||
|
||||
smprScStateTblPassKeyKeypress,
|
||||
smprScStateTblPassWaitAuthRsp,
|
||||
smprScStateTblPasskeyWaitCnf,
|
||||
smprScStateTblPasskeyCalc,
|
||||
smprScStateTblPasskeyRand,
|
||||
smprScStateTblPasskeyCheck,
|
||||
smprScStateTblPasskeyRepeat,
|
||||
|
||||
smprScStateTblOobSendRand,
|
||||
smprScStateTblOobWaitRand,
|
||||
|
||||
smprScStateTblWaitDhCheck,
|
||||
smprScStateTblCalcDHKey,
|
||||
smprScStateTblCalcF5TKey,
|
||||
smprScStateTblCalcF5MacKey,
|
||||
smprScStateTblCalcF5LTK,
|
||||
smprScStateTblDhCalcF6Ea,
|
||||
smprScStateTblDhCalcF6Eb,
|
||||
|
||||
smprStateTblPinPair1,
|
||||
smprStateTblPinPair2,
|
||||
smprStateTblCnfCalc1,
|
||||
smprStateTblCnfCalc2,
|
||||
smprStateTblPairRand,
|
||||
smprStateTblCnfVerCalc1,
|
||||
smprStateTblCnfVerCalc2,
|
||||
|
||||
smprScStateTblStkCalc,
|
||||
smprScStateTblEncrypt,
|
||||
smprScStateTblKeyDist,
|
||||
smprScStateTblAttempts,
|
||||
smprScStateTblRspTo
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! state machine interface */
|
||||
const smpSmIf_t smprScSmIf =
|
||||
{
|
||||
smprScStateTbl,
|
||||
smprScActionTbl,
|
||||
smprScStateTblCommon
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP initiator role.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmprScInit(void)
|
||||
{
|
||||
/* set up callback interface */
|
||||
smpCb.pSlave = &smprScSmIf;
|
||||
|
||||
/* General SMP LESC Initialization */
|
||||
SmpScInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Convert state into string for diagnostics.
|
||||
*
|
||||
* \param state State ID
|
||||
*
|
||||
* \return State string.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t *smprStateStr(uint8_t state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case SMPR_SC_SM_ST_IDLE: return (uint8_t*) "R_IDLE";
|
||||
case SMPR_SC_SM_ST_API_PAIR_REQ: return (uint8_t*) "R_API_PAIR_REQ";
|
||||
case SMPR_SC_SM_ST_API_PAIR_RSP: return (uint8_t*) "R_API_PAIR_RSP";
|
||||
case SMPR_SC_SM_ST_MODE_SELECT: return (uint8_t*) "R_MODE_SELECT";
|
||||
case SMPR_SC_SM_ST_PUB_KEY: return (uint8_t*) "R_PUB_KEY";
|
||||
case SMPR_SC_SM_ST_LESC_PIN: return (uint8_t*) "R_LESC_PIN";
|
||||
case SMPR_SC_SM_ST_AUTH_SELECT: return (uint8_t*) "R_AUTH_SELECT";
|
||||
case SMPR_SC_SM_ST_JWNC_SETUP: return (uint8_t*) "R_JWNC_SETUP";
|
||||
case SMPR_SC_SM_ST_JWNC_WAIT_RAND: return (uint8_t*) "R_JWNC_WAIT_RAND";
|
||||
case SMPR_SC_SM_ST_JWNC_CALC_G2: return (uint8_t*) "R_JWNC_CALC_G2";
|
||||
case SMPR_SC_SM_ST_JWNC_WAIT_USER: return (uint8_t*) "R_JWNC_WAIT_USER";
|
||||
case SMPR_SC_SM_ST_JWNC_WAIT_USER_DH_CHECK_RCVD: return (uint8_t*) "R_JWNC_WAIT_USER_DH";
|
||||
|
||||
case SMPR_SC_SM_ST_PK_KEYPRESS: return (uint8_t*) "R_PK_KEYPRESS";
|
||||
case SMPR_SC_SM_ST_PK_WAIT_AUTH: return (uint8_t*) "R_PK_WAIT_AUTH";
|
||||
case SMPR_SC_SM_ST_PK_WAIT_CNF: return (uint8_t*) "R_PK_WAIT_CNF";
|
||||
case SMPR_SC_SM_ST_PK_CALC: return (uint8_t*) "R_PK_CALC";
|
||||
case SMPR_SC_SM_ST_PK_RAND: return (uint8_t*) "R_PK_RAND";
|
||||
case SMPR_SC_SM_ST_PK_CHECK: return (uint8_t*) "R_PK_CHECK";
|
||||
case SMPR_SC_SM_ST_PK_REPEAT: return (uint8_t*) "R_PK_REPEAT";
|
||||
|
||||
case SMPR_SC_SM_ST_OOB_SEND_RAND: return (uint8_t*) "R_OOB_SEND_RAND";
|
||||
case SMPR_SC_SM_ST_OOB_WAIT_RAND: return (uint8_t*) "R_OOB_WAIT_RAND";
|
||||
|
||||
case SMPR_SC_SM_ST_WAIT_DH_CHECK: return (uint8_t*) "R_WAIT_DH_CHECK";
|
||||
case SMPR_SC_SM_ST_CALC_DHKEY: return (uint8_t*) "R_CALC_DHKEY";
|
||||
case SMPR_SC_SM_ST_CALC_F5_TKEY: return (uint8_t*) "R_CALC_F5_TKEY";
|
||||
case SMPR_SC_SM_ST_CALC_F5_MACKEY: return (uint8_t*) "R_CALC_F5_MACKEY";
|
||||
case SMPR_SC_SM_ST_CALC_F5_LTK: return (uint8_t*) "R_CALC_F5_LTK";
|
||||
case SMPR_SC_SM_ST_CALC_F6_EA: return (uint8_t*) "R_CALC_F6_EA";
|
||||
case SMPR_SC_SM_ST_CALC_F6_EB: return (uint8_t*) "R_CALC_F6_EB";
|
||||
case SMPR_SC_SM_ST_PIN_PAIR_1: return (uint8_t*) "R_PIN_PAIR_1";
|
||||
case SMPR_SC_SM_ST_PIN_PAIR_2: return (uint8_t*) "R_PIN_PAIR_2";
|
||||
case SMPR_SC_SM_ST_CNF_CALC_1: return (uint8_t*) "R_CNF_CALC_1";
|
||||
case SMPR_SC_SM_ST_CNF_CALC_2: return (uint8_t*) "R_CNF_CALC_2";
|
||||
case SMPR_SC_SM_ST_PAIR_RAND: return (uint8_t*) "R_PAIR_RAND";
|
||||
case SMPR_SC_SM_ST_CNF_VER_CALC_1: return (uint8_t*) "R_CNF_VER_CALC_1";
|
||||
case SMPR_SC_SM_ST_CNF_VER_CALC_2: return (uint8_t*) "R_CNF_VER_CALC_2";
|
||||
case SMPR_SC_SM_ST_STK_CALC: return (uint8_t*) "R_STK_CALC";
|
||||
case SMPR_SC_SM_ST_ENCRYPT: return (uint8_t*) "R_ENCRYPT";
|
||||
case SMPR_SC_SM_ST_KEY_DIST: return (uint8_t*) "R_KEY_DIST";
|
||||
case SMPR_SC_SM_ST_ATTEMPTS: return (uint8_t*) "R_ATTEMPTS";
|
||||
case SMPR_SC_SM_ST_RSP_TO: return (uint8_t*) "R_RSP_TO";
|
||||
|
||||
default: return (uint8_t*) "R_Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief SMP responder state machine.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "smp_api.h"
|
||||
#include "smp_main.h"
|
||||
#include "smpr_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function enumeration */
|
||||
enum
|
||||
{
|
||||
SMPR_ACT_NONE, /*!< No Action */
|
||||
SMPR_ACT_CLEANUP, /*!< Process Pairing Cleanup */
|
||||
SMPR_ACT_PAIRING_FAILED, /*!< Process Pairing Failed */
|
||||
SMPR_ACT_PAIRING_CANCEL, /*!< Process Pairing Canceled */
|
||||
SMPR_ACT_STORE_PIN, /*!< Process Store Pin */
|
||||
SMPR_ACT_PAIR_CNF_CALC_1, /*!< Process Confirm Value Calculation 1 */
|
||||
SMPR_ACT_PAIR_CNF_CALC_2, /*!< Process Confirm Value Calculation 2 */
|
||||
SMPR_ACT_SEND_PAIR_CNF, /*!< Process Send Confirm Value */
|
||||
SMPR_ACT_PAIR_CNF_VER_CALC_1, /*!< Process Received Confirm Value Verification Calculation 1 */
|
||||
SMPR_ACT_PAIR_CNF_VER_CALC_2, /*!< Process Received Confirm Value Verification Calculation 2 */
|
||||
SMPR_ACT_MAX_ATTEMPTS, /*!< Process Maximum Attempts */
|
||||
SMPR_ACT_ATTEMPT_RCVD, /*!< Process Attempts Received */
|
||||
SMPR_ACT_CHECK_ATTEMPTS, /*!< Process Check Attempts */
|
||||
SMPR_ACT_NOTIFY_DM_ATTEMPTS, /*!< Process Notify DM of Attempts Failure */
|
||||
SMPR_ACT_NOTIFY_DM_RSP_TO, /*!< Process Notify DM of Response Timeout Failure */
|
||||
SMPR_ACT_PAIRING_CMPL, /*!< Process Pairing Complete */
|
||||
SMPR_ACT_SEND_SECURITY_REQ, /*!< Process Send Slave Security Request */
|
||||
SMPR_ACT_PROC_PAIR_REQ, /*!< Process Pairing Request */
|
||||
SMPR_ACT_SEND_PAIR_RSP, /*!< Process Send Pairing Response */
|
||||
SMPR_ACT_PROC_PAIR_CNF, /*!< Process Pair Confirm Value */
|
||||
SMPR_ACT_PROC_PAIR_CNF_CALC_1, /*!< Process Received Confirm Value */
|
||||
SMPR_ACT_CNF_VERIFY, /*!< Process Recevied Confirm Value Verification */
|
||||
SMPR_ACT_SEND_PAIR_RANDOM, /*!< Process Send Random Value */
|
||||
SMPR_ACT_SETUP_KEY_DIST, /*!< Process Setup Key Distribution */
|
||||
SMPR_ACT_SEND_KEY, /*!< Process Send Key */
|
||||
SMPR_ACT_RCV_KEY, /*!< Process Received Key */
|
||||
};
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Static Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Action function table; order matches action function enumeration */
|
||||
static const smpAct_t smprActionTbl[] =
|
||||
{
|
||||
smpActNone,
|
||||
smpActCleanup,
|
||||
smpActPairingFailed,
|
||||
smpActPairingCancel,
|
||||
smpActStorePin,
|
||||
smpActPairCnfCalc1,
|
||||
smpActPairCnfCalc2,
|
||||
smpActSendPairCnf,
|
||||
smpActPairCnfVerCalc1,
|
||||
smpActPairCnfVerCalc2,
|
||||
smpActMaxAttempts,
|
||||
smpActAttemptRcvd,
|
||||
smpActCheckAttempts,
|
||||
smpActNotifyDmAttemptsFailure,
|
||||
smpActNotifyDmRspToFailure,
|
||||
smpActPairingCmpl,
|
||||
smprActSendSecurityReq,
|
||||
smprActProcPairReq,
|
||||
smprActSendPairRsp,
|
||||
smprActProcPairCnf,
|
||||
smprActProcPairCnfCalc1,
|
||||
smprActCnfVerify,
|
||||
smprActSendPairRandom,
|
||||
smprActSetupKeyDist,
|
||||
smprActSendKey,
|
||||
smprActRcvKey
|
||||
};
|
||||
|
||||
/*! State table for common actions */
|
||||
static const smpTblEntry_t smprStateTblCommon[SMP_STATE_TBL_COMMON_MAX] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SM_ST_IDLE, SMPR_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SM_ST_IDLE, SMPR_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_IDLE, SMPR_ACT_PAIRING_CANCEL},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SM_ST_RSP_TO, SMPR_ACT_PAIRING_FAILED},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for IDLE */
|
||||
static const smpTblEntry_t smprStateTblIdle[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_SECURITY_REQ, SMPR_SM_ST_API_PAIR_REQ, SMPR_ACT_SEND_SECURITY_REQ},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_API_PAIR_RSP, SMPR_ACT_PROC_PAIR_REQ},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SM_ST_IDLE, SMPR_ACT_NONE},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SM_ST_IDLE, SMPR_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for API_PAIR_REQ */
|
||||
static const smpTblEntry_t smprStateTblApiPairReq[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_API_PAIR_RSP, SMPR_ACT_PROC_PAIR_REQ},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SM_ST_IDLE, SMPR_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_DM_ENCRYPT_CMPL, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_DM_ENCRYPT_FAILED, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for API_PAIR_RSP */
|
||||
static const smpTblEntry_t smprStateTblApiPairRsp[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_PAIR_RSP, SMPR_SM_ST_PIN_PAIR_1, SMPR_ACT_SEND_PAIR_RSP},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PIN_PAIR_1 */
|
||||
static const smpTblEntry_t smprStateTblPinPair1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SM_ST_PIN_PAIR_2, SMPR_ACT_STORE_PIN},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_PIN_PAIR_2, SMPR_ACT_PROC_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for PIN_PAIR_2 */
|
||||
static const smpTblEntry_t smprStateTblPinPair2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_API_AUTH_RSP, SMPR_SM_ST_CNF_CALC_1, SMPR_ACT_PAIR_CNF_CALC_1},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_CNF_CALC_1, SMPR_ACT_PROC_PAIR_CNF_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_CALC_1 */
|
||||
static const smpTblEntry_t smprStateTblCnfCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SM_ST_CNF_CALC_2, SMPR_ACT_PAIR_CNF_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_CALC_2 */
|
||||
static const smpTblEntry_t smprStateTblCnfCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SM_ST_PAIR_RAND, SMPR_ACT_SEND_PAIR_CNF},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
/*! State table for PAIR_RAND */
|
||||
static const smpTblEntry_t smprStateTblPairRand[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_CNF_VER_CALC_1, SMPR_ACT_PAIR_CNF_VER_CALC_1},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_VER_CALC_1 */
|
||||
static const smpTblEntry_t smprStateTblCnfVerCalc1[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SM_ST_CNF_VER_CALC_2, SMPR_ACT_PAIR_CNF_VER_CALC_2},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for CNF_VER_CALC_2 */
|
||||
static const smpTblEntry_t smprStateTblCnfVerCalc2[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SM_ST_STK_CALC, SMPR_ACT_CNF_VERIFY},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for STK_CALC */
|
||||
static const smpTblEntry_t smprStateTblStkCalc[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_WSF_AES_CMPL, SMPR_SM_ST_ENCRYPT, SMPR_ACT_SEND_PAIR_RANDOM},
|
||||
{SMP_MSG_INT_MAX_ATTEMPTS, SMPR_SM_ST_ATTEMPTS, SMPR_ACT_MAX_ATTEMPTS},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ENCRYPT */
|
||||
static const smpTblEntry_t smprStateTblEncrypt[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_ENCRYPT_CMPL, SMPR_SM_ST_KEY_DIST, SMPR_ACT_SETUP_KEY_DIST},
|
||||
{SMP_MSG_DM_ENCRYPT_FAILED, SMPR_SM_ST_IDLE, SMPR_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_ENCRYPT, SMPR_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for KEY_DIST */
|
||||
static const smpTblEntry_t smprStateTblKeyDist[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_SEND_NEXT_KEY, SMPR_SM_ST_KEY_DIST, SMPR_ACT_SEND_KEY},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_KEY_DIST, SMPR_ACT_RCV_KEY},
|
||||
{SMP_MSG_INT_PAIRING_CMPL, SMPR_SM_ST_IDLE, SMPR_ACT_PAIRING_CMPL},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_KEY_DIST, SMPR_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for ATTEMPTS */
|
||||
static const smpTblEntry_t smprStateTblAttempts[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_INT_WI_TIMEOUT, SMPR_SM_ST_IDLE, SMPR_ACT_CHECK_ATTEMPTS},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SM_ST_RSP_TO, SMPR_ACT_PAIRING_FAILED},
|
||||
{SMP_MSG_CMD_PKT, SMPR_SM_ST_ATTEMPTS, SMPR_ACT_ATTEMPT_RCVD},
|
||||
{SMP_MSG_API_SECURITY_REQ, SMPR_SM_ST_IDLE, SMPR_ACT_NOTIFY_DM_ATTEMPTS},
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SM_ST_ATTEMPTS, SMPR_ACT_NONE},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! State table for RSP_TO */
|
||||
static const smpTblEntry_t smprStateTblRspTo[] =
|
||||
{
|
||||
/* Event Next state Action */
|
||||
{SMP_MSG_DM_CONN_CLOSE, SMPR_SM_ST_IDLE, SMPR_ACT_CLEANUP},
|
||||
{SMP_MSG_CMD_PAIRING_FAILED, SMPR_SM_ST_RSP_TO, SMPR_ACT_NONE},
|
||||
{SMP_MSG_API_CANCEL_REQ, SMPR_SM_ST_RSP_TO, SMPR_ACT_NONE},
|
||||
{SMP_MSG_INT_RSP_TIMEOUT, SMPR_SM_ST_RSP_TO, SMPR_ACT_NONE},
|
||||
{SMP_MSG_API_SECURITY_REQ, SMPR_SM_ST_RSP_TO, SMPR_ACT_NOTIFY_DM_RSP_TO},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/*! Table of individual state tables */
|
||||
const smpTblEntry_t * const smprStateTbl[] =
|
||||
{
|
||||
smprStateTblIdle,
|
||||
smprStateTblApiPairReq,
|
||||
smprStateTblApiPairRsp,
|
||||
smprStateTblPinPair1,
|
||||
smprStateTblPinPair2,
|
||||
smprStateTblCnfCalc1,
|
||||
smprStateTblCnfCalc2,
|
||||
smprStateTblPairRand,
|
||||
smprStateTblCnfVerCalc1,
|
||||
smprStateTblCnfVerCalc2,
|
||||
smprStateTblStkCalc,
|
||||
smprStateTblEncrypt,
|
||||
smprStateTblKeyDist,
|
||||
smprStateTblAttempts,
|
||||
smprStateTblRspTo
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! state machine interface */
|
||||
const smpSmIf_t smprSmIf =
|
||||
{
|
||||
smprStateTbl,
|
||||
smprActionTbl,
|
||||
smprStateTblCommon
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize SMP responder role.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void SmprInit(void)
|
||||
{
|
||||
/* set up state machine interface */
|
||||
smpCb.pSlave = &smprSmIf;
|
||||
smpCb.procPairing = smpProcPairing;
|
||||
smpCb.procAuthReq = smpAuthReq;
|
||||
}
|
||||
Reference in New Issue
Block a user