Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1214 lines
35 KiB

  1. // CSmartCard.cpp: implementation of the CSmartCard class.
  2. //
  3. // (c) Copyright Schlumberger Technology Corp., unpublished work, created
  4. // 2000. This computer program includes Confidential, Proprietary
  5. // Information and is a Trade Secret of Schlumberger Technology Corp. All
  6. // use, disclosure, and/or reproduction is prohibited unless authorized
  7. // in writing. All Rights Reserved.
  8. //////////////////////////////////////////////////////////////////////
  9. #include "NoWarning.h"
  10. #include <string>
  11. #include <wtypes.h>
  12. #include <scuOsExc.h>
  13. #include <scuExcHelp.h>
  14. #include <scuArrayP.h>
  15. #include "iopExc.h"
  16. #include "SmartCard.h"
  17. #include "LockWrap.h"
  18. using namespace std;
  19. //////////////////////////////////////////////////////////////////////
  20. // Construction/Destruction
  21. //////////////////////////////////////////////////////////////////////
  22. //////////////////// Begin CSmartCard::Exception //////////////////////////
  23. /////////////////////////// LOCAL/HELPER /////////////////////////////////
  24. namespace
  25. {
  26. using namespace iop;
  27. // Transfer data to/from the card. The data to read/write is
  28. // broken up into cMaxBlock sized chunks when calling rsc's
  29. // (CSmartCard) member procedure pbtm (pointer to member routine)
  30. // to actually do the read/write.
  31. template<class BlockType, class PBlockTransferMember>
  32. void
  33. TransferData(const WORD wOffset, // file offset to start
  34. const WORD wDataLength, // amount to transfer
  35. BlockType bData, // data buffer to read/write
  36. CSmartCard &rsc, // card object to use
  37. PBlockTransferMember pbtm, // member proc to read/write
  38. WORD cMaxBlock) // max size transfer at once
  39. {
  40. WORD wBytesTransferred = 0;
  41. WORD wFullRounds = wDataLength / cMaxBlock;
  42. /////////////////////////////////////////////////
  43. // Transfer maximum bytes at each full round //
  44. /////////////////////////////////////////////////
  45. for (WORD wCurrentRound = 0; wCurrentRound < wFullRounds; wCurrentRound++)
  46. {
  47. (rsc.*pbtm)(wOffset + wBytesTransferred,
  48. bData + wBytesTransferred, cMaxBlock);
  49. wBytesTransferred += cMaxBlock;
  50. }
  51. // Transfer any leftovers
  52. BYTE bBytesLeft = wDataLength - wBytesTransferred;
  53. if (bBytesLeft != 0)
  54. {
  55. (rsc.*pbtm)(wOffset + wBytesTransferred,
  56. bData + wBytesTransferred, bBytesLeft);
  57. }
  58. }
  59. scu::CauseCodeDescriptionTable<CSmartCard::CauseCode> ccdt[] =
  60. {
  61. {
  62. CSmartCard::ccAccessConditionsNotMet,
  63. TEXT("Access conditions not met.")
  64. },
  65. {
  66. CSmartCard::ccAlgorithmIdNotSupported,
  67. TEXT("The algorithm ID is not supported in the card.")
  68. },
  69. {
  70. CSmartCard::ccAskRandomNotLastApdu,
  71. TEXT("The random number is no longer available. The "
  72. "AskRandom APDU must be sent immediately previous "
  73. "to this one.")
  74. },
  75. {
  76. CSmartCard::ccAuthenticationFailed,
  77. TEXT("Authentication failed (i.e. CHV or key rejected, or "
  78. "wrong cryptogram).")
  79. },
  80. {
  81. CSmartCard::ccBadFilePath,
  82. TEXT("The file path is invalid. Ensure that each file "
  83. "name in the path is 4 characters long and is a valid "
  84. "representation of the hexadecimal ID.")
  85. },
  86. {
  87. CSmartCard::ccBadState,
  88. TEXT("The Application is not in a state permitting this "
  89. "operation.")
  90. },
  91. {
  92. CSmartCard::ccCannotReadOutsideFileBoundaries,
  93. TEXT("Could not read outside the file boundaries.")
  94. },
  95. {
  96. CSmartCard::ccCannotWriteOutsideFileBoundaries,
  97. TEXT("Could not write outside the file boundaries.")
  98. },
  99. {
  100. CSmartCard::ccCardletNotInRegisteredState,
  101. TEXT("Cardlet is not in a registered state. It may be "
  102. "blocked or not completely installed.")
  103. },
  104. {
  105. CSmartCard::ccChvNotInitialized,
  106. TEXT("No CHV is initialzed.")
  107. },
  108. {
  109. CSmartCard::ccChvVerificationFailedMoreAttempts,
  110. TEXT("CHV verification was unsuccessful, at least one "
  111. "attempt remains.")
  112. },
  113. {
  114. CSmartCard::ccContradictionWithInvalidationStatus,
  115. TEXT("Contradiction with invalidation status occured.")
  116. },
  117. {
  118. CSmartCard::ccCurrentDirectoryIsNotSelected,
  119. TEXT("The current directory is not selected.")
  120. },
  121. {
  122. CSmartCard::ccDataPossiblyCorrupted,
  123. TEXT("Data possibly corrupted.")
  124. },
  125. {
  126. CSmartCard::ccDefaultLoaderNotSelected,
  127. TEXT("Cardlet is currently selected and install cannot "
  128. "run. Default loader application must be selected.")
  129. },
  130. {
  131. CSmartCard::ccDirectoryNotEmpty,
  132. TEXT("This directory still contains other files or "
  133. "directories and may not be deleted.")
  134. },
  135. {
  136. CSmartCard::ccFileAlreadyInvalidated,
  137. TEXT("File already invalidated.")
  138. },
  139. {
  140. CSmartCard::ccFileExists,
  141. TEXT("The file ID requested is already in use.")
  142. },
  143. {
  144. CSmartCard::ccFileIdExistsOrTypeInconsistentOrRecordTooLong,
  145. TEXT("Either the file ID already exists in the current "
  146. "directory, the file type is inconsisent with the "
  147. "command or the record length is too long.")
  148. },
  149. {
  150. CSmartCard::ccFileIndexDoesNotExist,
  151. TEXT("The file index passed does not exist in the current "
  152. "directory.")
  153. },
  154. {
  155. CSmartCard::ccFileInvalidated,
  156. TEXT("The command attempted to operate on an invalidated "
  157. "file.")
  158. },
  159. {
  160. CSmartCard::ccFileNotFound,
  161. TEXT("The file requested for this operation was not "
  162. "found.")
  163. },
  164. {
  165. CSmartCard::ccFileNotFoundOrNoMoreFilesInDf,
  166. TEXT("The file specified was not found or no more files in "
  167. "the current DF.")
  168. },
  169. {
  170. CSmartCard::ccFileTypeInvalid,
  171. TEXT("File type is invalid.")
  172. },
  173. {
  174. CSmartCard::ccIncorrectP1P2,
  175. TEXT("Incorrect parameter P1 or P2.")
  176. },
  177. {
  178. CSmartCard::ccIncorrectP3,
  179. TEXT("Incorrect P3.")
  180. },
  181. {
  182. CSmartCard::ccInstallCannotRun,
  183. TEXT("Cardlet is currently selected and install cannot "
  184. "run. Default loader application must be selected.")
  185. },
  186. {
  187. CSmartCard::ccInstanceIdInUse,
  188. TEXT("Instance ID is being used by another file.")
  189. },
  190. {
  191. CSmartCard::ccInsufficientSpace,
  192. TEXT("Insufficient space available.")
  193. },
  194. {
  195. CSmartCard::ccInvalidAnswerReceived,
  196. TEXT("Invalid answer received from the card.")
  197. },
  198. {
  199. CSmartCard::ccInvalidKey,
  200. TEXT("CHV verification was unsuccessful; at least one "
  201. "attempt remains.")
  202. },
  203. {
  204. CSmartCard::ccInvalidSignature,
  205. TEXT("Signature is invalid.")
  206. },
  207. {
  208. CSmartCard::ccJava,
  209. TEXT("Applet exception occured.")
  210. },
  211. {
  212. CSmartCard::ccKeyBlocked,
  213. TEXT("Key is blocked. No attempts remain.")
  214. },
  215. {
  216. CSmartCard::ccLimitReached,
  217. TEXT("Limit has been reached. Additional value would "
  218. "exceed the record's limit.")
  219. },
  220. {
  221. CSmartCard::ccMemoryProblem,
  222. TEXT("Memory problem occured.")
  223. },
  224. {
  225. CSmartCard::ccNoAccess,
  226. TEXT("Access conditions not met.")
  227. },
  228. {
  229. CSmartCard::ccNoEfSelected,
  230. TEXT("No elementary file selected.")
  231. },
  232. {
  233. CSmartCard::ccNoEfExistsOrNoChvKeyDefined,
  234. TEXT("No EF exists, or no CHV or key defined.")
  235. },
  236. {
  237. CSmartCard::ccNoFileSelected,
  238. TEXT("No elementary file selected.")
  239. },
  240. {
  241. CSmartCard::ccNoGetChallengeBefore,
  242. TEXT("A Get Challenge was not performed before this "
  243. "operation.")
  244. },
  245. {
  246. CSmartCard::ccOperationNotActivatedForApdu,
  247. TEXT("Algorithm is supported, but the operation is not "
  248. "activated for this APDU.")
  249. },
  250. {
  251. CSmartCard::ccOutOfRangeOrRecordNotFound,
  252. TEXT("Out of range or record not found.")
  253. },
  254. {
  255. CSmartCard::ccOutOfSpaceToCreateFile,
  256. TEXT("Not enough space is available to create the file.")
  257. },
  258. {
  259. CSmartCard::ccProgramFileInvalidated,
  260. TEXT("Program file invalidated.")
  261. },
  262. {
  263. CSmartCard::ccRecordInfoIncompatible,
  264. TEXT("Record information is incompatible with the file "
  265. "size.")
  266. },
  267. {
  268. CSmartCard::ccRecordLengthTooLong,
  269. TEXT("Record length is too long.")
  270. },
  271. {
  272. CSmartCard::ccRequestedAlgIdMayNotMatchKeyUse,
  273. TEXT("The requested algorithm ID may not match the key "
  274. "used.")
  275. },
  276. {
  277. CSmartCard::ccReturnedDataCorrupted,
  278. TEXT("Data return from the card is corrupted.")
  279. },
  280. {
  281. CSmartCard::ccRootDirectoryNotErasable,
  282. TEXT("It is not valid to delete the root directory.")
  283. },
  284. {
  285. CSmartCard::ccTimeOut,
  286. TEXT("Time-out occured.")
  287. },
  288. {
  289. CSmartCard::ccTooMuchDataForProMode,
  290. TEXT("Too much data for PRO mode.")
  291. },
  292. {
  293. CSmartCard::ccUnknownInstructionClass,
  294. TEXT("Unknown instruction class.")
  295. },
  296. {
  297. CSmartCard::ccUnknownInstructionCode,
  298. TEXT("Unknown instruction code.")
  299. },
  300. {
  301. CSmartCard::ccUnknownStatus,
  302. TEXT("An unknown error status was returned from the "
  303. "card.")
  304. },
  305. {
  306. CSmartCard::ccUnidentifiedTechnicalProblem,
  307. TEXT("Unidentified technical problem.")
  308. },
  309. {
  310. CSmartCard::ccUpdateImpossible,
  311. TEXT("Update is impossible.")
  312. },
  313. {
  314. CSmartCard::ccVerificationFailed,
  315. TEXT("Verification failed.")
  316. },
  317. };
  318. } // namespace
  319. namespace iop
  320. {
  321. /////////////////////////// PUBLIC /////////////////////////////////
  322. // Types
  323. // C'tors/D'tors
  324. CSmartCard::Exception::Exception(CauseCode cc,
  325. ClassByte cb,
  326. Instruction ins,
  327. StatusWord sw) throw()
  328. : scu::Exception(scu::Exception::fcSmartCard),
  329. m_cc(cc),
  330. m_cb(cb),
  331. m_ins(ins),
  332. m_sw(sw)
  333. {}
  334. CSmartCard::Exception::~Exception()
  335. {}
  336. // Operators
  337. // Operations
  338. scu::Exception *
  339. CSmartCard::Exception::Clone() const
  340. {
  341. return new CSmartCard::Exception(*this);
  342. }
  343. void
  344. CSmartCard::Exception::Raise() const
  345. {
  346. throw *this;
  347. }
  348. // Access
  349. CSmartCard::Exception::CauseCode
  350. CSmartCard::Exception::Cause() const throw()
  351. {
  352. return m_cc;
  353. }
  354. CSmartCard::ClassByte
  355. CSmartCard::Exception::Class() const throw()
  356. {
  357. return m_cb;
  358. }
  359. char const *
  360. CSmartCard::Exception::Description() const
  361. {
  362. return scu::FindDescription(Cause(), ccdt, sizeof ccdt / sizeof *ccdt);
  363. }
  364. CSmartCard::Exception::ErrorCode
  365. CSmartCard::Exception::Error() const throw()
  366. {
  367. return m_cc;
  368. }
  369. CSmartCard::Instruction
  370. CSmartCard::Exception::Ins() const throw()
  371. {
  372. return m_ins;
  373. }
  374. CSmartCard::StatusWord
  375. CSmartCard::Exception::Status() const throw()
  376. {
  377. return m_sw;
  378. }
  379. // Predicates
  380. // Static Variables
  381. /////////////////////////// PROTECTED /////////////////////////////////
  382. // C'tors/D'tors
  383. // Operators
  384. // Operations
  385. // Access
  386. // Predicates
  387. // Static Variables
  388. /////////////////////////// PRIVATE /////////////////////////////////
  389. // C'tors/D'tors
  390. // Operators
  391. // Operations
  392. // Access
  393. // Predicates
  394. // Static Variables
  395. ///////////////////// End CSmartCard::Exception ///////////////////////////
  396. CSmartCard::CSmartCard(const SCARDHANDLE hCardHandle,
  397. const char* szReaderName,
  398. const SCARDCONTEXT hContext,
  399. const DWORD dwMode)
  400. : m_hCard(hCardHandle),
  401. m_hContext(hContext),
  402. m_CurrentDirectory(),
  403. m_CurrentFile(),
  404. m_dwShareMode(dwMode),
  405. m_fSupportLogout(false),
  406. m_IOPLock(szReaderName),
  407. m_apSharedMarker(new CSharedMarker(string(szReaderName))),
  408. m_vecEvents(),
  409. m_dwEventCounter(0),
  410. m_cResponseAvailable(0),
  411. m_sCardName()
  412. {
  413. m_IOPLock.Init(this);
  414. ResetSelect();
  415. }
  416. CSmartCard::~CSmartCard()
  417. {
  418. try {
  419. while(m_vecEvents.size())
  420. {
  421. delete *(m_vecEvents.begin());
  422. m_vecEvents.erase(m_vecEvents.begin());
  423. }
  424. // Disconnect the card.
  425. if (m_hCard)
  426. SCardDisconnect(m_hCard, SCARD_LEAVE_CARD);
  427. }
  428. catch(...) {}
  429. }
  430. void CSmartCard::ReConnect()
  431. {
  432. DWORD dwProtocol;
  433. HRESULT hr = SCardReconnect(m_hCard, m_dwShareMode, SCARD_PROTOCOL_T0, SCARD_LEAVE_CARD, &dwProtocol);
  434. if (hr != SCARD_S_SUCCESS)
  435. throw scu::OsException(hr);
  436. }
  437. void CSmartCard::ResetCard()
  438. {
  439. //*
  440. CLockWrap wrap(&m_IOPLock);
  441. ResetSelect();
  442. HRESULT hResult;
  443. hResult = SCardBeginTransaction(m_hCard);
  444. // We don't apply full logic to handle error detection since
  445. // this was done in the CLockWrap constructor.
  446. if (hResult != SCARD_S_SUCCESS)
  447. throw scu::OsException(hResult);
  448. hResult = SCardEndTransaction(m_hCard,SCARD_RESET_CARD);
  449. if (hResult != SCARD_S_SUCCESS)
  450. throw scu::OsException(hResult);
  451. //*/
  452. }
  453. char const *
  454. CSmartCard::getCardName() const
  455. {
  456. return m_sCardName.c_str();
  457. }
  458. void
  459. CSmartCard::setCardName(char const *szName)
  460. {
  461. m_sCardName = string(szName);
  462. }
  463. void
  464. CSmartCard::SendCardAPDU(const BYTE bCLA, const BYTE bINS,
  465. const BYTE bP1, const BYTE bP2,
  466. const BYTE bLengthIn, const BYTE* bDataIn,
  467. const BYTE bLengthOut, BYTE* bDataOut)
  468. {
  469. CLockWrap wrap(&m_IOPLock);
  470. HRESULT hResult;
  471. DWORD dwRecvLength;
  472. BYTE bSW[2];
  473. StatusWord sw;
  474. //////////////////
  475. // Build APDU //
  476. //////////////////
  477. scu::AutoArrayPtr<BYTE> aabInput(new BYTE[5 + bLengthIn]);
  478. scu::AutoArrayPtr<BYTE> aabOutput;
  479. aabInput[0] = bCLA;
  480. aabInput[1] = bINS;
  481. aabInput[2] = bP1;
  482. aabInput[3] = bP2;
  483. aabInput[4] = bLengthIn;
  484. ///////////////////////////
  485. // Is data being sent? //
  486. ///////////////////////////
  487. if (bLengthIn)
  488. {
  489. memcpy(&aabInput[5], bDataIn, bLengthIn);
  490. dwRecvLength = 2;
  491. hResult = SCardTransmit(m_hCard, SCARD_PCI_T0,
  492. aabInput.Get(), bLengthIn + 5,
  493. NULL, bSW, &dwRecvLength);
  494. if (hResult != SCARD_S_SUCCESS)
  495. {
  496. DWORD dwState;
  497. DWORD dwProtocol;
  498. BYTE bATR[cMaxAtrLength];
  499. DWORD dwATRLen = sizeof bATR / sizeof *bATR;
  500. DWORD dwReaderNameLen = 0;
  501. HRESULT hr = SCardStatus(m_hCard, NULL,
  502. &dwReaderNameLen, &dwState,
  503. &dwProtocol, bATR,
  504. &dwATRLen);
  505. if (hr == SCARD_W_RESET_CARD)
  506. {
  507. ResetSelect();
  508. ReConnect();
  509. }
  510. else
  511. throw scu::OsException(hr);
  512. hr=SCardTransmit(m_hCard, SCARD_PCI_T0,
  513. aabInput.Get(), bLengthIn + 5, NULL,
  514. bSW, &dwRecvLength);
  515. if (hr != SCARD_S_SUCCESS)
  516. throw scu::OsException(hr);
  517. }
  518. //////////////////////////////////////////////////////////////////////////////////
  519. // Rebuffer information so registered functions may not alter data in the IOP //
  520. //////////////////////////////////////////////////////////////////////////////////
  521. scu::AutoArrayPtr<BYTE> aabSendData(new BYTE[bLengthIn + 5]);
  522. memcpy((void*)aabSendData.Get(), (void*)aabInput.Get(),
  523. bLengthIn + 5);
  524. BYTE bReceiveData[2];
  525. memcpy((void*)bReceiveData, (void*)bSW, 2);
  526. ///////////////////////////////////////
  527. // Fire event for information sent //
  528. ///////////////////////////////////////
  529. FireEvents(0, bLengthIn + 5, aabSendData.Get());
  530. FireEvents(1, 2, bReceiveData);
  531. sw = (bSW[0] * 256) + bSW[1];
  532. ProcessReturnStatus(bCLA, bINS, sw);
  533. //////////////////////////////////
  534. // Should we expect data back? //
  535. //////////////////////////////////
  536. if (bLengthOut)
  537. {
  538. if (ResponseLengthAvailable())
  539. GetResponse(bCLA, bLengthOut, bDataOut);
  540. else
  541. throw iop::Exception(iop::ccNoResponseAvailable);
  542. }
  543. }
  544. //////////////////////////////
  545. // Data is NOT being sent //
  546. //////////////////////////////
  547. else
  548. {
  549. aabInput[4] = bLengthOut;
  550. dwRecvLength = bLengthOut + 2;
  551. aabOutput = scu::AutoArrayPtr<BYTE>(new BYTE[dwRecvLength]);
  552. memset(aabOutput.Get(), 0, dwRecvLength);
  553. hResult = SCardTransmit(m_hCard, SCARD_PCI_T0,
  554. aabInput.Get(), 5, NULL,
  555. aabOutput.Get(), &dwRecvLength);
  556. /////////////////////////////////////////////
  557. // if card has been reset, then reconnect //
  558. /////////////////////////////////////////////
  559. if (hResult != SCARD_S_SUCCESS)
  560. {
  561. DWORD dwState;
  562. DWORD dwProtocol;
  563. BYTE bATR[cMaxAtrLength];
  564. DWORD dwATRLen = sizeof bATR / sizeof *bATR;
  565. DWORD dwReaderNameLen = 0;
  566. HRESULT hr = SCardStatus(m_hCard, NULL, &dwReaderNameLen, &dwState, &dwProtocol, bATR, &dwATRLen);
  567. if (hr == SCARD_W_RESET_CARD)
  568. {
  569. ResetSelect();
  570. ReConnect();
  571. }
  572. else
  573. throw scu::OsException(hResult);
  574. hr=SCardTransmit(m_hCard, SCARD_PCI_T0,
  575. aabInput.Get(), 5, NULL,
  576. aabOutput.Get(), &dwRecvLength);
  577. if (hr != SCARD_S_SUCCESS)
  578. throw scu::OsException(hResult);
  579. }
  580. //////////////////////////////////////////////////////////////////////////////////
  581. // Rebuffer information so registered functions may not alter data in the IOP //
  582. //////////////////////////////////////////////////////////////////////////////////
  583. BYTE bSendData[5];
  584. memcpy((void*)bSendData, (void*)aabInput.Get(), 5);
  585. scu::AutoArrayPtr<BYTE> aabReceiveData(new BYTE[dwRecvLength/*bLengthOut + 2*/]);
  586. memcpy((void*)aabReceiveData.Get(), (void*)aabOutput.Get(),
  587. dwRecvLength/*bLengthOut + 2*/);
  588. ////////////////////////////////////////////////////
  589. // Fire event for information sent and received //
  590. ////////////////////////////////////////////////////
  591. FireEvents(0, 5, bSendData);
  592. FireEvents(1, dwRecvLength/*bLengthOut + 2*/,
  593. aabReceiveData.Get());
  594. sw = (aabOutput[dwRecvLength - 2] * 256) +
  595. aabOutput[dwRecvLength - 1];
  596. ProcessReturnStatus(bCLA, bINS, sw);
  597. memcpy(bDataOut, aabOutput.Get(), bLengthOut);
  598. }
  599. }
  600. void CSmartCard::RequireSelect()
  601. {
  602. if ((m_CurrentDirectory.IsEmpty()) || (m_CurrentFile.IsEmpty()))
  603. throw iop::Exception(iop::ccNoFileSelected);
  604. }
  605. void
  606. CSmartCard::GetResponse(ClassByte cb,
  607. BYTE bDataLength,
  608. BYTE *bDataOut)
  609. {
  610. // TO DO: lock redundant??? Wouldn't GetResponse always be called
  611. // by a routine that establishes a lock?
  612. CLockWrap wrap(&m_IOPLock);
  613. if (0 == ResponseLengthAvailable())
  614. throw iop::Exception(iop::ccNoResponseAvailable);
  615. struct Command // T=0 command bytes
  616. {
  617. ClassByte m_cb;
  618. Instruction m_ins;
  619. BYTE m_bP1;
  620. BYTE m_bP2;
  621. BYTE m_bP3;
  622. } cmnd = { cb, insGetResponse, 0x00, 0x00, bDataLength };
  623. DWORD dwRecvLength = bDataLength + sizeof StatusWord;
  624. BYTE bOutput[cMaxGetResponseLength];
  625. memset(bOutput, 0, dwRecvLength);
  626. HRESULT hr = SCardTransmit(m_hCard, SCARD_PCI_T0,
  627. reinterpret_cast<LPCBYTE>(&cmnd),
  628. sizeof cmnd, NULL, bOutput,
  629. &dwRecvLength);
  630. if (hr != SCARD_S_SUCCESS)
  631. throw scu::OsException(hr);
  632. //////////////////////////////////////////////////////////////////////////////////
  633. // Rebuffer information so registered functions may not alter data in the IOP //
  634. //////////////////////////////////////////////////////////////////////////////////
  635. BYTE bSendData[sizeof cmnd];
  636. memcpy(static_cast<void *>(bSendData),
  637. static_cast<void const *>(&cmnd), sizeof cmnd);
  638. scu::AutoArrayPtr<BYTE> aabReceiveData(new BYTE[dwRecvLength/*bDataLength + 2*/]);
  639. memcpy((void*)aabReceiveData.Get(), (void*)bOutput, dwRecvLength/*bDataLength + 2*/);
  640. ////////////////////////////////////////////////////
  641. // Fire event for information sent and received //
  642. ////////////////////////////////////////////////////
  643. FireEvents(0, sizeof bSendData, bSendData);
  644. FireEvents(1, dwRecvLength/*bDataLength + 2*/, aabReceiveData.Get());
  645. //////////////////////////////////////////////////////////
  646. // Set card's status code and map to IOP status codes //
  647. //////////////////////////////////////////////////////////
  648. StatusWord sw = (bOutput[dwRecvLength - sizeof StatusWord]*256) +
  649. bOutput[dwRecvLength - (sizeof StatusWord - 1)];
  650. ProcessReturnStatus(cb, insGetResponse, sw);
  651. memcpy(bDataOut, bOutput, bDataLength);
  652. }
  653. void
  654. CSmartCard::ReadBinary(const WORD wOffset,
  655. const WORD wDataLength,
  656. BYTE* bData)
  657. {
  658. CLockWrap wrap(&m_IOPLock);
  659. TransferData(wOffset, wDataLength, bData, *this,
  660. &CSmartCard::DoReadBlock, cMaxRwDataBlock);
  661. }
  662. void
  663. CSmartCard::WriteBinary(const WORD wOffset,
  664. const WORD wDataLength,
  665. const BYTE* bData)
  666. {
  667. CLockWrap wrap(&m_IOPLock);
  668. m_apSharedMarker->UpdateMarker(CMarker::WriteMarker);
  669. TransferData(wOffset, wDataLength, bData, *this,
  670. &CSmartCard::DoWriteBlock, cMaxRwDataBlock);
  671. }
  672. void CSmartCard::ResetSelect()
  673. {
  674. m_CurrentDirectory.Clear();
  675. m_CurrentFile.Clear();
  676. }
  677. void
  678. CSmartCard::GetCurrentDir(char* CurrentDirectory)
  679. {
  680. if (!m_CurrentDirectory.IsEmpty())
  681. strcpy(CurrentDirectory,m_CurrentDirectory.GetStringPath().c_str());
  682. else
  683. throw iop::Exception(ccInvalidParameter);
  684. }
  685. void
  686. CSmartCard::GetCurrentFile(char* CurrentFile)
  687. {
  688. if (!m_CurrentFile.IsEmpty())
  689. strcpy(CurrentFile,m_CurrentFile.GetStringPath().c_str());
  690. else
  691. throw iop::Exception(ccInvalidParameter);
  692. }
  693. DWORD CSmartCard::RegisterEvent(void (*FireEvent)(void *pToCard, int
  694. iEventCode, DWORD
  695. dwLen, BYTE* bData),
  696. void *pToCard)
  697. {
  698. EventInfo *Event = new EventInfo;
  699. Event->dwHandle = ++m_dwEventCounter;
  700. Event->FireEvent = FireEvent;
  701. Event->pToCard = pToCard;
  702. m_vecEvents.push_back(Event);
  703. return m_dwEventCounter;
  704. }
  705. bool CSmartCard::UnregisterEvent(DWORD dwHandle)
  706. {
  707. vector<EventInfo*>::iterator iter;
  708. for(iter = m_vecEvents.begin(); iter != m_vecEvents.end(); iter++)
  709. {
  710. if ((*iter)->dwHandle == dwHandle)
  711. break;
  712. }
  713. if (iter == m_vecEvents.end())
  714. return false;
  715. delete (*iter);
  716. m_vecEvents.erase(iter);
  717. return true;
  718. }
  719. bool CSmartCard::HasProperty(WORD wPropNumber)
  720. {
  721. if (wPropNumber > 512)
  722. return false;
  723. ////////////////////////////////////
  724. // Open path to registered keys //
  725. ////////////////////////////////////
  726. HKEY hkCardKey;
  727. HKEY hkTestKey;
  728. char szCardPath[] = "SOFTWARE\\Schlumberger\\Smart Cards and Terminals\\Smart Cards";
  729. RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCardPath, NULL, KEY_READ, &hkCardKey);
  730. //////////////////////////////////////////////
  731. // Enumerate subkeys to find an ATR match //
  732. //////////////////////////////////////////////
  733. FILETIME fileTime;
  734. char szATR[] = "ATR";
  735. char szMask[] = "ATR Mask";
  736. char szProperties[] = "Properties";
  737. char sBuffer[1024];
  738. BYTE bATR[cMaxAtrLength];
  739. BYTE bATRtest[cMaxAtrLength];
  740. BYTE bMask[cMaxAtrLength];
  741. BYTE bProperties[512];
  742. BYTE bATRLength = sizeof bATR / sizeof *bATR;
  743. DWORD dwBufferSize = sizeof(sBuffer);
  744. DWORD dwATRSize = sizeof bATR / sizeof *bATR;
  745. DWORD dwMaskSize = sizeof bMask / sizeof *bMask;
  746. DWORD dwPropSize = sizeof(bProperties);
  747. DWORD index = 0;
  748. getATR(bATR, bATRLength);
  749. LONG iRetVal = RegEnumKeyEx(hkCardKey, index, sBuffer, &dwBufferSize, NULL, NULL, NULL, &fileTime);
  750. while (iRetVal == ERROR_SUCCESS)
  751. {
  752. RegOpenKeyEx(hkCardKey, sBuffer, NULL, KEY_READ, &hkTestKey);
  753. RegQueryValueEx(hkTestKey, szATR, NULL, NULL, bATRtest, &dwATRSize);
  754. RegQueryValueEx(hkTestKey, szMask, NULL, NULL, bMask, &dwMaskSize);
  755. if (dwATRSize == bATRLength)
  756. {
  757. scu::AutoArrayPtr<BYTE> aabMaskedATR(new BYTE[dwATRSize]);
  758. for (DWORD count = 0; count < dwATRSize; count++)
  759. aabMaskedATR[count] = bATR[count] & bMask[count];
  760. if (!memcmp(aabMaskedATR.Get(), bATRtest, dwATRSize))
  761. break;
  762. }
  763. index++;
  764. dwBufferSize = sizeof(sBuffer);
  765. dwATRSize = cMaxAtrLength;
  766. dwMaskSize = cMaxAtrLength;
  767. RegCloseKey(hkTestKey);
  768. iRetVal = RegEnumKeyEx(hkCardKey, index, sBuffer, &dwBufferSize, NULL, NULL, NULL, &fileTime);
  769. }
  770. // if loop was broken, iRetVal is still ERROR_SUCCESS, and type holds correct card to use
  771. if (iRetVal == ERROR_SUCCESS)
  772. {
  773. RegQueryValueEx(hkTestKey, szProperties, NULL, NULL, bProperties, &dwPropSize);
  774. return (bProperties[(wPropNumber - 1) / 8] & (1 << ((wPropNumber - 1) % 8))) ? true : false;
  775. }
  776. // loop wasn't broken, i.e., ATR not found
  777. else
  778. return false;
  779. }
  780. void
  781. CSmartCard::getATR(BYTE* bATR, BYTE& iATRLength)
  782. {
  783. DWORD dwProtocol;
  784. LPDWORD pcchReaderLen = 0;
  785. DWORD dwState;
  786. BYTE bMyATR[cMaxAtrLength];
  787. DWORD dwAtrLen = sizeof bMyATR / sizeof *bMyATR;
  788. HRESULT hr = SCardStatus(m_hCard, NULL, pcchReaderLen, &dwState, &dwProtocol, bMyATR, &dwAtrLen);
  789. if (hr == SCARD_W_RESET_CARD)
  790. {
  791. ResetSelect();
  792. ReConnect();
  793. hr = SCardStatus(m_hCard, NULL, pcchReaderLen, &dwState, &dwProtocol, bMyATR, &dwAtrLen);
  794. }
  795. if (hr != SCARD_S_SUCCESS)
  796. throw scu::OsException(hr);
  797. if ((BYTE)dwAtrLen > iATRLength)
  798. throw iop::Exception(ccInvalidParameter);
  799. memcpy(bATR, bMyATR, dwAtrLen);
  800. iATRLength = (BYTE)dwAtrLen;
  801. }
  802. void CSmartCard::FireEvents(int iEventCode, DWORD dwLength, BYTE *bsData)
  803. {
  804. vector<EventInfo*>::iterator iter;
  805. for (iter = m_vecEvents.begin(); iter != m_vecEvents.end(); iter++)
  806. {
  807. EventInfo* pEvent = *iter;
  808. pEvent->FireEvent(pEvent->pToCard, iEventCode, dwLength, bsData);
  809. }
  810. }
  811. BYTE CSmartCard::FormatPath(char *szOutputPath, const char *szInputPath)
  812. {
  813. bool fResult = true;
  814. BYTE bIndex = 0;
  815. BYTE bFileCount = 1; // always allocate memory for at least 1 token
  816. BYTE bFileIDLength = 0;
  817. BYTE bPathLength = strlen(szInputPath);
  818. WORD wFileHexID;
  819. char szPad[] = "0";
  820. char *cTestChar;
  821. char *szHexID;
  822. //////////////////////////////////////////////
  823. // Count number of tokens in desired path //
  824. //////////////////////////////////////////////
  825. for (bIndex = 0; bIndex < bPathLength - 1; bIndex++)
  826. {
  827. if (szInputPath[bIndex] == '/' && szInputPath[bIndex + 1] != '/')
  828. bFileCount++;
  829. }
  830. // Check path size
  831. if (bFileCount * 5 + 1 > cMaxPathLength)
  832. throw iop::Exception(iop::ccFilePathTooLong);
  833. scu::AutoArrayPtr<char> aaszPathIn(new char[bPathLength + 1]);
  834. memset((void*)aaszPathIn.Get(), 0, bPathLength + 1);
  835. memset((void*)szOutputPath, 0, bFileCount * 5 + 1);
  836. strcpy(aaszPathIn.Get(), szInputPath);
  837. iop::CauseCode cc;
  838. szHexID = strtok(aaszPathIn.Get(), "/");
  839. for (bFileCount = 0; szHexID; bFileCount++, szHexID = strtok(NULL, "/"))
  840. {
  841. /////////////////////////////////////////////////////////
  842. // File ID is too large -- greater than 4 characters //
  843. /////////////////////////////////////////////////////////
  844. if (strlen(szHexID) > 4)
  845. {
  846. fResult = false;
  847. cc = iop::ccFileIdTooLarge;
  848. break;
  849. }
  850. wFileHexID = (WORD)strtoul(szHexID, &cTestChar, 16);
  851. /////////////////////////////////////////////////////
  852. // File ID was not in hexadecimal representation //
  853. /////////////////////////////////////////////////////
  854. if (*cTestChar != NULL)
  855. {
  856. fResult = false;
  857. cc = iop::ccFileIdNotHex;
  858. break;
  859. }
  860. szOutputPath[bFileCount * 5] = '/';
  861. /////////////////////////////////////////////////////////////////
  862. // Pad file ID and put formatted file ID into formatted path //
  863. /////////////////////////////////////////////////////////////////
  864. for (bFileIDLength = strlen(szHexID); bFileIDLength < 4; bFileIDLength++)
  865. strcat((szOutputPath + (bFileCount * 5) + (4 - bFileIDLength)), szPad);
  866. strcpy((szOutputPath + (bFileCount * 5) + (5 - strlen(szHexID))), szHexID);
  867. }
  868. ///////////////////////////////////////////
  869. // If file ID formatting fails, throw //
  870. ///////////////////////////////////////////
  871. if (!fResult)
  872. {
  873. // delete [] szOutputPath; // Can not mean to delete this???? HB.
  874. throw iop::Exception(cc);
  875. }
  876. _strupr(szOutputPath);
  877. return bFileCount;
  878. }
  879. CMarker CSmartCard::Marker(CMarker::MarkerType Type)
  880. {
  881. return m_apSharedMarker->Marker(Type);
  882. }
  883. void
  884. CSmartCard::GetState(DWORD &rdwState,
  885. DWORD &rdwProtocol)
  886. {
  887. BYTE bATR[cMaxAtrLength];
  888. DWORD dwATRLen = sizeof bATR / sizeof *bATR;
  889. DWORD dwReaderNameLen = 0;
  890. HRESULT hr = SCardStatus(m_hCard, 0, &dwReaderNameLen, &rdwState,
  891. &rdwProtocol, bATR, &dwATRLen);
  892. if (SCARD_W_RESET_CARD == hr)
  893. {
  894. ResetSelect();
  895. ReConnect();
  896. // try again...
  897. hr = SCardStatus(m_hCard, 0, &dwReaderNameLen, &rdwState,
  898. &rdwProtocol, bATR, &dwATRLen);
  899. }
  900. if (SCARD_S_SUCCESS != hr)
  901. throw scu::OsException(hr);
  902. }
  903. void
  904. CSmartCard::DefaultDispatchError(ClassByte cb,
  905. Instruction ins,
  906. StatusWord sw) const
  907. {
  908. CauseCode cc;
  909. bool fDoThrow = true;
  910. switch (sw)
  911. {
  912. case 0x6283:
  913. cc = ccFileInvalidated;
  914. break;
  915. case 0x6581:
  916. cc = ccMemoryProblem;
  917. break;
  918. case 0x6982:
  919. cc = ccNoAccess;
  920. break;
  921. case 0x6983:
  922. cc = ccKeyBlocked;
  923. break;
  924. case 0x6A80:
  925. cc = ccFileTypeInvalid;
  926. break;
  927. case 0x6A82:
  928. cc = ccFileNotFound;
  929. break;
  930. case 0x6A84:
  931. cc = ccInsufficientSpace;
  932. break;
  933. case 0x6B00:
  934. cc = ccIncorrectP1P2;
  935. break;
  936. case 0x6D00:
  937. cc = ccUnknownInstructionCode;
  938. break;
  939. case 0x6E00:
  940. cc = ccUnknownInstructionClass;
  941. break;
  942. case 0x6F00:
  943. cc = ccUnidentifiedTechnicalProblem;
  944. break;
  945. case 0x90FF:
  946. cc = ccTimeOut;
  947. break;
  948. case 0x9002:
  949. cc = ccInvalidAnswerReceived;
  950. break;
  951. default:
  952. if (0x67 == HIBYTE(sw))
  953. cc = ccIncorrectP3;
  954. else
  955. cc = ccUnknownStatus;
  956. break;
  957. }
  958. if (fDoThrow)
  959. throw Exception(cc, cb, ins, sw);
  960. }
  961. void
  962. CSmartCard::DispatchError(ClassByte cb,
  963. Instruction ins,
  964. StatusWord sw) const
  965. {
  966. CauseCode cc;
  967. bool fDoThrow = true;
  968. switch (ins)
  969. {
  970. case insGetResponse:
  971. switch (sw)
  972. {
  973. case 0x6281:
  974. cc = ccReturnedDataCorrupted;
  975. break;
  976. case 0x6A86:
  977. cc = ccIncorrectP1P2;
  978. break;
  979. default:
  980. if (0x6C == HIBYTE(sw))
  981. cc = ccIncorrectP3;
  982. else
  983. fDoThrow = false;
  984. break;
  985. }
  986. default:
  987. fDoThrow = false;
  988. break;
  989. }
  990. if (fDoThrow)
  991. throw Exception(cc, cb, ins, sw);
  992. DefaultDispatchError(cb, ins, sw);
  993. }
  994. BYTE
  995. CSmartCard::ResponseLengthAvailable() const
  996. {
  997. return m_cResponseAvailable;
  998. }
  999. void
  1000. CSmartCard::ResponseLengthAvailable(BYTE cResponseLength)
  1001. {
  1002. m_cResponseAvailable = cResponseLength;
  1003. }
  1004. void
  1005. CSmartCard::WriteBlock(WORD wOffset,
  1006. BYTE const *pbBuffer,
  1007. BYTE cLength)
  1008. {
  1009. DoWriteBlock(wOffset, pbBuffer, cLength);
  1010. m_apSharedMarker->UpdateMarker(CMarker::WriteMarker);
  1011. }
  1012. void
  1013. CSmartCard::ProcessReturnStatus(ClassByte cb,
  1014. Instruction ins,
  1015. StatusWord sw)
  1016. {
  1017. ResponseLengthAvailable(0);
  1018. if (swSuccess != sw)
  1019. {
  1020. if (0x61 == HIBYTE(sw))
  1021. ResponseLengthAvailable(LOBYTE(sw));
  1022. else
  1023. DispatchError(cb, ins, sw);
  1024. }
  1025. }
  1026. } // namespace iop