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.

1567 lines
46 KiB

  1. // CryptoCard.cpp: implementation of the CCryptoCard 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 <scuArrayP.h>
  11. #include "iopExc.h"
  12. #include "CryptoCard.h"
  13. #include "LockWrap.h"
  14. using namespace std;
  15. using namespace iop;
  16. namespace
  17. {
  18. BYTE
  19. AsPrivateAlgId(KeyType kt)
  20. {
  21. BYTE bAlgId = 0;
  22. switch (kt)
  23. {
  24. case ktRSA512:
  25. bAlgId = 0x40;
  26. break;
  27. case ktRSA768:
  28. bAlgId = 0x60;
  29. break;
  30. case ktRSA1024:
  31. bAlgId = 0x80;
  32. break;
  33. case ktDES:
  34. bAlgId = 0x08;
  35. break;
  36. default:
  37. throw Exception(ccInvalidParameter);
  38. break;
  39. }
  40. return bAlgId;
  41. }
  42. } // namespace
  43. //////////////////////////////////////////////////////////////////////
  44. // Construction/Destruction
  45. //////////////////////////////////////////////////////////////////////
  46. CCryptoCard::CCryptoCard(const SCARDHANDLE hCardHandle, const char* szReaderName,
  47. const SCARDCONTEXT pContext, const DWORD dwMode)
  48. : CSmartCard(hCardHandle, szReaderName, pContext, dwMode)
  49. {
  50. m_fSupportLogout = SupportLogout();
  51. }
  52. CCryptoCard::~CCryptoCard()
  53. {
  54. }
  55. void
  56. CCryptoCard::LogoutAll()
  57. {
  58. if(m_fSupportLogout)
  59. {
  60. CLockWrap wrap(&m_IOPLock);
  61. SendCardAPDU(0xF0, 0x22, 0x07, 0, 0, NULL, 0, NULL);
  62. }
  63. else
  64. ResetCard();
  65. }
  66. void
  67. CCryptoCard::DeleteFile(const WORD wFileID)
  68. {
  69. CLockWrap wrap(&m_IOPLock);
  70. RequireSelect();
  71. ////////////////////////////////////////////////////////
  72. // Ensure that a directory is empty before deletion //
  73. ////////////////////////////////////////////////////////
  74. char cFilePathFormatter[2] = "/";
  75. char cZero[2] = "0";
  76. char sBuffer[4] = { 0, 0, 0, 0 };
  77. char szFileToDelete[80];
  78. FILE_HEADER FHeader;
  79. int iPad;
  80. if (!(m_CurrentDirectory == m_CurrentFile))
  81. {
  82. /////////////////////////////////////////////////////////////////////////////////////////////
  83. // File's parent directory was not selected (Currently selected file is not a directory) //
  84. /////////////////////////////////////////////////////////////////////////////////////////////
  85. throw iop::Exception(iop::ccSelectedFileNotDirectory);
  86. }
  87. strcpy(szFileToDelete, m_CurrentDirectory.GetStringPath().c_str());
  88. strcat(szFileToDelete, cFilePathFormatter);
  89. _itoa(wFileID, sBuffer, 16);
  90. /////////////////////////////////////////////////////////////////////////
  91. // Padding file path with 0 if file ID does not contain 4 characters //
  92. /////////////////////////////////////////////////////////////////////////
  93. iPad = strlen(sBuffer);
  94. while (iPad < 4)
  95. {
  96. strcat(szFileToDelete, cZero);
  97. iPad++;
  98. }
  99. strcat(szFileToDelete, sBuffer); //
  100. szFileToDelete[m_CurrentDirectory.NumComponents() * 5 + 5] = '\0'; // Select file to delete
  101. Select(szFileToDelete, &FHeader);
  102. if (FHeader.file_type == directory && (FHeader.nb_file + FHeader.nb_sub_dir) > 0)
  103. {
  104. ////////////////////////////////////////////////////////
  105. // re-establish current file and directory pointers //
  106. ////////////////////////////////////////////////////////
  107. SelectParent();
  108. //////////////////////////////////////////////////////////////////////////////
  109. // Directory was not empty, and will not be deleted. Cryptoflex does not //
  110. // support this check internally -- this is the Cyberflex status code! //
  111. //////////////////////////////////////////////////////////////////////////////
  112. throw iop::Exception(iop::ccDirectoryNotEmpty);
  113. }
  114. ////////////////////////////////////////////////////////
  115. // re-establish current file and directory pointers //
  116. ////////////////////////////////////////////////////////
  117. szFileToDelete[strlen(szFileToDelete) - 5] = '\0';
  118. Select(szFileToDelete);
  119. ///////////////////////////////////////////////////////////////////////////
  120. // File was not a directory or directory was empty - proceed to delete //
  121. ///////////////////////////////////////////////////////////////////////////
  122. BYTE bDataIn[2];
  123. bDataIn[0] = (BYTE)(MSB(wFileID));
  124. bDataIn[1] = (BYTE)(LSB(wFileID));
  125. SendCardAPDU(0xF0, 0xE4, 0x00, 0x00, 0x02, bDataIn, 0, NULL);
  126. Dirty(true);
  127. }
  128. void
  129. CCryptoCard::CreateFile(const FILE_HEADER* pMyFile)
  130. {
  131. CLockWrap wrap(&m_IOPLock);
  132. switch(pMyFile->file_type)
  133. {
  134. case Binary_File:
  135. case Variable_Record_File:
  136. case Cyclic_File:
  137. case Fixed_Record_File:
  138. {
  139. BYTE bData[17];
  140. BYTE bP2;
  141. BYTE bDataLength;
  142. if (pMyFile->file_type == Binary_File)
  143. bP2 = 0x00; // binary files have no records
  144. else
  145. bP2 = pMyFile->nb_file; // number of records
  146. if (pMyFile->file_type == Binary_File || pMyFile->file_type == Variable_Record_File)
  147. {
  148. bDataLength = 0x10;
  149. bData[12] = 0x03;
  150. }
  151. else
  152. {
  153. //////////////////////////////////////////////////////
  154. // Cyclic and Fixed Record files contain an extra //
  155. // byte that denotes the length of their records //
  156. //////////////////////////////////////////////////////
  157. bDataLength = 0x11;
  158. bData[12] = 0x04;
  159. }
  160. /////////////////////////////////////////////////////////////////////////////////
  161. // Note: cyclic files also have an added 4B header allocated for each record //
  162. // in the file in addition to the space allocated by CreateFile(...) //
  163. /////////////////////////////////////////////////////////////////////////////////
  164. bData[0] = 0; // RFU
  165. bData[1] = 0; // RFU
  166. bData[2] = MSB(pMyFile->file_size); // File Size
  167. bData[3] = LSB(pMyFile->file_size); // File Size
  168. bData[4] = MSB(pMyFile->file_id); // File ID
  169. bData[5] = LSB(pMyFile->file_id); // File ID
  170. switch(pMyFile->file_type) // File type
  171. {
  172. case Binary_File: bData[6] = 0x01; break;
  173. case Variable_Record_File: bData[6] = 0x04; break;
  174. case Cyclic_File: bData[6] = 0x06; break;
  175. case Fixed_Record_File: bData[6] = 0x02; break;
  176. }
  177. bData[7] = 0xFF;
  178. bData[8] = 0; // File ACL, to be set
  179. bData[9] = 0; // File ACL, to be set
  180. bData[10] = 0; // File ACL, to be set
  181. bData[11] = pMyFile->file_status & 1; // File Status
  182. // bData[12] = 0x03; // Length of the following data, already set
  183. bData[13] = 0; // AUT key numbers, to be set
  184. bData[14] = 0; // AUT key numbers, to be set
  185. bData[15] = 0; // AUT key numbers, to be set
  186. bData[16] = pMyFile->nb_sub_dir; // Record length (irrelevant for
  187. // binary and variable record files)
  188. bool ReadACL[8];
  189. bool WriteACL[8];
  190. bool InvalidateACL[8];
  191. bool RehabilitateACL[8];
  192. CryptoACL Read = { 0, 0, 0, 0, 0 };
  193. CryptoACL Write = { 0, 0, 0, 0, 0 };
  194. CryptoACL Invalidate = { 0, 0, 0, 0, 0 };
  195. CryptoACL Rehabilitate = { 0, 0, 0, 0, 0 };
  196. ////////////////////////////////////////////////////////////////////////////
  197. // Determination of the state of each action for each member of the ACL //
  198. ////////////////////////////////////////////////////////////////////////////
  199. for(int i = 0; i < 8; i++)
  200. {
  201. ReadACL[i] = ((pMyFile->access_cond[i]) & 1) ? true : false;
  202. WriteACL[i] = ((pMyFile->access_cond[i]) & 2) ? true : false;
  203. InvalidateACL[i] = ((pMyFile->access_cond[i]) & 8) ? true : false;
  204. RehabilitateACL[i] = ((pMyFile->access_cond[i]) & 16) ? true : false;
  205. }
  206. /////////////////////////////////////////////////
  207. // Remapping Cyberflex ACL to Cryptoflex ACL //
  208. /////////////////////////////////////////////////
  209. AccessToCryptoACL(ReadACL, &Read);
  210. AccessToCryptoACL(WriteACL, &Write);
  211. AccessToCryptoACL(InvalidateACL, &Invalidate);
  212. AccessToCryptoACL(RehabilitateACL, &Rehabilitate);
  213. ////////////////////////////////////
  214. // Assignment of security level //
  215. ////////////////////////////////////
  216. bData[8] = Read.Level * 16 + Write.Level;
  217. bData[10] = Rehabilitate.Level * 16 + Invalidate.Level;
  218. bData[13] = Read.AUTnumber * 16 + Write.AUTnumber;
  219. bData[15] = Rehabilitate.AUTnumber * 16 + Invalidate.AUTnumber;
  220. // If all the cyberflex ACL are 0, but the Cryptoflex are not, use the Cryptoflex.
  221. bool zero = true;
  222. for (int j = 0; j < 8; j++)
  223. if (pMyFile->access_cond[j] != 0x00) zero = false;
  224. if (zero)
  225. {
  226. // Use cryptoflex ACL)
  227. memcpy(&bData[7], pMyFile->CryptoflexACL, 4);
  228. memcpy(&bData[13], &(pMyFile->CryptoflexACL[4]),3);
  229. }
  230. SendCardAPDU(0xF0, insCreateFile, 0x00, bP2, bDataLength,
  231. bData, 0, NULL);
  232. }
  233. break; // end case non-Directory file
  234. case directory:
  235. {
  236. BYTE bData[17];
  237. bData[0] = 0; // RFU
  238. bData[1] = 0; // RFU
  239. bData[2] = MSB(pMyFile->file_size); // File Size
  240. bData[3] = LSB(pMyFile->file_size); // File Size
  241. bData[4] = MSB(pMyFile->file_id); // File ID
  242. bData[5] = LSB(pMyFile->file_id); // File ID
  243. bData[6] = 0x38; // File type
  244. bData[7] = 0x00; // No Use for Dedicated files
  245. bData[8] = 0; // File ACL, to be set
  246. bData[9] = 0; // File ACL, to be set
  247. bData[10] = 0x00; // RFU
  248. bData[11] = pMyFile->file_status & 1; // File Status
  249. bData[12] = 0x04; // Length of the following data
  250. bData[13] = 0; // AUT key numbers, to be set
  251. bData[14] = 0; // AUT key numbers, to be set
  252. bData[15] = 0x00; // RFU
  253. bData[16] = 0xFF; // RFU
  254. bool DirNextACL[8];
  255. bool DeleteACL[8];
  256. bool CreateACL[8];
  257. CryptoACL DirNext = { 0, 0, 0, 0, 0 };
  258. CryptoACL Delete = { 0, 0, 0, 0, 0 };
  259. CryptoACL Create = { 0, 0, 0, 0, 0 };
  260. ////////////////////////////////////////////////////////////////////////////
  261. // Determination of the state of each action for each member of the ACL //
  262. ////////////////////////////////////////////////////////////////////////////
  263. for(int i = 0; i < 8; i++)
  264. {
  265. DirNextACL[i] = ((pMyFile->access_cond[i]) & 1) ? true : false;
  266. DeleteACL[i] = ((pMyFile->access_cond[i]) & 2) ? true : false;
  267. CreateACL[i] = ((pMyFile->access_cond[i]) & 32) ? true : false;
  268. }
  269. /////////////////////////////////////////////////
  270. // Remapping Cyberflex ACL to Cryptoflex ACL //
  271. /////////////////////////////////////////////////
  272. AccessToCryptoACL(DirNextACL, &DirNext);
  273. AccessToCryptoACL(DeleteACL, &Delete);
  274. AccessToCryptoACL(CreateACL, &Create);
  275. ////////////////////////////////////
  276. // Assignment of security level //
  277. ////////////////////////////////////
  278. bData[8] = DirNext.Level * 16;
  279. bData[9] = Delete.Level * 16 + Create.Level;
  280. bData[13] = DirNext.AUTnumber * 16;
  281. bData[14] = Delete.AUTnumber * 16 + Create.AUTnumber;
  282. bool zero = true;
  283. for (int j = 0; j < 8; j++)
  284. if (pMyFile->access_cond[j] != 0x00) zero = false;
  285. if (zero)
  286. {
  287. for (int j = 0; j < 7; j++)
  288. if (pMyFile->CryptoflexACL[j] != 00) zero = false;
  289. if (!zero)
  290. {
  291. // Use cryptoflex ACL)
  292. memcpy(&bData[7], pMyFile->CryptoflexACL, 4);
  293. memcpy(&bData[13], &(pMyFile->CryptoflexACL[4]),3);
  294. }
  295. }
  296. SendCardAPDU(0xF0, 0xE0, 0x00, 0x00, 0x11, bData, 0, NULL);
  297. }
  298. break; // end case Directory file
  299. default:
  300. throw iop::Exception(iop::ccFileTypeInvalid);
  301. break;
  302. }
  303. Dirty(true);
  304. }
  305. void
  306. CCryptoCard::Directory(BYTE bFile_Nb, FILE_HEADER* pMyFile)
  307. {
  308. CLockWrap wrap(&m_IOPLock);
  309. RequireSelect();
  310. BYTE bDataOut[18];
  311. for (BYTE index = 0; index < bFile_Nb; index++)
  312. SendCardAPDU(0xF0, 0xA8, 0x00, 0x00, 0, NULL, 0x10, bDataOut);
  313. switch(bDataOut[4])
  314. {
  315. case 0x38: // Directory file
  316. {
  317. pMyFile->file_id = (WORD)(bDataOut[2] * 256 + bDataOut[3]);
  318. pMyFile->file_type = directory;
  319. pMyFile->nb_file = bDataOut[15];
  320. pMyFile->nb_sub_dir = bDataOut[14];
  321. pMyFile->file_status = bDataOut[9];
  322. memcpy(pMyFile->CryptoflexACL, &bDataOut[6], 3);
  323. memcpy(&(pMyFile->CryptoflexACL[3]), &bDataOut[11],3);
  324. ///////////////////////////////////////////////////////////////////////
  325. // Build ACL //
  326. ///////////////////////////////////////////////////////////////////////
  327. BYTE bACL[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  328. BYTE bACLNibble;
  329. BYTE bKeyNibble;
  330. ///////////////////
  331. // Dir Next AC //
  332. ///////////////////
  333. bACLNibble = bDataOut[6] / 16;
  334. bKeyNibble = bDataOut[11] / 16;
  335. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 0);
  336. //////////////////////
  337. // Delete File AC //
  338. //////////////////////
  339. bACLNibble = bDataOut[7] / 16;
  340. bKeyNibble = bDataOut[12] / 16;
  341. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 1);
  342. //////////////////////
  343. // Create File AC //
  344. //////////////////////
  345. bACLNibble = bDataOut[7] % 16;
  346. bKeyNibble = bDataOut[12] % 16;
  347. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 5);
  348. ////////////////////////////////////////////////
  349. // done remapping; assigning to file header //
  350. ////////////////////////////////////////////////
  351. memcpy((void*)(pMyFile->access_cond), (void*)(bACL), 8);
  352. memset((void*)(pMyFile->applicationID), 0x00, 16);
  353. break;
  354. } // end case Directory
  355. case 0x01: // Binary_File
  356. case 0x02: // Fixed_Record_File
  357. case 0x04: // Variable_Record_File
  358. case 0x06: // Cyclic_File
  359. {
  360. pMyFile->file_id = (WORD)(bDataOut[2] * 256 + bDataOut[3]);
  361. pMyFile->file_status = bDataOut[9];
  362. pMyFile->nb_sub_dir = bDataOut[14];
  363. pMyFile->nb_file = bDataOut[15];
  364. memcpy(pMyFile->CryptoflexACL, &bDataOut[6], 3);
  365. memcpy(&(pMyFile->CryptoflexACL[3]), &bDataOut[11],3);
  366. ////////////////////////////////////////////////////////////////////////
  367. // Cryptoflex includes the file header in the file size -- removing //
  368. ////////////////////////////////////////////////////////////////////////
  369. pMyFile->file_size = (WORD)(bDataOut[0] * 256 + bDataOut[1] - 16);
  370. //////////////////////////////////////////
  371. // Remove flag for file size rounding //
  372. //////////////////////////////////////////
  373. if (pMyFile->file_size >= 0x3FFF)
  374. pMyFile->file_size &= 0x3FFF;
  375. switch(bDataOut[4])
  376. {
  377. case 0x01: pMyFile->file_type = Binary_File;
  378. break;
  379. case 0x02: pMyFile->file_type = Fixed_Record_File;
  380. break;
  381. case 0x04: pMyFile->file_type = Variable_Record_File;
  382. break;
  383. case 0x06: pMyFile->file_type = Cyclic_File;
  384. break;
  385. }
  386. ////////////////////////////////////////////////////////////////////////
  387. // Also includes 4 bytes record headers in cyclic files -- removing //
  388. ////////////////////////////////////////////////////////////////////////
  389. if (pMyFile->file_type == Cyclic_File)
  390. pMyFile->file_size -= pMyFile->nb_file * 4;
  391. ///////////////////////////////////////////////////////////////////////
  392. // Build ACL //
  393. ///////////////////////////////////////////////////////////////////////
  394. BYTE bACL[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  395. BYTE bACLNibble;
  396. BYTE bKeyNibble;
  397. ////////////////////
  398. // Read file AC //
  399. ////////////////////
  400. bACLNibble = bDataOut[6] / 16;
  401. bKeyNibble = bDataOut[11] / 16;
  402. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 0);
  403. ////////////////////////
  404. // Write to file AC //
  405. ////////////////////////
  406. bACLNibble = bDataOut[6] % 16;
  407. bKeyNibble = bDataOut[11] % 16;
  408. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 1);
  409. ///////////////////////
  410. // Rehabilitate AC //
  411. ///////////////////////
  412. bACLNibble = bDataOut[8] / 16;
  413. bKeyNibble = bDataOut[13] / 16;
  414. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 4);
  415. /////////////////////
  416. // Invalidate AC //
  417. /////////////////////
  418. bACLNibble = bDataOut[8] % 16;
  419. bKeyNibble = bDataOut[13] % 16;
  420. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 3);
  421. ////////////////////////
  422. // Create Record AC //
  423. ////////////////////////
  424. if (bDataOut[4] != 0x01) // omit create record file AC for binary file
  425. {
  426. bACLNibble = bDataOut[7] % 16;
  427. bKeyNibble = bDataOut[12] % 16;
  428. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 2);
  429. }
  430. ////////////////////////////////////////////////////
  431. // done remapping ACL; assigning to file header //
  432. ////////////////////////////////////////////////////
  433. memcpy((void*)(pMyFile->access_cond), (void*)(bACL), 8);
  434. memset((void*)(pMyFile->applicationID), 0x00, 16);
  435. break;
  436. } // end case non-Directory file
  437. default:
  438. break;
  439. }
  440. /////////////////////////////
  441. // reset DirNext pointer //
  442. /////////////////////////////
  443. char szCurrentFile[80];
  444. strcpy(szCurrentFile, m_CurrentFile.GetStringPath().c_str());
  445. Select(m_CurrentDirectory.GetStringPath().c_str(), NULL, true);
  446. Select(szCurrentFile, NULL);
  447. }
  448. void
  449. CCryptoCard::Select(const WORD wFileID)
  450. {
  451. CLockWrap wrap(&m_IOPLock);
  452. BYTE bDataIn[2];
  453. bDataIn[0] = (BYTE)(MSB(wFileID));
  454. bDataIn[1] = (BYTE)(LSB(wFileID));
  455. SendCardAPDU(0xC0, 0xA4, 0x00, 0x00, 0x02, bDataIn, 0, NULL);
  456. }
  457. void
  458. CCryptoCard::Select(const char* szFileFullPath,
  459. FILE_HEADER* pMyFile,
  460. const bool fSelectAll)
  461. {
  462. CLockWrap wrap(&m_IOPLock);
  463. BYTE bIndex = 0;
  464. char szFormattedPath[cMaxPathLength];
  465. BYTE bFileCount = FormatPath(szFormattedPath, szFileFullPath);
  466. BYTE bPathLength = strlen(szFormattedPath);
  467. auto_ptr<FilePath> apfp(new FilePath(string(szFormattedPath)));
  468. ///////////////////////////////////////////////////////////
  469. // Select all files in path regardless of current path. //
  470. // Do this on request, or if cache is empty //
  471. ///////////////////////////////////////////////////////////
  472. if (fSelectAll || (m_CurrentFile.IsEmpty()) || (m_CurrentDirectory.IsEmpty()))
  473. {
  474. bIndex = 0;
  475. }
  476. ////////////////////////////////////////////////////////
  477. // if path names match, do nothing //
  478. ////////////////////////////////////////////////////////
  479. else if (m_CurrentFile == *apfp)
  480. {
  481. if (pMyFile) // force Select so file info is retrieved
  482. {
  483. if (1 < bFileCount)
  484. {
  485. if (m_CurrentFile == m_CurrentDirectory)
  486. bIndex = bFileCount - 1; // just reselect dir
  487. else
  488. bIndex = bFileCount - 2; // select dir & file
  489. SelectParent();
  490. }
  491. }
  492. else
  493. bIndex = bFileCount;
  494. }
  495. ////////////////////////////////////////////////////////////////////
  496. // if current directory is in path, only select remaining files //
  497. ////////////////////////////////////////////////////////////////////
  498. else if(m_CurrentDirectory.NumComponents() < apfp->NumComponents())
  499. {
  500. if (apfp->GreatestCommonPrefix(m_CurrentDirectory) == m_CurrentDirectory)
  501. bIndex = m_CurrentDirectory.NumComponents();
  502. else
  503. bIndex = 0;
  504. }
  505. //////////////////////////////////////////
  506. // Select the necessary files in path //
  507. //////////////////////////////////////////
  508. char sFileToSelect[5] = { 0, 0, 0, 0, 0 };
  509. bool fFileSelected = false;
  510. bool fSelectFailed = false;
  511. try
  512. {
  513. while (bIndex < bFileCount)
  514. {
  515. WORD wFileHexID = (*apfp)[bIndex].GetShortID();
  516. Select(wFileHexID);
  517. fFileSelected = true;
  518. bIndex++;
  519. }
  520. }
  521. catch (Exception const &)
  522. {
  523. fSelectFailed = true;
  524. if (fSelectAll)
  525. throw;
  526. }
  527. if (fSelectFailed) // assert(!fSelectAll)
  528. {
  529. Select(szFormattedPath, pMyFile, true);
  530. fFileSelected = true;
  531. }
  532. BYTE bResponseLength = 0;
  533. if (fFileSelected)
  534. bResponseLength = ResponseLengthAvailable();
  535. /////////////////////////////////////////
  536. // Get response and fill file header //
  537. /////////////////////////////////////////
  538. switch(bResponseLength)
  539. {
  540. case 0x17: //
  541. case 0x16: //
  542. case 0x15: // Directory file
  543. case 0x14: //
  544. case 0x13: //
  545. case 0x12: //
  546. {
  547. //////////////////////////////////////////
  548. // Update file and directory pointers //
  549. //////////////////////////////////////////
  550. m_CurrentDirectory = *apfp;
  551. m_CurrentFile = *apfp;
  552. if (pMyFile)
  553. {
  554. BYTE bDataOut[0x19];
  555. GetResponse(0xC0, bResponseLength, bDataOut);
  556. pMyFile->file_id = (unsigned short)(bDataOut[4] * 256 + bDataOut[5]);
  557. pMyFile->file_size = (unsigned short)(bDataOut[2] * 256 + bDataOut[3]);
  558. pMyFile->file_type = directory;
  559. pMyFile->nb_file = bDataOut[15];
  560. pMyFile->nb_sub_dir = bDataOut[14];
  561. pMyFile->file_status = bDataOut[11];
  562. memcpy(m_bLastACL, &bDataOut[7],4);
  563. //////////////////////////////////////////////////////////////
  564. // Build ACL
  565. //////////////////////////////////////////////////////////////
  566. BYTE bACL[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
  567. 0x00, 0x00, 0x00 };
  568. BYTE bKeyNibble = 0xFF; // flag to ignore AUT keys
  569. // -- useless for
  570. // Select(...)
  571. BYTE bACLNibble;
  572. //////////////////
  573. // Dir Next AC //
  574. //////////////////
  575. bACLNibble = bDataOut[8] / 16;
  576. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 0);
  577. //////////////////////
  578. // Delete File AC //
  579. //////////////////////
  580. bACLNibble = bDataOut[9] / 16;
  581. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 1);
  582. /////////////////////
  583. // CreateFile AC //
  584. /////////////////////
  585. bACLNibble = bDataOut[9] % 16;
  586. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 5);
  587. ////////////////////////////////////////////////////
  588. // done remapping ACL; assigning to file header //
  589. ////////////////////////////////////////////////////
  590. memcpy((void*)(pMyFile->access_cond), (void*)(bACL), 8);
  591. memset((void*)(pMyFile->applicationID), 0x00, 16);
  592. }
  593. } // end case Directory file
  594. break;
  595. case 0x0F: // non-Directory file types
  596. case 0x0E: //
  597. {
  598. //////////////////////////////////////////
  599. // Update file and directory pointers //
  600. //////////////////////////////////////////
  601. m_CurrentFile = *apfp;
  602. apfp->ChopTail();
  603. m_CurrentDirectory = *apfp;
  604. if (pMyFile)
  605. {
  606. BYTE bDataOut[0x11];
  607. GetResponse(0xC0, bResponseLength, bDataOut);
  608. pMyFile->file_size = (WORD)(bDataOut[2]*256+bDataOut[3]);
  609. pMyFile->file_id = (WORD)(bDataOut[4]*256+bDataOut[5]);
  610. pMyFile->file_status = bDataOut[11];
  611. memcpy(m_bLastACL, &bDataOut[7],4);
  612. switch(bDataOut[6])
  613. {
  614. case 0x01: pMyFile->file_type = Binary_File;
  615. break;
  616. case 0x02: pMyFile->file_type = Fixed_Record_File;
  617. break;
  618. case 0x04: pMyFile->file_type = Variable_Record_File;
  619. break;
  620. case 0x06: pMyFile->file_type = Cyclic_File;
  621. break;
  622. }
  623. if (pMyFile->file_type == Cyclic_File ||
  624. pMyFile->file_type == Fixed_Record_File)
  625. {
  626. pMyFile->nb_sub_dir = bDataOut[14];
  627. pMyFile->nb_file = (pMyFile->nb_sub_dir)
  628. ? pMyFile->file_size / pMyFile->nb_sub_dir
  629. : 0;
  630. }
  631. else
  632. {
  633. ///////////////////////////////////////////////////////////
  634. // number of records inaccessable except by file //
  635. // size calculation above //
  636. ///////////////////////////////////////////////////////////
  637. pMyFile->nb_file = 0x00;
  638. pMyFile->nb_sub_dir = 0x00;
  639. }
  640. //////////////////////////////////////////////////////////////
  641. // Build ACL //
  642. //////////////////////////////////////////////////////////////
  643. BYTE bACL[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  644. BYTE bKeyNibble = 0xFF; // flag to ignore AUT keys
  645. // -- useless for
  646. // Select(...)
  647. BYTE bACLNibble;
  648. ////////////////////
  649. // Read file AC //
  650. ////////////////////
  651. bACLNibble = bDataOut[8] / 16;
  652. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 0);
  653. ////////////////////////
  654. // Write to file AC //
  655. ////////////////////////
  656. bACLNibble = bDataOut[8] % 16;
  657. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 1);
  658. ///////////////////////
  659. // Rehabilitate AC //
  660. ///////////////////////
  661. bACLNibble = bDataOut[10] / 16;
  662. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 4);
  663. /////////////////////
  664. // Invalidate AC //
  665. /////////////////////
  666. bACLNibble = bDataOut[10] % 16;
  667. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 3);
  668. ////////////////////////
  669. // Create Record AC //
  670. ////////////////////////
  671. if (bDataOut[6] != 0x01) // omit create record file
  672. // AC for binary file
  673. {
  674. bACLNibble = bDataOut[9] % 16;
  675. CryptoToAccessACL(bACL, bACLNibble, bKeyNibble, 2);
  676. }
  677. ////////////////////////////////////////////////////
  678. // done remapping ACL; assigning to file header //
  679. ////////////////////////////////////////////////////
  680. memcpy((void*)(pMyFile->access_cond), (void*)(bACL), 8);
  681. memset((void*)(pMyFile->applicationID), 0x00, 16);
  682. }
  683. } // end case non-Directory file
  684. break;
  685. default:
  686. break;
  687. }
  688. }
  689. void
  690. CCryptoCard::SelectParent()
  691. {
  692. CLockWrap wrap(&m_IOPLock);
  693. RequireSelect();
  694. ///////////////////////////////////////////////////
  695. // If current directory is root, reselect root //
  696. ///////////////////////////////////////////////////
  697. if (m_CurrentDirectory.NumComponents() == 1)
  698. {
  699. Select(0x3F00);
  700. m_CurrentFile = m_CurrentDirectory;
  701. }
  702. else
  703. {
  704. if (m_CurrentDirectory == m_CurrentFile)
  705. {
  706. m_CurrentDirectory.ChopTail();
  707. Select(m_CurrentDirectory.Tail().GetShortID());
  708. m_CurrentFile = m_CurrentDirectory;
  709. }
  710. else
  711. {
  712. Select(m_CurrentDirectory.Tail().GetShortID());
  713. m_CurrentFile = m_CurrentDirectory;
  714. }
  715. }
  716. }
  717. void
  718. CCryptoCard::VerifyKey(const BYTE bKeyNumber, const BYTE bKeyLength,
  719. const BYTE* bKey)
  720. {
  721. CLockWrap wrap(&m_IOPLock);
  722. SendCardAPDU(0xF0, 0x2A, 0x00, bKeyNumber, bKeyLength, bKey, 0, NULL);
  723. }
  724. void
  725. CCryptoCard::VerifyCHV(const BYTE bCHVNumber, const BYTE* bCHV)
  726. {
  727. CLockWrap wrap(&m_IOPLock);
  728. SendCardAPDU(0xC0, insVerifyChv, 0x00, bCHVNumber,
  729. 0x08, bCHV, 0, NULL);
  730. }
  731. void
  732. CCryptoCard::VerifyTransportKey(const BYTE *bKey)
  733. {
  734. CLockWrap wrap(&m_IOPLock);
  735. VerifyKey(1, 8, bKey);
  736. }
  737. void
  738. CCryptoCard::GetChallenge(const DWORD dwNumberLength, BYTE* bRandomNumber)
  739. {
  740. CLockWrap wrap(&m_IOPLock);
  741. const DWORD dwMaxLen = 64;
  742. DWORD dwRamainingBytes = dwNumberLength;
  743. BYTE *bpBuf = bRandomNumber;
  744. while(dwRamainingBytes)
  745. {
  746. BYTE bNumGet = (dwRamainingBytes > dwMaxLen) ? dwMaxLen : dwRamainingBytes;
  747. SendCardAPDU(0xC0, 0x84, 0x00, 0x00, 0, NULL,
  748. bNumGet, bpBuf);
  749. bpBuf += bNumGet;
  750. dwRamainingBytes -= bNumGet;
  751. }
  752. }
  753. void
  754. CCryptoCard::ExternalAuth(const KeyType kt, const BYTE bKeyNb,
  755. const BYTE bDataLength, const BYTE* bData)
  756. {
  757. CLockWrap wrap(&m_IOPLock);
  758. //BYTE bAlgo_ID = AsPrivateAlgId(kt);
  759. SendCardAPDU(0xC0, 0x82, 0, bKeyNb, bDataLength,
  760. bData, 0, NULL);
  761. }
  762. void
  763. CCryptoCard::InternalAuth(const KeyType kt, const BYTE bKeyNb,
  764. const BYTE bDataLength, const BYTE* bDataIn,
  765. BYTE* bDataOut)
  766. {
  767. CLockWrap wrap(&m_IOPLock);
  768. if ((bDataLength < 0x40) || (bDataLength > 0x80))
  769. throw iop::Exception(iop::ccAlgorithmIdNotSupported);
  770. SendCardAPDU(0xC0, insInternalAuth, 0, bKeyNb,
  771. bDataLength, bDataIn, 0, NULL);
  772. GetResponse(0xC0, ResponseLengthAvailable(), bDataOut);
  773. }
  774. void
  775. CCryptoCard::WritePublicKey(const CPublicKeyBlob aKey, const BYTE bKeyNum)
  776. {
  777. CLockWrap wrap(&m_IOPLock);
  778. WORD wOffset;
  779. Select(0x1012);
  780. WORD wKeyBlockLen = 7 + 5 * aKey.bModulusLength / 2;
  781. scu::AutoArrayPtr<BYTE> aabKeyBlob(new BYTE[wKeyBlockLen]);
  782. aabKeyBlob[0] = HIBYTE(wKeyBlockLen);
  783. aabKeyBlob[1] = LOBYTE(wKeyBlockLen);
  784. aabKeyBlob[2] = bKeyNum + 1; // Cryptoflex key numbers are offset by one on the file...
  785. memcpy((void*) &aabKeyBlob[3], (void*)&aKey.bModulus, aKey.bModulusLength);
  786. // Would need to set Montgomery constants here, but since nobody seems
  787. // to know what they are...
  788. // Montgomery constants take 3 * modulus_length / 2 bytes
  789. memcpy((void*) &aabKeyBlob[3 + aKey.bModulusLength + (3 * aKey.bModulusLength / 2)], aKey.bExponent,4);
  790. wOffset = bKeyNum * wKeyBlockLen;
  791. WriteBinary(wOffset, wKeyBlockLen, aabKeyBlob.Get());
  792. }
  793. void
  794. CCryptoCard::GetSerial(BYTE* bSerial, size_t &SerialLength)
  795. {
  796. CLockWrap wrap(&m_IOPLock);
  797. try {
  798. FILE_HEADER fh;
  799. Select("/3f00/0002", &fh);
  800. if (SerialLength < fh.file_size)
  801. {
  802. SerialLength = fh.file_size;
  803. return;
  804. }
  805. ReadBinary(0, fh.file_size, bSerial);
  806. }
  807. catch(Exception &rExc)
  808. {
  809. if(rExc.Cause()==ccFileNotFound || rExc.Cause()==ccFileNotFoundOrNoMoreFilesInDf)
  810. SerialLength = 0;
  811. else
  812. throw;
  813. }
  814. }
  815. void
  816. CCryptoCard::ReadPublicKey(CPublicKeyBlob *aKey, const BYTE bKeyNum)
  817. {
  818. CLockWrap wrap(&m_IOPLock);
  819. BYTE bKeyLength[2];
  820. Select(0x1012);
  821. ReadBinary(0, 2, bKeyLength);
  822. WORD wKeyBlockLength = bKeyLength[0] * 256 + bKeyLength[1];
  823. WORD wOffset = wKeyBlockLength * bKeyNum;
  824. scu::AutoArrayPtr<BYTE> aabBuffer(new BYTE[wKeyBlockLength]);
  825. ReadBinary(wOffset, wKeyBlockLength, aabBuffer.Get());
  826. aKey->bModulusLength = ((wKeyBlockLength - 7) * 2) / 5;
  827. memcpy((void*)aKey->bModulus, (void*)&aabBuffer[3], aKey->bModulusLength);
  828. memcpy((void*)aKey->bExponent, (void*)&aabBuffer[wKeyBlockLength - 4], 4);
  829. }
  830. void
  831. CCryptoCard::WritePrivateKey(const CPrivateKeyBlob aKey, const BYTE bKeyNum)
  832. {
  833. CLockWrap wrap(&m_IOPLock);
  834. Select(0x0012);
  835. WORD wHalfModulus = aKey.bPLen; // Check that the lengths are all equal?
  836. WORD wKeyBlockLength = wHalfModulus * 5 + 3;
  837. WORD wOffset = bKeyNum * wKeyBlockLength;
  838. scu::SecureArray<BYTE> aabKeyBlob(wKeyBlockLength);
  839. aabKeyBlob[0] = HIBYTE(wKeyBlockLength);
  840. aabKeyBlob[1] = LOBYTE(wKeyBlockLength);
  841. aabKeyBlob[2] = bKeyNum + 1; // Cryptoflex key numbers are offset by one on the file...
  842. memcpy(&aabKeyBlob[3 ], aKey.bP.data(), wHalfModulus);
  843. memcpy(&aabKeyBlob[3 + wHalfModulus], aKey.bQ.data(), wHalfModulus);
  844. memcpy(&aabKeyBlob[3 + 2 * wHalfModulus], aKey.bInvQ.data(), wHalfModulus);
  845. memcpy(&aabKeyBlob[3 + 3 * wHalfModulus], aKey.bKsecModP.data(), wHalfModulus);
  846. memcpy(&aabKeyBlob[3 + 4 * wHalfModulus], aKey.bKsecModQ.data(), wHalfModulus);
  847. WriteBinary(wOffset, wKeyBlockLength, aabKeyBlob.data());
  848. }
  849. CPublicKeyBlob CCryptoCard::GenerateKeyPair(const BYTE *bpPublExp, const WORD wPublExpLen,
  850. const BYTE bKeyNum, const KeyType kt)
  851. {
  852. // This function generates a key-pair, using the public exponent as specified in
  853. // in CPublicKeyBlob parameter. The private key is stored in the private
  854. // key file at position specified by bKeyNum. The public key components are
  855. // returned through the CPublicKeyBlob parameter. Prior to call, the correct
  856. // DF containing the key file must be selected.
  857. // Implementation:
  858. // The offset of the key in the private key file is proportional to the key number
  859. // and it is assumed that all keys in a private key file have the same length. It
  860. // assumes that there is a public key file available with space for at least one
  861. // public key. The public key will always be written to the first position in the
  862. // public key file.
  863. BYTE bModulusLength;
  864. switch(kt)
  865. {
  866. case ktRSA512:
  867. bModulusLength = 0x40;
  868. break;
  869. case ktRSA768:
  870. bModulusLength = 0x60;
  871. break;
  872. case ktRSA1024:
  873. bModulusLength = 0x80;
  874. break;
  875. default:
  876. throw iop::Exception(iop::ccAlgorithmIdNotSupported);
  877. }
  878. // Check public exponent size and copy to 4 byte buffer
  879. if(wPublExpLen < 1 || wPublExpLen > 4)
  880. throw iop::Exception(iop::ccInvalidParameter);
  881. BYTE bPublExponent[4];
  882. memset(bPublExponent,0,4);
  883. memcpy(bPublExponent,bpPublExp,wPublExpLen);
  884. // Pre-define public key
  885. CPublicKeyBlob PublKey;
  886. PublKey.bModulusLength = bModulusLength;
  887. memset(PublKey.bModulus,0,bModulusLength);
  888. memset(PublKey.bExponent,0,4);
  889. WritePublicKey(PublKey, 0); // Write in first position.
  890. // Specify the correct key number in this position
  891. BYTE bKeyNumPlus1 = bKeyNum + 1; // Cryptoflex key numbers are offset by one on the file...
  892. Select(0x1012);
  893. WriteBinary(2, 1, &bKeyNumPlus1);
  894. // Pre-define private key
  895. CPrivateKeyBlob PrivKey;
  896. PrivKey.bPLen = bModulusLength/2;
  897. memset(PrivKey.bP.data(),0,PrivKey.bPLen);
  898. PrivKey.bQLen = bModulusLength/2;
  899. memset(PrivKey.bQ.data(),0,PrivKey.bQLen);
  900. PrivKey.bInvQLen = bModulusLength/2;
  901. memset(PrivKey.bInvQ.data(),0,PrivKey.bInvQLen);
  902. PrivKey.bKsecModQLen = bModulusLength/2;
  903. memset(PrivKey.bKsecModQ.data(),0,PrivKey.bKsecModQLen);
  904. PrivKey.bKsecModPLen = bModulusLength/2;
  905. memset(PrivKey.bKsecModP.data(),0,PrivKey.bKsecModPLen);
  906. WritePrivateKey(PrivKey, bKeyNum); // Write in actual position.
  907. // Generate the key pair
  908. SendCardAPDU(0xF0, insKeyGeneration, bKeyNum, bModulusLength,
  909. 4, bPublExponent, 0, NULL);
  910. ReadPublicKey(&PublKey,0);
  911. return PublKey;
  912. }
  913. void
  914. CCryptoCard::ChangeCHV(const BYTE bKey_nb, const BYTE *bOldCHV,
  915. const BYTE *bNewCHV)
  916. {
  917. CLockWrap wrap(&m_IOPLock);
  918. scu::SecureArray<BYTE> bDataIn(16);
  919. memcpy((void*)(bDataIn.data()), (void*)bOldCHV, 8);
  920. memcpy((void*)(bDataIn.data() + 8), (void*)bNewCHV, 8);
  921. SendCardAPDU(0xF0, insChangeChv, 0x00, bKey_nb, 0x10, bDataIn.data(), 0, NULL);
  922. Dirty(true);
  923. }
  924. void
  925. CCryptoCard::ChangeCHV(const BYTE bKey_nb, const BYTE *bNewCHV)
  926. {
  927. CLockWrap wrap(&m_IOPLock);
  928. switch (bKey_nb)
  929. {
  930. case 1: Select("/3f00/0000"); // CHV1 and CHV2 are the only CHV's supported
  931. break;
  932. case 2: Select("/3f00/0100");
  933. break;
  934. default: throw iop::Exception(iop::ccInvalidChv);
  935. break;
  936. }
  937. WriteBinary(3, 8, bNewCHV);
  938. BYTE bRemaingAttempts = 1;
  939. WriteBinary(12, 1, &bRemaingAttempts);
  940. Dirty(true);
  941. VerifyCHV(bKey_nb,bNewCHV);
  942. }
  943. void
  944. CCryptoCard::UnblockCHV(const BYTE bKey_nb, const BYTE *bUnblockPIN,
  945. const BYTE *bNewPin)
  946. {
  947. CLockWrap wrap(&m_IOPLock);
  948. scu::SecureArray<BYTE> bDataIn(16);
  949. memcpy((void*)(bDataIn.data()), (void*)bUnblockPIN, 8);
  950. memcpy((void*)(bDataIn.data() + 8), (void*)bNewPin, 8);
  951. SendCardAPDU(0xF0, insUnblockChv, 0x00, bKey_nb, 0x10, bDataIn.data(), 0, NULL);
  952. Dirty(true);
  953. }
  954. void
  955. CCryptoCard::ChangeUnblockKey(const BYTE bKey_nb, const BYTE *bNewPIN)
  956. {
  957. CLockWrap wrap(&m_IOPLock);
  958. switch (bKey_nb)
  959. {
  960. case 1: Select("/3f00/0000"); // CHV1 and CHV2 are the only CHV's supported
  961. break;
  962. case 2: Select("/3f00/0100");
  963. break;
  964. default: throw iop::Exception(iop::ccInvalidChv);
  965. break;
  966. }
  967. WriteBinary(13, 8, bNewPIN);
  968. }
  969. void
  970. CCryptoCard::ChangeTransportKey(const BYTE *bNewKey)
  971. {
  972. CLockWrap wrap(&m_IOPLock);
  973. Select("/3f00/0011");
  974. //////////////////////////////////////////
  975. // Build byte string to write to card //
  976. //////////////////////////////////////////
  977. BYTE bKeyString[10] =
  978. {
  979. 0x08, // length of key
  980. 0x00, // tag to identify key as a DES key
  981. 0, 0, 0, 0, 0, 0, 0, 0 // 8 bytes for key
  982. };
  983. // Copy the template into secure arry for storing the key
  984. const WORD wKeySize = 10;
  985. scu::SecureArray<BYTE> newbKeyStr(bKeyString,wKeySize);
  986. //////////////////////////////////////////////////////
  987. // insert new key into key string to pass to card //
  988. //////////////////////////////////////////////////////
  989. memcpy((void*)(newbKeyStr.data() + 2), (void*)bNewKey, 8);
  990. WriteBinary(13, wKeySize, newbKeyStr.data());
  991. BYTE bRemainingAttempt = 1; // Minumum # of verification attempts remaining before card is blocked
  992. WriteBinary(24, 1, &bRemainingAttempt);
  993. // Make a (hopefully) successfull verification to re-set attempt counter
  994. VerifyTransportKey(bNewKey);
  995. }
  996. void
  997. CCryptoCard::ChangeACL(const BYTE *bACL)
  998. {
  999. throw iop::Exception(iop::ccUnsupportedCommand);
  1000. }
  1001. void
  1002. CCryptoCard::AccessToCryptoACL(bool* fAccessACL, CryptoACL* pCryptoACL)
  1003. {
  1004. if (fAccessACL[0] == true)
  1005. pCryptoACL->Level = 0;
  1006. else
  1007. {
  1008. pCryptoACL->Level = 0x0F;
  1009. for(BYTE i = 1; i < 3; i++)
  1010. {
  1011. if (fAccessACL[i] == true)
  1012. {
  1013. pCryptoACL->CHVcounter++;
  1014. pCryptoACL->CHVnumber = i;
  1015. }
  1016. if (pCryptoACL->CHVcounter > 1 )
  1017. {
  1018. // More than one CHV for a single action
  1019. // is not supported by Cryptoflex
  1020. throw iop::Exception(iop::ccAclNotSupported);
  1021. }
  1022. }
  1023. for(i = 3; i < 8; i++)
  1024. {
  1025. if (fAccessACL[i] == true)
  1026. {
  1027. pCryptoACL->AUTcounter++;
  1028. pCryptoACL->AUTnumber = i - 3; // AUT0 starts with an index of 3
  1029. }
  1030. if (pCryptoACL->AUTcounter > 1)
  1031. {
  1032. // More than one AUT for a single action
  1033. // is not supported by Cryptoflex
  1034. throw iop::Exception(iop::ccAclNotSupported);
  1035. }
  1036. }
  1037. }
  1038. if (pCryptoACL->CHVcounter == 1 && pCryptoACL->AUTcounter == 1)
  1039. {
  1040. if(pCryptoACL->CHVnumber == 1)
  1041. pCryptoACL->Level = 8;
  1042. else
  1043. pCryptoACL->Level = 9;
  1044. }
  1045. if (pCryptoACL->CHVcounter == 1 && pCryptoACL->AUTcounter == 0)
  1046. {
  1047. if(pCryptoACL->CHVnumber == 1)
  1048. pCryptoACL->Level = 1;
  1049. else
  1050. pCryptoACL->Level = 2;
  1051. }
  1052. if (pCryptoACL->CHVcounter == 0 && pCryptoACL->AUTcounter == 1)
  1053. pCryptoACL->Level = 4;
  1054. }
  1055. void CCryptoCard::CryptoToAccessACL(BYTE* bAccessACL, const BYTE bACLNibble,
  1056. const BYTE bKeyNibble, const BYTE bShift)
  1057. {
  1058. switch (bACLNibble)
  1059. {
  1060. case 0x00: bAccessACL[0] = (1 << bShift) | bAccessACL[0];
  1061. break;
  1062. case 0x01:
  1063. case 0x06:
  1064. case 0x08: bAccessACL[1] = (1 << bShift) | bAccessACL[1];
  1065. break;
  1066. case 0x02:
  1067. case 0x07:
  1068. case 0x09: bAccessACL[2] = (1 << bShift) | bAccessACL[2];
  1069. break;
  1070. default: // bAccessACL already initialized to 0x00
  1071. break;
  1072. }
  1073. if (bACLNibble == 0x04 || bACLNibble == 0x08 || bACLNibble == 0x09)
  1074. {
  1075. ////////////////////////////////////////////////////////////////////////////
  1076. // Cyberflex only supports 5 AUT keys, and AUT0 starts at bAccessACL[3] //
  1077. ////////////////////////////////////////////////////////////////////////////
  1078. if (bKeyNibble < 0x05)
  1079. bAccessACL[3 + bKeyNibble] = (1 << bShift) | bAccessACL[3 + bKeyNibble];
  1080. }
  1081. }
  1082. void
  1083. CCryptoCard::DefaultDispatchError(ClassByte cb,
  1084. Instruction ins,
  1085. StatusWord sw) const
  1086. {
  1087. CauseCode cc;
  1088. bool fDoThrow = true;
  1089. switch (sw)
  1090. {
  1091. case 0x6281:
  1092. cc = ccDataPossiblyCorrupted;
  1093. break;
  1094. case 0x6300:
  1095. cc = ccAuthenticationFailed;
  1096. break;
  1097. case 0x6982:
  1098. cc = ccAccessConditionsNotMet;
  1099. break;
  1100. case 0x6981:
  1101. cc = ccNoEfExistsOrNoChvKeyDefined;
  1102. break;
  1103. case 0x6985:
  1104. cc = ccNoGetChallengeBefore;
  1105. break;
  1106. case 0x6986:
  1107. cc = ccNoEfSelected;
  1108. break;
  1109. case 0x6A83:
  1110. cc = ccOutOfRangeOrRecordNotFound;
  1111. break;
  1112. case 0x6A84:
  1113. cc = ccInsufficientSpace;
  1114. break;
  1115. case 0x6A82:
  1116. cc = ccFileNotFoundOrNoMoreFilesInDf;
  1117. break;
  1118. default:
  1119. fDoThrow = false;
  1120. break;
  1121. }
  1122. if (fDoThrow)
  1123. throw Exception(cc, cb, ins, sw);
  1124. CSmartCard::DefaultDispatchError(cb, ins, sw);
  1125. }
  1126. void
  1127. CCryptoCard::DispatchError(ClassByte cb,
  1128. Instruction ins,
  1129. StatusWord sw) const
  1130. {
  1131. CauseCode cc;
  1132. bool fDoThrow = true;
  1133. switch (ins)
  1134. {
  1135. case insChangeChv:
  1136. // fall-through intentional
  1137. case insUnblockChv:
  1138. switch (sw)
  1139. {
  1140. case 0x6300:
  1141. cc = ccChvVerificationFailedMoreAttempts;
  1142. break;
  1143. case 0x6581:
  1144. cc = ccUpdateImpossible;
  1145. break;
  1146. default:
  1147. fDoThrow = false;
  1148. break;
  1149. }
  1150. break;
  1151. case insCreateFile:
  1152. switch (sw)
  1153. {
  1154. case 0x6A80:
  1155. cc = ccFileIdExistsOrTypeInconsistentOrRecordTooLong;
  1156. break;
  1157. default:
  1158. fDoThrow = false;
  1159. break;
  1160. }
  1161. break;
  1162. case insGetResponse:
  1163. switch (sw)
  1164. {
  1165. case 0x6500:
  1166. cc = ccTooMuchDataForProMode;
  1167. break;
  1168. default:
  1169. fDoThrow = false;
  1170. break;
  1171. }
  1172. break;
  1173. case insReadBinary:
  1174. switch (sw)
  1175. {
  1176. case 0x6B00:
  1177. cc = ccCannotReadOutsideFileBoundaries;
  1178. break;
  1179. default:
  1180. fDoThrow = false;
  1181. break;
  1182. }
  1183. break;
  1184. case insVerifyChv:
  1185. switch (sw)
  1186. {
  1187. case 0x6300:
  1188. cc = ccChvVerificationFailedMoreAttempts;
  1189. break;
  1190. default:
  1191. fDoThrow = false;
  1192. break;
  1193. }
  1194. break;
  1195. default:
  1196. fDoThrow = false;
  1197. break;
  1198. }
  1199. if (fDoThrow)
  1200. throw Exception(cc, cb, ins, sw);
  1201. DefaultDispatchError(cb, ins, sw);
  1202. }
  1203. void
  1204. CCryptoCard::DoReadBlock(WORD wOffset,
  1205. BYTE *pbBuffer,
  1206. BYTE bLength)
  1207. {
  1208. SendCardAPDU(0xC0, insReadBinary, HIBYTE(wOffset),
  1209. LOBYTE(wOffset), 0, 0, bLength, pbBuffer);
  1210. }
  1211. void
  1212. CCryptoCard::DoWriteBlock(WORD wOffset,
  1213. BYTE const *pbBuffer,
  1214. BYTE cLength)
  1215. {
  1216. SendCardAPDU(0xC0, insUpdateBinary, HIBYTE(wOffset),
  1217. LOBYTE(wOffset), cLength, pbBuffer, 0, 0);
  1218. }
  1219. bool
  1220. CCryptoCard::SupportLogout()
  1221. {
  1222. bool fSuccess = true;
  1223. try
  1224. {
  1225. CLockWrap wrap(&m_IOPLock);
  1226. SendCardAPDU(0xF0, 0x22, 0x07, 0, 0, NULL, 0, NULL);
  1227. }
  1228. catch(...)
  1229. {
  1230. fSuccess = false;
  1231. }
  1232. return fSuccess;
  1233. }
  1234. void CCryptoCard::GetACL(BYTE *bACL)
  1235. {
  1236. CLockWrap wrap(&m_IOPLock);
  1237. memcpy(bACL,m_bLastACL,4);
  1238. BYTE bTemp[5];
  1239. SendCardAPDU(0xF0, 0xC4, 0x00, 0x00, 0x00, NULL, 0x03, bTemp);
  1240. memcpy(&bACL[4], bTemp, 3);
  1241. }