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