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); |