19#include <freerdp/config.h>
26#include <winpr/assert.h>
27#include <winpr/endian.h>
29#include <freerdp/channels/log.h>
31#include "rdpewa_cbor.h"
33#define TAG CHANNELS_TAG("rdpewa.client")
35BOOL rdpewa_cbor_decode_request(
const BYTE* data,
size_t length,
RDPEWA_REQUEST* out)
37 struct cbor_load_result result = WINPR_C_ARRAY_INIT;
43 memset(out, 0,
sizeof(*out));
45 cbor_item_t* root = cbor_load(data, length, &result);
46 if (!root || result.error.code != CBOR_ERR_NONE)
48 WLog_ERR(TAG,
"Failed to decode CBOR request, error %u at position %" PRIuz,
49 result.error.code, result.error.position);
53 if (!cbor_isa_map(root))
55 WLog_ERR(TAG,
"CBOR request is not a map");
59 const size_t mapSize = cbor_map_size(root);
60 struct cbor_pair* pairs = cbor_map_handle(root);
62 WLog_DBG(TAG,
"Request CBOR map has %" PRIuz
" entries", mapSize);
64 for (
size_t i = 0; i < mapSize; i++)
66 cbor_item_t* key = pairs[i].key;
67 cbor_item_t* value = pairs[i].value;
69 if (!cbor_isa_string(key))
72 const char* keyStr = (
const char*)cbor_string_handle(key);
73 const size_t keyLen = cbor_string_length(key);
75 WLog_DBG(TAG,
" key[%" PRIuz
"]: \"%.*s\" type=%u", i,
76 WINPR_ASSERTING_INT_CAST(
int, keyLen), keyStr, cbor_typeof(value));
81 if (memcmp(keyStr,
"rpId", 4) == 0)
83 if (cbor_isa_string(value))
85 size_t slen = cbor_string_length(value);
86 if (slen >=
sizeof(out->rpId))
87 slen =
sizeof(out->rpId) - 1;
88 memcpy(out->rpId, cbor_string_handle(value), slen);
89 out->rpId[slen] =
'\0';
94 if (memcmp(keyStr,
"flags", 5) == 0)
96 if (!cbor_isa_uint(value))
98 WLog_ERR(TAG,
"\"flags\"is not an unsigned int");
101 out->flags = WINPR_ASSERTING_INT_CAST(UINT32, cbor_get_int(value));
105 if (memcmp(keyStr,
"command", 7) == 0)
107 if (!cbor_isa_uint(value))
109 WLog_ERR(TAG,
"\"command\"is not an unsigned int");
112 out->command = WINPR_ASSERTING_INT_CAST(UINT32, cbor_get_int(value));
114 else if (memcmp(keyStr,
"request", 7) == 0)
116 if (!cbor_isa_bytestring(value))
118 WLog_ERR(TAG,
"\"request\"is not a byte string");
121 out->requestLen = cbor_bytestring_length(value);
122 out->request = malloc(out->requestLen);
128 memcpy(out->request, cbor_bytestring_handle(value), out->requestLen);
130 else if (memcmp(keyStr,
"timeout", 7) == 0)
132 if (!cbor_isa_uint(value))
134 WLog_ERR(TAG,
"\"timeout\"is not an unsigned int");
137 out->timeout = WINPR_ASSERTING_INT_CAST(UINT32, cbor_get_int(value));
141 if (memcmp(keyStr,
"transactionId", 13) == 0)
143 if (!cbor_isa_bytestring(value) || cbor_bytestring_length(value) != 16)
145 WLog_ERR(TAG,
"\"transactionId\"is not a 16-byte byte string");
148 memcpy(out->transactionId, cbor_bytestring_handle(value), 16);
149 out->hasTransactionId = TRUE;
157 if (out->command == 0)
159 WLog_ERR(TAG,
"Missing or invalid \"command\" in request");
168 out->request =
nullptr;
176static BOOL wrap_cbor_map_add(cbor_item_t* root, cbor_item_t* diKey, cbor_item_t* diMap)
178 const bool rc = cbor_map_add(root, (
struct cbor_pair){ .key = diKey, .value = diMap });
184wStream* rdpewa_cbor_encode_webauthn_response(HRESULT hresult, BYTE ctapStatus,
185 const BYTE* ctapData,
size_t ctapLen,
189 cbor_item_t* root =
nullptr;
192 WINPR_ASSERT(devInfo);
195 size_t responseLen = 1 + ctapLen;
196 BYTE* responseData = malloc(responseLen);
200 responseData[0] = ctapStatus;
201 if (ctapData && ctapLen > 0)
202 memcpy(responseData + 1, ctapData, ctapLen);
204 root = cbor_new_definite_map(3);
209 cbor_item_t* diKey = cbor_build_string(
"deviceInfo");
210 cbor_item_t* diMap = cbor_new_definite_map(11);
211 if (!diKey || !diMap)
221 cbor_item_t* pairs[][2] = {
222 { cbor_build_string(
"maxMsgSize"),
223 cbor_build_uint16(WINPR_ASSERTING_INT_CAST(uint16_t, devInfo->maxMsgSize)) },
224 { cbor_build_string(
"maxSerializedLargeBlobArray"),
226 WINPR_ASSERTING_INT_CAST(uint16_t, devInfo->maxSerializedLargeBlobArray)) },
227 { cbor_build_string(
"providerType"), cbor_build_string(devInfo->providerType) },
228 { cbor_build_string(
"providerName"), cbor_build_string(devInfo->providerName) },
229 { cbor_build_string(
"devicePath"), cbor_build_string(devInfo->devicePath) },
230 { cbor_build_string(
"Manufacturer"), cbor_build_string(devInfo->manufacturer) },
231 { cbor_build_string(
"Product"), cbor_build_string(devInfo->product) },
232 { cbor_build_string(
"aaGuid"),
233 cbor_build_bytestring(devInfo->aaGuid,
sizeof(devInfo->aaGuid)) },
234 { cbor_build_string(
"uvStatus"), cbor_build_uint8(devInfo->uvStatus) },
235 { cbor_build_string(
"uvRetries"), cbor_build_uint8(devInfo->uvRetries) },
236 { cbor_build_string(
"transports"),
237 cbor_build_uint8(WINPR_ASSERTING_INT_CAST(uint8_t, devInfo->transports)) }
239 for (
size_t i = 0; i < 11; i++)
241 if (!wrap_cbor_map_add(diMap, pairs[i][0], pairs[i][1]))
245 if (!wrap_cbor_map_add(root, diKey, diMap))
249 cbor_item_t* statusKey = cbor_build_string(
"status");
250 cbor_item_t* statusVal = cbor_build_uint8(0);
251 if (!wrap_cbor_map_add(root, statusKey, statusVal))
255 cbor_item_t* respKey = cbor_build_string(
"response");
256 cbor_item_t* respVal = cbor_build_bytestring(responseData, responseLen);
257 if (!wrap_cbor_map_add(root, respKey, respVal))
260 cborLen = cbor_serialized_size(root);
265 s = Stream_New(
nullptr, 4 + cborLen);
269 Stream_Write_UINT32(s, (UINT32)hresult);
270 if (cbor_serialize(root, Stream_Pointer(s), cborLen) == 0)
272 Stream_Free(s, TRUE);
276 Stream_Seek(s, cborLen);
285wStream* rdpewa_cbor_encode_simple_response(HRESULT hresult, UINT32 value)
287 wStream* s = Stream_New(
nullptr, 8);
291 Stream_Write_UINT32(s, (UINT32)hresult);
292 Stream_Write_UINT32(s, value);
296wStream* rdpewa_cbor_encode_hresult_response(HRESULT hresult)
298 wStream* s = Stream_New(
nullptr, 4);
302 Stream_Write_UINT32(s, (UINT32)hresult);
Device info for the response map.
Decoded MS-RDPEWA request message.