From a1ff38ee1a9c085cd79b7fcd952b4696910fd167 Mon Sep 17 00:00:00 2001 From: bjornvolcker Date: Tue, 17 Dec 2024 15:39:06 +0100 Subject: [PATCH] Updates public APIs and READMEs wrt AV1 --- README.md | 2 +- feature-description.md | 46 +++--- lib/README.md | 10 +- lib/src/README.md | 22 +-- lib/src/includes/signed_video_auth.h | 117 +++++++------- lib/src/includes/signed_video_common.h | 24 +-- lib/src/includes/signed_video_sign.h | 208 +++++++++++++------------ tests/README.md | 2 +- 8 files changed, 221 insertions(+), 210 deletions(-) diff --git a/README.md b/README.md index b4100f41..c37dece4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ *Copyright (C) 2021, Axis Communications AB, Lund, Sweden. All Rights Reserved.* # Signed Video Framework -This repository holds the framework code of the feature Signed Video. The Signed Video feature secures the video from tampering after signing by adding cryptographic signatures to the video. Each video frame is hashed and signatures are generated repeatedly based on these hashes using a private key set by the signer. The signature data added to the video does not affect the video rendering. The data is added in a Supplemental Enhancement Information (SEI) NALU with type "user data unregistered". This SEI has a UUID of `5369676e-6564-2056-6964-656f2e2e2e30` in hexadecimal. +This repository holds the framework code of the feature Signed Video. The Signed Video feature secures the video from tampering after signing by adding cryptographic signatures to the video. Each video frame is hashed and signatures are generated repeatedly based on these hashes using a private key set by the signer. The signature data added to the video does not affect the video rendering. The data is added in a Supplemental Enhancement Information (SEI) NALU with type "user data unregistered" (OBU Metadata of type "user private" for AV1). This SEI has a UUID of `5369676e-6564-2056-6964-656f2e2e2e30` in hexadecimal. A more detailed description of the Signed Video feature is found in [feature-description](./feature-description.md). diff --git a/feature-description.md b/feature-description.md index f71c72ca..24737f63 100644 --- a/feature-description.md +++ b/feature-description.md @@ -14,32 +14,32 @@ A video consists of picture frames displayed at a certain frame rate. If these f In brief, the principle of signing documents is used, that is, collect information and sign the information using a Private encryption key. Then, packetize the produced signature together with some additional information. For validation, the user can then verify the information by using the signature and the corresponding Public key. -On a high level, *Signed Video* hashes encoded video frames and on a regular basis creates a `document` representing these hashes and signs that `document`. This signature, together with the `document`, is added to the video using Supplementary Enhancement Information (SEI) frames. +On a high level, *Signed Video* hashes encoded video frames and on a regular basis creates a `document` representing these hashes and signs that `document`. This signature, together with the `document`, is added to the video using Supplementary Enhancement Information (SEI) frames, or OBU Metadata for AV1. ## Limitations and properties -*Signed Video* is currently only available for the video codec formats H264 and H265. Therefore, most of the description uses the Network Abstraction Layer (NAL) concept. Note that raw videos are not supported. +*Signed Video* is currently only available for the video codec formats H.264, H.265 and AV1. Therefore, most of the description uses the Network Abstraction Layer (NAL) and OBU concept. Note that raw videos are not supported. Signing frequency. Signing is done upon transition between two Group of Pictures (GOP). For short GOP lengths the time between two GOP transitions may be shorter than the time it takes to perform the signing. Hence, there is a limit on how short GOPs the framework can allow for to be able to sign a video in real-time. -Authenticity level. *Signed Video* supports two levels of authenticity; GOP level and NALU level. For GOP level, all frames between two signatures are treated in one single chunk and if the validation fails, all these frames are marked as not authentic even if it is due to a lost frame. For NALU level the framework can identify which frames are authentic or not, or even lost. This means that frame drops can be handled, but not packet losses. Losing packets in general means losing parts of a frame, hence is equivalent with modifying a frame. The cost for validating the authenticity of each individual NAL is an increase in bitrate. +Authenticity level. *Signed Video* supports two levels of authenticity; GOP level and NALU/OBU level. For GOP level, all frames between two signatures are treated in one single chunk and if the validation fails, all these frames are marked as not authentic even if it is due to a lost frame. For NALU/OBU level the framework can identify which frames are authentic or not, or even lost. This means that frame drops can be handled, but not packet losses. Losing packets in general means losing parts of a frame, hence is equivalent with modifying a frame. The cost for validating the authenticity of each individual NAL is an increase in bitrate. ## Detailed description -As mentioned, the framework currently only supports H264 and H265. These codec formats allow the user to add arbitrary data to a stream through SEI frames of type *user data unregistered*. *Signed Video* puts the produced signatures and additional metadata in such frames. These SEI frames are ignored by the decoder and will therefore not affect the video rendering. -One obvious drawback is that it is easy to destroy the signed video and make it unsigned by simply dropping those SEI frames. In some cases this can also be beneficial if, e.g., the user is no longer interested in its authenticity. -It is out of scope to protect against lost SEI frames. +As mentioned, the framework currently only supports H.264, H.265 and AV1. These codec formats allow the user to add arbitrary data to a stream through SEI/OBU Metadata frames of type *user data unregistered*/*user private*. *Signed Video* puts the produced signatures and additional metadata in such frames. These SEI/OBU Metadata frames are ignored by the decoder and will therefore not affect the video rendering. +One obvious drawback is that it is easy to destroy the signed video and make it unsigned by simply dropping those SEI/OBU Metadata frames. In some cases this can also be beneficial if, e.g., the user is no longer interested in its authenticity. +It is out of scope to protect against lost SEI/OBU Metadata frames. -All operations are done on the encoded video stream. Each picture frame is split into NAL Units (NALU) and *Signed Video* operates on these NALUs. NALUs that are not part of a picture frame are ignored. These NALUs are +All operations are done on the encoded video stream. Each picture frame is split into NAL Units (NALU) (OBU for AV1) and *Signed Video* operates on these NALUs/OBUs. NALUs/OBUs that are not part of a picture frame are ignored. These NALUs/OBUs are - SPS/PPS/VPS -- AUD -- SEIs other than Signed Video specific +- AUD/SH +- SEIs other than Signed Video specific (for H.264 and H.265) Note that these can still affect the visual aspect of a video. ### Signing a GOP Without loss of generality, consider three consecutive GOPs each starting with an IDR (I-frame) followed by 4 non-IDRs (P-frames). In text format it would look like `IPPPPIPPPPIPPPP`. -The signing information is collected in a SEI frame (`S`) and put just before the picture frame to follow the Access Unit (AU) format. Each I-frame will trigger a signing procedure and ideally the SEI is generated and available instantaneously and can be attached to the stream as `SIPPPPSIPPPPSIPPPP`. +The signing information is collected in a SEI frame (`S`) and put just before the picture frame to follow the Access Unit (AU) format. Each I-frame will trigger a signing procedure and ideally the SEI/OBU Metadata is generated and available instantaneously and can be attached to the stream as `SIPPPPSIPPPPSIPPPP`. -Each NALU is hashed using SHA-256, but not in a straightforward manner. Since every P-frame directly or indirectly refers to the I-frame starting the GOP they are linked together. Let `h(F)` denote the hash of a frame `F`, and `href = h(I)` is the hash of the first I-frame in a GOP and used as reference. Then each frame in a GOP is hashed according to `hash(F) = h(href, h(F))` where `href` and `h(F)` have been aligned in memory. +Each NALU/OBU is hashed using SHA-256, but not in a straightforward manner. Since every P-frame directly or indirectly refers to the I-frame starting the GOP they are linked together. Let `h(F)` denote the hash of a frame `F`, and `href = h(I)` is the hash of the first I-frame in a GOP and used as reference. Then each frame in a GOP is hashed according to `hash(F) = h(href, h(F))` where `href` and `h(F)` have been aligned in memory. All hashes are collected in a list and together with some metadata form a `document`, which later will be signed. To preserve the order of GOPs the I-frame of the next GOP is also include in the list of hashes, that is, `hash(Inext) = h(href, h(Inext))` is added as well. @@ -48,21 +48,15 @@ This `document` is then hashed, denoted _gop hash_ (`= h(document)`), and signed `signature = sign(h(document))` -and together with the `document` itself is added to the stream in a SEI, that is, SEI = `document + signature`. +and together with the `document` itself is added to the stream in a SEI/OBU Metadata, that is, SEI = `document + signature`. After signing, the next GOP is then initiated with a new `href` using the very same I-frame that closed the previous GOP. For the end user to validate the authenticity of a signed video the public key, associated with the private key used when signing, is needed. The *Signed Video Framework* supports including the public key as part of the metadata. This simplifies validating the authenticity of the video, but requires a separate logic to verify its origin. #### Signing at GOP authenticity level -Transmitting the list of hashes can be too expensive in terms of an increased bitrate. The *Signed Video Framework* therefore offer a light version in GOP level as authenticitiy level. Instead of transmitting the hash list a single hash representing all the frames and the metadata is computed. This single hash is implemented recursively and is then signed. +Transmitting the list of hashes can be too expensive in terms of an increased bitrate. The *Signed Video Framework* therefore offer a light version in GOP level as authenticitiy level. Instead of transmitting the hash list a single hash representing all the frames and the metadata is computed. This single hash is a hash of all the hashes in the GOP and is then signed. +The GOP hash is initialized with a hashed salt `hash(0) = h(salt)`. -The recursive operation is initialized with a hashed salt `hash(0) = h(salt)`. The next step is to add `href` as `hash(1) = h(hash(0), href)` and the n'th hash becomes `hash(n) = h(hash(n-1), hash(F_n))`, where `F_n` is the frame that produced the n'th hash. The last frame added to the recursive hash is `Inext` and a `document` is created just like above, but now without the hash list, hence it includes the metadata only. -The recursive hash is then finalized with the hash of this `document` which now becomes the _gop hash_ - -`hash(gop) = h(hash(N), hash(document))` - -The _gop hash_ is then signed by generating a signature. Combine the metadata, which by definition is the `document`, and the signature to form the SEI = `document + signature` where `signature = sign(hash(gop))` - -For NALU level and long GOP lengths, *Signed Video* automatically falls back to GOP level to avoid very large SEI frames. +For NALU/OBU level and long GOP lengths, *Signed Video* automatically falls back to GOP level to avoid very large SEI frames. ### Metadata Part from the public key it is possible to add some signer specific information. That information is today locked to the fields @@ -72,7 +66,7 @@ Part from the public key it is possible to add some signer specific information. - Manufacturer (Who is the signer, for example Axis Communication AB) - Address (Contact information of signer, e.g., url, email, mail) -### SEI format +### SEI/OBU Metadata format The framework uses the *user data unregistered* type of SEIs. These are organized as `| NALU header | payload size | UUID | payload | stop bit |` @@ -85,5 +79,11 @@ The UUID is used to put a *Signed Video* identity to the SEI. The payload includ By definition the `document` includes everything from the NALU header to the signature tag, hence the entire frame is secured. +For AV1 this looks like +`| OBU header | payload size | metadata type | UUID | metadata | list of hashes | signature | stop bit |` + +`| -------------------------------- document ---------------------------------- | signature | stop bit |` + + ### Signing in a secure hardware -When signing in hardware the signing itself may take some time and to avoid piling up frames *Signed Video Framework* supports the SEI frames being added at a later stage, but no later than at the next signing request. Using the example above, a signed video segment could look like `IPSPPPIPPPPSIPPPSP` where the `S`s show up delayed compared to the ideal case `SIPPPPSIPPPPSIPPPP`. +When signing in hardware the signing itself may take some time and to avoid piling up frames *Signed Video Framework* supports the SEI/OBU Metadata frames being added at a later stage, but no later than at the next signing request. Using the example above, a signed video segment could look like `IPSPPPIPPPPSIPPPSP` where the `S`s show up delayed compared to the ideal case `SIPPPPSIPPPPSIPPPP`. diff --git a/lib/README.md b/lib/README.md index 21c5d8e4..c210b2aa 100644 --- a/lib/README.md +++ b/lib/README.md @@ -27,8 +27,8 @@ plugin. The interfaces can be found in with both a threaded and an unthreaded signing plugin. When building the library with the meson structure in this repository, the library includes that plugin. -Vendor specific code and APIs are typically handling extra metadata added to the SEI, which needs to -be interpreted correctly when validating authenticity. With the meson option `vendor` the user can -select which vendor(s) to include in the build. Typically, when building for signing the vendor for -that camera is selected, whereas when building for validation all vendors are included. By default, -all vendors are added. +Vendor specific code and APIs are typically handling extra metadata added to the SEI/OBU Metadata, +which needs to be interpreted correctly when validating authenticity. With the meson option `vendor` +the user can select which vendor(s) to include in the build. Typically, when building for signing +the vendor for that camera is selected, whereas when building for validation all vendors are +included. By default, all vendors are added. diff --git a/lib/src/README.md b/lib/src/README.md index d89fc559..531e411f 100644 --- a/lib/src/README.md +++ b/lib/src/README.md @@ -6,24 +6,24 @@ APIs needed are located in [includes/](./includes/). ## Making your own validation application The APIs needed are [signed_video_common.h](./includes/signed_video_common.h) and -[signed_video_auth.h](./includes/signed_video_auth.h). To validate a H264 or H265 video you need to -split the video into NAL Units. For a detailed description and example code see +[signed_video_auth.h](./includes/signed_video_auth.h). To validate a H.264, H.265 or AV1 video you +need to split the video into NAL Units/OBUs. For a detailed description and example code see [signed_video_auth.h](./includes/signed_video_auth.h) or look at the validator in the [signed-video-framework-examples](https://github.com/AxisCommunications/signed-video-framework-examples) repository. ## Making your own signing application The APIs needed are [signed_video_common.h](./includes/signed_video_common.h) and -[signed_video_sign.h](./includes/signed_video_sign.h). To sign a H264 or H265 video you need to -split the video into NAL Units. Before signing can begin you need to configure the Signed Video -session. Setting a private key is mandatory, but there are also possibilities to add some product -information and what level of authentication to use. The public key, needed for validation, is -automatically added to the stream. +[signed_video_sign.h](./includes/signed_video_sign.h). To sign a H.264, H.265 or AV1 video you need +to split the video into NAL Units/OBUs. Before signing can begin you need to configure the Signed +Video session. Setting a private key is mandatory, but there are also possibilities to add some +product information and what level of authentication to use. The public key, needed for validation, +is automatically added to the stream. -The Signed Video Framework generates SEI frames including signatures and other information. Getting -them and instructions on how to add them to the current stream are handled through the API -`signed_video_get_nalu_to_prepend()`. Note that the framework follows the Access Unit format of -H264, hence SEI frames must prepend the current picture frame. +The Signed Video Framework generates SEI/OBU Metadata frames including signatures and other +information. Getting them and instructions on how to add them to the current stream are handled +through the API `signed_video_get_nalu_to_prepend()`. Note that the framework follows the Access +Unit format of H.264, hence SEI frames must prepend the current picture frame. For a detailed description and example code see [signed_video_sign.h](./includes/signed_video_sign.h) or look at the signer in the diff --git a/lib/src/includes/signed_video_auth.h b/lib/src/includes/signed_video_auth.h index 98fa345a..ebed1519 100644 --- a/lib/src/includes/signed_video_auth.h +++ b/lib/src/includes/signed_video_auth.h @@ -37,18 +37,19 @@ extern "C" { */ typedef enum { SV_AUTH_RESULT_NOT_SIGNED = 0, - // The consumed NALUs so far contain no signature information. + // The consumed NALUs/OBUs so far contain no signature information. SV_AUTH_RESULT_SIGNATURE_PRESENT = 1, // Signed video has been detected present, but there is not enough information to complete a // validation. This state is shown until validation has been performed. SV_AUTH_RESULT_NOT_OK = 2, - // At least one NALU failed verification. + // At least one NALU/OBU failed verification. SV_AUTH_RESULT_OK_WITH_MISSING_INFO = 3, - // Successfully verified all NALUs that could be verified, but missing NALUs were detected. + // Successfully verified all NALUs/OBUs that could be verified, but missing NALUs were detected. // Further actions need to be taken to judge these losses and complete the authenticity // validation. SV_AUTH_RESULT_OK = 4, - // Successfully verified all NALUs that could be verified, and all expected NALUs are present. + // Successfully verified all NALUs/OBUs that could be verified, and all expected NALUs/OBUs are + // present. SV_AUTH_RESULT_VERSION_MISMATCH = 5, // Video has been signed with a version newer than that used by the validation part. Correct // validation cannot be guaranteed. The user is encouraged to update the validation code with a @@ -64,8 +65,8 @@ typedef enum { // There are no means to verify the public key. This happens if no attestation exists or if the // public key was not part of the stream. SV_PUBKEY_VALIDATION_NOT_OK = 1, - // The Public key in the SEI was not validated successfully. The video might be correct, but its - // origin could not be verified. + // The Public key in the SEI/OBU Metadata was not validated successfully. The video might be + // correct, but its origin could not be verified. SV_PUBKEY_VALIDATION_OK = 2, // The Public key in the stream was validated successfully. The origin of the key is correct and // trustworthy when validating the video. @@ -84,7 +85,7 @@ typedef struct { int number_of_expected_picture_nalus; // Indicates how many picture NALUs (i.e., excluding SEI, PPS/SPS/VPS, AUD) were expected, and // part of the signature, since last validation. A negative value indicates that such information - // is lacking due to a missing, or tampered, SEI. + // is lacking due to a missing, or tampered, SEI/OBU Metadata. int number_of_received_picture_nalus; // Indicates how many picture NALUs (i.e., excluding SEI, PPS/SPS/VPS, AUD) have been received // since last validation, and used to verify the signature. If the signed video feature is @@ -93,21 +94,23 @@ typedef struct { // Indicates how many picture NALUs (i.e., excluding SEI, PPS/SPS/VPS, AUD) are pending // validation. char *validation_str; - // A string displaying the validation status of all the latest NALUs. The string ends with a null - // terminated character. The validated NALUs are removed after fetching the authenticity_report. - // This means that the user can count backwards from the latest/current NALU and verify each - // NALU's authenticity individually. Each NALU is marked by one of these characters: - // 'P' : Pending validation. This is the initial value. The NALU has been registered and waiting - // for authenticity validation. - // 'U' : The NALU has an unknown authenticity. This occurs if the NALU could not be parsed, or if - // : the SEI is associated with NALUs not part of the validating segment. - // '_' : The NALU is ignored and therefore not part of the signature. The NALU has no impact on - // the video and is validated as authentic. - // '.' : The NALU has been validated as authentic. - // 'N' : The NALU has been validated as not authentic. - // 'M' : The validation has detected one or more missing NALUs at this position. + // A string displaying the validation status of all the latest NALUs/OBUs. The string ends with a + // null terminated character. The validated NALUs/OBUs are removed after fetching the + // authenticity_report. + // This means that the user can count backwards from the latest/current NALU/OBU and verify each + // NALU/OBU's authenticity individually. Each NALU/OBU is marked by one of these characters: + // 'P' : Pending validation. This is the initial value. The NALU/OBU has been registered and + // waiting for authenticity validation. + // 'U' : The NALU/OBU has an unknown authenticity. This occurs if the NALU/OBU could not be + // parsed, or if the SEI/OBU Metadata is associated with NALUs/OBUs not part of the + // validating segment. + // '_' : The NALU/OBU is ignored and therefore not part of the signature. The NALU/OBU has no + // impact on the video and is validated as authentic. + // '.' : The NALU/OBU has been validated as authentic. + // 'N' : The NALU/OBU has been validated as not authentic. + // 'M' : The validation has detected one or more missing NALUs/OBUs at this position. // 'E' : An error occurred and validation could not be performed. This should be treated as an - // invalid NALU. + // invalid NALU/OBU. // Example: // Two consecutive |validation_str|. After 10 NALUs a authentication result was received @@ -120,20 +123,20 @@ typedef struct { // ._....PP. char *nalu_str; // As a complement to the validation_str above, this string displays the type of all the latest - // NALUs. The string ends with a null terminated character. Each NALU is marked by one of these - // characters: + // NALUs/OBUs. The string ends with a null terminated character. Each NALU/OBU is marked by one of + // these characters: // 'I' : I-frame (primary slice) // 'i' : I-frame (not primary slice) // 'P' : P-frame (primary slice) // 'p' : P-frame (not primary slice) - // 'S' : SEI, generated by Signed Video including a signature - // 's' : SEI, generated by Signed Video not including a signature - // 'z' : SEI, other type than Signed Video generated - // 'v' : Parameter Set NALU, i.e., SPS/PPS/VPS - // '_' : AUD - // 'o' : Other valid type of NALU - // 'U' : Undefined NALU - // ' ' : No NALU present, e.g., when missing NALUs are detected + // 'S' : SEI/OBU Metadata, generated by Signed Video including a signature + // 's' : SEI/OBU Metadata, generated by Signed Video not including a signature + // 'z' : SEI/OBU Metadata, other type than Signed Video generated + // 'v' : Parameter Set NALU/OBU, i.e., SPS/PPS/VPS, SH + // '_' : AUD/TD + // 'o' : Other valid type of NALU/OBU + // 'U' : Undefined NALU/OBU + // ' ' : No NALU/OBU present, e.g., when missing NALUs/OBU are detected // Example: // Complementing the example above. @@ -142,13 +145,14 @@ typedef struct { // IzPSPPIPS // ._....PP. SignedVideoPublicKeyValidation public_key_validation; - // The result of the latest Public key validation. If the Public key is present in the SEI, it has - // to be validated to associate the video with a source. If it is not feasible to validate the - // Public key, it should be validated manually to secure proper video authenticity. + // The result of the latest Public key validation. If the Public key is present in the + // SEI/OBU Metadata, it has to be validated to associate the video with a source. If it is not + // feasible to validate the Public key, it should be validated manually to secure proper video + // authenticity. bool has_timestamp; // True if the timestamp member is valid to look at, false otherwise. int64_t timestamp; - // Unix epoch UTC timestamp in microseconds of the latest signed NALU. + // Unix epoch UTC timestamp in microseconds of the latest signed NALU/OBU. } signed_video_latest_validation_t; /** @@ -162,22 +166,22 @@ typedef struct { // A new Public key has been detected. Signing an ongoing stream with a new key is not allowed. If // this flag is set the |authenticity| is automatically set to SV_AUTH_RESULT_NOT_OK. unsigned int number_of_received_nalus; - // Total number of received NALUs, that is all NALUs added for validation. + // Total number of received NALUs/OBUs, that is all NALUs/OBUs added for validation. unsigned int number_of_validated_nalus; - // Total number of validated NALUs, that is, how many of the received NALUs that so far have been - // validated. + // Total number of validated NALUs/OBUs, that is, how many of the received NALUs/OBUs that so far + // have been validated. unsigned int number_of_pending_nalus; - // The number of NALUs that currently are pending validation. + // The number of NALUs/OBUs that currently are pending validation. SignedVideoPublicKeyValidation public_key_validation; - // The result of the Public key validation. If the Public key is present in the SEI, it has to be - // validated to associate the video with a source. If it is not feasible to validate the Public - // key, it should be validated manually to secure proper video authenticity. + // The result of the Public key validation. If the Public key is present in the SEI/OBU Metadata, + // it has to be validated to associate the video with a source. If it is not feasible to validate + // the Public key, it should be validated manually to secure proper video authenticity. bool has_timestamp; // True if the session included timestamps. int64_t first_timestamp; - // Unix epoch UTC timestamp in microseconds of the first signed NALU. + // Unix epoch UTC timestamp in microseconds of the first signed NALU/OBU. int64_t last_timestamp; - // Unix epoch UTC timestamp in microseconds of the last signed NALU. + // Unix epoch UTC timestamp in microseconds of the last signed NALU/OBU. } signed_video_accumulated_validation_t; /** @@ -207,7 +211,7 @@ typedef struct { signed_video_latest_validation_t latest_validation; // Holds the information of the latest validation. signed_video_accumulated_validation_t accumulated_validation; - // Holds the information of the total validation since the first added NALU. + // Holds the information of the total validation since the first added NALU/OBU. } signed_video_authenticity_t; /** @@ -285,11 +289,11 @@ signed_video_get_authenticity_report(signed_video_t *self); */ /** - * @brief Add NALU data to the session and get an authentication report + * @brief Add NALU/OBU data to the session and get an authentication report * * This function should be called for each H26x NALU the user receives. It is assumed that - * |nalu_data| consists of one single NALU including Start Code and NALU, so that NALU type can be - * parsed. That is, the format should look like this: + * |nalu_data| consists of one single NALU/OBU including Start Code and NALU/OBU, so that NALU/OBU + * type can be parsed. That is, the format should look like this: * * |------------|------| * | Start Code | NALU | @@ -299,10 +303,11 @@ signed_video_get_authenticity_report(signed_video_t *self); * * NOTE: NALUs sent into the API cannot be in packetized format (access units)! * The access unit has to be split into NALUs if so. + * NOTE: AV1 does not have start codes. * * The input |nalu_data| is not changed by this call. Note that it is assumed that ALL H26x NALUs - * are passed to this function. Otherwise, they will be treated as missing/lost packets which may - * affect the validation. + * and AV1 OBUs are passed to this function. Otherwise, they will be treated as missing/lost packets + * which may affect the validation. * * Signatures are sent on regular basis. Currently this is done at the end of each GOP (Group Of * Pictures). For every input |nalu_data| with a signature, or when a signature is expected, @@ -315,13 +320,13 @@ signed_video_get_authenticity_report(signed_video_t *self); * Two typical use cases are; 1) live monitoring which could be screening the video until * authenticity can no longer be validated OK, and 2) screening a recording and get a full report at * the end. In the first case further operations can simply be aborted as soon as a validation - * fails, whereas in the latter case all the NALUs need to be screened. + * fails, whereas in the latter case all the NALUs/OBUs need to be screened. * NOTE: Only the live monitoring use case is currently supported. * * Example code of usage; See example code above. * * @param self Pointer to the signed_video_t object to update - * @param nalu_data Pointer to the H26x NALU data to be added + * @param nalu_data Pointer to the H26x NALU or AV1 OBU data to be added * @param nalu_data_size Size of the nalu_data * @param authenticity Pointer to the autenticity report. Passing in a NULL pointer will not provide * latest validation results. The user is then responsible to get a report using @@ -338,15 +343,15 @@ signed_video_add_nalu_and_authenticate(signed_video_t *self, /** * @brief Sets the public key used to validate the video authenticity * - * For videos where the public key, necessary to verify the signature, is not present in the SEIs - * the user needs to provide that key manually. + * For videos where the public key, necessary to verify the signature, is not present in the + * SEIs/OBU Metadata the user needs to provide that key manually. * * This function allows the user to add the public key to the current Signed Video session. The * operation has to be performed before the session starts. It is not allowed to change the public * key on the fly, for which SV_NOT_SUPPORTED is returned. * - * If the public key is added for a session already including a public key in the SEI, the key in - * the SEI rules the other key. + * If the public key is added for a session already including a public key in the SEI/OBU Metadata, + * the key in the SEI/OBU Metadata rules the other key. * * The |public_key| data is assumed to be in PEM format. * diff --git a/lib/src/includes/signed_video_common.h b/lib/src/includes/signed_video_common.h index 9084d1ea..b8a375b8 100644 --- a/lib/src/includes/signed_video_common.h +++ b/lib/src/includes/signed_video_common.h @@ -99,9 +99,9 @@ signed_video_free(signed_video_t* self); * Resets the session and puts it in a pre-stream state, that is, waiting for a new GOP. Once a new * GOP is found the operations start over. * - * For the signing part, this means starting to produce the required SEI-NALUs needed for + * For the signing part, this means starting to produce the required SEIs/OBU Metadata needed for * authentication. For the authentication part, this should be used when scrubbing the video. - * Otherwise the lib will fail authentication due to skipped NALUs. + * Otherwise the lib will fail authentication due to skipped NALUs/OBUs. * * @param self Signed Video session in use * @@ -133,20 +133,20 @@ int signed_video_compare_versions(const char* version1, const char* version2); /** - * @brief Checks if a NALU is a golden SEI + * @brief Checks if a NALU/OBU is a golden SEI/OBU Metadata * - * A golden SEI is a self-signed SEI that includes all information only needed once - * such as the Public key. Usually a golden SEI is sent only once in the beginning of - * a stream. - * With this function the validation side can detect these to store them for later use, - * e.g., at file export. - * For the signing side it can help out to verify that a pre-generated golden SEI - * actually is a golden SEI before adding it to the stream + * A golden SEI/OBU Metadata is a self-signed SEI/OBU Metadata that includes all information only + * needed once such as the Public key. Usually a golden SEI/OBU Metadata is sent only once in the + * beginning of a stream. + * With this function the validation side can detect these to store them for later use, e.g., at + * file export. + * For the signing side it can help out to verify that a pre-generated golden SEI/OBU Metadata + * actually is a golden SEI/OBU Metadata before adding it to the stream. * - * @param nalu A pointer to the NALU data + * @param nalu A pointer to the NALU/OBU data * @param nalu_size Size of the |nalu| * - * @returns True if |nalu| is a golden SEI + * @returns True if |nalu| is a golden SEI/OBU Metadata */ bool signed_video_is_golden_sei(signed_video_t* self, const uint8_t* nalu, size_t nalu_size); diff --git a/lib/src/includes/signed_video_sign.h b/lib/src/includes/signed_video_sign.h index f6e11a28..490ba3bb 100644 --- a/lib/src/includes/signed_video_sign.h +++ b/lib/src/includes/signed_video_sign.h @@ -34,16 +34,16 @@ extern "C" { #endif /** - * Instruction on where to prepend a generated NALU. + * Instruction on where to prepend a generated NALU/OBU. * - * If an action is to prepend a NALU (SIGNED_VIDEO_PREPEND_NALU) the generated NALU should prepend - * the input NALU + all already prepended NALUs. - * If an action is to prepend an access unit (SIGNED_VIDEO_PREPEND_ACCESS_UNIT) the generated NALU - * should be added to an extra access unit (AU) preceding the current one. If an extra AU has - * already been created, this generated NALU should prepend all already added NALUs in that extra - * AU. + * If an action is to prepend a NALU/OBU (SIGNED_VIDEO_PREPEND_NALU) the generated NALU/OBU should + * prepend the input NALU/OBU + all already prepended NALUs/OBUs. + * If an action is to prepend an access unit (SIGNED_VIDEO_PREPEND_ACCESS_UNIT) the generated + * NALU/OBU should be added to an extra access unit (AU) preceding the current one. If an extra AU + * has already been created, this generated NALU/OBU should prepend all already added NALUs/OBUs in + * that extra AU. * - * For example, assume one AU with one NALU F0, that is, the memory looks like + * For example, assume one AU with one NALU/OBU F0, that is, the memory looks like * * | AUD | F0 | * @@ -60,20 +60,20 @@ typedef enum { SIGNED_VIDEO_PREPEND_NOTHING, // Nothing more to prepend. SIGNED_VIDEO_PREPEND_ACCESS_UNIT, - // Prepend the NALUs in a preceding access unit. + // Prepend the NALUs/OBUs in a preceding access unit. SIGNED_VIDEO_PREPEND_NALU, - // Prepend the NALUs in the same access unit as the input H26x NALU. + // Prepend the NALUs/OBU in the same access unit as the input H26x NALU/AV1 OBU. } SignedVideoPrependInstruction; /** - * A struct composed of the data of a, by Signed Video, generated NALU and instructions on how to - * add it to the stream. + * A struct composed of the data of a, by Signed Video, generated NALU/OBU and instructions on how + * to add it to the stream. */ typedef struct { SignedVideoPrependInstruction prepend_instruction; - // Instructions on where to prepend the NALU. + // Instructions on where to prepend the NALU/OBU. uint8_t *nalu_data; - // Data of generated NALU. + // Data of generated NALU/OBU. size_t nalu_data_size; // Size of generated |nalu_data|. } signed_video_nalu_to_prepend_t; @@ -84,45 +84,46 @@ typedef struct { typedef enum { SV_AUTHENTICITY_LEVEL_GOP = 0, // The entire GOP is verified as one solid chunk. Hence, if validation fails it is unknown which - // NALUs were incorrect or missing. + // NALUs/OBUs were incorrect or missing. SV_AUTHENTICITY_LEVEL_FRAME = 1, - // Individual NALUs are verified. Hence, if validation fails the incorrect or missing NALU(s) are - // detected. + // Individual NALUs/OBUs are verified. Hence, if validation fails the incorrect or missing + // NALU/OBU(s) are detected. SV_AUTHENTICITY_LEVEL_NUM } SignedVideoAuthenticityLevel; /** - * @brief Updates Signed Video, with a H26x NALU, for signing + * @brief Updates Signed Video, with a H26x NALU or AV1 OBU, for signing * - * Each NALU in a video has to be processed for signing. Sometimes the NALU data is split in parts - * and cannot be hashed in one go. This API adds a NALU part to the signed_video_t object for - * signing. It is very important that the video NALUs are fed to this API in the same order as they - * are transmitted. Otherwise, the authentication will fail. + * Each NALU/OBU in a video has to be processed for signing. Sometimes the NALU/OBU data is split in + * parts and cannot be hashed in one go. This API adds a NALU/OBU part to the signed_video_t object + * for signing. It is very important that the video NALUs/OBUs are fed to this API in the same order + * as they are transmitted. Otherwise, the authentication will fail. * - * Signed Video adds SEI-NALUs of type "user data unregistered" to communicate data for - * authentication. These SEI-NALUs are generated by the Signed Video library and are complete NALUs - * + 4 start code bytes. The user is responsible for pulling these generated NALUs from the object. - * Hence, upon a successful signed_video_add_nalu_for_signing_with_timestamp(...) call the user - * should always call signed_video_get_nalu_to_prepend(...) to get the additional NALUs. + * Signed Video adds SEIs/OBU Metadata of type "user data unregistered"/"user private" to + * communicate data for authentication. These SEIs/OBU Metadata are generated by the Signed Video + * library and are complete NALUs + 4 start code bytes, or OBUs. The user is responsible for pulling + * these generated NALUs/OBUs from the object. Hence, upon a successful + * signed_video_add_nalu_for_signing_with_timestamp(...) call the user should always call + * signed_video_get_nalu_to_prepend(...) to get the additional NALUs/OBUs. * * The timestamp parameter shall be a UNIX epoch value in UTC format. The integrator of this signed * video framework shall make sure this is true, so that the client side knows the expected format * and is able to convert the timestamp to whatever format is desired. If the timestamp is not NULL - * and the NALU is the first in the gop (i.e. the first I-frame slice), it will be included in the - * general SEI. All other timestamps and NULL will be disregarded. + * and the NALU/OBU is the first in the gop (i.e. the first I-frame slice), it will be included in + * the general SEI/OBU Metadata. All other timestamps and NULL will be disregarded. * * For sample code, see the description of signed_video_get_nalu_to_prepend(...) below. * * @param self Pointer to the signed_video_t object in use. - * @param nalu_data A pointer to the NALU data - * @param nalu_data_size The size of the NALU data. + * @param nalu_data A pointer to the NALU/OBU data + * @param nalu_data_size The size of the NALU/OBU data. * @param timestamp Unix epoch in UTC. - * @param is_last_part Flag to mark the last part of the NALU data. + * @param is_last_part Flag to mark the last part of the NALU/OBU data. * * @returns SV_OK - the NALU was processed successfully. * SV_NOT_SUPPORTED - signed_video_set_private_key_new(...) has not been set * OR - * there are generated NALUs waiting to be pulled. Use + * there are generated NALUs/OBUs waiting to be pulled. Use * signed_video_get_nalu_to_prepend(...) to fetch them. Then call this * function again to process the |nalu_data|. * otherwise a different error code. @@ -156,22 +157,23 @@ signed_video_add_nalu_for_signing(signed_video_t *self, size_t nalu_data_size); /** - * @brief Gets generated NALUs to prepend the latest added NALU + * @brief Gets generated NALUs/OBUs to prepend the latest added NALU/OBU * * This function should always be called after a successful * signed_video_add_nalu_for_signing_with_timestamp(...). Otherwise, the functionality of Signed * Video is jeopardized, since vital SEI-NALUs may not be added to the video stream. The * signed_video_add_nalu_for_signing_with_timestamp(...) returns SV_NOT_SUPPORTED if there are - * available NALUs to prepend. The user should then pull these before continuing; See return values - * in signed_video_add_nalu_for_signing_with_timestamp(...). + * available NALUs/OBUs to prepend. The user should then pull these before continuing; See return + * values in signed_video_add_nalu_for_signing_with_timestamp(...). * - * These SEI-NALUs are generated by the Signed Video library and are complete NALUs + 4 start code - * bytes. Hence, the user can simply pull and prepend existing H26x NALUs. Pull NALUs to prepend - * from signed_video_t one by one until no further action is required. When this happens, a - * SIGNED_VIDEO_PREPEND_NOTHING instruction is pulled. The signed_video_get_nalu_to_prepend(...) - * API provides the user with the NALU data as well as instructions on where to prepend that data. + * These SEIs are generated by the Signed Video library and are complete NALUs + 4 start code + * bytes, or OBUs. Hence, the user can simply pull and prepend existing H26x NALUs, or AV1 OBUs. + * Pull NALUs/OBUs to prepend from signed_video_t one by one until no further action is required. + * When this happens, a SIGNED_VIDEO_PREPEND_NOTHING instruction is pulled. The + * signed_video_get_nalu_to_prepend(...) API provides the user with the NALU/OBU data as well as + * instructions on where to prepend that data. * - * NOTE that as soon as the user pulls a new NALU to prepend, the ownership of the |nalu_data| + * NOTE that as soon as the user pulls a new NALU/OBU to prepend, the ownership of the |nalu_data| * memory (see members of signed_video_nalu_to_prepend_t) is transferred. Free the |nalu_data| * memory with signed_video_nalu_data_free(...). * @@ -215,10 +217,10 @@ signed_video_add_nalu_for_signing(signed_video_t *self, * } * * @param self Pointer to the signed_video_t object in use. - * @param nalu_to_prepend A pointer to a signed_video_nalu_to_prepend_t object holding NALU data + * @param nalu_to_prepend A pointer to a signed_video_nalu_to_prepend_t object holding NALU/OBU data * and prepend instructions. * - * @returns SV_OK - NALU was pulled successfully, + * @returns SV_OK - NALU/OBU was pulled successfully, * SV_NOT_SUPPORTED - no available data, the action is not supported, * otherwise - an error code. */ @@ -227,19 +229,19 @@ signed_video_get_nalu_to_prepend(signed_video_t *self, signed_video_nalu_to_prepend_t *nalu_to_prepend); /** - * @brief Gets generated SEIs to add to the stream + * @brief Gets generated SEIs/OBU Metadata to add to the stream * * This function should be called before * signed_video_add_nalu_for_signing_with_timestamp(...). The user has an option to - * provide this function with a |peek_nalu|, which is the same NAL Unit that is to be + * provide this function with a |peek_nalu|, which is the same NAL Unit/OBU that is to be * added for signing. Even though, the user does not have to call this function before * adding NAL Units for signing, it is highly recommended to avoid missing or delaying - * SEIs. + * SEIs/OBU Metadata. * - * These SEIs are generated by the Signed Video library and are complete NAL Units + 4 - * start code bytes. Hence, the user can simply pull and prepend existing H26x NAL Units. - * Pull NAL Units to prepend from signed_video_t one by one until no more generated SEIs - * exists, that is, when |sei_size| is zero. + * These SEIs/OBU Metadata are generated by the Signed Video library and are complete NAL Units + 4 + * start code bytes, or OBUs. Hence, the user can simply pull and prepend existing H26x NAL Units, + * or AV1 OBUs. Pull NAL Units/OBUs to prepend from signed_video_t one by one until no more + * generated SEIs/OBU Metadata exists, that is, when |sei_size| is zero. * * NOTE: The user is responsible for allocating memory for the |sei|. * @@ -275,20 +277,21 @@ signed_video_get_nalu_to_prepend(signed_video_t *self, * } * * @param self Pointer to the signed_video_t object in use. - * @param sei Pointer to the memory to which a complete SEI will be copied. + * @param sei Pointer to the memory to which a complete SEI/OBU Metadata will be copied. * If a NULL pointer is used, only the |sei_size| is updated. - * @param sei_size Pointer to where the size of the SEI is written. - * @param payload_offset Pointer to where the offset to the start of the SEI payload is written. - * This is useful if the SEI is added by the encoder, which would take the SEI payload only and - * then fill in the header, payload size and apply emulation prevention onto the data. - * @param peek_nalu Pointer to the NAL Unit of which the SEI will be prepended as a - * header. When peeking at the next NAL Unit, SEIs can only be fetched if the NAL is a - * primary slice. A NULL pointer means that the user is responsible to add the SEI - * according to standard. - * @param peek_nalu_size The size of the peek NAL Unit. - * @param num_pending_seis Pointer to where the number of pending SEIs is written. - * - * @return SV_OK - NALU was copied successfully, + * @param sei_size Pointer to where the size of the SEI/OBU Metadata is written. + * @param payload_offset Pointer to where the offset to the start of the SEI/OBU Metadata payload is + * written. This is useful if the SEI/OBU Metadata is added by the encoder, which would take the + * SEI/OBU Metadata payload only and then fill in the header, payload size and apply emulation + * prevention onto the data. + * @param peek_nalu Pointer to the NAL Unit/OBU of which the SEI/OBU Metadata will be prepended as a + * header. When peeking at the next NAL Unit/OBU, SEIs/OBU Metadata can only be fetched if the + * NAL/OBU is a primary slice. A NULL pointer means that the user is responsible to add the + * SEI/OBU Metadata according to standard. + * @param peek_nalu_size The size of the peek NAL Unit/OBU. + * @param num_pending_seis Pointer to where the number of pending SEIs/OBU Metadata is written. + * + * @return SV_OK - NALU/OBU was copied successfully, * SV_NOT_SUPPORTED - no available data, the action is not supported, * otherwise - an error code. */ @@ -315,10 +318,10 @@ signed_video_nalu_data_free(uint8_t *nalu_data); /** * @brief Tells Signed Video that the stream has ended * - * When reaching the end of a stream (EOS) a final SEI-NALU needs to be transmitted to be able to - * validate all the way to the end, thereby avoiding a dangling end. + * When reaching the end of a stream (EOS) a final SEI/OBU Metadata needs to be transmitted to be + * able to validate all the way to the end, thereby avoiding a dangling end. * - * This API can be called when the end of a stream is reached. Afterwards, all NALUs to prepend + * This API can be called when the end of a stream is reached. Afterwards, all NALUs/OBUs to prepend * should be pulled as normal using signed_video_get_nalu_to_prepend(...) above. * * @param self Pointer to the signed_video_t object in use. @@ -330,13 +333,13 @@ SignedVideoReturnCode signed_video_set_end_of_stream(signed_video_t *self); /** - * @brief Generates a golden SEI. + * @brief Generates a golden SEI/OBU Metadata. * - * A golden SEI is a self-signed SEI that includes all information only needed once - * such as the Public key. Usually a golden SEI is sent only once in the beginning of - * a stream. - * With this function a golden SEI can be generated and the user can store it for later use, - * and easily added to the stream when needed. + * A golden SEI/OBU Metadata is a self-signed SEI/OBU Metadata that includes all information only + * needed once such as the Public key. Usually a golden SEI/OBU Metadata is sent only once in the + * beginning of a stream. + * With this function a golden SEI/OBU Metadata can be generated and the user can store it for later + * use, and easily added to the stream when needed. * * Here is an example code of usage: * @@ -428,18 +431,18 @@ signed_video_set_private_key(signed_video_t *self, size_t private_key_size); /** - * @brief Setter for adding the Public key to the SEI or not + * @brief Setter for adding the Public key to the SEI/OBU Metadata or not * * If the public key, used to verify the signatures, cannot be secured through a hardware * certificate or key attestation, it should not be added to the video stream. Without securing it, * anyone can sign arbitrary (tampered) videos. * * This function should be used before starting the Signed Video session. If it is not used, the - * public key is added to the SEI. + * public key is added to the SEI/OBU Metadata. * * @param self Pointer to the current Signed Video session - * @param add_public_key_to_sei Flag to indicate if the public key should be added to the SEI - * (default true) + * @param add_public_key_to_sei Flag to indicate if the public key should be added to the + * SEI/OBU Metadata (default true) * * @return A Signed Video Return Code (SignedVideoReturnCode) */ @@ -475,8 +478,8 @@ signed_video_set_authenticity_level(signed_video_t *self, * * Metadata that is only needed once when validating the authenticity can be transmitted with a * different recurrence interval than the signatures. This API sets that recurrence, counted in - * frames (not NALUs). Note that this type of metadata is still bundled together in the same SEI - * as the signature, hence the true recurrence will be correct on the average. + * frames (not NALUs/OBUs). Note that this type of metadata is still bundled together in the same + * SEI/OBU Metadata as the signature, hence the true recurrence will be correct on the average. * Example of metadata that is only needed once are the public key and product info. * @@ -515,22 +518,23 @@ SignedVideoReturnCode signed_video_set_sei_epb(signed_video_t *self, bool sei_epb); /** - * @brief Configures Signed Video to use golden SEI principle + * @brief Configures Signed Video to use golden SEI/OBU Metadata principle * - * The principle of the golden SEI sends all information only needed once, such as the Public key, - * at the start of the stream with the golden SEI. After that, the rest of the SEIs in the stream - * only include mandatory information. + * The principle of the golden SEI/OBU Metadata sends all information only needed once, such as the + * Public key, at the start of the stream with the golden SEI/OBU Metadata. After that, the rest of + * the SEIs/OBU Metadata in the stream only include mandatory information. * - * It is the user's responsibility to ensure that the first SEI in the stream is a golden SEI. - * This golden SEI does not necessarily have to be at the very beginning of the stream, but it must - * be the first SEI included. + * It is the user's responsibility to ensure that the first SEI/OBU Metadata in the stream is a + * golden SEI/OBU Metadata. + * This golden SEI/OBU Metadata does not necessarily have to be at the very beginning of the stream, + * but it must be the first SEI/OBU Metadata included. * - * Note: It is not feasible to set this on an ongoing session. + * NOTE: It is not feasible to set this on an ongoing session. * * @param self Session struct pointer - * @param using_golden_sei Flag to enable or disable the golden SEI principle. + * @param using_golden_sei Flag to enable or disable the golden SEI/OBU Metadata principle. * - * @returns SV_OK SEI |using_golden_sei| was successfully set, + * @returns SV_OK SEI/OBU Metadata |using_golden_sei| was successfully set, * SV_INVALID_PARAMETER Invalid parameter. * SV_NOT_SUPPORTED if set during an ongoing session. */ @@ -538,27 +542,28 @@ SignedVideoReturnCode signed_video_set_using_golden_sei(signed_video_t *self, bool using_golden_sei); /** - * @brief Configures Signed Video to limit the payload size of the SEI NAL Units + * @brief Configures Signed Video to limit the payload size of the SEIs/OBU Metadata * - * In many Signed Video integrations on the signing side SEIs cannot become arbitrary large due to - * hardware constraints. This API sets an upper limit on the payload size of the generated SEI. If - * the, to be generated, SEI exceeds the set |max_sei_payload_size| Signed Video falls back to GOP - * level authentication. + * In many Signed Video integrations on the signing side SEIs/OBU Metadata cannot become arbitrary + * large due to hardware constraints. This API sets an upper limit on the payload size of the + * generated SEI/OBU Metadata. If the, to be generated, SEI/OBU Metadata exceeds the set + * |max_sei_payload_size| Signed Video falls back to GOP level authentication. * * Note that it is a soft limit. If the payload size is still too large even for GOP level - * authentication the SEI NAL Unit is generated. Further, note that the API sets the maximum SEI - * payload size. The final SEI size can become larger since it includes headers, size bytes and - * potentional emulation prevention. + * authentication the SEI/OBU Metadata is generated. Further, note that the API sets the maximum + * SEI/OBU Metadata payload size. The final SEI/OBU Metadata size can become larger since it + * includes headers, size bytes and potentional emulation prevention. * - * If this API is not used, an unlimited SEI payload size is used (|max_sei_payload_size| = 0). + * If this API is not used, an unlimited SEI/OBU Metadata payload size is used + * (|max_sei_payload_size| = 0). * * The behavior of this API may change in the future and replace the fallback mechanism with a * forced signing mechanism. * * @param self Session struct pointer - * @param max_sei_payload_size Upper limit on SEI payload (default 0 = unlimited) + * @param max_sei_payload_size Upper limit on SEI/OBU Metadata payload (default 0 = unlimited) * - * @returns SV_OK Max SEI payload size was successfully set, + * @returns SV_OK Max SEI/OBU Metadata payload size was successfully set, * SV_INVALID_PARAMETER Invalid parameter. */ SignedVideoReturnCode @@ -567,7 +572,8 @@ signed_video_set_max_sei_payload_size(signed_video_t *self, size_t max_sei_paylo /** * @brief Configures Signed Video to use a specific hash algorithm * - * Signed Video hashes NAL Units and, depending on configuration, sends these hashes in a SEI. + * Signed Video hashes NAL Units/OBUs and, depending on configuration, sends these hashes in a + * SEI/OBU Metadata. * The default hash algorithm used is SHA256. With this function, the user can change hash * algorithm. * diff --git a/tests/README.md b/tests/README.md index 472c53b5..732487c3 100644 --- a/tests/README.md +++ b/tests/README.md @@ -8,7 +8,7 @@ The repository comes with unittests which use the check test framework. For gett ## Description The main scope of the unittests is to verify that the framework behaves as expected for - incorrect calls of public APIs -- correctly generating SEIs +- correctly generating SEIs/OBU Metadata - correct validation results of various tampering attempts - correct validation results of various valid and invalid operations of a signed video