static bool BeidCardSelectApplet(CContext *poContext, SCARDHANDLE hCard) { long lRetVal = 0; unsigned char tucSelectApp[] = {0x00, 0xA4, 0x04, 0x00}; CByteArray oCmd(40); oCmd.Append(tucSelectApp, sizeof(tucSelectApp)); oCmd.Append((unsigned char) sizeof(APPLET_AID)); oCmd.Append(APPLET_AID, sizeof(APPLET_AID)); CByteArray oResp; try { oResp = poContext->m_oPCSC.Transmit(hCard, oCmd, &lRetVal); } catch(CMWException e) { MWLOG(LEV_CRIT, MOD_CAL, L"Failed to select applet: 0x%0x", e.GetError()); return false; } catch(...) { MWLOG(LEV_CRIT, MOD_CAL, L"Failed to select applet"); return false; } return (oResp.Size() == 2 && (oResp.GetByte(0) == 0x61 || oResp.GetByte(0) == 0x90)); }
static long TestPteidSendApdu(CReader & oReader) { long lErrors = 0; printf("\nTesting SendAPDU()\n"); // Send a Get Card Data APDU unsigned char tucGetCardData[] = {0x80, 0xE4, 0x00, 0x00, 0x1C}; CByteArray oGetCardData(tucGetCardData, sizeof(tucGetCardData)); CByteArray oData = oReader.SendAPDU(oGetCardData); // Serial nr. are the first 16 bytes of the Get Card Data APDU std::string csSerialNr = oReader.GetSerialNr(); if (csSerialNr != oData.ToString(false, true, 0, 16)) ERR_LOG("SendAPDU(GetCardData) returns wrong data (bad serial nr.)\n", lErrors); // Send a Select MF APDU unsigned char tucSelectMF[] = {0x00, 0xa4, 0x02, 0x0C, 0x02, 0x3f, 0x00}; CByteArray oSelectMF(tucSelectMF, sizeof(tucSelectMF)); oData = oReader.SendAPDU(oSelectMF); // Result should be 90 00 if (oData.Size() != 2 || oData.GetByte(0) != 0x90 || oData.GetByte(1) != 0x00) { ERR_LOG("SendAPDU(GetCardData) returns wrong data (bad serial nr.)\n", lErrors); printf(" (result = %s\n", oData.ToString().c_str()); } return lErrors; }
static long TestPteid(CReader & oReader, const std::string & csPin) { long lErrors = 0; CByteArray oCardData = oReader.GetInfo(); unsigned char ucVersion = oCardData.GetByte(21); printf("Card: Belgian eID V%d.%d\n", ucVersion / 16, ucVersion % 16); lErrors += TestPteidSendApdu(oReader); lErrors += TestPteidCtrl(oReader, ucVersion); lErrors += TestCache(oReader, "3F00DF014035"); lErrors += TestReadShortFile(oReader, "3F002F00"); lErrors += TestReadLongFile(oReader, "3F00DF005038"); std::vector <CByteArray> vAIDs; vAIDs.push_back(CByteArray("A000000177504B43532D3135", true)); if (ucVersion >= 0x20) vAIDs.push_back(CByteArray("A000000177496446696C6573", true)); lErrors += TestSelectApplication(oReader, vAIDs); lErrors += TestRandom(oReader); lErrors += TestPteidP15(oReader, ucVersion); lErrors += TestPteidPinStatus(oReader, ucVersion); lErrors += TestSignatures(oReader, csPin); return lErrors; }
CCard *SISCardGetInstance(unsigned long ulVersion, const char *csReader, SCARDHANDLE hCard, CContext *poContext, CPinpad *poPinpad) { CCard *poCard = NULL; bool bIsSisCard = false; CByteArray oData; // Check if it's a SIS card by reading the ATR and serial number try { poContext->m_oPCSC.BeginTransaction(hCard); #ifndef SWITCH_TO_ASYNC_AFTER_READ unsigned long ulReadLen = 26; // read only the first part #else unsigned long ulReadLen = 404; // read everything try { #endif oData = ReadInternal(&poContext->m_oPCSC, hCard, 0, ulReadLen); bIsSisCard = (oData.Size() >= 26) && (oData.GetByte(21) == 0xA0) && (oData.GetByte(22) == 0x00) && (oData.GetByte(23) == 0x00) && (oData.GetByte(24) == 0x00) && (oData.GetByte(25) == 0x33); #ifdef SWITCH_TO_ASYNC_AFTER_READ } catch (...) { // Switch back to asynchronous mode. BackToAsyncMode(hCard, &poContext->m_oPCSC, csReader); throw; } // Switch back to asynchronous mode. BackToAsyncMode(hCard, &poContext->m_oPCSC, csReader); #endif if (bIsSisCard) poCard = new CSISCard(hCard, poContext, poPinpad, oData); poContext->m_oPCSC.EndTransaction(hCard); } catch(...) { poContext->m_oPCSC.EndTransaction(hCard); //printf("Exception in cardPluginSIS.SISCardGetInstance()\n"); } return poCard; }
static long TestPteidCtrl(CReader & oReader, unsigned char ucVersion) { long lErrors = 0; printf("\nTesting Ctrl()\n"); // CTRL_PTEID_GETCARDDATA CByteArray oCardInfo = oReader.GetInfo(); CByteArray oUnsignedCardData = oReader.Ctrl(CTRL_PTEID_GETCARDDATA, CByteArray()); if (!oCardInfo.Equals(oUnsignedCardData)) ERR_LOG("ERR: Ctrl(CTRL_PTEID_GETCARDDATA) != GetInfo()\n", lErrors); // CTRL_PTEID_GETSIGNEDCARDDATA if (ucVersion >= 0x20) { CByteArray oSignedCardData = oReader.Ctrl(CTRL_PTEID_GETSIGNEDCARDDATA, CByteArray()); if (oSignedCardData.Size() != oUnsignedCardData.Size() + 128) ERR_LOG("ERR: signed and unsigned card data should differ in size by 128 bytes\n", lErrors); oSignedCardData.Chop(128); if (!oUnsignedCardData.Equals(oSignedCardData)) ERR_LOG("ERR: start of unsigned card data should be the same as for unsigned card data\n", lErrors); } // CTRL_PTEID_GETSIGNEDPINSTATUS if (ucVersion >= 0x20) { tPin pin = oReader.GetPin(0); CByteArray oData(1); oData.Append((unsigned char) pin.ulPinRef); CByteArray oSignedPinStatus = oReader.Ctrl(CTRL_PTEID_GETSIGNEDPINSTATUS, oData); if (oSignedPinStatus.Size() != 129) ERR_LOG("ERR: signed pin status response should be (1 + 128) bytes\n", lErrors); else if (oSignedPinStatus.GetByte(0) != oReader.PinStatus(pin)) ERR_LOG("ERR: signed pin status differs from unsigned PIN status\n", lErrors); } // CTRL_PTEID_INTERNAL_AUTH CByteArray oData(21); // Key ref (1 byte) + challenge(20 bytes) oData.Append(0x81); for (int i = 0; i < 20; i++) oData.Append((unsigned char) rand()); CByteArray oResp1 = oReader.Ctrl(CTRL_PTEID_INTERNAL_AUTH, oData); if (oResp1.Size() != 128) ERR_LOG("ERR: Internal Auth. didn't return 128 bytes\n", lErrors); CByteArray oResp2 = oReader.Ctrl(CTRL_PTEID_INTERNAL_AUTH, oData); if (!oResp1.Equals(oResp2)) ERR_LOG("ERR: Internal Auth. on the same data returns a different result\n", lErrors); oData.SetByte(oData.GetByte(5) + 0x01, 5); CByteArray oResp3 = oReader.Ctrl(CTRL_PTEID_INTERNAL_AUTH, oData); if (oResp1.Equals(oResp3)) ERR_LOG("ERR: Internal Auth. on the different data returns the same result\n", lErrors); return lErrors; }
unsigned long CBeidCard::PinStatus(const tPin & Pin) { // This command isn't supported on V1 cards if (m_oCardData.GetByte(21) < 0x20) return PIN_STATUS_UNKNOWN; try { m_ucCLA = 0x80; CByteArray oResp = SendAPDU(0xEA, 0x00, (unsigned char) Pin.ulPinRef, 1); m_ucCLA = 0x00; getSW12(oResp, 0x9000); return oResp.GetByte(0); } catch(...) { m_ucCLA = 0x00; throw; } }
CByteArray CPinpadLibOldBeid::PinCmd(SCARDHANDLE hCard, unsigned long ulControl, CByteArray oCmd, unsigned char ucPintype, unsigned char ucOperation) { if (ulControl == CCID_IOCTL_GET_FEATURE_REQUEST) { unsigned char tucFeatures[] = {0x06, 0x04, 0x00, 0x31, 0x32, 0x33, 0x07, 0x04, 0x00 ,0x31, 0x32, 0x33}; return CByteArray(tucFeatures, sizeof(tucFeatures)); } SCR_Card xCard = { hCard, tcsLangs[m_iLangIdx], {NULL, 0}, NULL }; unsigned char tucStatus[2]; long lRet = SCARD_F_INTERNAL_ERROR; if (ucOperation == EIDMW_PP_OP_VERIFY) { SCR_PinUsage xPinUsage = { ucPintype == EIDMW_PP_TYPE_SIGN ? SCR_USAGE_SIGN: SCR_USAGE_AUTH, ucPintype == EIDMW_PP_TYPE_SIGN ? "SIG" : "AUT", ucPintype == EIDMW_PP_TYPE_SIGN ? tcsUsageSig[m_iLangIdx] : tcsUsageAuth[m_iLangIdx] }; lRet = m_pVerifyPin(&xCard, oCmd.GetByte(22), &xPinUsage, &xApp, tucStatus); } else if (ucOperation == EIDMW_PP_OP_CHANGE) { lRet = m_pChangePin(&xCard, oCmd.GetByte(27), &xApp, tucStatus); } else throw CMWEXCEPTION(EIDMW_ERR_PIN_OPERATION); CByteArray oResp(2); switch(lRet) { case SCARD_S_SUCCESS: if (tucStatus[0] == 0xEC && tucStatus[1] == 0xD2) oResp.Append(tucErrTimeout, sizeof(tucErrTimeout)); else if (tucStatus[0] == 0xEC && tucStatus[1] == 0xD6) oResp.Append(tucErrCancel, sizeof(tucErrCancel)); else oResp.Append(tucStatus, 2); break; case SCARD_E_CANCELLED: oResp.Append(tucErrCancel, sizeof(tucErrCancel)); break; case SCARD_W_REMOVED_CARD: throw CMWEXCEPTION(EIDMW_ERR_NO_CARD); break; case SCR_I_PIN_CHECK_FAILED: oResp.Append(tucErrPinsDiffer, sizeof(tucErrPinsDiffer)); break; default: oResp.Append(tucErrGeneral, sizeof(tucErrGeneral)); } return oResp; }
CCard *BeidCardGetInstance(unsigned long ulVersion, const char *csReader, SCARDHANDLE hCard, CContext *poContext, CPinpad *poPinpad) { CCard *poCard = NULL; if ((ulVersion % 100) == (PLUGIN_VERSION % 100)) { unsigned long ulLockCount = 1; try { bool bNeedToSelectApplet = false; CByteArray oData; CByteArray oCmd(40); unsigned char tucSelectApp[] = {0x00, 0xA4, 0x04, 0x0C}; oCmd.Append(tucSelectApp, sizeof(tucSelectApp)); oCmd.Append((unsigned char) sizeof(BELPIC_AID)); oCmd.Append(BELPIC_AID, sizeof(BELPIC_AID)); long lRetVal; // Don't remove these brackets, CAutoLock dtor must be called! //{ //don't use autolock when card might be reset //CAutoLock oAutLock(&poContext->m_oPCSC, hCard); poContext->m_oPCSC.BeginTransaction(hCard); oData = poContext->m_oPCSC.Transmit(hCard, oCmd, &lRetVal); if (lRetVal == SCARD_E_COMM_DATA_LOST || lRetVal == SCARD_E_NOT_TRANSACTED) { poContext->m_oPCSC.Recover(hCard, &ulLockCount); bNeedToSelectApplet = BeidCardSelectApplet(poContext, hCard); if (bNeedToSelectApplet)// try again to select the belpic app oData = poContext->m_oPCSC.Transmit(hCard, oCmd,&lRetVal); } if (oData.Size() == 2 && oData.GetByte(0) == 0x6A && (oData.GetByte(1) == 0x82 || oData.GetByte(1) == 0x86)) { // Perhaps the applet is no longer selected; so try to select it // first; and if successfull then try to select the Belpic AID again bNeedToSelectApplet = BeidCardSelectApplet(poContext, hCard); if (bNeedToSelectApplet) oData = poContext->m_oPCSC.Transmit(hCard, oCmd,&lRetVal); } bool bIsBeidCard = oData.Size() == 2 && oData.GetByte(0) == 0x90 && oData.GetByte(1) == 0x00; if (bIsBeidCard) poCard = new CBeidCard(hCard, poContext, poPinpad, oData, bNeedToSelectApplet ? ALW_SELECT_APPLET : TRY_SELECT_APPLET); #ifdef __APPLE__ else { // On Mac, if an unknown asynchronous card is inserted, // we don't return NULL but a CUnknownCard instance. // Reason: if we return NULL then the SISCardPlugin who // will be consulted next in card of a ACR38U reader // causes the reader/driver to get in a strange state // (if no SIS card is present) and if then a CUnknownCard // is instantiated, it will throw an exception if e.g. // SCardStatus() is called. // Remark: this trick won't work if synchronous card // (other then the SIS card is inserted). if(ulLockCount) { poContext->m_oPCSC.EndTransaction(hCard); } return new CUnknownCard(hCard, poContext, poPinpad, CByteArray()); } #endif //} if(ulLockCount) { poContext->m_oPCSC.EndTransaction(hCard); } } catch(...) { if(ulLockCount) { poContext->m_oPCSC.EndTransaction(hCard); } //printf("Exception in cardPluginBeid.CardGetInstance()\n"); } } return poCard; }
CByteArray CBeidCard::Ctrl(long ctrl, const CByteArray & oCmdData) { CAutoLock oAutoLock(this); switch(ctrl) { case CTRL_BEID_GETCARDDATA: return m_oCardData; case CTRL_BEID_GETSIGNEDCARDDATA: if (m_ucAppletVersion < 0x17) throw CMWEXCEPTION(EIDMW_ERR_NOT_SUPPORTED); else { if (m_selectAppletMode == ALW_SELECT_APPLET) SelectApplet(); m_ucCLA = 0x80; CByteArray oRet = SendAPDU(0xE4, 0x02, 0x00, 0x9C); m_ucCLA = 0; getSW12(oRet, 0x9000); oRet.Chop(2); return oRet; } case CTRL_BEID_GETSIGNEDPINSTATUS: // oCmdData must contain: // - the pin reference (1 byte) if (m_ucAppletVersion < 0x17) throw CMWEXCEPTION(EIDMW_ERR_NOT_SUPPORTED); else { if (m_selectAppletMode == ALW_SELECT_APPLET) SelectApplet(); unsigned char ucPinRef = oCmdData.GetByte(0); m_ucCLA = 0x80; CByteArray oRet = SendAPDU(0xEA, 0x02, ucPinRef, 0x81); m_ucCLA = 0; if (ShouldSelectApplet(0xEA, getSW12(oRet))) { if (SelectApplet()) { m_selectAppletMode = ALW_SELECT_APPLET; m_ucCLA = 0x80; CByteArray oRet = SendAPDU(0xEA, 0x02, ucPinRef, 0x81); m_ucCLA = 0; } } getSW12(oRet, 0x9000); oRet.Chop(2); return oRet; } case CTRL_BEID_INTERNAL_AUTH: // oCmdData must contain: // - the key reference (1 byte) // - the challenge to be signed (20 bytes) if (oCmdData.Size() != 21) throw CMWEXCEPTION(EIDMW_ERR_PARAM_BAD); else { if (m_selectAppletMode == ALW_SELECT_APPLET) SelectApplet(); unsigned char ucKeyRef = oCmdData.GetByte(0); CByteArray oData(22); oData.Append(0x94); oData.Append(0x14); oData.Append(oCmdData.GetBytes() + 1, 20); CByteArray oRet = SendAPDU(0x88, 0x02, ucKeyRef, oData); if (ShouldSelectApplet(0x88, getSW12(oRet))) { if (SelectApplet()) { m_selectAppletMode = ALW_SELECT_APPLET; CByteArray oRet = SendAPDU(0x88, 0x02, ucKeyRef, oData); } } getSW12(oRet, 0x9000); oRet.Chop(2); return oRet; } default: MWLOG(LEV_WARN, MOD_CAL, L"Ctrl(): Unknown CRTL code %d (0x%0x) specified", ctrl, ctrl); throw CMWEXCEPTION(EIDMW_ERR_PARAM_BAD); } }