PCSC那事儿(二十二--SCardGetAttrib)

时间:2021-07-19 21:02:21

 

SCardGetAttrib

SCardGetAttrib 定义在 winscard_clnt.c

实现如下:

 

2658 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,

2659         LPDWORD pcbAttrLen)

2660 {

2661         LONG ret;

2662         unsigned char *buf = NULL;

2663

2664         PROFILE_START

2665

 

2666         if (NULL == pcbAttrLen)

2667                 return SCARD_E_INVALID_PARAMETER;

2668

2669         if (SCARD_AUTOALLOCATE == *pcbAttrLen)

2670         {

2671                 if (NULL == pbAttr)

2672                         return SCARD_E_INVALID_PARAMETER;

2673

2674                 *pcbAttrLen = MAX_BUFFER_SIZE;

2675                 buf = malloc(*pcbAttrLen);

2676                 if (NULL == buf)

2677                         return SCARD_E_NO_MEMORY;

2678

2679                 *(unsigned char **)pbAttr = buf;

2680          }

 

 

2669 行当传入的 pcbAttrLen 所指内容为 SCARD_AUTOALLOCATE ,则要求 SCardGetAttrib 内部为参数 pbAttr 分配内存。这个在前面也有所提到。

 

 

2681         else

2682         {

2683                 buf = pbAttr;

2684

2685                 /* if only get the length */

2686                 if (NULL == pbAttr)

2687                          /* use a reasonable size */

2688                         *pcbAttrLen = MAX_BUFFER_SIZE;

2689         }

2690

2691         ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,

2692                 pcbAttrLen);

2693

2694         PROFILE_END(ret)

2695

2696         return ret;

2697 }

 

 

2686 行,如果传入的参数 pbAttr 为0,则只是需要返回 pbAttr 可能需要的长度,

在这里,这个长度是固定的, MAX_BUFFER_SIZE 264. 这个在前面也提到了,

用到短 APDU 收发的时候。

 

现在看看 SCardGetSetAttrib. 为了体现 extract SCardGetAttrib 用到了 SCardGetSetAttrib ,也就是调用了 SCardGetSetAttrib ,第二个参数是

SCARD_GET_ATTRIB.

SCardGetSetAttrib 定义在 winscard_clnt.c

实现如下:

2750 static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,

2751         LPBYTE pbAttr, LPDWORD pcbAttrLen)

2752 {

2753         LONG rv;

2754         getset_struct scGetSetStruct;

2755         sharedSegmentMsg msgStruct;

2756         int i;

2757         DWORD dwContextIndex, dwChannelIndex;

2758

2759         rv = SCardCheckDaemonAvailability();

2760         if (rv != SCARD_S_SUCCESS)

2761                 return rv;

2762

2763         /*

2764          * Make sure this handle has been opened

2765          */

2766         rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);

2767         if (rv == -1)

2768                 return SCARD_E_INVALID_HANDLE;

2769

2770          (void)SYS_MutexLock(psContextMap[dwContextIndex].mMutex);

 

 

 

2750~2770 行,看到了什么。所有的代码都讲解过了。提了 n 次。

2771

2772         /* check the handle is still valid */

2773         rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);

2774         if (rv == -1)

2775                 /* the handle is now invalid

2776                  * -> another thread may have called SCardReleaseContext

2777                  * -> so the mMutex has been unlocked */

2778                 return SCARD_E_INVALID_HANDLE;

2779

2780         for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)

 

2781         {

2782                 char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;

2783

2784                 /* by default r == NULL */

2785                 if (r && strcmp(r, (readerStates[i])->readerName) == 0)

2786                         break;

2787         }

2788

2789         if (i == PCSCLITE_MAX_READERS_CONTEXTS)

2790         {

2791                 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);

2792                 return SCARD_E_READER_UNAVAILABLE;

2793          }

 

 

 

 

2771~2793 行,昨夜星辰昨夜风。讲解过了。如果忘记了,可以回到昨夜去看看。

当然了忘记些事情很正常。佳菲猫说, The more you learn,the more you know,the

more you know,the more you forget.The more you forget,the less you know.

So,why bother to learn. 所以,不要有任何愧疚。

 

2794

2795         if (*pcbAttrLen > MAX_BUFFER_SIZE)

2796         {

2797                 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);

2798                 return SCARD_E_INSUFFICIENT_BUFFER;

2799          }

 

 

 

 

2794~2799 行,比起上面提到的 SCardTransmit SCardControl ,这里的日子轻松多了。

仅仅处理短 APDU 。所以如果想要获取的属性数据的长度比 MAX_BUFFER_SIZE 长,

直接返回了。这是采用鸵鸟手法。

 

接下来,做什么呢?当然是发送请求,然后接收回应了。

2800

2801         scGetSetStruct.hCard = hCard;

2802         scGetSetStruct.dwAttrId = dwAttrId;

2803         scGetSetStruct.cbAttrLen = *pcbAttrLen;

2804         scGetSetStruct.rv = SCARD_E_NO_SERVICE;

 

2805         memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));

2806         if (SCARD_SET_ATTRIB == command)

2807                  memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);

 

 

 

 

SCardGetSetAttrib 与上面提到的 SCardTransmit SCardControl 又有点不同,实际上

上面提过了。这里的情况是几乎一致的算法,处理不一样的数据结构。

 

发送采用 getset_struct 结构,接收采用 sharedSegmentMsg 结构, data 域内嵌 getset_struct 结构。

 

2808

2809         rv = WrapSHMWrite(command,

2810                 psContextMap[dwContextIndex].dwClientID, sizeof(scGetSetStruct),

2811                  PCSCLITE_CLIENT_ATTEMPTS, &scGetSetStruct);

2812

2813         if (rv == -1)

2814         {

2815                 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);

2816                 return SCARD_E_NO_SERVICE;

2817         }

2818

2819         /*

2820          * Read a message from the server

2821          */

2822         rv = SHMClientRead(&msgStruct, psContextMap[dwContextIndex].dwClientID,

2823                 PCSCLITE_CLIENT_ATTEMPTS);

2824

2825         if (rv == -1)

2826         {

2827                 (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);

2828                 return SCARD_F_COMM_ERROR;

2829         }

2830

2831         memcpy(&scGetSetStruct, &msgStruct.data, sizeof(scGetSetStruct));

 

 

 

 

2808~2831 行,还需要解说吗?

 

 

2832

2833         if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))

2834         {

2835                 /*

2836                  * Copy and zero it so any secret information is not leaked

2837                  */

2838                  if (*pcbAttrLen < scGetSetStruct.cbAttrLen)

2839                 {

2840                         scGetSetStruct.cbAttrLen = *pcbAttrLen;

2841                         scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;

2842                 }

2843                  else

2844                         *pcbAttrLen = scGetSetStruct.cbAttrLen;

2845

2846                 if (pbAttr)

2847                         memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);

2848

2849                 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));

2850         }

2851

2852         (void)SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);

2853

2854         return scGetSetStruct.rv;

2855 }

 

 

2838 行,如果返回数据的长度比参数传入要求的长度还要长,则设置返回值错误,不过

还是返回了部分被截断的数据。

2844 行,否则返回真正获取的数据长度。

2847 行,复制数据到传入的参数 pbAttr.

 

SCardGetAttrib 解说结束。

 

回头看看这个 API 的定义

2658 LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,

2659          LPDWORD pcbAttrLen)

 

 

 

第二个参数的目前取值如下,定义在 /PCSC/reader.h

 

规则如下,比如

 

#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag)))

 

#define SCARD_CLASS_PROTOCOL        3   /**< Protocol definitions */

 

#define SCARD_ATTR_ASYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0120)

 

 

 

这个 DWORD ,高 16bit Class 信息,低 16bit 放请求的 Tag.

DWORD 定义在 PCSC/wintypes.h

  36         typedef unsigned long DWORD;

 

DWORD 共有一下几种类型,定义在 PCSC/reader.h.

SCARD_ATTR_ASYNC_PROTOCOL_TYPES

SCARD_ATTR_ATR_STRING

SCARD_ATTR_CHANNEL_ID

SCARD_ATTR_CHARACTERISTICS

SCARD_ATTR_CURRENT_BWT

SCARD_ATTR_CURRENT_CLK

SCARD_ATTR_CURRENT_CWT

SCARD_ATTR_CURRENT_D

SCARD_ATTR_CURRENT_EBC_ENCODING

SCARD_ATTR_CURRENT_F

SCARD_ATTR_CURRENT_IFSC

SCARD_ATTR_CURRENT_IFSD

SCARD_ATTR_CURRENT_IO_STATE

SCARD_ATTR_CURRENT_N

SCARD_ATTR_CURRENT_PROTOCOL_TYPE

SCARD_ATTR_CURRENT_W

SCARD_ATTR_DEFAULT_CLK

SCARD_ATTR_DEFAULT_DATA_RATE

SCARD_ATTR_DEVICE_FRIENDLY_NAME

SCARD_ATTR_DEVICE_IN_USE

SCARD_ATTR_DEVICE_SYSTEM_NAME

SCARD_ATTR_DEVICE_UNIT

SCARD_ATTR_ESC_AUTHREQUEST

SCARD_ATTR_ESC_CANCEL

SCARD_ATTR_ESC_RESET

SCARD_ATTR_EXTENDED_BWT

SCARD_ATTR_ICC_INTERFACE_STATUS

SCARD_ATTR_ICC_PRESENCE

SCARD_ATTR_ICC_TYPE_PER_ATR

SCARD_ATTR_MAX_CLK

 

SCARD_ATTR_MAX_DATA_RATE

SCARD_ATTR_MAX_IFSD

SCARD_ATTR_MAXINPUT

SCARD_ATTR_POWER_MGMT_SUPPORT

SCARD_ATTR_SUPRESS_T1_IFS_REQUEST

SCARD_ATTR_SYNC_PROTOCOL_TYPES

SCARD_ATTR_USER_AUTH_INPUT_DEVICE

SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE

SCARD_ATTR_VENDOR_IFD_SERIAL_NO

SCARD_ATTR_VENDOR_IFD_TYPE

SCARD_ATTR_VENDOR_IFD_VERSION

SCARD_ATTR_VENDOR_NAME

 

 

 

 

这么多?多乎哉?

 

回头。回到 testpcsc.c

注意不要蓦然回首,要坚决回头。常回家看看。

 

295         test_rv(rv, hContext, DONT_PANIC);

296         if (rv == SCARD_S_SUCCESS)

297         {

298                 printf("SCARD_ATTR_ATR_STRING length: " GREEN "%ld/n" NORMAL , pcbAttrLen);

299                  printf("SCARD_ATTR_ATR_STRING: " GREEN);

300                 for (i = 0; i < pcbAttrLen; i++)

301                         printf("%02X ", pbAttr[i]);

302                 printf("/n" NORMAL );

303         }

304

305 #ifdef USE_AUTOALLOCATE

306          printf("Testing SCardFreeMemory/t/t: ");

307         rv = SCardFreeMemory(hContext, pbAttr);

308         test_rv(rv, hContext, PANIC);

309 #else

310         if (pbAttr)

311                 free(pbAttr);

312 # endif

 

 

 

 

 

前面的 293 行获取了 ATR 字符串。

293         rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAttr, &pcbAttrLen);

 

 

 

 

295~303 行,把获取到的 ATR 的字符串打印。

 

304~312 行,前面提过了。

 

313

314         printf("Testing SCardGetAttrib/t/t: ");

315         dwBufLen = sizeof(buf);

316         rv = SCardGetAttrib(hCard, SCARD_ATTR_VENDOR_IFD_VERSION, buf.as_char, &dwBufLen);

317         test_rv(rv, hContext, DONT_PANIC);

318         if (rv == SCARD_S_SUCCESS)

319                 printf("Vendor IFD version/t/t: " GREEN "0x%08lX/n" NORMAL,

320                          buf.as_DWORD);

321

 

 

 

 

313~321 行,这次也是测试 SCardGetAttrib. SCardGetAttrib 在前面分析过了。

再分析一次。 Kidding

这里是发出 SCARD_ATTR_VENDOR_IFD_VERSION 请求。获取 Vendor IFD

version 版本号。

 

322         printf("Testing SCardGetAttrib/t/t: ");

323         dwBufLen = sizeof(buf);

324         rv = SCardGetAttrib(hCard, SCARD_ATTR_MAXINPUT, buf.as_char, &dwBufLen);

325         test_rv(rv, hContext, DONT_PANIC);

326         if (rv == SCARD_S_SUCCESS)

327         {

328                 if (dwBufLen == sizeof(uint32_t))

329                         printf("Max message length/t/t: " GREEN "%d/n" NORMAL,

330                                 buf.as_uint32_t);

331                 else

332                         printf(RED "Wrong size" NORMAL);

333          }

 

 

 

 

322~333 行,还是测试 SCardGetAttrib. 不过这次是测试获取 Max message length.

到底 length 是多少呢?从 SCardGetAttrib 的分析可以知道,这个答案来源于服务端。

目前还没有到分析服务端的时候,有否有机会分析服务端呢?谁能预计未来。

 

334

335         printf("Testing SCardGetAttrib/t/t: ");

336         dwBufLen = sizeof(buf);

337         rv = SCardGetAttrib(hCard, SCARD_ATTR_VENDOR_NAME, buf.as_char, &dwBufLen);

338         test_rv(rv, hContext, DONT_PANIC);

339         if (rv == SCARD_S_SUCCESS)

340                 printf("Vendor name/t/t/t: " GREEN "%s/n" NORMAL , buf.as_char);

341

 

 

 

 

334~341 行,还是测试 SCardGetAttrib. 这次是获取产商名字。

342         printf("Testing SCardSetAttrib/t/t: ");

343         rv = SCardSetAttrib(hCard, SCARD_ATTR_ATR_STRING, (LPCBYTE)"", 1);

344          test_rv(rv, hContext, DONT_PANIC);