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.

1521 lines
42 KiB

  1. // AccessCard.cpp: implementation of the CAccessCard class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "NoWarning.h"
  5. #include <scuArrayP.h>
  6. #include "AccessCard.h"
  7. #include <stdio.h>
  8. #include "iopExc.h"
  9. #include "LockWrap.h"
  10. #include "FilePath.h"
  11. using namespace std;
  12. using namespace iop;
  13. namespace
  14. {
  15. BYTE
  16. AsPrivateAlgId(KeyType kt)
  17. {
  18. BYTE bAlgId = 0;
  19. switch (kt)
  20. {
  21. case ktRSA512:
  22. bAlgId = 0xC4;
  23. break;
  24. case ktRSA768:
  25. bAlgId = 0xC6;
  26. break;
  27. case ktRSA1024:
  28. bAlgId = 0xC8;
  29. break;
  30. case ktDES:
  31. bAlgId = 0x00;
  32. break;
  33. default:
  34. throw Exception(ccInvalidParameter);
  35. break;
  36. }
  37. return bAlgId;
  38. }
  39. } // namespace
  40. //////////////////////////////////////////////////////////////////////
  41. // Construction/Destruction
  42. //////////////////////////////////////////////////////////////////////
  43. CAccessCard::CAccessCard(const SCARDHANDLE hCardHandle, const char* szReaderName,
  44. const SCARDCONTEXT pContext, const DWORD dwMode)
  45. : CSmartCard(hCardHandle, szReaderName, pContext, dwMode)
  46. {
  47. if (ValidClassByte(0xF0))
  48. m_bClassByte = 0xF0;
  49. else
  50. if (ValidClassByte(0x00))
  51. m_bClassByte = 0x00;
  52. else // Not an access card!
  53. throw iop::Exception(iop::ccUnknownCard);
  54. m_fSupportLogout = SupportLogout();
  55. }
  56. CAccessCard::~CAccessCard()
  57. {
  58. }
  59. void
  60. CAccessCard::GetChallenge(const DWORD dwNumberLength, BYTE* bRandomNumber)
  61. {
  62. CLockWrap wrap(&m_IOPLock);
  63. const BYTE bMinLen = 4, bMaxLen = 64; // Max 64 due to bug in old cards.
  64. if(dwNumberLength < bMinLen)
  65. {
  66. BYTE bBuf[bMinLen];
  67. SendCardAPDU(m_bClassByte, 0x84, 0x00, 0x00, 0, NULL,
  68. bMinLen, bBuf);
  69. memcpy(bRandomNumber,bBuf,dwNumberLength);
  70. }
  71. else
  72. {
  73. DWORD dwRamainingBytes = dwNumberLength;
  74. BYTE *bpBuf = bRandomNumber;
  75. while(dwRamainingBytes)
  76. {
  77. BYTE bNumGet = (dwRamainingBytes > bMaxLen) ? bMaxLen : dwRamainingBytes;
  78. SendCardAPDU(m_bClassByte, 0x84, 0x00, 0x00, 0, NULL,
  79. bNumGet, bpBuf);
  80. bpBuf += bNumGet;
  81. dwRamainingBytes -= bNumGet;
  82. }
  83. }
  84. }
  85. void
  86. CAccessCard::DeleteFile(const WORD wFileID)
  87. {
  88. CLockWrap wrap(&m_IOPLock);
  89. BYTE bDataIn[2];
  90. bDataIn[0] = (BYTE)(MSB(wFileID));
  91. bDataIn[1] = (BYTE)(LSB(wFileID));
  92. SendCardAPDU(m_bClassByte, insDeleteFile, 0x00, 0x00, 0x02, bDataIn,
  93. 0, NULL);
  94. }
  95. void
  96. CAccessCard::Directory(const BYTE bFile_Nb, FILE_HEADER* pMyfile)
  97. {
  98. CLockWrap wrap(&m_IOPLock);
  99. RequireSelect();
  100. BYTE bDataOut[40];
  101. memset(bDataOut, 0, 40);
  102. SendCardAPDU(m_bClassByte, 0xA8, 0x00, bFile_Nb, 0, NULL, 40, bDataOut);
  103. switch(bDataOut[6])
  104. {
  105. case 0x01: // Root directory file
  106. case 0x02: // Other directory file or Instance file
  107. {
  108. pMyfile->file_id = (WORD)(bDataOut[4] * 256 + bDataOut[5]);
  109. pMyfile->file_size = (WORD)(bDataOut[2] * 256 + bDataOut[3]);
  110. pMyfile->nb_file = bDataOut[15];
  111. pMyfile->nb_sub_dir = bDataOut[14];
  112. pMyfile->file_status = 0x01;
  113. if (bDataOut[9] == 0)
  114. {
  115. memset((void*)(pMyfile->applicationID), 0x00, 16);
  116. pMyfile->file_type = directory;
  117. }
  118. else
  119. if (bDataOut[9] == 0x01 || bDataOut[9] == 0x02 ||
  120. bDataOut[9] == 0x03)
  121. {
  122. /////////////////////////////////////////////////////////////////
  123. // Instance files contain one "hidden" file for program data //
  124. // that should not be shown to the users //
  125. /////////////////////////////////////////////////////////////////
  126. pMyfile->nb_file--;
  127. pMyfile->file_type = Instance;
  128. pMyfile->AIDLength = bDataOut[23];
  129. memcpy((void*)(pMyfile->applicationID), (void*)(&bDataOut[24]), pMyfile->AIDLength);
  130. /////////////////////////////////////////////////////////////////////
  131. // Set flags in file status to discriminate applets/applications //
  132. /////////////////////////////////////////////////////////////////////
  133. switch(bDataOut[9])
  134. {
  135. case 0x01: pMyfile->file_status |= (1 << 5); // Applet
  136. break;
  137. case 0x02: pMyfile->file_status |= (1 << 4); // Application
  138. break;
  139. case 0x03: pMyfile->file_status |= (3 << 4); // Both
  140. break;
  141. }
  142. ////////////////////////////////////////////////
  143. // Set flags in file status to discriminate //
  144. // created/installed/registered instances //
  145. ////////////////////////////////////////////////
  146. switch(bDataOut[10])
  147. {
  148. case 0x01: pMyfile->file_status |= (1 << 1); // Created
  149. break;
  150. case 0x02: pMyfile->file_status |= (1 << 2); // Installed
  151. break;
  152. case 0x03: pMyfile->file_status |= (1 << 3); // Registered
  153. break;
  154. }
  155. }
  156. ///////////////////////////////////////////////
  157. // guard against a bad Instance file //
  158. // created without an AID for file control //
  159. ///////////////////////////////////////////////
  160. else
  161. {
  162. pMyfile->AIDLength = 0x00;
  163. memset((void*)(pMyfile->applicationID), 0x00, 16);
  164. throw iop::Exception(iop::ccBadInstanceFile);
  165. }
  166. ///////////////////////////////
  167. // Select file and get ACL //
  168. ///////////////////////////////
  169. Select(pMyfile->file_id);
  170. SendCardAPDU(m_bClassByte, insGetACL, 0x00, 0x00, 0,
  171. NULL, 0x08, bDataOut);
  172. memcpy((void*)(pMyfile->access_cond), (void*)(bDataOut),8);
  173. /////////////////////////////////
  174. // Reselect parent directory //
  175. /////////////////////////////////
  176. Select(m_CurrentDirectory.Tail().GetShortID());
  177. break;
  178. } // end case directory or Instance file
  179. case 0x04: // all other file types
  180. {
  181. pMyfile->file_id = (WORD)(bDataOut[4] * 256 + bDataOut[5]);
  182. pMyfile->file_size = (WORD)(bDataOut[2] * 256 + bDataOut[3]);
  183. pMyfile->nb_file = 0x00;
  184. pMyfile->nb_sub_dir = 0x00;
  185. pMyfile->file_status = bDataOut[11];
  186. switch(bDataOut[13])
  187. {
  188. case 0x00: pMyfile->file_type = Binary_File;
  189. break;
  190. case 0x01: pMyfile->file_type = Fixed_Record_File;
  191. break;
  192. case 0x02: pMyfile->file_type = Variable_Record_File;
  193. break;
  194. case 0x03: pMyfile->file_type = Cyclic_File;
  195. break;
  196. case 0x04: pMyfile->file_type = Program_File;
  197. break;
  198. ///////////////////////////////////////////////////////////////////////
  199. // if GetResponse(...) is successful but bad file type is returned //
  200. ///////////////////////////////////////////////////////////////////////
  201. default: pMyfile->file_type = Unknown;
  202. throw iop::Exception(iop::ccFileTypeUnknown);
  203. }
  204. if (pMyfile->file_type == Cyclic_File ||
  205. pMyfile->file_type == Fixed_Record_File)
  206. {
  207. pMyfile->nb_sub_dir = bDataOut[14];
  208. pMyfile->nb_file = (pMyfile->nb_sub_dir)
  209. ? pMyfile->file_size / pMyfile->nb_sub_dir
  210. : 0;
  211. }
  212. ///////////////////////////////
  213. // Select file and get ACL //
  214. ///////////////////////////////
  215. if (pMyfile->file_id != 0xFFFF)
  216. {
  217. Select(pMyfile->file_id);
  218. SendCardAPDU(m_bClassByte, insGetACL, 0x00, 0x00, 0,
  219. NULL, 0x08, bDataOut);
  220. memcpy((void*)(pMyfile->access_cond), (void*)(bDataOut), 8);
  221. memset((void*)(pMyfile->applicationID), 0x00, 16);
  222. /////////////////////////////////
  223. // Reselect parent directory //
  224. /////////////////////////////////
  225. Select(m_CurrentDirectory.Tail().GetShortID());
  226. }
  227. break;
  228. } // end case non-Directory/Instance files
  229. default:
  230. ///////////////////////////////////////////////////////////////////////////
  231. // if GetResponse(...) is successful but bad file category is returned //
  232. ///////////////////////////////////////////////////////////////////////////
  233. throw iop::Exception(iop::ccBadFileCategory);
  234. } // end switch
  235. }
  236. void
  237. CAccessCard::ExternalAuth(const KeyType kt, const BYTE bKeyNb,
  238. const BYTE bDataLength, const BYTE* bData)
  239. {
  240. CLockWrap wrap(&m_IOPLock);
  241. BYTE bAlgo_ID = AsPrivateAlgId(kt);
  242. SendCardAPDU(m_bClassByte, insExternalAuth, bAlgo_ID,
  243. bKeyNb, bDataLength, bData, 0, NULL);
  244. }
  245. void
  246. CAccessCard::InternalAuth(const KeyType kt, const BYTE bKeyNb,
  247. const BYTE bDataLength, const BYTE*
  248. bDataIn, BYTE* bDataOut)
  249. {
  250. CLockWrap wrap(&m_IOPLock);
  251. ////////////////////////////////////////////////////////////////////////////
  252. // The following checks to make sure the internal Auth is not being //
  253. // used for DES, or for an RSA key operation of greater than 128 bytes. //
  254. ////////////////////////////////////////////////////////////////////////////
  255. BYTE bAlgo_ID = AsPrivateAlgId(kt);
  256. if (((bAlgo_ID != 0xC4) && (bAlgo_ID != 0xC6) &&
  257. (bAlgo_ID != 0xC8)) ||
  258. (bDataLength > 0x80))
  259. throw iop::Exception(iop::ccAlgorithmIdNotSupported);
  260. /////////////////////////////////////////////////////////////////////////
  261. // Need to reverse the byte order of the input data (big endian card) //
  262. /////////////////////////////////////////////////////////////////////////
  263. if (cMaxApduLength < bDataLength)
  264. throw iop::Exception(iop::ccInvalidParameter);
  265. BYTE bReversedData[cMaxApduLength];
  266. for (BYTE bIndex = 0; bIndex < bDataLength; bIndex++)
  267. bReversedData[bIndex] = bDataIn[bDataLength - 1 - bIndex];
  268. SendCardAPDU(m_bClassByte, insInternalAuth,
  269. bAlgo_ID, bKeyNb, bDataLength,
  270. bReversedData, 0, NULL);
  271. GetResponse(m_bClassByte, bDataLength, bReversedData);
  272. //////////////////////////////////////////////////////
  273. // Need to reverse the byte order of output data. //
  274. //////////////////////////////////////////////////////
  275. for (bIndex = 0; bIndex < bDataLength; bIndex++)
  276. bDataOut[bIndex] = bReversedData[bDataLength - 1 - bIndex];
  277. }
  278. void
  279. CAccessCard::ReadRecord(const BYTE bRecNum, const BYTE bMode,
  280. const BYTE bDataLen, BYTE *bData)
  281. {
  282. CLockWrap wrap(&m_IOPLock);
  283. SendCardAPDU(m_bClassByte, 0xB2, bRecNum, bMode, 0, NULL,
  284. bDataLen, bData);
  285. }
  286. void
  287. CAccessCard::UpdateRecord(const BYTE bRecNum, const BYTE bMode,
  288. const BYTE bDataLen, BYTE *bData)
  289. {
  290. CLockWrap wrap(&m_IOPLock);
  291. SendCardAPDU(m_bClassByte, 0xDC, bRecNum, bMode, bDataLen, bData, 0, NULL);
  292. }
  293. void
  294. CAccessCard::VerifyCHV(const BYTE bCHVNumber, const BYTE* bCHV)
  295. {
  296. CLockWrap wrap(&m_IOPLock);
  297. SendCardAPDU(m_bClassByte, insVerifyChv, 0x00, bCHVNumber, 0x08,
  298. bCHV, 0, NULL);
  299. }
  300. void
  301. CAccessCard::VerifyKey(const BYTE bKeyNumber, const BYTE bKeyLength,
  302. const BYTE* bKey)
  303. {
  304. CLockWrap wrap(&m_IOPLock);
  305. SendCardAPDU(m_bClassByte, 0x2A, 0x00, bKeyNumber, bKeyLength,
  306. bKey, 0, NULL);
  307. }
  308. void
  309. CAccessCard::SelectCardlet(const BYTE *bAID, const BYTE bAIDLen)
  310. {
  311. CLockWrap wrap(&m_IOPLock);
  312. SendCardAPDU(m_bClassByte, 0xA4, 0x04, 0x00, bAIDLen, bAID, 0, NULL);
  313. }
  314. void
  315. CAccessCard::SelectLoader()
  316. {
  317. CLockWrap wrap(&m_IOPLock);
  318. SendCardAPDU(m_bClassByte, 0xA4, 0x04, 0x00, 0x00, NULL, 0, NULL);
  319. }
  320. void
  321. CAccessCard::DeleteApplet()
  322. {
  323. CLockWrap wrap(&m_IOPLock);
  324. SendCardAPDU(m_bClassByte, 0x08, 0x02, 0x00, 0x00, NULL, 0, NULL);
  325. }
  326. void
  327. CAccessCard::ResetInstance()
  328. {
  329. CLockWrap wrap(&m_IOPLock);
  330. SendCardAPDU(m_bClassByte, 0x08, 0x03, 0x00, 0x00,
  331. NULL, 0, NULL);
  332. }
  333. void
  334. CAccessCard::SetCurrentAsLoader()
  335. {
  336. CLockWrap wrap(&m_IOPLock);
  337. SendCardAPDU(m_bClassByte, 0x08, 0x04, 0x00, 0x00, NULL, 0, NULL);
  338. }
  339. void
  340. CAccessCard::SetDefaultAsLoader()
  341. {
  342. CLockWrap wrap(&m_IOPLock);
  343. SendCardAPDU(m_bClassByte, 0x08, 0x05, 0x00, 0x00, NULL, 0, NULL);
  344. }
  345. void
  346. CAccessCard::BlockApplet()
  347. {
  348. CLockWrap wrap(&m_IOPLock);
  349. SendCardAPDU(m_bClassByte, 0x08, 0x07, 0x00, 0x00, NULL, 0, NULL);
  350. }
  351. void
  352. CAccessCard::ValidateProgram(const BYTE *bSig, const BYTE bSigLength)
  353. {
  354. CLockWrap wrap(&m_IOPLock);
  355. SendCardAPDU(m_bClassByte, 0x0A, 0x01, 0x00, bSigLength, bSig, 0, NULL);
  356. }
  357. void
  358. CAccessCard::ResetProgram()
  359. {
  360. CLockWrap wrap(&m_IOPLock);
  361. SendCardAPDU(m_bClassByte, 0x0A, 0x02, 0x00, 0x00, NULL, 0, NULL);
  362. }
  363. void
  364. CAccessCard::VerifyTransportKey(const BYTE *bKey)
  365. {
  366. VerifyKey(0, 8, bKey);
  367. }
  368. void
  369. CAccessCard::ExecuteMain()
  370. {
  371. CLockWrap wrap(&m_IOPLock);
  372. SendCardAPDU(m_bClassByte, insExecuteMethod, 0x02, 0x00, 0x00,
  373. NULL, 0, NULL);
  374. }
  375. void
  376. CAccessCard::ExecuteInstall(const BYTE *bBlock, const BYTE bLen)
  377. {
  378. CLockWrap wrap(&m_IOPLock);
  379. SendCardAPDU(m_bClassByte, insExecuteMethod, 0x13, 0x00, bLen,
  380. bBlock, 0, NULL);
  381. }
  382. void
  383. CAccessCard::SelectParent()
  384. {
  385. CLockWrap wrap(&m_IOPLock);
  386. RequireSelect();
  387. ///////////////////////////////////////////////////
  388. // If current directory is root, reselect root //
  389. ///////////////////////////////////////////////////
  390. if (m_CurrentDirectory.NumComponents() == 1)
  391. Select(0x3F00);
  392. else
  393. {
  394. SendCardAPDU(m_bClassByte, 0xA4, 0x03, 0x00, 0, NULL, 0, NULL);
  395. m_CurrentDirectory.ChopTail();
  396. m_CurrentFile = m_CurrentDirectory;
  397. }
  398. }
  399. void
  400. CAccessCard::Select(const WORD wFileID)
  401. {
  402. CLockWrap wrap(&m_IOPLock);
  403. BYTE bDataIn[2];
  404. bDataIn[0] = (BYTE)(MSB(wFileID));
  405. bDataIn[1] = (BYTE)(LSB(wFileID));
  406. SendCardAPDU(m_bClassByte, 0xA4, 0x00, 0x00, 0x02, bDataIn, 0, NULL);
  407. }
  408. void
  409. CAccessCard::LogoutAll()
  410. {
  411. if(m_fSupportLogout)
  412. {
  413. CLockWrap wrap(&m_IOPLock);
  414. SendCardAPDU(m_bClassByte, 0x22, 0x07, 0x00, 0x00, NULL, 0, NULL);
  415. }
  416. else
  417. ResetCard();
  418. }
  419. void
  420. CAccessCard::Select(const char* szFileFullPath, FILE_HEADER* pMyfile,
  421. const bool fSelectAll)
  422. {
  423. CLockWrap wrap(&m_IOPLock);
  424. BYTE bIndex = 0;
  425. char szFormattedPath[cMaxPathLength];
  426. BYTE bFileCount = FormatPath(szFormattedPath, szFileFullPath);
  427. BYTE bPathLength = strlen(szFormattedPath);
  428. auto_ptr<FilePath> apfp(new FilePath(string(szFormattedPath)));
  429. ///////////////////////////////////////////////////////////
  430. // Select all files in path regardless of current path. //
  431. // Do this on request, or if cache is empty //
  432. ///////////////////////////////////////////////////////////
  433. if (fSelectAll || (m_CurrentFile.IsEmpty()) || (m_CurrentDirectory.IsEmpty()))
  434. {
  435. bIndex = 0;
  436. }
  437. ////////////////////////////////////////////////////////
  438. // if path names match, do nothing except get file info //
  439. ////////////////////////////////////////////////////////
  440. else if (m_CurrentFile == *apfp)
  441. {
  442. bIndex = 0;
  443. if (pMyfile) // force Select to get file info
  444. {
  445. if (1 < bFileCount)
  446. {
  447. if (m_CurrentFile == m_CurrentDirectory)
  448. bIndex = bFileCount - 1; // just reselect dir
  449. else
  450. bIndex = bFileCount - 2; // select dir & file
  451. SelectParent();
  452. }
  453. }
  454. else
  455. bIndex = bFileCount;
  456. }
  457. ////////////////////////////////////////////////////////////////////
  458. // if current directory is in path, only select remaining files //
  459. ////////////////////////////////////////////////////////////////////
  460. else if(m_CurrentDirectory.NumComponents() < apfp->NumComponents())
  461. {
  462. if (apfp->GreatestCommonPrefix(m_CurrentDirectory) == m_CurrentDirectory)
  463. bIndex = m_CurrentDirectory.NumComponents();
  464. else
  465. bIndex = 0;
  466. }
  467. ////////////////////////////////////////////////////////////////////
  468. // if new path share part of current directory, step upwards //
  469. ////////////////////////////////////////////////////////////////////
  470. else if(m_CurrentDirectory.NumComponents() > apfp->NumComponents())
  471. {
  472. BYTE bSharedPathLen;
  473. bSharedPathLen = apfp->GreatestCommonPrefix(m_CurrentDirectory).NumComponents();
  474. if(bSharedPathLen>1) // Not worth while to step up to 3F00.
  475. {
  476. BYTE bLevelsUp = m_CurrentDirectory.NumComponents() - bSharedPathLen;
  477. bool fSelectFailed = false;
  478. try
  479. {
  480. for(int i=0; i < bLevelsUp; i++)
  481. {
  482. SelectParent();
  483. }
  484. }
  485. catch (Exception const &)
  486. {
  487. // TODO: Not sure if this is handling correctly!
  488. fSelectFailed = true;
  489. }
  490. if (fSelectFailed)
  491. bIndex = 0;
  492. else
  493. bIndex = bSharedPathLen;
  494. }
  495. else
  496. bIndex = 0;
  497. }
  498. //////////////////////////////////////////
  499. // Select the necessary files in path //
  500. //////////////////////////////////////////
  501. char sFileToSelect[5] = { 0, 0, 0, 0, 0 };
  502. bool fFileSelected = false;
  503. bool fSelectFailed = false;
  504. try
  505. {
  506. while (bIndex < bFileCount)
  507. {
  508. WORD wFileHexID = (*apfp)[bIndex].GetShortID();
  509. Select(wFileHexID);
  510. fFileSelected = true;
  511. bIndex++;
  512. }
  513. }
  514. catch (Exception const &)
  515. {
  516. fSelectFailed = true;
  517. if (fSelectAll)
  518. throw; // TODO: throw something useful, eh?
  519. }
  520. if (fSelectFailed) // assert(!fSelectAll)
  521. {
  522. Select(szFormattedPath,pMyfile,true);
  523. fFileSelected = true;
  524. }
  525. BYTE bResponseLength = 0;
  526. if (fFileSelected)
  527. bResponseLength = ResponseLengthAvailable();
  528. ////////////////////////////////////////////////////
  529. // GetResponse and fill file header information //
  530. ////////////////////////////////////////////////////
  531. switch(bResponseLength)
  532. {
  533. case 0x17:
  534. case 0x28:
  535. {
  536. ////////////////////////////////////////////////
  537. // File selected is a directory or Instance //
  538. ////////////////////////////////////////////////
  539. m_CurrentDirectory = *apfp;
  540. m_CurrentFile = *apfp;
  541. if (pMyfile)
  542. {
  543. BYTE bDataOut[0x28];
  544. GetResponse(m_bClassByte, bResponseLength, bDataOut);
  545. pMyfile->file_id = (WORD)(bDataOut[4] * 256 + bDataOut[5]);
  546. pMyfile->file_size = (WORD)(bDataOut[2] * 256 + bDataOut[3]);
  547. pMyfile->nb_file = bDataOut[15];
  548. pMyfile->nb_sub_dir = bDataOut[14];
  549. pMyfile->file_status = 0x01;
  550. if (bResponseLength == 0x17)
  551. {
  552. ////////////////////////////////////
  553. // File selected is a directory //
  554. ////////////////////////////////////
  555. pMyfile->file_type = directory;
  556. pMyfile->AIDLength = 0;
  557. memset((void*)(pMyfile->applicationID), 0x00, 16);
  558. }
  559. else
  560. {
  561. ////////////////////////////////////
  562. // File selected is an Instance //
  563. ////////////////////////////////////
  564. /////////////////////////////////////////////////////
  565. // Instance files contain one "hidden" file for //
  566. // program data that should not be shown to the //
  567. // users //
  568. /////////////////////////////////////////////////////
  569. pMyfile->nb_file--;
  570. pMyfile->file_type = Instance;
  571. pMyfile->AIDLength = bDataOut[23];
  572. memcpy((void*)(pMyfile->applicationID),
  573. (void*)(&bDataOut[24]), pMyfile->AIDLength);
  574. ////////////////////////////////////////////////////
  575. // Set flags in file status to discriminate //
  576. // applets/applications //
  577. ///////////////////////////////////////////////////
  578. switch(bDataOut[9])
  579. {
  580. case 0x01: pMyfile->file_status |= (1 << 5); // Applet
  581. break;
  582. case 0x02: pMyfile->file_status |= (1 << 4); // Application
  583. break;
  584. case 0x03: pMyfile->file_status |= (3 << 4); // Both
  585. break;
  586. }
  587. ////////////////////////////////////////////////
  588. // Set flags in file status to discriminate //
  589. // created/installed/registered instances //
  590. ////////////////////////////////////////////////
  591. switch(bDataOut[10])
  592. {
  593. case 0x01: pMyfile->file_status |= (1 << 1); // Created
  594. break;
  595. case 0x02: pMyfile->file_status |= (1 << 2); // Installed
  596. break;
  597. case 0x03: pMyfile->file_status |= (1 << 3); // Registered
  598. break;
  599. }
  600. }
  601. ////////////////////
  602. // Get file ACL //
  603. ////////////////////
  604. SendCardAPDU(m_bClassByte, 0xFE, 0x00, 0x00, 0,
  605. NULL,0x08, bDataOut);
  606. memcpy((void*)(pMyfile->access_cond), (void*)(bDataOut), 8);
  607. }
  608. break;
  609. } // end case directory or Instance file
  610. case 0x0F:
  611. {
  612. ////////////////////////////////////////////////////////
  613. // File selected is an elementary file of some type //
  614. ////////////////////////////////////////////////////////
  615. m_CurrentFile = *apfp;
  616. apfp->ChopTail();
  617. m_CurrentDirectory = *apfp;
  618. if (pMyfile)
  619. {
  620. BYTE bDataOut[0x0F];
  621. GetResponse(m_bClassByte, bResponseLength, bDataOut);
  622. pMyfile->file_id = (WORD)(bDataOut[4] * 256 + bDataOut[5]);
  623. pMyfile->file_size = (WORD)(bDataOut[2] * 256 + bDataOut[3]);
  624. pMyfile->nb_file = 0x00;
  625. pMyfile->nb_sub_dir = 0x00;
  626. pMyfile->AIDLength = 0x00;
  627. pMyfile->file_status = bDataOut[11];
  628. memset((void*)pMyfile->applicationID, 0, 16);
  629. switch(bDataOut[13])
  630. {
  631. case 0x00: pMyfile->file_type = Binary_File;
  632. break;
  633. case 0x01: pMyfile->file_type = Fixed_Record_File;
  634. pMyfile->nb_sub_dir = bDataOut[14];
  635. pMyfile->nb_file = pMyfile->file_size /
  636. pMyfile->nb_sub_dir;
  637. break;
  638. case 0x02: pMyfile->file_type = Variable_Record_File;
  639. break;
  640. case 0x03: pMyfile->file_type = Cyclic_File;
  641. pMyfile->nb_sub_dir = bDataOut[14];
  642. pMyfile->nb_file = pMyfile->file_size /
  643. pMyfile->nb_sub_dir;
  644. break;
  645. case 0x04: pMyfile->file_type = Program_File;
  646. break;
  647. //////////////////////////////////////////////////////////
  648. // if GetResponse(...) is successful but bad file //
  649. // type is returned //
  650. //////////////////////////////////////////////////////////
  651. default: pMyfile->file_type = Unknown;
  652. throw iop::Exception(iop::ccFileTypeUnknown);
  653. }
  654. ////////////////////
  655. // Get file ACL //
  656. ////////////////////
  657. SendCardAPDU(m_bClassByte, 0xFE, 0x00, 0x00, 0,
  658. NULL, 0x08, bDataOut);
  659. memcpy((void*)(pMyfile->access_cond), (void*)(bDataOut), 8);
  660. }
  661. break;
  662. } // end case elementary file
  663. default:
  664. //////////////////////////////////////////////////////////////////
  665. // GetResponse was successful but returned an uninterpretable //
  666. //////////////////////////////////////////////////////////////////
  667. if (fFileSelected)
  668. throw iop::Exception(iop::ccCannotInterpretGetResponse);
  669. } // end of SWITCH
  670. }
  671. void
  672. CAccessCard::CreateFile(const FILE_HEADER* pMyfile)
  673. {
  674. CLockWrap wrap(&m_IOPLock);
  675. BYTE bDataIn[16];
  676. /////////////////////////////////////////////////////
  677. // Cyberflex cards don't allocate space for file //
  678. // headers implicity, so it's done here manually //
  679. /////////////////////////////////////////////////////
  680. WORD wFileSize;
  681. if (pMyfile->file_type == directory)
  682. wFileSize = pMyfile->file_size + 24;
  683. else
  684. wFileSize = pMyfile->file_size + 16;
  685. ////////////////////////////////////////////////////
  686. // Cyclic files need a 4 byte header per record //
  687. ////////////////////////////////////////////////////
  688. if (pMyfile->file_type == Cyclic_File)
  689. {
  690. /////////////////////////////////////////
  691. // prevent overflow error in card OS! //
  692. /////////////////////////////////////////
  693. if (pMyfile->nb_sub_dir > 251)
  694. throw iop::Exception(iop::ccCyclicRecordSizeTooLarge);
  695. bDataIn[6] = pMyfile->nb_sub_dir + 4;
  696. wFileSize += pMyfile->nb_file * 4;
  697. }
  698. else
  699. bDataIn[6] = pMyfile->nb_sub_dir;
  700. bDataIn[0] = MSB(wFileSize);
  701. bDataIn[1] = LSB(wFileSize);
  702. bDataIn[2] = MSB(pMyfile->file_id);
  703. bDataIn[3] = LSB(pMyfile->file_id);
  704. bDataIn[5] = pMyfile->file_status & 1;
  705. bDataIn[7] = pMyfile->nb_file;
  706. switch(pMyfile->file_type)
  707. {
  708. case Binary_File: bDataIn[4] = 0x02;
  709. break;
  710. case directory: bDataIn[4] = 0x20;
  711. break;
  712. case Cyclic_File: bDataIn[4] = 0x1D;
  713. break;
  714. case Variable_Record_File: bDataIn[4] = 0x19;
  715. break;
  716. case Fixed_Record_File: bDataIn[4] = 0x0C;
  717. break;
  718. case Instance: bDataIn[4] = 0x21;
  719. break;
  720. case Program_File: bDataIn[4] = 0x03;
  721. break;
  722. //////////////////////////////////
  723. // Requested file type is bad //
  724. //////////////////////////////////
  725. default:
  726. // TO DO: Why not let the card return the
  727. // error?
  728. throw iop::Exception(iop::ccFileTypeInvalid);
  729. }
  730. memcpy((void*)&bDataIn[8], (void*)(pMyfile->access_cond), 8);
  731. SendCardAPDU(m_bClassByte, insCreateFile, 0x00, 0x00, 0x10,
  732. bDataIn, 0, NULL);
  733. m_apSharedMarker->UpdateMarker(CMarker::WriteMarker);
  734. }
  735. void
  736. CAccessCard::WritePublicKey(const CPublicKeyBlob aKey, const BYTE bKeyNum)
  737. {
  738. CLockWrap wrap(&m_IOPLock);
  739. BYTE bAlgoID;
  740. switch(aKey.bModulusLength)
  741. {
  742. case 0x40:
  743. bAlgoID = 0xC5;
  744. break;
  745. case 0x60:
  746. bAlgoID = 0xC7;
  747. break;
  748. case 0x80:
  749. bAlgoID = 0xC9;
  750. break;
  751. default:
  752. throw iop::Exception(iop::ccAlgorithmIdNotSupported);
  753. }
  754. Select(0x1012);
  755. DWORD dwKeyBlockLen = 4 + 9 + aKey.bModulusLength + 4;
  756. BYTE bKeyBlob[256];
  757. bKeyBlob[0] = (BYTE) ((dwKeyBlockLen >> 8) & 0xFF);
  758. bKeyBlob[1] = (BYTE) (dwKeyBlockLen & 0xFF);
  759. bKeyBlob[2] = bKeyNum;
  760. bKeyBlob[3] = bAlgoID;
  761. bKeyBlob[4] = 0xC1;
  762. bKeyBlob[5] = 0x01;
  763. bKeyBlob[6] = 0x02;
  764. bKeyBlob[7] = 0xC0;
  765. bKeyBlob[8] = (BYTE)aKey.bModulusLength + 1;
  766. bKeyBlob[9] = 0x00;
  767. //////////////////////////////////////////////////
  768. // Convert modulus to big endian for the card //
  769. //////////////////////////////////////////////////
  770. for (int i = 0; i < aKey.bModulusLength; i++)
  771. bKeyBlob[10 + i] = aKey.bModulus[aKey.bModulusLength - 1 - i];
  772. bKeyBlob[10 + aKey.bModulusLength] = 0xC0;
  773. bKeyBlob[11 + aKey.bModulusLength] = 0x04;
  774. ///////////////////////////////////////////////////
  775. // Convert exponent to big endian for the card //
  776. ///////////////////////////////////////////////////
  777. for (i = 0; i < 4; i++)
  778. bKeyBlob[12 + aKey.bModulusLength + i] = aKey.bExponent[3 - i];
  779. WORD wOffset = (WORD) (dwKeyBlockLen * bKeyNum);
  780. WriteBinary(wOffset, (WORD) dwKeyBlockLen, bKeyBlob);
  781. }
  782. void
  783. CAccessCard::GetSerial(BYTE* bSerial, size_t &SerialLength)
  784. {
  785. if (bSerial == NULL)
  786. {
  787. SerialLength = 22;
  788. return;
  789. }
  790. if (SerialLength < 22)
  791. {
  792. throw iop::Exception(ccBufferTooSmall);
  793. }
  794. SerialLength = 22;
  795. SendCardAPDU(m_bClassByte, 0xCA, 0x00, 0x01, 0,
  796. NULL, 22, bSerial);
  797. }
  798. void
  799. CAccessCard::ReadPublicKey(CPublicKeyBlob *aKey, const BYTE bKeyNum)
  800. {
  801. CLockWrap wrap(&m_IOPLock);
  802. BYTE bKeyLength[2];
  803. Select(0x1012);
  804. ReadBinary(0,2,bKeyLength);
  805. WORD wKeyBlockLength = bKeyLength[0] * 256 + bKeyLength[1];
  806. WORD wOffset = (WORD)(wKeyBlockLength * bKeyNum);
  807. BYTE bBuffer[512];
  808. ReadBinary(wOffset, wKeyBlockLength, bBuffer);
  809. aKey->bModulusLength = bBuffer[8] - 1;
  810. scu::AutoArrayPtr<BYTE> aabModule(new BYTE[aKey->bModulusLength]);
  811. BYTE aExponent[4];
  812. memcpy((void*)aabModule.Get(), (void*)&bBuffer[10], aKey->bModulusLength);
  813. memcpy((void*)aExponent, (void*)&bBuffer[10 + aKey->bModulusLength + 2], 4);
  814. /////////////////////////////////////////////////////////////////////////
  815. // Change from big endian on the card to little endian in the struct //
  816. /////////////////////////////////////////////////////////////////////////
  817. for (WORD i = 0; i < aKey->bModulusLength; i++)
  818. aKey->bModulus[i] = aabModule[aKey->bModulusLength - 1 - i];
  819. for (i = 0; i < 4; i++)
  820. aKey->bExponent[i] = aExponent[3 - i];
  821. }
  822. // There are some slightly arbitrary constants used here...tighten down later.
  823. void
  824. CAccessCard::WritePrivateKey(const CPrivateKeyBlob aKey, const BYTE bKeyNum)
  825. {
  826. CLockWrap wrap(&m_IOPLock);
  827. BYTE bAlgoID;
  828. switch(aKey.bPLen)
  829. {
  830. case 0x20:
  831. bAlgoID = 0xC4;
  832. break;
  833. case 0x30:
  834. bAlgoID = 0xC6;
  835. break;
  836. case 0x40:
  837. bAlgoID = 0xC8;
  838. break;
  839. default:
  840. throw iop::Exception(iop::ccAlgorithmIdNotSupported);
  841. }
  842. Select(0x0012);
  843. CPrivateKeyBlob anotherKey;
  844. WORD wKeyBlockLength = 22 + 5 * aKey.bPLen;
  845. WORD wOffset = (WORD)(bKeyNum * wKeyBlockLength);
  846. BYTE bKeyBlob[1024];
  847. bKeyBlob[0] = (BYTE)((wKeyBlockLength >> 8) & 0xFF);
  848. bKeyBlob[1] = (BYTE)(wKeyBlockLength & 0xFF);
  849. bKeyBlob[2] = bKeyNum;
  850. bKeyBlob[3] = bAlgoID;
  851. bKeyBlob[4] = 0xC2;
  852. bKeyBlob[5] = 0x01;
  853. bKeyBlob[6] = 0x05;
  854. ////////////////////////////////////////////////////////////////////////
  855. // Need to convert from little endian (struct) to big endian (card) //
  856. ////////////////////////////////////////////////////////////////////////
  857. BYTE bP[256];
  858. BYTE bQ[256];
  859. BYTE bQInv[256];
  860. BYTE bKmodP[256];
  861. BYTE bKmodQ[256];
  862. for (WORD i = 0; i < aKey.bPLen; i++)
  863. {
  864. bP[i] = aKey.bP[aKey.bQLen - 1 - i];
  865. bQ[i] = aKey.bQ[aKey.bPLen - 1 - i];
  866. bQInv[i] = aKey.bInvQ[aKey.bInvQLen - 1 - i];
  867. bKmodP[i] = aKey.bKsecModP[aKey.bKsecModQLen - 1 - i];
  868. bKmodQ[i] = aKey.bKsecModQ[aKey.bKsecModPLen - 1 - i];
  869. }
  870. //////////////////////////////////////////////////////
  871. // Now we need to left align the bytes of P and Q //
  872. //////////////////////////////////////////////////////
  873. BYTE pShift = 0, qShift = 0, qIShift = 0;
  874. /* Punting on bad keys!
  875. if ((bP[0] < 8) || (bQ[0] < 8)) {
  876. // Bad key?
  877. delete bP;
  878. delete bQ;
  879. delete bQInv;
  880. delete bKmodP;
  881. delete bKmodQ;
  882. delete bKeyBlob;
  883. return FALSE;
  884. }
  885. */
  886. bKeyBlob[7] = 0xC2;
  887. bKeyBlob[8] = (BYTE) aKey.bPLen + 1;
  888. bKeyBlob[9] = 0x00;
  889. memcpy((void*) &bKeyBlob[10], (void*)bQ, aKey.bPLen);
  890. bKeyBlob[10 + aKey.bPLen] = 0xC2;
  891. bKeyBlob[11 + aKey.bPLen] = (BYTE) aKey.bQLen + 1;
  892. bKeyBlob[12 + aKey.bPLen] = 0x00;
  893. memcpy((void*) &bKeyBlob[13 + aKey.bPLen], (void*)bP, aKey.bPLen);
  894. bKeyBlob[13 + 2* aKey.bPLen] = 0xC2;
  895. bKeyBlob[14 + 2* aKey.bPLen] = (BYTE) aKey.bQLen + 1;
  896. bKeyBlob[15 + 2* aKey.bPLen] = 0x00;
  897. memcpy((void*) &bKeyBlob[16 + 2* aKey.bPLen], (void*)bQInv, aKey.bPLen);
  898. bKeyBlob[16 + 3* aKey.bPLen] = 0xC2;
  899. bKeyBlob[17 + 3* aKey.bPLen] = (BYTE) aKey.bQLen + 1;
  900. bKeyBlob[18 + 3* aKey.bPLen] = 0x00;
  901. memcpy((void*) &bKeyBlob[19 + 3* aKey.bPLen], (void*)bKmodQ, aKey.bPLen);
  902. bKeyBlob[19 + 4* aKey.bPLen] = 0xC2;
  903. bKeyBlob[20 + 4* aKey.bPLen] = (BYTE) aKey.bQLen + 1;
  904. bKeyBlob[21 + 4* aKey.bPLen] = 0x00;
  905. memcpy((void*) &bKeyBlob[22 + 4 * aKey.bPLen], (void*)bKmodP, aKey.bPLen);
  906. WriteBinary(wOffset, wKeyBlockLength, bKeyBlob);
  907. }
  908. void
  909. CAccessCard::ChangeCHV(const BYTE bKeyNumber, const BYTE *bOldCHV,
  910. const BYTE *bNewCHV)
  911. {
  912. CLockWrap wrap(&m_IOPLock);
  913. BYTE bDataIn[16];
  914. memcpy((void*)bDataIn, (void*)bOldCHV, 8);
  915. memcpy((void*)(bDataIn + 8), (void*)bNewCHV, 8);
  916. SendCardAPDU(m_bClassByte, 0x24, 0x00, bKeyNumber, 16,
  917. bDataIn, 0, NULL);
  918. m_apSharedMarker->UpdateMarker(CMarker::PinMarker);
  919. }
  920. void
  921. CAccessCard::ChangeCHV(const BYTE bKey_nb, const BYTE *bNewCHV)
  922. {
  923. CLockWrap wrap(&m_IOPLock);
  924. switch (bKey_nb)
  925. {
  926. case 1: Select("/3f00/0000"); // CHV1 and CHV2 are the only CHV's supported
  927. break;
  928. case 2: Select("/3f00/0100");
  929. break;
  930. default: throw iop::Exception(iop::ccInvalidChv);
  931. break;
  932. }
  933. WriteBinary(3, 8, bNewCHV);
  934. BYTE bRemaingAttempts = 3; // Minumum number + 2
  935. WriteBinary(12, 1, &bRemaingAttempts);
  936. m_apSharedMarker->UpdateMarker(CMarker::PinMarker);
  937. VerifyCHV(bKey_nb,bNewCHV);
  938. }
  939. void
  940. CAccessCard::UnblockCHV(const BYTE bKeyNumber,
  941. const BYTE *bUnblockPIN, const BYTE *bNewPin)
  942. {
  943. CLockWrap wrap(&m_IOPLock);
  944. BYTE bDataIn[16];
  945. memcpy((void*)bDataIn, (void*)bUnblockPIN, 8);
  946. memcpy((void*)(bDataIn + 8), (void*)bNewPin, 8);
  947. SendCardAPDU(m_bClassByte, 0x2C, 0x00, bKeyNumber, 16,
  948. bDataIn, 0, NULL);
  949. m_apSharedMarker->UpdateMarker(CMarker::PinMarker);
  950. }
  951. void
  952. CAccessCard::ChangeUnblockKey(const BYTE bKeyNumber, const BYTE *bNewPIN)
  953. {
  954. CLockWrap wrap(&m_IOPLock);
  955. switch (bKeyNumber)
  956. {
  957. case 1: Select("/3f00/0000"); // CHV1 and CHV2 are the only CHV's supported
  958. break;
  959. case 2: Select("/3f00/0100");
  960. break;
  961. default: throw iop::Exception(iop::ccInvalidChv);
  962. break;
  963. }
  964. WriteBinary(13, 8, bNewPIN);
  965. }
  966. void
  967. CAccessCard::ChangeTransportKey(const BYTE *bNewKey)
  968. {
  969. CLockWrap wrap(&m_IOPLock);
  970. Select("/3f00/0011");
  971. //////////////////////////////////////////
  972. // Build byte string to write to card //
  973. //////////////////////////////////////////
  974. BYTE bKeyString[13] =
  975. {
  976. 0x00, // length of key
  977. 0x0E, // length of key
  978. 0x00, // Key number
  979. 0x01, // tag to identify key as an ID PIN
  980. 0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes for key
  981. 0x03 // # of verification attempts remaining before card is blocked + 2
  982. };
  983. //////////////////////////////////////////////////////
  984. // insert new key into key string to pass to card //
  985. //////////////////////////////////////////////////////
  986. memcpy((void*)(bKeyString + 4), (void*)bNewKey, 8);
  987. WriteBinary(0, 13, bKeyString);
  988. // Make a (hopefully) successfull verification to re-set attempt counter
  989. VerifyTransportKey(bNewKey);
  990. }
  991. void
  992. CAccessCard::ChangeACL(const BYTE *bACL)
  993. {
  994. CLockWrap wrap(&m_IOPLock);
  995. SendCardAPDU(m_bClassByte, 0xFC, 0x00, 0x00, 0x08,
  996. bACL, 0, NULL);
  997. m_apSharedMarker->UpdateMarker(CMarker::WriteMarker);
  998. }
  999. void
  1000. CAccessCard::DefaultDispatchError(ClassByte cb,
  1001. Instruction ins,
  1002. StatusWord sw) const
  1003. {
  1004. CauseCode cc;
  1005. bool fDoThrow = true;
  1006. switch (sw)
  1007. {
  1008. case 0x6283:
  1009. cc = ccContradictionWithInvalidationStatus;
  1010. break;
  1011. case 0x6300:
  1012. cc = ccChvVerificationFailedMoreAttempts;
  1013. break;
  1014. case 0x6981:
  1015. cc = ccChvNotInitialized;
  1016. break;
  1017. case 0x6985:
  1018. cc = ccNoFileSelected;
  1019. break;
  1020. case 0x6A00:
  1021. cc = ccFileExists;
  1022. break;
  1023. case 0x6A84:
  1024. cc = ccCannotReadOutsideFileBoundaries;
  1025. break;
  1026. case 0x6A86:
  1027. cc = ccLimitReached;
  1028. break;
  1029. case 0x6F11:
  1030. cc = ccDirectoryNotEmpty;
  1031. break;
  1032. case 0x6F12:
  1033. cc = ccInvalidSignature;
  1034. break;
  1035. case 0x6F14:
  1036. cc = ccBadState;
  1037. break;
  1038. default:
  1039. fDoThrow = false;
  1040. break;
  1041. }
  1042. if (fDoThrow)
  1043. throw Exception(cc, cb, ins, sw);
  1044. CSmartCard::DefaultDispatchError(cb, ins, sw);
  1045. }
  1046. void
  1047. CAccessCard::DispatchError(ClassByte cb,
  1048. Instruction ins,
  1049. StatusWord sw) const
  1050. {
  1051. CauseCode cc;
  1052. bool fDoThrow = true;
  1053. switch (ins)
  1054. {
  1055. case insCreateFile:
  1056. switch (sw)
  1057. {
  1058. case 0x6A00:
  1059. cc = ccFileExists;
  1060. break;
  1061. case 0x6A84:
  1062. cc = ccOutOfSpaceToCreateFile;
  1063. break;
  1064. case 0x6B00:
  1065. cc = ccRecordInfoIncompatible;
  1066. break;
  1067. default:
  1068. fDoThrow = false;
  1069. break;
  1070. }
  1071. break;
  1072. case insDeleteFile:
  1073. switch (sw)
  1074. {
  1075. case 0x6A00:
  1076. cc = ccRootDirectoryNotErasable;
  1077. break;
  1078. default:
  1079. fDoThrow = false;
  1080. break;
  1081. }
  1082. break;
  1083. case insDirectory:
  1084. switch (sw)
  1085. {
  1086. case 0x6985:
  1087. cc = ccCurrentDirectoryIsNotSelected;
  1088. break;
  1089. case 0x6A83:
  1090. cc = ccFileIndexDoesNotExist;
  1091. break;
  1092. default:
  1093. fDoThrow = false;
  1094. break;
  1095. }
  1096. break;
  1097. case insExecuteMethod:
  1098. switch (sw)
  1099. {
  1100. case 0x6283:
  1101. cc = ccProgramFileInvalidated;
  1102. break;
  1103. case 0x6A00:
  1104. cc = ccInstanceIdInUse;
  1105. break;
  1106. case 0x6F15:
  1107. cc = ccCardletNotInRegisteredState;
  1108. break;
  1109. case 0x6F19:
  1110. cc = ccInstallCannotRun;
  1111. break;
  1112. default:
  1113. if ((0x6230 <= sw) && (0x6260 <= sw))
  1114. cc = ccJava;
  1115. else
  1116. fDoThrow = false;
  1117. }
  1118. break;
  1119. case insExternalAuth:
  1120. switch (sw)
  1121. {
  1122. case 0x6300:
  1123. cc = ccVerificationFailed;
  1124. break;
  1125. case 0x6981:
  1126. cc = ccInvalidKey;
  1127. break;
  1128. case 0x6985:
  1129. cc = ccAskRandomNotLastApdu;
  1130. break;
  1131. case 0x6B00:
  1132. cc = ccAlgorithmIdNotSupported;
  1133. break;
  1134. case 0x6F15:
  1135. cc = ccOperationNotActivatedForApdu;
  1136. break;
  1137. default:
  1138. fDoThrow = false;
  1139. break;
  1140. }
  1141. break;
  1142. case insInternalAuth:
  1143. switch (sw)
  1144. {
  1145. case 0x6300:
  1146. cc = ccRequestedAlgIdMayNotMatchKeyUse;
  1147. break;
  1148. case 0x6981:
  1149. cc = ccInvalidKey;
  1150. break;
  1151. case 0x6B00:
  1152. cc = ccAlgorithmIdNotSupported;
  1153. break;
  1154. case 0x6F15:
  1155. cc = ccOperationNotActivatedForApdu;
  1156. break;
  1157. default:
  1158. fDoThrow = false;
  1159. break;
  1160. }
  1161. break;
  1162. case insReadBinary:
  1163. // fall-through intentional
  1164. case insUpdateBinary:
  1165. switch (sw)
  1166. {
  1167. case 0x6A84:
  1168. cc = ccCannotReadOutsideFileBoundaries;
  1169. break;
  1170. default:
  1171. fDoThrow = false;
  1172. break;
  1173. }
  1174. break;
  1175. default:
  1176. fDoThrow = false;
  1177. break;
  1178. }
  1179. if (fDoThrow)
  1180. throw Exception(cc, cb, ins, sw);
  1181. CSmartCard::DispatchError(cb, ins, sw);
  1182. }
  1183. void
  1184. CAccessCard::DoReadBlock(WORD wOffset,
  1185. BYTE *pbBuffer,
  1186. BYTE bLength)
  1187. {
  1188. SendCardAPDU(m_bClassByte, insReadBinary, HIBYTE(wOffset),
  1189. LOBYTE(wOffset), 0, 0, bLength, pbBuffer);
  1190. }
  1191. void
  1192. CAccessCard::DoWriteBlock(WORD wOffset,
  1193. BYTE const *pbBuffer,
  1194. BYTE cLength)
  1195. {
  1196. SendCardAPDU(m_bClassByte, insUpdateBinary, HIBYTE(wOffset),
  1197. LOBYTE(wOffset), cLength, pbBuffer, 0, 0);
  1198. }
  1199. bool
  1200. CAccessCard::ValidClassByte(BYTE bClassByte)
  1201. {
  1202. ////////////////////////////////////////////////////////////////
  1203. // Calling Directory on root to check for proper class byte //
  1204. ////////////////////////////////////////////////////////////////
  1205. BYTE bOutput[cMaxDirInfo];
  1206. bool fValidClassByte = true;
  1207. try
  1208. {
  1209. SendCardAPDU(bClassByte, insDirectory, 0x00, 0x00, 0, NULL,
  1210. sizeof bOutput / sizeof *bOutput, bOutput);
  1211. }
  1212. catch (Exception &)
  1213. {
  1214. fValidClassByte = false;
  1215. }
  1216. return fValidClassByte;
  1217. }
  1218. bool
  1219. CAccessCard::SupportLogout()
  1220. {
  1221. bool fSuccess = true;
  1222. try
  1223. {
  1224. CLockWrap wrap(&m_IOPLock);
  1225. SendCardAPDU(m_bClassByte, 0x22, 0x07, 0x00, 0x00, NULL, 0, NULL);
  1226. }
  1227. catch(...)
  1228. {
  1229. fSuccess = false;
  1230. }
  1231. return fSuccess;
  1232. }