Retrieve pointer and length of sub message in source buffer

200 views
Skip to first unread message

Elliot Makuh

unread,
Aug 30, 2022, 11:36:38 AM8/30/22
to nanopb
I need to retrieve the encoded length and pointer to the start of a sub message in an encoded byte blob.

For some background: I am interfacing with a third party SDK that provides a proto message with a SHA256 signature calculated over a portion of the encoded message.

When I receive the message I want to be able to re-calculate the signature over the encoded bytes to ensure it matches the signature in the protobuf.
Here is a simplified version of the proto message:

message command {
    optional uint32             field1      = 1;
    optional uint32             field2      = 2;
    repeated uint32             field3      = 3 [packed = true];
}

message SignedCommand {
    required Command        command          = 1;
    required bytes          sha256_signature = 2;
}


As mentioned above I want to re-calculate the SHA256 checksum of the encoded command bytes and compare it to sha256_signature to ensure command is valid.

In order to do this I'll need a pointer to the start of command as well as the encoded length of command in the source buffer.  I am wondering if there is a way to use field callbacks to get this information but I haven't been successful in doing this.

Does anyone have thoughts or ideas of how I could get a pointer to and length of the encoded bytes of the command field?

Best regards,
Elliot

Petteri Aimonen

unread,
Aug 30, 2022, 1:42:59 PM8/30/22
to nan...@googlegroups.com
Hi,

If you are using pb_istream_from_buffer(), you can get the pointer to
the data from stream.state. In a submessage callback, the length of the
stream is the length of the message data.

Using 0.4.x style callbacks I would do it this way:

message SignedCommand {
required Command command = 1
[(nanopb).type = FT_CALLBACK,
(nanopb).callback_datatype = "struct location_t { uint8_t *start; uint32_t len; }",
(nanopb).callback_function = "SignedCommand_Command_callback"
];
required bytes sha256_signature = 2
[(nanopb).max_size = 32, (nanopb).fixed_length = true];
}

bool SignedCommand_Command_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
{
if (istream)
{
// Store the location of data
struct location_t *dest = (struct location_t*)field->pData;
dest->start = (uint8_t*)istream->state;
dest->len = istream->bytes_left;
}
return true;
}

The struct definition in generated .pb.h file will be like this:

typedef struct _SignedCommand {
struct location_t { uint8_t *start; uint32_t len; } command;
pb_byte_t sha256_signature[32];
} SignedCommand;

The callback is bound by name, and the message will have fields
msg.command.start and msg.command.len which are filled in after the
decoding.

You can then proceed to check the hash and after that decode the
submessage by passing the start and length to a new call of
pb_istream_from_buffer().

If you are on 0.3.x or prefer function pointer callbacks, the idea is
the same except you need to use the arg pointer to store the results
somewhere.

--
Petteri

Elliot Makuh

unread,
Aug 30, 2022, 3:50:03 PM8/30/22
to nanopb
Thank you for the feedback!  Unfortunately I am unable to modify the structure of the proto as it is provided by the third party SDK.  What I ended up doing was enabling a sub message callback for the command message.  In the sub message decoder callback I am checking to see if the field tag matches the sub message I am interested in and then using stream->state and stream->bytes_left as the address and length of the sub message.  This approach required the least number of modifications to the SDK and seems to work with the rest of their code.

Thanks for the suggestion as that help me understand how to solve the problem I was having!

Petteri Aimonen

unread,
Aug 31, 2022, 2:24:39 AM8/31/22
to nan...@googlegroups.com
Hi,

> Unfortunately I am unable to modify the
> structure of the proto as it is provided by the third party SDK.

Do note that all the options can be applied using a separate .options
file, avoiding the need to modify the proto file:
https://jpa.kapsi.fi/nanopb/docs/reference.html#defining-the-options-in-a-.options-file

--
Petteri
Reply all
Reply to author
Forward
0 new messages