Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates authenticity report #285

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions lib/src/signed_video_h26x_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ static const char *kAuthResultValidStr[SV_AUTH_NUM_SIGNED_GOP_VALID_STATES] = {"
"SIGNATURE PRESENT", "NOT OK", "OK WITH MISSING INFO", "OK", "VERSION MISMATCH"};
#endif

/* Before the first SEI/OBU Metadata arrives the hashing algorithm is unknown. While waiting, the
* complete NALU/OBU data is stored. As a result, the memory increases dramatically in particular
* if the stream is not signed. If no SEI/OBU Metadata has arrived after 20 GOPs, the default hash
* is used. This limits the size to a minimum and the operations can proceed. */
#define MAX_UNHASHED_GOPS 20

/**
* The function is called when we receive a SEI NALU holding all the GOP information such as a
* signed hash. The payload is decoded and the signature hash is verified against the gop_hash in
Expand Down Expand Up @@ -504,7 +510,6 @@ verify_hashes_with_sei(signed_video_t *self, int *num_expected_nalus, int *num_r
int num_received_hashes = -1;
char validation_status = 'P';
h26x_nalu_list_item_t *sei = h26x_nalu_list_get_next_sei_item(self->nalu_list);
svrc_t status = SV_UNKNOWN_FAILURE;

bool gop_is_ok = verify_gop_hash(self);
bool order_ok = verify_linked_hash(self);
Expand Down Expand Up @@ -552,7 +557,7 @@ verify_hashes_with_sei(signed_video_t *self, int *num_expected_nalus, int *num_r
if (num_expected_nalus) *num_expected_nalus = num_expected_hashes;
if (num_received_nalus) *num_received_nalus = num_received_hashes;

return (status == SV_OK);
return true;
}

/* Verifying hashes without the SEI means that we have nothing to verify against. Therefore, we mark
Expand Down Expand Up @@ -1093,7 +1098,16 @@ maybe_validate_gop(signed_video_t *self, h26x_nalu_t *nalu)
update_validation_status = true;
}
self->gop_info->verified_signature_hash = -1;
self->validation_flags.has_auth_result = true;
validation_flags->has_auth_result = true;
if (latest->authenticity == SV_AUTH_RESULT_NOT_SIGNED) {
// Only report "stream is unsigned" in the accumulated report.
validation_flags->has_auth_result = false;
}
if (latest->authenticity == SV_AUTH_RESULT_SIGNATURE_PRESENT) {
// Do not report "stream is signed" more than once.
validation_flags->has_auth_result =
latest->authenticity != self->accumulated_validation->authenticity;
}
public_key_has_changed |= latest->public_key_has_changed; // Pass on public key failure.
}

Expand Down Expand Up @@ -1205,10 +1219,11 @@ signed_video_add_h26x_nalu(signed_video_t *self, const uint8_t *nalu_data, size_
// Skip validation if it is done with the legacy code.
if (self->legacy_sv) return SV_OK;

validation_flags_t *validation_flags = &(self->validation_flags);
h26x_nalu_list_t *nalu_list = self->nalu_list;
h26x_nalu_t nalu = parse_nalu_info(nalu_data, nalu_data_size, self->codec, true, true);
DEBUG_LOG("Received a %s of size %zu B", nalu_type_to_str(&nalu), nalu.nalu_data_size);
self->validation_flags.has_auth_result = false;
validation_flags->has_auth_result = false;

self->accumulated_validation->number_of_received_nalus++;

Expand All @@ -1221,22 +1236,24 @@ signed_video_add_h26x_nalu(signed_video_t *self, const uint8_t *nalu_data, size_
// is set accordingly.
SV_THROW(h26x_nalu_list_append(nalu_list, &nalu));
SV_THROW_IF(nalu.is_valid < 0, SV_UNKNOWN_FAILURE);
update_validation_flags(&self->validation_flags, &nalu);
update_validation_flags(validation_flags, &nalu);
SV_THROW(register_nalu(self, nalu_list->last_item));
// As soon as the first Signed Video SEI arrives (|signing_present| is true) and the
// crypto TLV tag has been decoded it is feasible to hash the temporarily stored NAL
// Units.
if (!self->validation_flags.hash_algo_known && self->validation_flags.signing_present &&
is_recurrent_data_decoded(self)) {
if (!self->validation_flags.hash_algo_known) {
if (!validation_flags->hash_algo_known &&
((validation_flags->signing_present && is_recurrent_data_decoded(self)) ||
(nalu_list->num_gops > MAX_UNHASHED_GOPS))) {
if (!validation_flags->hash_algo_known) {
DEBUG_LOG("No cryptographic information found in SEI. Using default hash algo");
self->validation_flags.hash_algo_known = true;
validation_flags->hash_algo_known = true;
}
if (nalu.is_golden_sei) SV_THROW(prepare_golden_sei(self, nalu_list->last_item));

// Determine if legacy validation should be applied, that is, if the legacy way of
// using linked hashes and recursive GOP hash is detected.
if (!(nalu.reserved_byte & 0x30) && !nalu.is_golden_sei) {
if (validation_flags->signing_present &&
(!(nalu.reserved_byte & 0x30) && !nalu.is_golden_sei)) {
self->legacy_sv = legacy_sv_create(self);
SV_THROW_IF(!self->legacy_sv, SV_MEMORY);
accumulated_validation_init(self->accumulated_validation);
Expand All @@ -1249,7 +1266,7 @@ signed_video_add_h26x_nalu(signed_video_t *self, const uint8_t *nalu_data, size_

// Need to make a copy of the |nalu| independently of failure.
svrc_t copy_nalu_status =
h26x_nalu_list_copy_last_item(nalu_list, self->validation_flags.hash_algo_known);
h26x_nalu_list_copy_last_item(nalu_list, validation_flags->hash_algo_known);
// Make sure to return the first failure if both operations failed.
status = (status == SV_OK) ? copy_nalu_status : status;
if (status != SV_OK) {
Expand Down
1 change: 1 addition & 0 deletions lib/src/signed_video_h26x_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct _h26x_nalu_list_t {
h26x_nalu_list_item_t *last_item; // Points to the last item in the linked list, that is, the
// latest NALU added for validation.
int num_items; // The number of items linked together in the list.
int num_gops; // The number of gops linked together in the list, that is, I-frames.
};

/**
Expand Down
4 changes: 4 additions & 0 deletions lib/src/signed_video_h26x_nalu_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ h26x_nalu_list_refresh(h26x_nalu_list_t *list)

// Start from scratch, that is, reset num_items.
list->num_items = 0;
list->num_gops = -1;
// Rewind first_item to get the 'true' first list item.
while (list->first_item && (list->first_item)->prev) {
list->first_item = (list->first_item)->prev;
Expand All @@ -225,6 +226,9 @@ h26x_nalu_list_refresh(h26x_nalu_list_t *list)
h26x_nalu_list_item_t *item = list->first_item;
while (item) {
list->num_items++;
if (item->nalu && item->nalu->is_first_nalu_in_gop) {
list->num_gops++;
}

if (!item->next) break;
item = item->next;
Expand Down
Loading
Loading