initial commit

This commit is contained in:
2022-10-23 23:45:43 -07:00
commit e190fa5193
6450 changed files with 8626944 additions and 0 deletions
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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)
{
}
}
@@ -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 */
@@ -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);
}
File diff suppressed because it is too large Load Diff
@@ -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
}
@@ -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 */
@@ -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;
}
}
@@ -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 */
@@ -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);
}
}
@@ -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";
}
}
@@ -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;
}
@@ -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);
}
}
@@ -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 */
@@ -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);
}
}
@@ -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";
}
}
@@ -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;
}