Esempio n. 1
0
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);
}
Esempio n. 2
0
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);
  }
}
Esempio n. 3
0
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)
  {

  }
}
Esempio n. 4
0
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);
  }
}
Esempio n. 5
0
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);
    }
  }
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
  }
}
Esempio n. 8
0
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);
  }
}
Esempio n. 9
0
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);
      }
    }
  }
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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);
  }
}
Esempio n. 12
0
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);
  }
}
Esempio n. 13
0
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;
      }
    }
  }
}