phStatus_t phalVca_SamAV2_SelectVc( phalVca_SamAV2_DataParams_t * pDataParams, uint16_t wValidIidIndex, uint16_t wKeyNumber, uint16_t wKeyVersion ) { /* local variables */ phStatus_t PH_MEMLOC_REM status; phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCommand[9]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; status = phalVca_SamAV2_Int_ResolveValidIndex( pDataParams, wValidIidIndex, &wValidIidIndex); /* for the case of an overflow we always send the first random number to the SAM */ if ((status & PH_ERR_MASK) == PH_ERR_INVALID_PARAMETER) { wValidIidIndex = 0; } else { PH_CHECK_SUCCESS(status); } aCommand[0] = PHAL_VCA_CMD_SVC; /* Prepare Buffer */ PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SamAV2_Cmd_SAM_SelectVirtualCardMfp( pDataParams->pSamHal, (uint8_t)wKeyNumber, (uint8_t)wKeyVersion, &pDataParams->pRndq[wValidIidIndex * 12], NULL, 0, &aCommand[1])); /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCommand, 9, &pResponse, &wRxLength)); PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* STATUS */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_SamAV2_DeselectVc( phalVca_SamAV2_DataParams_t * pDataParams ) { /* local variables */ phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCommand[1 /* command code */]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; /* command code */ aCommand[0] = PHAL_VCA_CMD_DVC; /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCommand, 1, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* STATUS */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
/* * Should return SW1+SW2 */ phStatus_t phalMfdf_Int_Send7816Apdu( void * pDataParams, void * pPalMifareDataParams, uint8_t bOption, uint8_t bIns, uint8_t bP1, uint8_t bP2, uint8_t bLc, uint8_t * pDataIn, uint8_t bLe, uint8_t ** ppDataOut, uint16_t *pDataLen ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM bCmdBuff[20]; uint16_t PH_MEMLOC_REM wRxlen; uint16_t PH_MEMLOC_REM wCmdLen = 0; uint8_t PH_MEMLOC_REM *pRecv; bCmdBuff[wCmdLen++] = 0x00; /* Class is always 0x00 */ bCmdBuff[wCmdLen++] = bIns; bCmdBuff[wCmdLen++] = bP1; bCmdBuff[wCmdLen++] = bP2; if (bOption & 0x01) { bCmdBuff[wCmdLen++] = bLc; } PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, bCmdBuff, wCmdLen, &pRecv, &wRxlen )); if ((bOption & 0x01) && (bLc > 0)) { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, pDataIn, bLc, &pRecv, &wRxlen )); } wCmdLen = 0; if (bOption & 0x02) { bCmdBuff[wCmdLen++] = bLe; } PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, bCmdBuff, wCmdLen, &pRecv, &wRxlen )); statusTmp = pRecv[wRxlen - 2]; statusTmp <<= 8; statusTmp |= pRecv[wRxlen - 1]; PH_CHECK_SUCCESS_FCT(statusTmp, phalMfdf_Int_ComputeErrorResponse(pDataParams, statusTmp)); if (pDataLen != NULL) { *pDataLen = wRxlen -2; } if (ppDataOut != NULL) { *ppDataOut = pRecv; } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_MFDF); }
/* * * Should take care of wrapping and unwrapping if ISO 7816 Wrapped mode * Does not handle any chaining or CMAC generation/verification or encryption/decryption */ phStatus_t phalMfdf_ExchangeCmd( void * pDataParams, void * pPalMifareDataParams, uint8_t bWrappedMode, uint8_t * pSendBuff, uint16_t wCmdLen, uint8_t ** ppResponse, uint16_t * pRxlen ) { uint16_t PH_MEMLOC_REM wFrameLen; uint8_t PH_MEMLOC_REM * pRecv; phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM bStatusByte = 0xFF; uint8_t PH_MEMLOC_REM pApdu[5] = { PHAL_MFDF_WRAPPEDAPDU_CLA, 0x00, PHAL_MFDF_WRAPPEDAPDU_P1, PHAL_MFDF_WRAPPEDAPDU_P2, 0x00 }; if (bWrappedMode) { wFrameLen = PHAL_MFDF_MAXWRAPPEDAPDU_SIZE; } else { wFrameLen = PHAL_MFDF_MAXDFAPDU_SIZE; } if (wCmdLen > wFrameLen) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_MFDF); } /* Send the data to PICC */ if (bWrappedMode) { pApdu[1] = pSendBuff[0]; /* Desfire cmd code in INS */ pApdu[4] = (uint8_t)(wCmdLen) - 0x01u; PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, pApdu[4] == 0x00 ? PH_EXCHANGE_DEFAULT : PH_EXCHANGE_BUFFER_FIRST, pApdu, PHAL_MFDF_WRAP_HDR_LEN, &pRecv, pRxlen)); if (pApdu[4] != 0x00) { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &pSendBuff[1], wCmdLen - 1, &pRecv, pRxlen)); /* Le byte */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &pApdu[2], /* Le is always zero in wrapped mode. */ 0x01, &pRecv, pRxlen)); } } else { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pPalMifareDataParams, PH_EXCHANGE_DEFAULT, pSendBuff, wCmdLen, &pRecv, pRxlen)); } if (bWrappedMode) { /* memcpy(pResponse, pRecv, (*pRxlen) - 2); PRQA S 3200 */ *ppResponse = pRecv; bStatusByte = pRecv[(*pRxlen) - 1]; (*pRxlen) -= 2; } else { /* memcpy(pResponse, &pRecv[1], (*pRxlen) - 1); PRQA S 3200 */ *ppResponse = pRecv + 1; bStatusByte = pRecv[0]; (*pRxlen) -= 1; } return phalMfdf_Int_ComputeErrorResponse(pDataParams, bStatusByte); }
phStatus_t phalMfdf_Sw_Int_IsoRead( phalMfdf_Sw_DataParams_t * pDataParams, uint16_t wOption, uint8_t * bCmdBuff, uint16_t wCmdLen, uint8_t ** ppRxBuffer, uint16_t * pBytesRead ) { phStatus_t PH_MEMLOC_REM status; uint16_t PH_MEMLOC_REM statusTmp; uint16_t PH_MEMLOC_REM wRxBufferSize; uint16_t PH_MEMLOC_REM wNextPos; uint16_t PH_MEMLOC_REM wRxlen; uint16_t PH_MEMLOC_REM wTmp; uint8_t PH_MEMLOC_REM *pRecv; uint8_t PH_MEMLOC_REM bBackupBytes[3]; status = phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, wOption, bCmdBuff, wCmdLen, ppRxBuffer, pBytesRead ); /* First put everything on the reader Rx buffer upto buffer size - 60 */ wRxlen = *pBytesRead; pRecv = *ppRxBuffer; if ((status != PH_ERR_SUCCESS) && ((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING)) { return status; } while ((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING) { PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_GetConfig( pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXBUFFER_BUFSIZE, &wRxBufferSize )); wNextPos = *pBytesRead; memcpy(bBackupBytes, &pRecv[wNextPos - 3], 3); /* PRQA S 3200 */ if (wNextPos + PHAL_MFDF_MAX_FRAME_SIZE >= wRxBufferSize) { /* Calculate partical cmac if authenticated and return PH_ERR_SUCCESS_CHAINING */ break; } PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig( pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXBUFFER_STARTPOS, wNextPos )); status = phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_RXCHAINING, bCmdBuff, wCmdLen, ppRxBuffer, pBytesRead ); /* Put back the backed up bytes */ memcpy(&pRecv[wNextPos - 3], bBackupBytes, 3); /* PRQA S 3200 */ if ((status != PH_ERR_SUCCESS) && ((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING)) { return status; } wRxlen = *pBytesRead; } /* The data is now in *ppRxBuffer, length = wRxlen */ /* Size of MAC bytes */ wTmp = 0x08; if (status == PH_ERR_SUCCESS) { statusTmp = (*ppRxBuffer)[*pBytesRead - 2]; /* SW1 */ statusTmp = statusTmp << 8; /* Shift SW1 to MSB */ statusTmp |= (*ppRxBuffer)[*pBytesRead - 1]; /* SW2 */ if (pDataParams->bAuthMode == PHAL_MFDF_NOT_AUTHENTICATED) { *pBytesRead -= 2; return phalMfdf_Int_ComputeErrorResponse(pDataParams, statusTmp); } statusTmp = phalMfdf_Int_ComputeErrorResponse(pDataParams, statusTmp); if (statusTmp != PH_ERR_SUCCESS) { return statusTmp; } } return PH_ADD_COMPCODE((status & PH_ERR_MASK), PH_COMP_AL_MFDF); }
phStatus_t phalMfdf_Sw_Int_SendDataToPICC( phalMfdf_Sw_DataParams_t * pDataParams, uint8_t * pCmd, uint16_t wCmdLen, uint8_t * pData, uint16_t wDataLen, uint8_t * pResp, uint16_t * pRespLen ) { /* Utility function to send encrypted data to PICC as and when it is available from SAM */ phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM bStatusByte; uint16_t PH_MEMLOC_REM wIndex; uint16_t PH_MEMLOC_REM wTmp; uint16_t PH_MEMLOC_REM wLen; uint16_t PH_MEMLOC_REM wFrameLen; uint8_t PH_MEMLOC_REM pApdu[5] = { PHAL_MFDF_WRAPPEDAPDU_CLA, 0x00, PHAL_MFDF_WRAPPEDAPDU_P1, PHAL_MFDF_WRAPPEDAPDU_P2, 0x00 }; uint8_t PH_MEMLOC_REM * pRecv; if (pDataParams->bWrappedMode) { wFrameLen = PHAL_MFDF_MAXWRAPPEDAPDU_SIZE; } else { wFrameLen = PHAL_MFDF_MAXDFAPDU_SIZE; } /* Send the data to PICC */ wIndex = 0; wTmp = wDataLen; do { wLen = (wTmp < (wFrameLen - wCmdLen))? wTmp : (wFrameLen - wCmdLen); if (pDataParams->bWrappedMode) { pApdu[1] = pCmd[0]; /* Desfire cmd code in INS */ pApdu[4] = (uint8_t)(wCmdLen + wLen) - 0x01u; PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, pApdu, PHAL_MFDF_WRAP_HDR_LEN, &pRecv, pRespLen)); PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &pCmd[1], wCmdLen - 1, &pRecv, pRespLen)); PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &pData[wIndex], wLen, &pRecv, pRespLen)); /* Le byte */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &pApdu[2], 0x01, &pRecv, pRespLen)); } else { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, pCmd, wCmdLen, &pRecv, pRespLen)); PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &pData[wIndex], wLen, &pRecv, pRespLen)); } wIndex = wIndex + wLen; wTmp = wTmp - wLen; if (pDataParams->bWrappedMode) { memcpy(pResp, pRecv, (*pRespLen) - 2); /* PRQA S 3200 */ bStatusByte = pRecv[(*pRespLen) - 1]; (*pRespLen) -= 2; } else { memcpy(pResp, &pRecv[1], (*pRespLen) - 1); /* PRQA S 3200 */ bStatusByte = pRecv[0]; (*pRespLen) -= 1; } if ((bStatusByte != PHAL_MFDF_RESP_ADDITIONAL_FRAME) && (bStatusByte != PH_ERR_SUCCESS)) { return phalMfdf_Int_ComputeErrorResponse(pDataParams, bStatusByte); } /* Success returned even before writing all data? protocol error */ if ((bStatusByte == PH_ERR_SUCCESS) && (wTmp != 0)) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } if(bStatusByte != 0x00) { pCmd[0] = PHAL_MFDF_RESP_ADDITIONAL_FRAME; wCmdLen = 1; } } while(wTmp); return phalMfdf_Int_ComputeErrorResponse(pDataParams, bStatusByte); }
phStatus_t phalMfdf_Sw_Int_Write_Plain( phalMfdf_Sw_DataParams_t * pDataParams, uint8_t * bCmdBuff, uint16_t wCmdLen, uint8_t bCommOption, uint8_t * pData, uint16_t wDataLen ) { phStatus_t PH_MEMLOC_REM statusTmp = 0; uint16_t PH_MEMLOC_REM status = 0; uint16_t PH_MEMLOC_REM wRxlen = 0; uint8_t PH_MEMLOC_REM bWorkBuffer[32]; uint16_t PH_MEMLOC_REM wFrameLen = 0; uint16_t PH_MEMLOC_REM wTotalLen = 0; uint16_t PH_MEMLOC_REM wTmp = 0; uint16_t PH_MEMLOC_REM wIndex = 0; uint8_t PH_MEMLOC_REM *pRecv; uint8_t PH_MEMLOC_REM pApdu[5] = { PHAL_MFDF_WRAPPEDAPDU_CLA, 0x00, PHAL_MFDF_WRAPPEDAPDU_P1, PHAL_MFDF_WRAPPEDAPDU_P2, 0x00 }; #ifndef NXPBUILD__PH_CRYPTOSYM PHAL_MFDF_UNUSED_VARIABLE(bCommOption) #endif /* NXPBUILD__PH_CRYPTOSYM */ memset(bWorkBuffer, 0x00, 16); /* PRQA S 3200 */ #ifndef NXPBUILD__PH_CRYPTOSYM wTotalLen = wDataLen; #endif /* NXPBUILD__PH_CRYPTOSYM */ if (pDataParams->bWrappedMode) { wFrameLen = PHAL_MFDF_MAXWRAPPEDAPDU_SIZE; } else { wFrameLen = PHAL_MFDF_MAXDFAPDU_SIZE; } wIndex = 0; if (wTotalLen == 0x0000) { /* Single frame cmd without any data. Just send it */ status = phalMfdf_ExchangeCmd( pDataParams, pDataParams->pPalMifareDataParams, pDataParams->bWrappedMode, bCmdBuff, wCmdLen, &pRecv, &wRxlen ); if ((status & PH_ERR_MASK) != PH_ERR_SUCCESS) { return PH_ADD_COMPCODE(status, PH_COMP_AL_MFDF); } /* TBD: SA */ if (wRxlen > 32) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } memcpy(bWorkBuffer, pRecv, wRxlen); /* PRQA S 3200 */ } else { if (pDataParams->bWrappedMode) { wFrameLen = PHAL_MFDF_MAXWRAPPEDAPDU_SIZE; } else { wFrameLen = PHAL_MFDF_MAXDFAPDU_SIZE; } wIndex = 0; wTmp = wTotalLen; if (wTmp <= (wFrameLen - wCmdLen)) { /* Send in one shot */ if (pDataParams->bWrappedMode) { pApdu[1] = bCmdBuff[0]; /* Desfire cmd code in INS */ pApdu[4] = (uint8_t)(wCmdLen + wTotalLen) - 0x01u; PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, pApdu, PHAL_MFDF_WRAP_HDR_LEN, &pRecv, &wRxlen)); PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &bCmdBuff[1], wCmdLen - 1, &pRecv, &wRxlen)); PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, pData, wDataLen, &pRecv, &wRxlen)); /* Le byte */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &pApdu[2], 0x01, &pRecv, &wRxlen)); } else { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, bCmdBuff, wCmdLen, &pRecv, &wRxlen)); #ifndef NXPBUILD__PH_CRYPTOSYM PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, pData, wDataLen, &pRecv, &wRxlen)); #endif /* NXPBUILD__PH_CRYPTOSYM */ } if (pDataParams->bWrappedMode) { status = pRecv[wRxlen - 1]; wRxlen -= 2; } else { status = pRecv[0]; pRecv++; /* Increment pointer to point only to data */ wRxlen -= 1; } if (status != PH_ERR_SUCCESS) { return phalMfdf_Int_ComputeErrorResponse(pDataParams, (uint8_t)status); } memcpy(bWorkBuffer, pRecv, wRxlen); /* PRQA S 3200 */ } else { /* Send command and data. Chain data to PICC */ statusTmp = phalMfdf_Sw_Int_SendDataToPICC( pDataParams, bCmdBuff, wCmdLen, pData, wDataLen, bWorkBuffer, &wRxlen ); } } #ifndef NXPBUILD__PH_CRYPTOSYM /* Should not get more bytes than the status bytes in case of no authentication */ if (wRxlen > 0) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } #endif /* NXPBUILD__PH_CRYPTOSYM */ return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_MFDF); }
phStatus_t phalMfdf_Sw_Int_GetData( phalMfdf_Sw_DataParams_t * pDataParams, uint8_t * pSendBuff, uint16_t wCmdLen, uint8_t ** pResponse, uint16_t * pRxlen ) { uint16_t PH_MEMLOC_REM wOption; uint8_t PH_MEMLOC_REM * pRecv; phStatus_t PH_MEMLOC_REM statusTmp = 0; uint8_t PH_MEMLOC_REM bStatusByte = 0xFF; uint8_t PH_MEMLOC_REM bCmdBuff[10]; uint8_t PH_MEMLOC_REM bBackupByte = 0; uint16_t PH_MEMLOC_REM wNextPos = 0; uint16_t PH_MEMLOC_REM wRxBufferSize = 0; uint8_t PH_MEMLOC_REM bBackupBytes[3]; uint8_t PH_MEMLOC_REM pApdu[5] = { PHAL_MFDF_WRAPPEDAPDU_CLA, 0x00, PHAL_MFDF_WRAPPEDAPDU_P1, PHAL_MFDF_WRAPPEDAPDU_P2, 0x00 }; uint8_t PH_MEMLOC_REM bBackUpByte; uint8_t PH_MEMLOC_REM bBackUpByte1; uint16_t PH_MEMLOC_REM wBackUpLen; uint16_t PH_MEMLOC_REM wTmp = 0; /* Status and two other bytes to be backed up before getting new frame of data */ memset(bBackupBytes, 0x00, 3); /* PRQA S 3200 */ PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_GetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXBUFFER_STARTPOS, &wTmp )); wOption = PH_EXCHANGE_DEFAULT; if (pDataParams->bWrappedMode) { if (wCmdLen > PHAL_MFDF_MAXWRAPPEDAPDU_SIZE) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_MFDF); } pApdu[1] = pSendBuff[0]; /* Desfire command code. */ /* Encode APDU Length*/ pApdu[4]= (uint8_t)wCmdLen - 1; /* Set APDU Length. */ statusTmp = phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, pApdu[4] == 0x00 ? PH_EXCHANGE_DEFAULT : PH_EXCHANGE_BUFFER_FIRST, pApdu, PHAL_MFDF_WRAP_HDR_LEN, &pRecv, pRxlen ); if ((pApdu[4] != 0x00) && (statusTmp == PH_ERR_SUCCESS)) { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &pSendBuff[1], wCmdLen - 1, &pRecv, pRxlen )); statusTmp = phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &pApdu[2], 0x01, &pRecv, pRxlen ); } /* To handle the case where the card returns only status 91 and returns AF in the next frame */ if ((statusTmp & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING) { if (((pDataParams->bWrappedMode) && (*pRxlen == 2)) || ((!(pDataParams->bWrappedMode)) && (*pRxlen == 1))) { /* AF should always be accompanied by data. Otherwise it is a protocol error */ return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } /* One more status byte to read from DesFire */ bBackUpByte = pRecv[0]; bBackUpByte1 = pRecv[1]; wBackUpLen = *pRxlen; PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_RXCHAINING, &pApdu[2], 0x01, &pRecv, pRxlen )); /* Received length can be one or two Ex: 0x91 0xAF */ if (*pRxlen == 2) { pRecv[wBackUpLen] = pRecv[0]; pRecv[wBackUpLen + 1] = pRecv[1]; bStatusByte = pRecv[1]; } else if (*pRxlen == 1) { bStatusByte = pRecv[0]; pRecv[wBackUpLen] = bStatusByte; } else { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } *pRxlen = wBackUpLen + *pRxlen; /* Set back the backed up bytes */ pRecv[0] = bBackUpByte; pRecv[1] = bBackUpByte1; } else { if (statusTmp != PH_ERR_SUCCESS) { return statusTmp; } } } else { /* Normal mode */ if (wCmdLen > PHAL_MFDF_MAXDFAPDU_SIZE) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_MFDF); } /* Send this on L4 */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, wOption, pSendBuff, wCmdLen, &pRecv, pRxlen )); } /* Storing the original pointer */ *pResponse = pRecv; /* Status is 0xAF or Ox00? */ if (*pRxlen > 0x0000) { if (pDataParams->bWrappedMode) { bStatusByte = (*pResponse)[(*pRxlen) - 1]; } else { bStatusByte = (*pResponse)[wTmp]; } } if (bStatusByte == PHAL_MFDF_RESP_ADDITIONAL_FRAME) { if (((pDataParams->bWrappedMode) && (*pRxlen == 2)) || ((!(pDataParams->bWrappedMode)) && (*pRxlen == 1))) { /* AF should always be accompanied by data. Otherwise it is a protocol error */ return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } if (pDataParams->bWrappedMode) { /* Next position will ensure overwriting on the SW1SW2 received from previous command */ wNextPos = (*pRxlen) - 2; memcpy(bBackupBytes, &(*pResponse)[wNextPos - 3], 3); /* PRQA S 3200 */ } else { /* Backup the last byte */ bBackupByte = (*pResponse)[(*pRxlen - 1)]; memcpy(bBackupBytes, &(*pResponse)[(*pRxlen - 3)], 3); /* PRQA S 3200 */ wNextPos = (*pRxlen) - 1; } PH_CHECK_SUCCESS_FCT(statusTmp,phhalHw_GetConfig( pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXBUFFER_BUFSIZE, &wRxBufferSize )); } while (bStatusByte == PHAL_MFDF_RESP_ADDITIONAL_FRAME) { if (((pDataParams->bWrappedMode) && (*pRxlen == 2)) || ((!(pDataParams->bWrappedMode)) && (*pRxlen == 1))) { /* AF should always be accompanied by data. Otherwise it is a protocol error */ return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } if (wNextPos + PHAL_MFDF_MAX_FRAME_SIZE >= wRxBufferSize) { /* Return 0xAF and let the caller recall the function with option = PH_EXCHANGE_RXCHAINING */ /* Return the data accumulated till now and its length */ if (pDataParams->bWrappedMode) { (*pRxlen) -= 2; } else { (*pRxlen) -= 1; (*pResponse)++; } return PH_ADD_COMPCODE(PH_ERR_SUCCESS_CHAINING, PH_COMP_AL_MFDF); } PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXBUFFER_STARTPOS, wNextPos )); bCmdBuff[0] = PHAL_MFDF_RESP_ADDITIONAL_FRAME; wCmdLen = 1; if ( pDataParams->bWrappedMode ) { pApdu[1] = bCmdBuff[0]; /* Desfire command code. */ /* Encode APDU Length*/ pApdu[4]= (uint8_t)wCmdLen - 1; /* Set APDU Length. */ statusTmp = phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, pApdu[4] == 0x00 ? PH_EXCHANGE_DEFAULT : PH_EXCHANGE_BUFFER_FIRST, pApdu, PHAL_MFDF_WRAP_HDR_LEN, &pRecv, pRxlen ); if ((pApdu[4] != 0x00) && (statusTmp == PH_ERR_SUCCESS)) { PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, bCmdBuff, wCmdLen, &pRecv, pRxlen )); bCmdBuff[0] = 0x00; /* Le */ statusTmp = phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, bCmdBuff, 0x01, &pRecv, pRxlen ); } /* To handle the case where the card returns only status 91 and returns AF in the next frame */ if ((statusTmp & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING) { /* One or two more status bytes to read from DesFire */ bBackUpByte = pRecv[0]; bBackUpByte1 = pRecv[1]; wBackUpLen = *pRxlen; PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_RXCHAINING, &pApdu[2], 0x01, &pRecv, pRxlen )); /* Received length can be one or two Ex: 0x91 0xAF */ if (*pRxlen == 2) { pRecv[wBackUpLen] = pRecv[0]; pRecv[wBackUpLen + 1] = pRecv[1]; bStatusByte = pRecv[1]; } else if (*pRxlen == 1) { bStatusByte = pRecv[0]; pRecv[wBackUpLen] = bStatusByte; } else { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_MFDF); } *pRxlen = wBackUpLen + *pRxlen; /* Set back the backed up bytes */ pRecv[0] = bBackUpByte; pRecv[1] = bBackUpByte1; } else { if (statusTmp != PH_ERR_SUCCESS) { return statusTmp; } } } else { /* Send this on L4 */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, wOption, bCmdBuff, wCmdLen, &pRecv, pRxlen )); } /* Update wNextPos */ if (pDataParams->bWrappedMode) { bStatusByte = (*pResponse)[(*pRxlen) - 1]; /* Putback the backed up bytes */ memcpy(&(*pResponse)[wNextPos - 3], bBackupBytes, 3); /* PRQA S 3200 */ wNextPos = (*pRxlen) - 2; memcpy(bBackupBytes, &(*pResponse)[wNextPos - 3], 3); /* PRQA S 3200 */ } else { bStatusByte = (*pResponse)[wNextPos]; /* Put back the previously backedup byte */ (*pResponse)[wNextPos] = bBackupByte; /* Putback the backed up bytes */ memcpy(&(*pResponse)[wNextPos - 2], bBackupBytes, 3); /* PRQA S 3200 */ wNextPos = (*pRxlen) - 1; bBackupByte = (*pResponse)[wNextPos]; /* Backup 3 bytes. The nxt frame will overwrite these */ memcpy(bBackupBytes, &(*pResponse)[wNextPos - 2], 3); /* PRQA S 3200 */ } } if (pDataParams->bWrappedMode) { (*pRxlen) -= 2; } else { (*pRxlen) -= 1; (*pResponse)++; } return phalMfdf_Int_ComputeErrorResponse(pDataParams, bStatusByte); }
phStatus_t phalVca_SamAV2_VcSupport( phalVca_SamAV2_DataParams_t * pDataParams, uint8_t* pIid, uint16_t wKeyEncNumber, uint16_t wKeyEncVersion, uint16_t wKeyMacNumber, uint16_t wKeyMacVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCommand[1 /* command code */]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint16_t PH_MEMLOC_REM wIndex; /* send buffer */ aCommand[0] = PHAL_VCA_CMD_VCS; /*Check available space in key duos list */ if (pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos >= pDataParams->bNumKeyDuos) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Add keys to key list */ wIndex = pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos; pDataParams->pKeyDuos[wIndex].bKeyEncNumber = (uint8_t)wKeyEncNumber; pDataParams->pKeyDuos[wIndex].bKeyEncVersion = (uint8_t)wKeyEncVersion; pDataParams->pKeyDuos[wIndex].bKeyMacNumber = (uint8_t)wKeyMacNumber; pDataParams->pKeyDuos[wIndex].bKeyMacVersion = (uint8_t)wKeyMacVersion; ++pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos; /* buffer the command frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aCommand, 1, &pResponse, &wRxLength)); /* Append IID and exchange the command */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, pIid, PHAL_VCA_IID_SIZE, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* STATUS */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_SamAV2_ProximityCheck( phalVca_SamAV2_DataParams_t * pDataParams, uint8_t bGenerateRndC, uint8_t* pRndC, uint8_t bPps1, uint8_t bNumSteps, uint16_t wKeyNumber, uint16_t wKeyVersion, uint8_t* pUsedRndC ) { /* local variables */ phStatus_t PH_MEMLOC_REM status; phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aCommand[9]; uint8_t PH_MEMLOC_REM bRndRC[14]; uint8_t PH_MEMLOC_REM bRndC[7]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; /* parameter checking */ if ((bGenerateRndC == 0) && (pRndC == NULL)) { return PH_ADD_COMPCODE(PH_ERR_INTERNAL_ERROR, PH_COMP_AL_VCA); } /* send "Prepare Proximity Check" command */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_PrepareProximityCheck(pDataParams->pPalMifareDataParams)); /* check whether to generate RndC or not */ if (bGenerateRndC) { pRndC = bRndC; PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SamAV2_Cmd_SAM_GetChallenge(pDataParams->pSamHal, PHAL_VCA_PC_RND_LEN, pRndC)); } /* send "Proximity Check" command */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ProximityCheck( pDataParams->pPalMifareDataParams, bNumSteps, pRndC, bRndRC)); /* send "Verify Proximity Check" command */ status = phhalHw_SamAV2_Cmd_SAM_ProximityCheckMfp_Part1( pDataParams->pSamHal, (uint8_t) wKeyNumber, (uint8_t) wKeyVersion, bPps1, bRndRC, NULL, 0, &aCommand[1]); if ((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING) { return status; } aCommand[0] = PHAL_VCA_CMD_VPC; /* append the MAC and exchange frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aCommand, 9, &pResponse, &wRxLength)); /* Check the status Code */ status = phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0]); if ((status & PH_ERR_MASK) != PH_ERR_SUCCESS) { /* finish SAM chaining with KillAuthenticate command */ /* Kill only card Auth */ statusTmp = phhalHw_SamAV2_Cmd_SAM_KillAuthentication(pDataParams->pSamHal, 0x01); return status; } /* check response length */ if (wRxLength != 1 /* Status */ + 8 /* MAC */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } /* send "Verify Proximity Check" command */ status = phhalHw_SamAV2_Cmd_SAM_ProximityCheckMfp_Part2( pDataParams->pSamHal, &pResponse[1]); if ((status & PH_ERR_MASK) == PHHAL_HW_SAMAV2_ERR_CRYPTO) { return PH_ADD_COMPCODE(PHAL_VCA_ERR_AUTH, PH_COMP_AL_VCA); } PH_CHECK_SUCCESS(status); /* Copy RndC if requested */ if (pUsedRndC != NULL) { memcpy(pUsedRndC, pRndC, PHAL_VCA_PC_RND_LEN); /* PRQA S 3200 */ } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_SamAV2_VcSupportLast( phalVca_SamAV2_DataParams_t * pDataParams, uint8_t* pIid, uint8_t bLenCap, uint8_t* pPcdCapabilities, uint16_t wKeyEncNumber, uint16_t wKeyEncVersion, uint16_t wKeyMacNumber, uint16_t wKeyMacVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint16_t PH_MEMLOC_REM wRxLength; uint8_t * PH_MEMLOC_REM pResponse; uint8_t PH_MEMLOC_REM aCommand[1 /* CMD */]; uint16_t PH_MEMLOC_REM wIndex; /* Now we create the message to be sent */ aCommand[0] = PHAL_VCA_CMD_VCSL; memset(pDataParams->pPcdCaps, 0x00, 4); /* PRQA S 3200 */ /* Copy PCD Caps */ if (bLenCap) { if (bLenCap > 3) { bLenCap = 3; } pDataParams->pPcdCaps[0] = bLenCap; memcpy(&pDataParams->pPcdCaps[1], pPcdCapabilities, bLenCap); /* PRQA S 3200 */ } /* Check available space in key duos list */ if (pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos >= pDataParams->bNumKeyDuos) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Add keys to key list */ wIndex = pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos; pDataParams->pKeyDuos[wIndex].bKeyEncNumber = (uint8_t)wKeyEncNumber; pDataParams->pKeyDuos[wIndex].bKeyEncVersion = (uint8_t)wKeyEncVersion; pDataParams->pKeyDuos[wIndex].bKeyMacNumber = (uint8_t)wKeyMacNumber; pDataParams->pKeyDuos[wIndex].bKeyMacVersion = (uint8_t)wKeyMacVersion; ++pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos; /* buffer command frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aCommand, 1, &pResponse, &wRxLength)); /* buffer installation identifier */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, pIid, PHAL_VCA_IID_SIZE, &pResponse, &wRxLength)); /* buffer RNDQ identifier */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &pDataParams->pRndq[pDataParams->wCurrentCardTablePos * 12], 12, &pResponse, &wRxLength)); /* append PCDCaps and transmit the command */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, pDataParams->pPcdCaps, 1+ bLenCap, &pResponse, &wRxLength)); PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /*Status */ + 16 /* Cryptogram */ + 8 /*MAC */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } /* Add Num key Duos */ PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SamAV2_Cmd_SAM_VirtualCardSupportMfp( pDataParams->pSamHal, PH_EXCHANGE_BUFFER_CONT, &pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos, 1, NULL, 0, NULL, NULL)); /* Add key Duos */ PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SamAV2_Cmd_SAM_VirtualCardSupportMfp( pDataParams->pSamHal, PH_EXCHANGE_BUFFER_CONT, (uint8_t*)pDataParams->pKeyDuos, pDataParams->pCardTable[pDataParams->wCurrentCardTablePos].bNumKeyDuos << 2, NULL, 0, NULL, NULL)); /* Add RNDQ */ PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SamAV2_Cmd_SAM_VirtualCardSupportMfp( pDataParams->pSamHal, PH_EXCHANGE_BUFFER_CONT, &pDataParams->pRndq[pDataParams->wCurrentCardTablePos * 12], 12, NULL, 0, NULL, NULL)); /* Add Card Data */ PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SamAV2_Cmd_SAM_VirtualCardSupportMfp( pDataParams->pSamHal, PH_EXCHANGE_BUFFER_CONT, &pResponse[1], 24, NULL, 0, NULL, NULL)); pDataParams->wCurrentCardTablePos++; return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_Sw_VcSupport( phalVca_Sw_DataParams_t * pDataParams, uint8_t * pIid, uint16_t wKeyEncNumber, uint16_t wKeyEncVersion, uint16_t wKeyMacNumber, uint16_t wKeyMacVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aTxBuffer[1]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; /* Check available space in key duos list */ if (pDataParams->wCurrentIidTablePos >= pDataParams->wNumIidTableEntries ) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Add keys and iids to the iid table list */ pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wIidIndex = pDataParams->wCurrentIidIndex; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyEncNumber = wKeyEncNumber; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyEncVersion = wKeyEncVersion; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyMacNumber = wKeyMacNumber; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyMacVersion = wKeyMacVersion; pDataParams->wCurrentIidTablePos++; pDataParams->wCurrentIidIndex++; /* command code */ aTxBuffer[0] = PHAL_VCA_CMD_VCS; /* buffer the command frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aTxBuffer, 1, &pResponse, &wRxLength)); /* Append IID and exchange the command */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, pIid, PHAL_VCA_IID_SIZE, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* STATUS */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_Sw_Cmd_VerifyProximityCheck( phalVca_Sw_DataParams_t * pDataParams, uint8_t* pRndRC, uint8_t bPps1, uint16_t wKeyNumber, uint16_t wKeyVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint8_t PH_MEMLOC_REM aTmpBuf[2 + PHAL_VCA_PC_RND_LEN * 2]; uint8_t PH_MEMLOC_REM aKey[PH_CRYPTOSYM_AES128_KEY_SIZE]; uint16_t PH_MEMLOC_REM wKeyType; uint8_t PH_MEMLOC_REM bMac[PH_CRYPTOSYM_AES_BLOCK_SIZE]; uint8_t PH_MEMLOC_REM bMacLength; /* prepare "Verify Proximity Check" command */ aTmpBuf[0] = PHAL_VCA_CMD_VPC; aTmpBuf[1] = bPps1; memcpy(&aTmpBuf[2], pRndRC, PHAL_VCA_PC_RND_LEN * 2); /* PRQA S 3200 */ /* Get Proximity Check Key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, wKeyNumber, wKeyVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load Proximity Check Key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* CMAC with Padding */ /* mac calculation: CMAC(CMD || PPS1 || (RndRC1 || ... || RndRC14)) */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, aTmpBuf, (2 + PHAL_VCA_PC_RND_LEN * 2), bMac, &bMacLength)); /* perform MAC truncation */ phalVca_Sw_Int_TruncateMac(bMac, bMac); /* buffer the command code */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aTmpBuf, 1, &pResponse, &wRxLength)); /* append the MAC and exchange frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, bMac, PHAL_VCA_TRUNCATED_MAC_SIZE, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* Status */ + 8 /* MAC */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } /* Calculate MAC */ aTmpBuf[0] = pResponse[0]; PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, aTmpBuf, (2 + PHAL_VCA_PC_RND_LEN * 2), bMac, &bMacLength)); /* perform MAC truncation */ phalVca_Sw_Int_TruncateMac(bMac, bMac); /* Compare MAC */ if (memcmp(bMac, &pResponse[1], PHAL_VCA_TRUNCATED_MAC_SIZE) != 0) { return PH_ADD_COMPCODE(PHAL_VCA_ERR_AUTH, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_Sw_SelectVc( phalVca_Sw_DataParams_t * pDataParams, uint16_t wValidIidIndex, uint16_t wKeyNumber, uint16_t wKeyVersion ) { phStatus_t PH_MEMLOC_REM statusTmp, status; uint8_t PH_MEMLOC_REM aTxBuffer[PHAL_VCA_IID_SIZE + 1]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint8_t PH_MEMLOC_REM aKey[PH_CRYPTOSYM_AES128_KEY_SIZE]; uint16_t PH_MEMLOC_REM wKeyType; uint8_t PH_MEMLOC_REM bMacLength; /* Prepare command header */ aTxBuffer[0] = PHAL_VCA_CMD_SVC; aTxBuffer[1] = PHAL_VCA_CMD_SVC; /* Resolve Iid index */ status = phalVca_Sw_Int_ResolveValidIndex( pDataParams, wValidIidIndex, &wValidIidIndex); /* for the case of an overflow we generate random data */ /* Prepare MAC data */ if ((status & PH_ERR_MASK) == PH_ERR_INVALID_PARAMETER) { wValidIidIndex = 0; PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoRng_Rnd(pDataParams->pCryptoRngDataParams, PHAL_VCA_IID_SIZE-1, &aTxBuffer[2])); } else { PH_CHECK_SUCCESS(status); memcpy(&aTxBuffer[2], &pDataParams->pCardTable[wValidIidIndex].pCardData[1], PHAL_VCA_IID_SIZE-1); /* PRQA S 3200 */ } /* Get MAC Key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, wKeyNumber, wKeyVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* Calculate MAC */ /* CMAC with Padding */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, &aTxBuffer[1], PHAL_VCA_IID_SIZE, &aTxBuffer[1], &bMacLength)); /* Truncate MAC */ phalVca_Sw_Int_TruncateMac(&aTxBuffer[1], &aTxBuffer[1]); /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aTxBuffer, 1 + PHAL_VCA_TRUNCATED_MAC_SIZE, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* STATUS */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_Sw_VcSupportLast( phalVca_Sw_DataParams_t * pDataParams, uint8_t * pIid, uint8_t bLenCap, uint8_t * pPcdCapabilities, uint16_t wKeyEncNumber, uint16_t wKeyEncVersion, uint16_t wKeyMacNumber, uint16_t wKeyMacVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aTmpBuf[PH_CRYPTOSYM_AES_BLOCK_SIZE * 2]; uint8_t PH_MEMLOC_REM aTxBuffer[1]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint8_t PH_MEMLOC_REM aKey[PH_CRYPTOSYM_AES128_KEY_SIZE]; uint16_t PH_MEMLOC_REM wKeyType; uint8_t PH_MEMLOC_REM bMac[PH_CRYPTOSYM_AES_BLOCK_SIZE]; uint8_t PH_MEMLOC_REM bMacLength; phalVca_Sw_CardTableEntry_t PH_MEMLOC_REM pDummyCardData; phalVca_Sw_CardTableEntry_t * PH_MEMLOC_REM pCardDataStorage; uint16_t PH_MEMLOC_REM wIndex; /* Build the command frame */ aTxBuffer[0] = PHAL_VCA_CMD_VCSL; /* Copy PCD Caps */ memset(aTmpBuf, 0x00, 4); /* PRQA S 3200 */ if (bLenCap) { if (bLenCap > 3) { bLenCap = 3; } aTmpBuf[0] = bLenCap; memcpy(&aTmpBuf[1], pPcdCapabilities, bLenCap); /* PRQA S 3200 */ } /* Check available space in key duos list */ if (pDataParams->wCurrentIidTablePos >= pDataParams->wNumIidTableEntries) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Check available space in card table */ if (pDataParams->wCurrentCardTablePos >= pDataParams->wNumCardTableEntries) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Add keys and iids to the iid table list */ pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wIidIndex = pDataParams->wCurrentIidIndex; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyEncNumber = wKeyEncNumber; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyEncVersion = wKeyEncVersion; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyMacNumber = wKeyMacNumber; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyMacVersion = wKeyMacVersion; pDataParams->wCurrentIidTablePos++; pDataParams->wCurrentIidIndex++; /* Generate RNDQ */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoRng_Rnd(pDataParams->pCryptoRngDataParams, 12, &aTmpBuf[PHAL_VCA_POS_RNDQ])); /* buffer command frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aTxBuffer, 1, &pResponse, &wRxLength)); /* buffer installation identifier */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, pIid, PHAL_VCA_IID_SIZE, &pResponse, &wRxLength)); /* buffer RNDQ identifier */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &aTmpBuf[PHAL_VCA_POS_RNDQ], 12, &pResponse, &wRxLength)); /* append PCDCaps and transmit the command */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &aTmpBuf[0], 1+ bLenCap, &pResponse, &wRxLength)); PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /*Status */ + 16 /* Cryptogram */ + 8 /*MAC */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } /* Prepare MAC data */ aTmpBuf[0] = pResponse[0]; memcpy(&aTmpBuf[PHAL_VCA_POS_PAYLOAD], &pResponse[1], 16); /* PRQA S 3200 */ /* Iterate over all available key pairs and try to find a match */ for (wIndex = pDataParams->wCurrentIidTablePos; wIndex > 0; --wIndex) { /* Retrieve MAC key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, pDataParams->pIidTable[(wIndex-1)].wKeyMacNumber, pDataParams->pIidTable[(wIndex-1)].wKeyMacVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load the key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* Set the correct MAC calculation mode */ /* CMAC with Padding */ /* Calculate the MAC */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, aTmpBuf, 32, bMac, &bMacLength)); /* Truncate the MAC */ phalVca_Sw_Int_TruncateMac(bMac, bMac); /* Compare the MACs */ if (memcmp(&pResponse[17], bMac, PHAL_VCA_TRUNCATED_MAC_SIZE) == 0) { pCardDataStorage = &pDataParams->pCardTable[pDataParams->wCurrentCardTablePos]; } else { pCardDataStorage = &pDummyCardData; } /* In any case, we need to decrypt */ pCardDataStorage->bValid = PHAL_VCA_CARD_TABLE_ENTRY_VALID; /* Retrieve ENC key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, pDataParams->pIidTable[(wIndex-1)].wKeyEncNumber, pDataParams->pIidTable[(wIndex-1)].wKeyEncVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load the key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* Load first IV*/ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadIv( pDataParams->pCryptoDataParams, phalVca_Sw_FirstIv, PH_CRYPTOSYM_AES_BLOCK_SIZE)); /* Perform decryption */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_Decrypt( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_CIPHER_MODE_CBC, &pResponse[1], PHAL_VCA_IID_SIZE, pCardDataStorage->pCardData )); /* Copy the found IID Index */ pCardDataStorage->wIidIndex = pDataParams->pIidTable[(wIndex-1)].wIidIndex; } pDataParams->wCurrentIidTablePos = 0; ++pDataParams->wCurrentCardTablePos; return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }