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 = { 0 };
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);
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, 0); /* cbHandle = 0 */
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, cbAttr); /* conformant count */
92 Stream_Zero(s, cbAttr); /* pbAttr payload */
93 if (pad)
94 Stream_Zero(s, pad); /* NDR 4-byte alignment padding */
95
96 Stream_SealLength(s);
97 if (!Stream_SetPosition(s, 0))
98 {
99 Stream_Free(s, TRUE);
100 return nullptr;
101 }
102 return s;
103}
104
105/* cbAttrLen must be clamped to the pbAttr payload length, never to the padded
106 * NDR size, otherwise SCardSetAttrib reads past the pbAttr allocation. */
107static BOOL run_set_attrib_case(UINT32 cbAttr, UINT32 cbAttrLen)
108{
109 wStream* s = build_set_attrib(cbAttr, cbAttrLen);
110 if (!s)
111 return FALSE;
112
113 SetAttrib_Call call = { 0 };
114 const LONG status = smartcard_unpack_set_attrib_call(s, &call);
115 Stream_Free(s, TRUE);
116
117 BOOL rc = TRUE;
118 if (status != SCARD_S_SUCCESS)
119 {
120 printf("set_attrib cbAttr=%" PRIu32 ": unpack returned 0x%08" PRIX32 "\n", cbAttr,
121 (UINT32)status);
122 rc = FALSE;
123 }
124 else if (call.cbAttrLen > cbAttr)
125 {
126 printf("set_attrib cbAttr=%" PRIu32 ": cbAttrLen=%" PRIu32 " exceeds payload\n", cbAttr,
127 call.cbAttrLen);
128 rc = FALSE;
129 }
130
131 free(call.pbAttr);
132 return rc;
133}
134
135int TestSmartcardPack(int argc, char* argv[])
136{
137 WINPR_UNUSED(argc);
138 WINPR_UNUSED(argv);
139
140 /* Valid: cbAtr within the fixed 36-byte rgbAtr/rgbMask arrays. */
141 if (!run_case(0, TRUE))
142 return -1;
143 if (!run_case(36, TRUE))
144 return -1;
145
146 /* Out of range: cbAtr larger than the buffers would later overrun them. */
147 if (!run_case(37, FALSE))
148 return -1;
149 if (!run_case(0xFFFFFFFF, FALSE))
150 return -1;
151
152 /* Unaligned pbAttr lengths must not let cbAttrLen reach into the NDR padding. */
153 if (!run_set_attrib_case(1, 0xFFFFFFFF))
154 return -1;
155 if (!run_set_attrib_case(5, 0xFFFFFFFF))
156 return -1;
157 /* Aligned length and a small cbAttrLen must be preserved. */
158 if (!run_set_attrib_case(4, 0xFFFFFFFF))
159 return -1;
160 if (!run_set_attrib_case(8, 2))
161 return -1;
162
163 return 0;
164}