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.

1528 lines
43 KiB

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