Skip to content

Commit

Permalink
Arbitrary message signing simplification
Browse files Browse the repository at this point in the history
Now supports key value reversal. Displays value JSON.
  • Loading branch information
relatko committed Mar 7, 2024
1 parent 60c439b commit 7323729
Show file tree
Hide file tree
Showing 88 changed files with 287 additions and 281 deletions.
34 changes: 13 additions & 21 deletions src/parser_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ parser_error_t json_matchToken(const parsed_json_t *parsedJson,
return PARSER_UNEXPECTED_TYPE;
}

if (token.end < token.start || strlen(expectedValue) != (size_t)(token.end - token.start)) {
if (token.end < token.start || strlen(expectedValue) != (size_t) (token.end - token.start)) {
return PARSER_UNEXPECTED_VALUE;
}

Expand All @@ -211,7 +211,7 @@ parser_error_t json_matchNull(const parsed_json_t *parsedJson, uint16_t tokenIdx
return PARSER_UNEXPECTED_TYPE;
}

if (token.end < token.start || 4 != (size_t)(token.end - token.start)) {
if (token.end < token.start || 4 != (size_t) (token.end - token.start)) {
return PARSER_UNEXPECTED_VALUE;
}

Expand Down Expand Up @@ -299,30 +299,22 @@ parser_error_t json_matchArbitraryKeyValue(const parsed_json_t *parsedJson,
uint16_t *keyTokenIdx,
uint16_t *valueTokenIdx) {
CHECK_PARSER_ERR(json_validateToken(parsedJson, tokenIdx))

if (!(tokenIdx + 4 < parsedJson->numberOfTokens)) {
// we need this token and 4 more
return PARSER_JSON_INVALID_TOKEN_IDX;
}

if (parsedJson->tokens[tokenIdx].type != JSMN_OBJECT) {
return PARSER_UNEXPECTED_TYPE;
return PARSER_JSON_INVALID;
}

if (parsedJson->tokens[tokenIdx].size != 2) {
return PARSER_UNEXPECTED_NUMBER_ITEMS;
uint16_t objectElements = 0;
CHECK_PARSER_ERR(object_get_element_count(parsedJson, tokenIdx, &objectElements));
if (objectElements != 2) {
return PARSER_JSON_INVALID;
}

// Type key/value
CHECK_PARSER_ERR(json_matchToken(parsedJson, tokenIdx + 1, (char *) "type"))
if (parsedJson->tokens[tokenIdx + 2].type != JSMN_STRING) {
CHECK_PARSER_ERR(object_get_value(parsedJson, tokenIdx, "type", keyTokenIdx));
CHECK_PARSER_ERR(object_get_value(parsedJson, tokenIdx, "value", valueTokenIdx));

if (parsedJson->tokens[*keyTokenIdx].type != JSMN_STRING) {
return PARSER_UNEXPECTED_TYPE;
}
CHECK_PARSER_ERR(json_matchToken(parsedJson, tokenIdx + 3, (char *) "value"))

*keyTokenIdx = tokenIdx + 2;
*valueJsonType = parsedJson->tokens[tokenIdx + 4].type;
*valueTokenIdx = tokenIdx + 4;
*valueJsonType = parsedJson->tokens[*valueTokenIdx].type;

return PARSER_OK;
}
Expand Down Expand Up @@ -595,7 +587,7 @@ parser_error_t _countArgumentItems(const flow_argument_list_t *v,
void checkAddressUsedInTx() {
addressUsedInTx = 0;
uint16_t authCount = parser_tx_obj.authorizers.authorizer_count;
for (uint16_t i = 0; i < (uint16_t)(authCount + 2); i++) { //+2 for proposer and payer
for (uint16_t i = 0; i < (uint16_t) (authCount + 2); i++) { //+2 for proposer and payer
parser_context_t *ctx = &parser_tx_obj.payer.ctx;
if (i == authCount) ctx = &parser_tx_obj.proposalKeyAddress.ctx;
if (i < authCount) ctx = &parser_tx_obj.authorizers.authorizer[i].ctx;
Expand Down
278 changes: 46 additions & 232 deletions src/parser_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,19 +280,14 @@ parser_error_t parser_printArgumentArray(const flow_argument_list_t *v,
return PARSER_OK;
}

#define FLAG_IS_NONE 0x1000
#define FLAG_IS_OPTIONAL_NOT_NONE 0x2000
#define FLAG_IS_ARRAY 0x4000
#define FLAGS_FURTHER_SCREENS 0x0FFF
// jsonToken points to thing that is going to be displayed:
// JSMN_ARRAY that contains actual array if it is an array or optional array,
// root JSMN_OBJECT it is optional none or non-optional scalar argument
// nested JSMN_OBJECT for optional scalar arguments
// The function validates json till jsonToken (excluded) but guarantees jsonToken type
parser_error_t parser_printArbitraryPrepareToDisplay(const flow_argument_list_t *v,
uint8_t argIndex,
uint16_t *flags,
uint16_t *jsonToken) {
parser_error_t parser_printArbitraryArgument(const flow_argument_list_t *v,
uint8_t argIndex,
char *outKey,
uint16_t outKeyLen,
char *outVal,
uint16_t outValLen,
uint8_t pageIdx,
uint8_t *pageCount) {
if (argIndex >= v->argCount) {
return PARSER_UNEXPECTED_NUMBER_ITEMS;
}
Expand All @@ -302,205 +297,48 @@ parser_error_t parser_printArbitraryPrepareToDisplay(const flow_argument_list_t
(char *) v->argCtx[argIndex].buffer,
v->argCtx[argIndex].bufferLen));

char bufferUI[ARGUMENT_BUFFER_SIZE_STRING];
*pageCount = 1; // default value

jsmntype_t valueJsonType = JSMN_UNDEFINED;
uint16_t keyTokenElementIdx = 0;
uint16_t valueTokenElementIdx = 0;
CHECK_PARSER_ERR(json_matchArbitraryKeyValue(&parsedJson,
0,
&valueJsonType,
&keyTokenElementIdx,
&valueTokenElementIdx));
uint16_t keyTokenIdx = 0;
uint16_t valueTokenIdx = 0;

const uint16_t baseValueTokenIndex = valueTokenElementIdx;
CHECK_PARSER_ERR(
json_matchArbitraryKeyValue(&parsedJson, 0, &valueJsonType, &keyTokenIdx, &valueTokenIdx));

switch (valueJsonType) {
case JSMN_ARRAY: // array
CHECK_PARSER_ERR(json_matchToken(&parsedJson, keyTokenElementIdx, "Array"));
CHECK_PARSER_ERR(array_get_element_count(&parsedJson, valueTokenElementIdx, flags));
_Static_assert(FLAGS_FURTHER_SCREENS > MAX_JSON_ARRAY_TOKEN_COUNT,
"Flags for further screens too small");
if (*flags > MAX_JSON_ARRAY_TOKEN_COUNT) {
return PARSER_TOO_MANY_ARGUMENTS;
case JSMN_PRIMITIVE:
case JSMN_STRING:
case JSMN_OBJECT:
case JSMN_ARRAY:;
parser_error_t err =
json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, keyTokenIdx);
if (err != PARSER_OK && err != PARSER_UNEXPECTED_BUFFER_END) {
return err;
}
*flags = (*flags & FLAGS_FURTHER_SCREENS) | FLAG_IS_ARRAY;
*jsonToken = valueTokenElementIdx;
return PARSER_OK;
case JSMN_STRING: // value
*flags = 0;
*jsonToken = 0;
return PARSER_OK;
case JSMN_PRIMITIVE: // optional null
*flags = FLAG_IS_NONE;
*jsonToken = 0;
return PARSER_OK;
case JSMN_OBJECT: // optional not null
CHECK_PARSER_ERR(json_matchToken(&parsedJson, keyTokenElementIdx, "Optional"));
CHECK_PARSER_ERR(json_matchArbitraryKeyValue(&parsedJson,
baseValueTokenIndex,
&valueJsonType,
&keyTokenElementIdx,
&valueTokenElementIdx));
switch (valueJsonType) {
case JSMN_ARRAY: // array
CHECK_PARSER_ERR(json_matchToken(&parsedJson, keyTokenElementIdx, "Array"));
CHECK_PARSER_ERR(
array_get_element_count(&parsedJson, valueTokenElementIdx, flags));
_Static_assert(FLAGS_FURTHER_SCREENS > MAX_METADATA_MAX_ARRAY_ITEMS,
"Flags for further screens too small");
if (*flags > MAX_METADATA_MAX_ARRAY_ITEMS) {
return PARSER_TOO_MANY_ARGUMENTS;
}
*flags = (*flags & FLAGS_FURTHER_SCREENS) | FLAG_IS_ARRAY |
FLAG_IS_OPTIONAL_NOT_NONE;
*jsonToken = valueTokenElementIdx;
return PARSER_OK;
case JSMN_STRING: // value
*flags = FLAG_IS_OPTIONAL_NOT_NONE;
*jsonToken = baseValueTokenIndex;
return PARSER_OK;
default:
return PARSER_JSON_INVALID;
// Key to long
if (err == PARSER_UNEXPECTED_BUFFER_END) {
snprintf(outKey, outKeyLen, "%d: <Long type name>", (int) (argIndex + 1));
} else {
int written = snprintf(outKey, outKeyLen, "%d: %s", (int) (argIndex + 1), bufferUI);
if (written < 0 || written >= outKeyLen) { // Error or buffer overflow
snprintf(outKey, outKeyLen, "%d: <Long type name>", (int) (argIndex + 1));
}
}
default:
return PARSER_JSON_INVALID;
}
}

parser_error_t parser_printArbitraryArgumentFirstScreen(const flow_argument_list_t *v,
uint8_t argIndex,
uint16_t flags,
uint16_t jsonToken,
char *outKey,
uint16_t outKeyLen,
char *outVal,
uint16_t outValLen,
uint8_t pageIdx,
uint8_t *pageCount) {
if (argIndex >= v->argCount) {
return PARSER_UNEXPECTED_NUMBER_ITEMS;
}

parsed_json_t parsedJson = {false};
CHECK_PARSER_ERR(json_parse(&parsedJson,
(char *) v->argCtx[argIndex].buffer,
v->argCtx[argIndex].bufferLen));

if (jsonToken >= parsedJson.numberOfTokens) {
return PARSER_JSON_INVALID_TOKEN_IDX;
}

char bufferUI[ARGUMENT_BUFFER_SIZE_STRING];
*pageCount = 1; // default value

if (flags & FLAG_IS_ARRAY) {
const uint16_t arrayElements = flags & FLAGS_FURTHER_SCREENS;
snprintf(outKey,
outKeyLen,
"%d: %s",
(int) (argIndex + 1),
(flags & FLAG_IS_OPTIONAL_NOT_NONE) ? "Opt. Array" : "Array");
snprintf(outVal, outValLen, "Length: %d", (int) arrayElements);
return PARSER_OK;
} else { // Not an array
jsmntype_t valueJsonType = JSMN_UNDEFINED;
uint16_t keyTokenIdx = 0;
uint16_t valueTokenIdx = 0;
if (flags & FLAG_IS_NONE) {
CHECK_PARSER_ERR(json_matchOptionalKeyValue(&parsedJson,
jsonToken,
"",
JSMN_STRING,
&valueTokenIdx));
if (valueTokenIdx != JSON_MATCH_VALUE_IDX_NONE) {
return PARSER_JSON_INVALID;
err = json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, valueTokenIdx);
if (err != PARSER_OK && err != PARSER_UNEXPECTED_BUFFER_END) {
return err;
}
snprintf(outKey, outKeyLen, "%d: Optional", (int) (argIndex + 1));
snprintf(outVal, outValLen, "None");
return PARSER_OK;
} else {
CHECK_PARSER_ERR(json_matchArbitraryKeyValue(&parsedJson,
jsonToken,
&valueJsonType,
&keyTokenIdx,
&valueTokenIdx));
if (valueJsonType != JSMN_STRING) {
return PARSER_JSON_INVALID;
if (err == PARSER_UNEXPECTED_BUFFER_END) {
snprintf(bufferUI, sizeof(bufferUI), "<Value too long>");
}
CHECK_PARSER_ERR(
json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, keyTokenIdx))
snprintf(outKey,
outKeyLen,
"%d: %s%s",
(int) (argIndex + 1),
bufferUI,
(flags & FLAG_IS_OPTIONAL_NOT_NONE) ? "?" : "");
CHECK_PARSER_ERR(
json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, valueTokenIdx))
pageString(outVal, outValLen, bufferUI, pageIdx, pageCount);
return PARSER_OK;
}
}
return PARSER_JSON_UNEXPECTED_ERROR;
}

parser_error_t parser_printArbitraryArrayElements(const flow_argument_list_t *v,
uint8_t argIndex,
uint16_t arrayIndex,
uint16_t arrayJsonToken,
char *outKey,
uint16_t outKeyLen,
char *outVal,
uint16_t outValLen,
uint8_t pageIdx,
uint8_t *pageCount) {
if (argIndex >= v->argCount) {
return PARSER_UNEXPECTED_NUMBER_ITEMS;
}

parsed_json_t parsedJson = {false};
CHECK_PARSER_ERR(json_parse(&parsedJson,
(char *) v->argCtx[argIndex].buffer,
v->argCtx[argIndex].bufferLen));
if (arrayJsonToken >= parsedJson.numberOfTokens) {
return PARSER_JSON_INVALID_TOKEN_IDX;
}

uint16_t arrayLen = 0;
CHECK_PARSER_ERR(array_get_element_count(&parsedJson, arrayJsonToken, &arrayLen));
if (arrayIndex >= arrayLen) {
return PARSER_JSON_INVALID_TOKEN_IDX;
}

uint16_t arrayElementToken = 0;
CHECK_PARSER_ERR(
array_get_nth_element(&parsedJson, arrayJsonToken, arrayIndex, &arrayElementToken))

jsmntype_t valueJsonType = JSMN_UNDEFINED;
uint16_t keyTokenElementIdx = 0;
uint16_t valueTokenElementIdx = 0;
CHECK_PARSER_ERR(json_matchArbitraryKeyValue(&parsedJson,
arrayElementToken,
&valueJsonType,
&keyTokenElementIdx,
&valueTokenElementIdx));

if (valueJsonType != JSMN_STRING) {
return PARSER_JSON_INVALID;
default:
return PARSER_JSON_INVALID;
}

char bufferUI[ARGUMENT_BUFFER_SIZE_STRING];

CHECK_PARSER_ERR(json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, keyTokenElementIdx))
snprintf(outKey,
outKeyLen,
"%d: %s %d",
(int) (argIndex + 1),
bufferUI,
(int) (arrayIndex + 1));
CHECK_PARSER_ERR(
json_extractToken(bufferUI, sizeof(bufferUI), &parsedJson, valueTokenElementIdx))
pageString(outVal, outValLen, bufferUI, pageIdx, pageCount);
return PARSER_OK;
}

parser_error_t parser_printBlockId(const flow_reference_block_id_t *v,
Expand Down Expand Up @@ -775,39 +613,15 @@ parser_error_t parser_getItem_internal(int8_t *displayIdx,
return PARSER_OK;
}
for (size_t i = 0; i < parser_tx_obj.arguments.argCount; i++) {
uint16_t flags = 0;
uint16_t jsonToken = 0;
CHECK_PARSER_ERR(parser_printArbitraryPrepareToDisplay(&parser_tx_obj.arguments,
i,
&flags,
&jsonToken));
SCREEN(true) {
return parser_printArbitraryArgumentFirstScreen(&parser_tx_obj.arguments,
i,
flags,
jsonToken,
outKey,
outKeyLen,
outVal,
outValLen,
pageIdx,
pageCount);
}
if (flags & FLAG_IS_ARRAY) {
for (size_t j = 0; j < (flags & FLAGS_FURTHER_SCREENS); j++) {
SCREEN(true) {
return parser_printArbitraryArrayElements(&parser_tx_obj.arguments,
i,
j,
jsonToken,
outKey,
outKeyLen,
outVal,
outValLen,
pageIdx,
pageCount);
}
}
return parser_printArbitraryArgument(&parser_tx_obj.arguments,
i,
outKey,
outKeyLen,
outVal,
outValLen,
pageIdx,
pageCount);
}
}
}
Expand Down
Loading

0 comments on commit 7323729

Please sign in to comment.