FreeRDP
Loading...
Searching...
No Matches
TestSmartcardPack.c
1
17#include <stdio.h>
18#include <string.h>
19
20#include <winpr/stream.h>
21#include <freerdp/channels/scard.h>
22#include <freerdp/utils/smartcard_pack.h>
23
24/* Build a LocateCardsByATRA call (cbContext=0, cAtrs=1, cReaders=0) holding a single
25 * LocateCards_ATRMask whose cbAtr is set to the requested value. */
26static wStream* build_locate_cards_by_atr_a(UINT32 cbAtr)
27{
28 wStream* s = Stream_New(nullptr, 24 + 8 + sizeof(LocateCards_ATRMask));
29 if (!s)
30 return nullptr;
31
32 Stream_Write_UINT32(s, 0); /* cbContext = 0 */
33 Stream_Write_UINT32(s, 0); /* pbContextNdrPtr = 0 */
34 Stream_Write_UINT32(s, 1); /* cAtrs = 1 */
35 Stream_Write_UINT32(s, 0x00020000); /* rgAtrMasksNdrPtr */
36 Stream_Write_UINT32(s, 0); /* cReaders = 0 */
37 Stream_Write_UINT32(s, 0); /* rgReaderStatesNdrPtr = 0 */
38 Stream_Write_UINT32(s, 1); /* conformant count = cAtrs */
39 Stream_Write_UINT32(s, cbAtr); /* LocateCards_ATRMask::cbAtr */
40 Stream_Zero(s, 36); /* rgbAtr[36] */
41 Stream_Zero(s, 36); /* rgbMask[36] */
42
43 Stream_SealLength(s);
44 if (!Stream_SetPosition(s, 0))
45 {
46 Stream_Free(s, TRUE);
47 return nullptr;
48 }
49 return s;
50}
51
52static BOOL run_case(UINT32 cbAtr, BOOL expectAccept)
53{
54 wStream* s = build_locate_cards_by_atr_a(cbAtr);
55 if (!s)
56 return FALSE;
57
58 LocateCardsByATRA_Call call = WINPR_C_ARRAY_INIT;
59 const LONG status = smartcard_unpack_locate_cards_by_atr_a_call(s, &call);
60 Stream_Free(s, TRUE);
61
62 const BOOL accepted = status == SCARD_S_SUCCESS;
63 if (accepted != expectAccept)
64 {
65 printf("cbAtr=%" PRIu32 ": expected %s, unpack returned 0x%08" PRIX32 "\n", cbAtr,
66 expectAccept ? "accept" : "reject", (UINT32)status);
67 free(call.rgAtrMasks);
68 return FALSE;
69 }
70
71 free(call.rgAtrMasks);
72 return TRUE;
73}
74
75/* Build a SetAttrib call (cbContext=0, cbHandle=0) whose pbAttr NDR conformant array
76 * carries cbAttr payload bytes, with the requested cbAttrLen field. */
77static wStream* build_set_attrib(UINT32 cbAttr, UINT32 cbAttrLen)
78{
79 const UINT32 pad = (4 - (cbAttr % 4)) % 4;
80 wStream* s = Stream_New(nullptr, 28 + 4 + cbAttr + pad + 12);
81 if (!s)
82 return nullptr;
83
84 Stream_Write_UINT32(s, 0); /* cbContext = 0 */
85 Stream_Write_UINT32(s, 0); /* pbContextNdrPtr = 0 */
86 Stream_Write_UINT32(s, 8); /* cbHandle = 8 */
87 Stream_Write_UINT32(s, 0x00020000); /* pbHandleNdrPtr */
88 Stream_Write_UINT32(s, 0); /* dwAttrId */
89 Stream_Write_UINT32(s, cbAttrLen); /* cbAttrLen */
90 Stream_Write_UINT32(s, 0x00020004); /* pbAttrNdrPtr */
91 Stream_Write_UINT32(s, 8); /* conformant cbHandle = 8 */
92 Stream_Write_UINT64(s, 0x123456789abcdef);
93 Stream_Write_UINT32(s, cbAttr); /* conformant count */
94 Stream_Zero(s, cbAttr); /* pbAttr payload */
95 if (pad)
96 Stream_Zero(s, pad); /* NDR 4-byte alignment padding */
97
98 Stream_SealLength(s);
99 if (!Stream_SetPosition(s, 0))
100 {
101 Stream_Free(s, TRUE);
102 return nullptr;
103 }
104 return s;
105}
106
107/* cbAttrLen must be clamped to the pbAttr payload length, never to the padded
108 * NDR size, otherwise SCardSetAttrib reads past the pbAttr allocation. */
109static BOOL run_set_attrib_case(UINT32 cbAttr, UINT32 cbAttrLen)
110{
111 wStream* s = build_set_attrib(cbAttr, cbAttrLen);
112 if (!s)
113 return FALSE;
114
115 SetAttrib_Call call = WINPR_C_ARRAY_INIT;
116 const LONG status = smartcard_unpack_set_attrib_call(s, &call);
117 Stream_Free(s, TRUE);
118
119 BOOL rc = TRUE;
120 if (status != SCARD_S_SUCCESS)
121 {
122 printf("set_attrib cbAttr=%" PRIu32 ": unpack returned 0x%08" PRIX32 "\n", cbAttr,
123 (UINT32)status);
124 rc = FALSE;
125 }
126 else if (call.cbAttrLen > cbAttr)
127 {
128 printf("set_attrib cbAttr=%" PRIu32 ": cbAttrLen=%" PRIu32 " exceeds payload\n", cbAttr,
129 call.cbAttrLen);
130 rc = FALSE;
131 }
132
133 free(call.pbAttr);
134 return rc;
135}
136
137int TestSmartcardPack(int argc, char* argv[])
138{
139 WINPR_UNUSED(argc);
140 WINPR_UNUSED(argv);
141
142 /* Valid: cbAtr within the fixed 36-byte rgbAtr/rgbMask arrays. */
143 if (!run_case(0, TRUE))
144 return -1;
145 if (!run_case(36, TRUE))
146 return -1;
147
148 /* Out of range: cbAtr larger than the buffers would later overrun them. */
149 if (!run_case(37, FALSE))
150 return -1;
151 if (!run_case(0xFFFFFFFF, FALSE))
152 return -1;
153
154 /* Unaligned pbAttr lengths must not let cbAttrLen reach into the NDR padding. */
155 if (!run_set_attrib_case(1, 0xFFFFFFFF))
156 return -1;
157 if (!run_set_attrib_case(5, 0xFFFFFFFF))
158 return -1;
159 /* Aligned length and a small cbAttrLen must be preserved. */
160 if (!run_set_attrib_case(4, 0xFFFFFFFF))
161 return -1;
162 if (!run_set_attrib_case(8, 2))
163 return -1;
164
165 return 0;
166}