Leaked source code of windows server 2003
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.

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