From 4992c1ac2b1567ecef16c5e77780cebd1ba16f2b Mon Sep 17 00:00:00 2001 From: Karsten Suehring <karsten.suehring@hhi.fraunhofer.de> Date: Wed, 1 Jan 2025 21:54:00 +0100 Subject: [PATCH] JVET-AJ0151: Implement Digitally Signed Content SEI messages Ported from JVET-TuC with small improvements on certificate handling --- cfg/keystore/README.md | 57 ++ cfg/keystore/ca/d8e118e3.0 | 1 + cfg/keystore/ca/jvet_example_ca.crt | 32 + cfg/keystore/ca_priv/ca.key | 28 + cfg/keystore/private/attacker_content.csr | 27 + cfg/keystore/private/attacker_content.key | 52 ++ cfg/keystore/private/jvet_example_ca.key | 54 ++ .../private/jvet_example_provider.csr | 27 + .../private/jvet_example_provider.key | 52 ++ cfg/keystore/private/untrusted_ca.crt | 32 + cfg/keystore/private/untrusted_ca.key | 52 ++ cfg/keystore/public/attacker_content.crt | 32 + cfg/keystore/public/jvet_example_provider.crt | 32 + cfg/sei_vui/digially_signed_content.cfg | 7 + doc/software-manual.tex | 49 ++ source/App/DecoderApp/DecApp.cpp | 3 + source/App/DecoderApp/DecAppCfg.cpp | 4 + source/App/DecoderApp/DecAppCfg.h | 4 + source/App/EncoderApp/EncApp.cpp | 3 + source/App/EncoderApp/EncAppCfg.cpp | 15 + source/App/EncoderApp/EncAppCfg.h | 3 + source/Lib/CommonAnalyserLib/CMakeLists.txt | 13 +- source/Lib/CommonLib/BitStream.h | 9 + source/Lib/CommonLib/CMakeLists.txt | 13 +- source/Lib/CommonLib/SEI.cpp | 5 + source/Lib/CommonLib/SEI.h | 5 + .../CommonLib/SEIDigitallySignedContent.cpp | 601 ++++++++++++++++++ .../Lib/CommonLib/SEIDigitallySignedContent.h | 218 +++++++ source/Lib/CommonLib/TypeDef.h | 11 +- source/Lib/DecoderLib/DecLib.cpp | 112 +++- source/Lib/DecoderLib/DecLib.h | 34 + source/Lib/DecoderLib/NALread.cpp | 6 + source/Lib/DecoderLib/SEIread.cpp | 76 ++- source/Lib/DecoderLib/SEIread.h | 11 +- source/Lib/EncoderLib/EncCfg.h | 13 + source/Lib/EncoderLib/EncCfgParam.h | 16 +- source/Lib/EncoderLib/EncGOP.cpp | 131 ++++ source/Lib/EncoderLib/EncGOP.h | 12 + source/Lib/EncoderLib/SEIEncoder.cpp | 25 + source/Lib/EncoderLib/SEIEncoder.h | 5 + source/Lib/EncoderLib/SEIwrite.cpp | 58 +- source/Lib/EncoderLib/SEIwrite.h | 11 + 42 files changed, 1935 insertions(+), 16 deletions(-) create mode 100644 cfg/keystore/README.md create mode 120000 cfg/keystore/ca/d8e118e3.0 create mode 100644 cfg/keystore/ca/jvet_example_ca.crt create mode 100644 cfg/keystore/ca_priv/ca.key create mode 100644 cfg/keystore/private/attacker_content.csr create mode 100644 cfg/keystore/private/attacker_content.key create mode 100644 cfg/keystore/private/jvet_example_ca.key create mode 100644 cfg/keystore/private/jvet_example_provider.csr create mode 100644 cfg/keystore/private/jvet_example_provider.key create mode 100644 cfg/keystore/private/untrusted_ca.crt create mode 100644 cfg/keystore/private/untrusted_ca.key create mode 100644 cfg/keystore/public/attacker_content.crt create mode 100644 cfg/keystore/public/jvet_example_provider.crt create mode 100644 cfg/sei_vui/digially_signed_content.cfg create mode 100644 source/Lib/CommonLib/SEIDigitallySignedContent.cpp create mode 100644 source/Lib/CommonLib/SEIDigitallySignedContent.h diff --git a/cfg/keystore/README.md b/cfg/keystore/README.md new file mode 100644 index 0000000000..467d549f57 --- /dev/null +++ b/cfg/keystore/README.md @@ -0,0 +1,57 @@ +# Keystore + +## Example CA and keys + +This directory contains example CA and content provider keys and certificates. These example keys SHALL NOT be used in production environments. + +Note that private keys should be kept secret. + +| location| explanation | +| -------- | ------- | +| keystore/private/jvet_example_ca.key | JVET example CA private key. The used password is "example". | +| keystore/private/jvet_example_provider.key | JVET example content provider private key. There is no password protection for this key. | +| keystore/public/jvet_example_provider.crt | JVET example content provider public key certificate signed by example CA key| +| keystore/ca | Location for CA certificates. After adding new certificates, run `openssl rehash keystore/ca` to create hash based links. | +| keystore/ca/jvet_example_ca.crt | JVET example CA certificate | + +## Creating certificates + +### Creating a Certificate Authority (CA) + +Note, that the following steps only illustrate creating an example CA. +For and actual CA it is of utmost importance to keep CA private keys secret, e.g. in offline storage. +Typically, CAs use multiple levels of intermediate signing certificates, which are used for everyday signing processes. + +For this example, only one CA level is used. + +For creating a CA, first a CA key need to be created. With OpenSSL, this can be done using the following command: + + openssl genrsa -out example_ca.key 4096 + +This creates a 4096 bit RSA key. In practical use, the key should be encrypted with a secure (long) passphrase, e.g. use + + openssl genrsa -aes256 -out example_ca.key 4096 + +to generate a key `example_ca.key` that is protected with AES encryption. + +The create a self-signed certificate for the CA: + + openssl req -x509 -new -nodes -key example_ca.key -sha256 -days 1826 -out example_ca.crt + +This will ask for Name, country, organization, etc. The days parameter indicates the number of days that the certificate will be valid. + +### Creating a Content Provider Certificate + +First create a key as for the CA: + + openssl genrsa -out example_content.key 4096 + +Create a signing request file: + + openssl req -new -key example_content.key -out example_content.csr + +Sign the request with the CA key: + + openssl x509 -req -in example_content.csr -CA example_ca.crt -CAkey example_ca.key -out example_content.crt -days 730 -sha256 + +The days parameter indicates the number of days that the certificate will be valid. diff --git a/cfg/keystore/ca/d8e118e3.0 b/cfg/keystore/ca/d8e118e3.0 new file mode 120000 index 0000000000..b636440947 --- /dev/null +++ b/cfg/keystore/ca/d8e118e3.0 @@ -0,0 +1 @@ +jvet_example_ca.crt \ No newline at end of file diff --git a/cfg/keystore/ca/jvet_example_ca.crt b/cfg/keystore/ca/jvet_example_ca.crt new file mode 100644 index 0000000000..52250a04ec --- /dev/null +++ b/cfg/keystore/ca/jvet_example_ca.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkTCCA3mgAwIBAgIUSBOrc6YNsshq9BgTlLx9dqzNTjMwDQYJKoZIhvcNAQEL +BQAwWDELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBkdlbmV2YTEPMA0GA1UEBwwGR2Vu +ZXZhMQ0wCwYDVQQKDARKVkVUMRgwFgYDVQQDDA9KVkVUIEV4YW1wbGUgQ0EwHhcN +MjQxMDI4MTcxMTI5WhcNMjkxMDI4MTcxMTI5WjBYMQswCQYDVQQGEwJDSDEPMA0G +A1UECAwGR2VuZXZhMQ8wDQYDVQQHDAZHZW5ldmExDTALBgNVBAoMBEpWRVQxGDAW +BgNVBAMMD0pWRVQgRXhhbXBsZSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAJk9aZbVIWkW4PlIWvrdYxIUOKlDtItx/yKk7Od15N0LIrHA577aja2O +wLmMRtmaO/pD2a95Jc1v3Er/e7cQnsO6IAkw4Oz76OslATFicFMMLVDUHavvsP6H +CDJkuqz/yxL4eWexQxVoxuyw9UHIoAJcRAQgb7SxzoDSSTaRh066Mr9/ch5NyIPs +nkf/sefH2jsAGnu8eOp5h4m9NTvaYgIwx9IZBjlK9Bf3CCuZD0BCrslIDFmS0CBf +I9lupEhrJ9jwdVQFm49ajMaZyCqoDSA9nP9ZVxbifRhRdo/SJw9DhtJWy02E4kTf +ZxStJi9s3Opred9hn6lSRMOmThgfr8vQcTPqSXOD/x+e6nJ0JYnOZd5K4h6EtrUR +mcW87i1FdjCAZyxQbisKxzHWcHDYwZHHE2TPc9YnKcc0sXwBKGjrECqgKPASQisW +RQdEGObKOF8S1om96TGSh/E0EH0lLsji3UF+YwuoouZiRhzArKMU13AuZ5e6YPby +G4v0zTK5hV8SjrMs04mwVzwXTlrinoFKBkkydyWn+3BtAHu4BrF46yYCVKXhEUVh +UIV7b7mhPboMFmAG1PjEvdRJDHTAL3ZZZEPSkdgYf0DQ+A9eCBmaMJuYrDMIwCDb +4wM5ofi/C92QWXhx84vTeTR1EGmIlBQGhrOEasgdPddTNkJZvE3fAgMBAAGjUzBR +MB0GA1UdDgQWBBQeiWHUtyAfBvwTlzjxhArENIKqNjAfBgNVHSMEGDAWgBQeiWHU +tyAfBvwTlzjxhArENIKqNjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4ICAQA/YYgNn/BOJ2iceNH47IWd9pvZ7EI/ix6MTpv/clc0TE4CYeGKjcCDQF07 +9qtSb351UvtIRwBRScefjzXqwEriOZMPop61lqkWr6LXfAnkoUsJLj+wIcote4E1 +qy8yNPeAVRDtuxnNBRNxdt4vkT/bENy4XcrtYmTj4mjColXT4riaLrVyxZiDb5Dw +tUocijTxubku2s01hkSWwRtaIWQTyCcr7oUuJEuBy+IdAWGq/wiWS2TVX377iMyX +/oLJFRqH97qT5d5DLUogKJcgJMyXqYDr8j42HvyDCGkyAAIWQvEdzF+CfYgW6d1/ +eSo6HLCuAlUPXv3FV2jljHuS/ov44baAUmLORvb4RgckAsqLgTebfZ1cvUkr6syw +I6aJgt4XjncHTHDMWe6QtU2SQRpKjE74PMI+ZWDmw/zZx5EYffrdDaJJlEf34RDS +Bs0Ge1u6oruVomm7bBfi9Tml9lPpfjFWuJxjxxZuR9sE3VOOXZIogb/RqQqCQm8o +htbcu3AH4flRkSgjSn8YMaWbc2BZitw6JiApc5rdLdzG5zDeOTZcjzjeHGQ5oOnm +A8PONCl33Wc29VTBIn9MdP43KrMRTDHUHeP3Fm1Ry6RmhkNg3k77da4/Zr6v0XGp +GKZcvu5Z7a1Jwdr3EPakrQ2WuoyJGQYWwPrKsay8ySgmTRt3Kg== +-----END CERTIFICATE----- diff --git a/cfg/keystore/ca_priv/ca.key b/cfg/keystore/ca_priv/ca.key new file mode 100644 index 0000000000..37ab6b0d80 --- /dev/null +++ b/cfg/keystore/ca_priv/ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCVjw3JUarJdR15 +LAS7kEES1MolCejiRTytdAZ2NmnAkdyoBwPlyru4Jb6VJofOLxorTNz0d7YP8sy9 +Bcvk5bH0o9sFEwysh6keY92axpUsU8i9SMM0M/lUJL5rNejHdh9Zz09H0jaNZFzg +de2oxbdnHTXBE3xOPjaec543Cjeno3MU9yC8MIhCv3sLKnBxy+jEIaUDpYk3Ki9E +u5D2xYhv90toWp5ISABQvoIAvKuexhlk4qG5HSbmd60bXcJzfyTFgI3Yk7yHoAxu +dC6FJtPO1b27B2hRs9F+03GNde4Tat7ut/OrK8sn8LHvwClIs2I4bfMqpZoFIUUd +D6agKTYNAgMBAAECggEAATCpuevh8YdyjBfLE9kCg41Y7HGHPmGxqWmucXteXQ9s +E5Q2tjnmQ4FdYl9znjLmwOh0K6fWNYtHkMt+g1xGjb1ODVzI8YiE0n6V8VjaMAec +pdDx6LTvK3m9YCoGJ6wrdLH/HgGwuHBPguO9V+X23yWu21H138OD+L/Pxv1YUwep +UgpdjqzaP36Q1TgOUb9sAvmaIpZvJtlIevN794+gBZ1dX7a6R+VXphgS+DVdnOEF +LC7bhhHbCgNKVIEUyDz/pc+hUg13sEvcgUTPkiAQtxIs+z+f9picI+iieqPRGx2I +LEQLyOQvz4LZes+C3vmERw84CUq7DiSFxVRmVAsrSwKBgQDFSVMtEWtRrRcwTgZx +Uf8Fm+VT/BPepMPAvVW7atSrKVPyQWbQVGiTF0re5LG5XA/lSn0fXPzrSNWwibNo +MUhs51MdhkDu4RM1OIn4nASIGkPVJKy5IXNEheXb5U2J+Z7bZSj1hnYK6S514UHY +RNyHYcckrgHkXADSaxMTeBkiUwKBgQDCEYBQbPZXDv/BZRSDwudEplbFRxr/mklO +wFvPojsxl3IE7PowUNYT6dFdwU8FxrJARo/eruZ/6gzVJy99M1lhz1B5EWJktzdH +Eey+aPHGm1e2TuCYAhKJSBJ04LXkgJIxSiBFmU+L3jhMbEIX1UJ7Upp8v4Pgbi57 +HOrTPuP6HwKBgDBoopkvagb7kvIOYzRRK2Nj8myeMP3zrfjQPIYlW5O4K1oJREIg +RBy7nWp98UILXfckRPl6JrFRCOYtk7EgTqYySMm41JwI7F6lxe0T02TWFQjq29r9 +YzxQIqvHYzRU5O7urpM4cCSTPQw9vptjoj0x99x/OgWfsa/wCBlB4eDzAoGAHUiI +xRn7/dz8iJEZDFy/iuNSmogFMeZ1A1YRRH5lUjFY+hdMFThNZUnV1sDRjLyTrxE2 +qlJX45tMfmlgSBMUfKbMrMgLwcjHpYi14XFychaEoLS8PROq+l4OsuYpbCZeaOOX +hQkCMMfCVP3M5029r2AigYpgeuAFUXxmjqOhwN8CgYEAjG6tNqJudNzs0ni20t2W +RmD4s7v1Dbowi7xsCkhq/MGCwPTPh1V4jeUbUSu2R9qpFfUSkBi226dCrzTWsGru +2gMfImsI7UnSA2v+sIaC+CkTK775lEGZUA5Q9mAojiAv3R4nyv2hih/o/7Bhinh5 +ZRrnX4Ja8NAQUw9r/8amJ0s= +-----END PRIVATE KEY----- diff --git a/cfg/keystore/private/attacker_content.csr b/cfg/keystore/private/attacker_content.csr new file mode 100644 index 0000000000..abc49855cd --- /dev/null +++ b/cfg/keystore/private/attacker_content.csr @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEoDCCAogCAQAwWzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQH +DAtMb3MgQW5nZWxlczEaMBgGA1UECgwRSlZFVCBpbXBlcnNvbmF0b3IxDTALBgNV +BAMMBEpWRVQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDdcG/xV8Bb +owQGTtCdAzrqSQShVoQTT6RReLbOVfJ8ysJEnzkF4X0Kj61FTphyShEnYmbqIAU+ +q/zIWiBIsBW1kvTY6EAhKmCrnN/kREf2HFSH3GyncJosJDtMuDIiKuyJyeKiI/Mv +/A1eXQyQ/Zp2Kqp9pZbIyBHa76A2ZzOTah7Pdbv/tN3Qxhyf2LYa8QJTdYA/xlt2 +0vd+OGcbs01C3tNnNS7pFgpW0iwIdnq0xdrkFpEENNF6FRQVoVmeDsojieecnALN +sIabXSaefSHgjixa7IR3IiL2yAs7GpCCK+m9SMRmyptsLZI1i1XswZyoqKzolt80 +V1EUrmypyZA64VXhv2RxZ1gD6cKPCXxA5BaVlmwPAr1C97ZIPsbTWps/+h8kAqEw +A8Oy2Ji/ro9UmbwSCQiWj/RqBC/m1He0gaHXcIOCEUIE30+f81DtgKJR5Ne03SwV ++JpveHNwK4cttONwNNV81XxnW5I4seTKIYXFMk3jWYETddfnjyBC4BFJoEqXpKeF +ubXCx9Ca1SxIqBfvW+3dYcDsc/36pPHTaJqSkMq8b39OO0VyMQKLt1qwY/d6lzNP +F3Y+s+QDPiGBz4ciWHApIhXP+G3en9IDrmuspI3b7bef2AIPnWEEXc91xcfAxzS2 +dLawrZjyEio4Rl0vZuyfCCmt9CSmQpN43wIDAQABoAAwDQYJKoZIhvcNAQELBQAD +ggIBAKTszgKEGaV8bt/mCw9w/HBrYvD/N3xP/9fGpOsj+uBpGKhN8zkbJoewD1rQ +sV7vCkCqOEdJE13QfP2fQrWSqQdyBL6H7RaTGO4wJtvHR7+6oNNWmF0T66P+G1/Z +PWmq0HYvVGKT5Vn6OInChMXDdUgYmb/ijKXVYTxvP1BNd4LFLypMHy34d6ePBORA +IHU4WqHz0pOEZVpryHbN1UYSs29rGPNF6oNA3p0S1WStc2ndO+sw+SemfhbH/FBY +CNuZKPr2gVHADSQ7kAT0e8R6E3MvyKcyn7Y7P43GdRBXKsKMXJo4kdW0ppyDLKj/ +kZOUoBILZIPrdW67H64dNnpL0+MpArywnQYkZ2sXwfEERxpqOsXcr/SYOlYUpk+7 +UJ79vc8+PG6ErKfv5O6+gT0OKx4hYRWFgDFcbLUDwBBpyU/zLPvjuvv6D9wgzqq0 +kjRSvOlIkjcKOM2azeCMG8ykggpCcZeUcPLHHx25S9Sk30a880WkbnY32wcuG42p +L0SzFmd7R95unJyxcMp8sN8Dja44Wo9ryqavZmxFssZl8hmIR+DUarFhLoa3LSJl +tMVtJX46o36x3DnWAX9TpBiLQJhHpzgdobvLh5gvWdyVM86nXaiYiAX+E0CZv8zn +AQ7hCC/wlFbIQr8BU/KO4AEeK3hUMik2loeWb3U3DLoQ6ndA +-----END CERTIFICATE REQUEST----- diff --git a/cfg/keystore/private/attacker_content.key b/cfg/keystore/private/attacker_content.key new file mode 100644 index 0000000000..2b6f6cc64c --- /dev/null +++ b/cfg/keystore/private/attacker_content.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +9tT+W9KNfEBYdu5W+pE2f6YtzzvSOA== +-----END PRIVATE KEY----- diff --git a/cfg/keystore/private/jvet_example_ca.key b/cfg/keystore/private/jvet_example_ca.key new file mode 100644 index 0000000000..217cc80169 --- /dev/null +++ b/cfg/keystore/private/jvet_example_ca.key @@ -0,0 +1,54 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIJtTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQf72G6RhDBS8GDtkm +TfedkAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEIGVw3EJqQdAHWVK +DUsPpfkEgglQ6rJptT852lDEC599+REb+M80JB+HaUa+J5KWONgSg13CfhYuEjH/ +WnoLd0Z4Li/yv9DfUMBdFBpWIy5lcow3ArN+3wqWxhFDcIN0o66XEutkluzQktHH +e6Jer5O9CUyD3A560cDvOZUkRtqfi9WdLmC/0U2RLlM2rzihlF4XCR4nUVtSDWON +F/uTnsmin6I6FmG3YFLoKp1/ZzHqcPH1J0prMPNo5yiYwvvutk60TQohvaZH2cX1 +di3epdPqsdpfxEiRMoMBk1xHVS++JlaJB/AyrH0nj9maD2YR7eXlFbPCMqgvUVTe +OBaGACqP8hWoezTbkTJN/NQKii0uCII3fKWEA34sfQdMUMxcfyaqafMvU3Yiyp1H +I4A53TXcrWK+vMGgUISJLaPbVcxCrlgsL7Af/Kl4FWHEAjmJ7lrZv76VbbiOB1nY +M1uwKUoaFwSWtOO1MnpXWTjobH0xgX3n36rJ5dDlhfy52aWqoW7vHW7i58ZUSsif +zlaK3gmTZfzzwmz3oiFlFddUkRBWZRoh2irCRSMYUFioMr1cUxQL9vuRWkcMV4+/ +ogcY+lggqnUXVUvlOAClX0Sur56IW2HAasjAxxNqYt2m0n+ukCx3FoCaHFhQ2iJ9 +IZh0SJnLMYinq6E6uahyd1jS+FO1YvPcXuzF+MhZgaID2HqSNIDa1MD+OR6cEJNa +RfpxLNsqnDhQlhvWHoKBaWfFHRHLeSw8hsLO9KaBoyxqJkZHVtT+Po2cGzL8wxx3 +3WGEjpgXWlDnSk1K7kALwQ5Xsj3kQkcNPHSKtZw5k9ysxUHdFQVH5yFjMEQ1WUzo +jwbS+/BBpMEwc740a3vZNLxm3OdvHMQbEdaxg4W+qALeVpGYIc/5HJCUXtjjLNY+ +ccaLepJWK13AOZkTTBdQXsoXBcFZM2uczkRcf3MeKLOA2vh2j1QKicp+jIInFj1H +iwREX7d/PH/14XnuPi0XWv/lZMukopVUG6jiKMDUlVwi1HocyjvkuBWq+ZMa7X02 +X6LU5FoLf5HF16K13Ul5cOkUzGK7eEWXAu8CozjiLoqICvEUrZUyuGtizB5mEwy0 +Zikc6v01GlDPfaZSm1QXcYaak2tq2gnPG6EidglYYt4e2mcr5iZIsiAYw3/S1uHZ +brcpobSZyxOS15nevKTGky3tD4VbiVe2fBSn7e1UUY51IEjRfC3ZAKoS4bUQP47y +kYpk0vfuvmKID3urDQuhKGIJ3aC3IkXJ/8zc0UnJvLS2PgL4YO1iQAfTvf7cAziG +PHKEH9NQsfBAYJNhYqJqsHqWtiFq5z+XP8v6td2k3CrcRBlsPb+DyNiwFY+VINct +D/52t8dpiRUyUKiPcPRhiEsm4W2s8HBj/xbeK82ykApv1tGd7oAE6n+rHTPaJA8M +Qu3QzMg7GRUs1DBy7nRCN6y4HGGn7I7H1gr6rgXp/TQe4TScMck0s2rC0TOO4+kR +X23HknN2nxr/k5IyhD+2tsJxMR4hTQKAC0NsxVChvmvSc8rahByOaIA/J5xfXYhA +AVIf8t+RZmpZ7FHhEdZTzhkIe/J/QbGokKTrj+eISmDK7bI3HaFWlRBPqpBbiCcQ +H/QZOHhZ16Tuf8fd/P2sGkPDbYv9M4bDm4vm67DpVbp570H/iUKXlonVgbaMOOJE +0FZ5yuBZUyD+2ABqK74U7qXNG+GjdFbGXRgDolul9pEJPb7EfrudOQP70DZHFEyR +TUYAg3DkwR5woGKO5/t07dYcbwYERUjPmnXx2m+SbKD9KdOT5hjfaB0D290Vq1aD +jZCEHn30x05zVaN8gWeRnMvB5Ckvpeyb8w3OBM5wn+hUsvDjvOGFklcMeECzTnzX +pu2V2wwzCR3n+yRu1ET9InFwEiZGt3EgnLIXkRv9PG35PVA+y+8Bq6GMDIro+FYl +TvH/XYmjLqg3gDcZ3N1YE2UQ3v47A5KEmtDZSpz8fL0nhHpxUzzLUwbqBk6RSp07 +9FPYyYhVgs62O2vteSsW6lfGwZpciOEkvS+XiRdsva8Xh2ui4y2pztSxehJqZ5MD +RJ/s9sHsK1iyY4kJwGGlPjEenWJp5S4nJZ8lHMjcot7AFx4X/AgSy9nVt54DErSR +Sx9qad5aeWZRqgJYImiZ36rFxa+iSJfE9UdJ7RVUC50kTfwnYe+uhcJZsfSYKtDF +LMQaHNKlPc8sHI1pavQB9QBUPugS0p+hpMe+z4s68Qgri0Ub4C/po/TZnNX1yYvf +d2AUBfewDTA9yomR3Py9YLiRUWnLJXas1/VpiUHgFbKD5XGj1ibP6AtLTnkAZARI ++feSiEq4CYXL1Rgx6O4ne2whd7EiTt8WowVfeXEczpVBO7Op3SrzHq7syIkuH/+2 +70j2bAy7hDl68gFQy2UU/YGHYG8/4jZgT/k0xtpyRM+6wZBa61gNdBmH2YdCLj8G +vSjfqMU7RDqlxNhh1WQ0NK24KJbG2QwNz/FmOinimZfQdPn/oqykHJAjLT/hIgr7 +ki9abaGmQbFxOodIFk6lHsyS9lpFAkrH5aKwsKyUEzLt1yhqlEoajGhQou0U4ntO +PB+r8PVFqFh2A0S/M7QnWHofyAWk/RoBjhzwnw3Qsl6QXS+A5o910DocdPEMFYde +vjbjebMwc5BMeQLHtAiwJ3qfY2giuiUZcrARETRhcfIlSMxsbXb3yf8MXtqPCMZv +Ibf7jvS3FDpp2mWHuvMtJWeuBeDa1bch6Pzs94AgDV3xrh/7LjQVSLe18C9BXWFG +ok9W/ye6ZY1UnxE+u2bqCutx4uT2tTtvzQkWO71FNhBHuFXsuFSFWX11HRYkxuBD +CRksNH69nl9qBzVoO5NZHUAm2T0ISJP5ODV1vC0QkAq4cGbGGjWs61NPfcskDTbJ +ZuJp20xZYr1U1SQqN8pzjDmU7hbpYuWIo5hD0WN97dhQrrm3HoGfxph/botEqDL+ +vsl4yfy7hcv52EOxFkWd7y9rrmYGy0fEz8GhatFrGQebe8Km+vKq8d1Ssv64L6Wz +S3EYj5oL+ihIWF++lKw32c+YRzLZ3CMjEruQoAjYStIm5wkcwyLPRMHnCYVRVIzg +nOvRiZ586KPcS4nOPARULeHDYf28sZOLrFHAWHBhmJ4sgpT95HoUs0sUn284yHn4 +hWcDZoLVVbZjx3rvsyMnadwnjkmlLt2AIvslgDS5AIMrJEwqFsUIgHA= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/cfg/keystore/private/jvet_example_provider.csr b/cfg/keystore/private/jvet_example_provider.csr new file mode 100644 index 0000000000..f003a94178 --- /dev/null +++ b/cfg/keystore/private/jvet_example_provider.csr @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEqzCCApMCAQAwZjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBkdlbmV2YTEPMA0G +A1UEBwwGR2VuZXZhMQ0wCwYDVQQKDARKVkVUMSYwJAYDVQQDDB1KVkVUIGV4YW1w +bGUgY29udGVudCBwcm92aWRlcjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAPNcwnh2TSh2NiLF1HkkV8AIuZ9j9SwvBp+RdGT8RHwp5oQXXIPYTC4ZQxmZ +diyt85aOL6hWNljzfgxQ4LJCyKOgofk4zyLEtgtuiS4jOQOH++UlGNf/vEKpXokX +RfJjPklpd7ow8JyRbrJkPcyg6RX3uGnOTlt5Kv8z7Ekg/TROm2l+3Du1fLu4tL0e +PzsyxPEmaOjmXsl9U028RuyEhAxNTe4GIZiwHAU0u1v5er6lv0YXOfZol8rxlfcp +18wqaKocu/TxtBDqln0d6XeC+e4Pt1j4AfJPUdaBt8qhW54nP1PN8oKyOHsHyt6g +v3aAlmk0b2FrVhx4UBhkRChctoKlkF3+JDSXnJdhmvnIfUlprlbbuF9MVOaMVHxG +J9VpWPsd/OZkebPMkzUmg37i08EX+kIQW/vbhYkLO1shF9gTDqqXFL2R9uNuTQL9 +DKt7s5S67+Cp05f0F293u+81DLrgA/cB6Vo6A1E/MIfjTig3tgjchhJuPxHYbx3l +BzQZ+IIuQofmtt/URUt7KGcaZAVgfvFPfVjEUZXOMhn6/jHmZWKsLtvRC8S2Vybj +/5psIvUa6Yj6o8w5KbZEXli7WKM9Mjwqpa3AanO0xHHvxsTiKr7RYR50cCaY4HhL +AQR3C9CYBIfj1tZ9DeEWhKLYRmRw30L9HpKl6Eq/xmihTlanAgMBAAGgADANBgkq +hkiG9w0BAQsFAAOCAgEAipuQa7cb+fo5KgjbyOlJ97MZTFSdYZyTUhJ9jAy58fTk +DE2ndyu6AQ0LptN7+V8Zu9opQjPTlV9j616tpogIZlbn0F+KM4d0agYIdXnBX6yj +5dJMpS/6m8DcWy6BMh51XIvYkVb8+2I/rsPF65w1ifrq8AQdOA3t6W3VHqxWyKIv +l8DOuB+pKbKgcfM8iL6/GjngTI0VfRepid5+1ODOMXvy/xsclVgvUTVyV7hKR7Z1 +/dTGKAouct9HXQWeEjQXJieh3Sln1kQ3+3bkoQS4UMzjEWAisulIOJEXhNiI8nHS +bhdCKcaYJXnThHXwDK/VOPRQuIZnENOCnyd2gtly1akKpL8YSGZugA5ArKb9VNVX +PJmVNaKhrn58vHiEidwfDoI5q1eKag7+p84tywEWVB89xVq5srprP/Yfm7kdlwUb +PfKf1FqwZGmuGBgoUa2H5OaX29jtlu2dd8mvZ4DT1fhzfJqR3hZeaisN7+E2+5Ns +rj4W+e2W0O4p5T+mD3oC6KWu45glcekH1rt69bGZkUdB9E1s9woM1b/XaTadJrE6 +4T9gc7RV8NOJOaxPmBYqFi3+r+srsVrDCTO3mOmWCanMPO9I6XM8wU0YT1jg/zQh +xzGGxLkarX0a+uHLk/BRdoCNHXeKOdFjik+z1w+B9xYXSM1Olg7xNQdcgDENIXo= +-----END CERTIFICATE REQUEST----- diff --git a/cfg/keystore/private/jvet_example_provider.key b/cfg/keystore/private/jvet_example_provider.key new file mode 100644 index 0000000000..9919719164 --- /dev/null +++ b/cfg/keystore/private/jvet_example_provider.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +bD+n4onvHpga5tN03nUvttB+g7PlQt8= +-----END PRIVATE KEY----- diff --git a/cfg/keystore/private/untrusted_ca.crt b/cfg/keystore/private/untrusted_ca.crt new file mode 100644 index 0000000000..92be67d72d --- /dev/null +++ b/cfg/keystore/private/untrusted_ca.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFmzCCA4OgAwIBAgIUXs/OsH/k0XEMr3SbtJSlZ03Dx+YwDQYJKoZIhvcNAQEL +BQAwXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh +bmNpc2NvMQ0wCwYDVQQKDARKVkVUMRowGAYDVQQDDBFKVkVUIHVudHJ1c3RlZCBD +QTAeFw0yNDExMDExNDM4MzlaFw0yOTExMDExNDM4MzlaMF0xCzAJBgNVBAYTAlVT +MQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwE +SlZFVDEaMBgGA1UEAwwRSlZFVCB1bnRydXN0ZWQgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDhJGsU27lndILc5lUc7AMTPLSS9Thi4tWwUVWpRVQ6 +da09U5Ep0eytmh1/mUNuFsoO4U9WnwZz9/yCB6L7bn6r6K8AXBvGBN7dXnXMxCdU +oCt0RPrT1EFxapn58OnyTCVCxTNHFFcNnRHxeeI3uiVBGJexhyQLbDItvDs7lO/t +Lv48yOI51d+fqMO4RXO5FuazQTMApRU9J9ochHxXDeBGguCwwNP/FtUt0fQJDlid +Z0jLiUxVBb5OzDSw7azwC5Uw0f80tIkA8PM3XZLv/OCYwPcK+mdoH/2mIaD0ljfz +l0RAe1BSNPdfz2mvooJPJgRuqQUTso4wHFnedDN5qIpgcDZF+YwwBScHFivxBrrn +CL0diMuCdVz0VTCIZYV2xS+71TTMzCaM4YGgHZ01yYhkXmMviE47rvnMsehOohSn +J5iPY66Ir2autC8z7Jcy8f3cSzMirkIElhUqs+65vqUzSPMYcMuu3FaQRLBFiGT0 +UIA3/MOzQYCyfVKjV2yW2bh9VanJTET4BN3ZzFCwJ5wcRyxgIWfzasJjMgZSuw/C +EH09OjD7MrvFsA1N/iHa0jStepHb8UGFsMAxU428Gm3rXPcTQavk5fgvlO/GqvjS +FYEvKw6xmVql3jhU2ogF6jKMtVJpAk1Au7b94oCgxiweVm0vCZwlre3enKYAk0TD +bwIDAQABo1MwUTAdBgNVHQ4EFgQUWZZ84GVCWypA5FAGkuuY7MfsB/wwHwYDVR0j +BBgwFoAUWZZ84GVCWypA5FAGkuuY7MfsB/wwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAEzCBpG6Enn9o6a8umDgDeIleUeHibM1XTlF6GmE3Wi/m +j9/1GgBIDvXcEBkgO+fMLCwzmVxwEEHa8D+civ3oGcpeKXlRMpA01c4j89ymUjU4 +FxGykzyCb+g28ixAKSUZLd4LtFWMeEH26jfLLHiIT9aPtEEcfSKkmkQixb1JPQrl ++4KuE6PwJ/M2rgBZqw5VUD1CVFsNgkng50Fc4E9081+C3pVq+KoRVg9yTwZDIswV +RJsVTJwUwe557FhRBca8B4jShgnJg8HAnNlU0oxebLjnv+1150G0P0ZnrS1Pe4su +/G6AAh2esTdKSuZHnEzbXMj7U++EZTTiRAM9DLpB1IGMPSYtlMOB/hau+QzobJ+e +yJTUsjGOWjcrva5nIGul6HkWYAbS4NhHu5FjIuHii9FvQS2yTAyNQz8Sm/qejexf +MJyDyBFodNoMLkTNe7qskkWRVbAU6IalqZqV6Gfjf3WKdfq5IkDmmwyBQnUwu1Ie +OWbJsi/6zqNUqPyymzdVORar7zRhPNRW0PV1Or9l9v/czTvvOUL/Vs6sZseaMO54 +9NNoq0LSaELroQy9xn2oPi9vajwd4Y5ea5hUMNfXAMb3vh7PWW/gQyfdxh1Qyccz +on+TMBo+b0hbvq+bbQFpqYkLpmPQO/bboSNV+C16ca13Sod7FijTUkzaqM0gUws= +-----END CERTIFICATE----- diff --git a/cfg/keystore/private/untrusted_ca.key b/cfg/keystore/private/untrusted_ca.key new file mode 100644 index 0000000000..7d14bbaa31 --- /dev/null +++ b/cfg/keystore/private/untrusted_ca.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +1A9XGKMkAjtKzNZOR1ZtXpMec+CxAQ== +-----END PRIVATE KEY----- diff --git a/cfg/keystore/public/attacker_content.crt b/cfg/keystore/public/attacker_content.crt new file mode 100644 index 0000000000..0db15eb6cf --- /dev/null +++ b/cfg/keystore/public/attacker_content.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIUagF3iqmccPfLUlrlZgtBbJp93okwDQYJKoZIhvcNAQEL +BQAwXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh +bmNpc2NvMQ0wCwYDVQQKDARKVkVUMRowGAYDVQQDDBFKVkVUIHVudHJ1c3RlZCBD +QTAeFw0yNDExMDExNDQyMzRaFw0yNjExMDExNDQyMzRaMFsxCzAJBgNVBAYTAlVT +MQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLTG9zIEFuZ2VsZXMxGjAYBgNVBAoMEUpW +RVQgaW1wZXJzb25hdG9yMQ0wCwYDVQQDDARKVkVUMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA3XBv8VfAW6MEBk7QnQM66kkEoVaEE0+kUXi2zlXyfMrC +RJ85BeF9Co+tRU6YckoRJ2Jm6iAFPqv8yFogSLAVtZL02OhAISpgq5zf5ERH9hxU +h9xsp3CaLCQ7TLgyIirsicnioiPzL/wNXl0MkP2adiqqfaWWyMgR2u+gNmczk2oe +z3W7/7Td0MYcn9i2GvECU3WAP8ZbdtL3fjhnG7NNQt7TZzUu6RYKVtIsCHZ6tMXa +5BaRBDTRehUUFaFZng7KI4nnnJwCzbCGm10mnn0h4I4sWuyEdyIi9sgLOxqQgivp +vUjEZsqbbC2SNYtV7MGcqKis6JbfNFdRFK5sqcmQOuFV4b9kcWdYA+nCjwl8QOQW +lZZsDwK9Qve2SD7G01qbP/ofJAKhMAPDstiYv66PVJm8EgkIlo/0agQv5tR3tIGh +13CDghFCBN9Pn/NQ7YCiUeTXtN0sFfiab3hzcCuHLbTjcDTVfNV8Z1uSOLHkyiGF +xTJN41mBE3XX548gQuARSaBKl6Snhbm1wsfQmtUsSKgX71vt3WHA7HP9+qTx02ia +kpDKvG9/TjtFcjECi7dasGP3epczTxd2PrPkAz4hgc+HIlhwKSIVz/ht3p/SA65r +rKSN2+23n9gCD51hBF3PdcXHwMc0tnS2sK2Y8hIqOEZdL2bsnwgprfQkpkKTeN8C +AwEAAaNCMEAwHQYDVR0OBBYEFD1kAkh1OfE4EO2JlgA3baJGdQCjMB8GA1UdIwQY +MBaAFFmWfOBlQlsqQORQBpLrmOzH7Af8MA0GCSqGSIb3DQEBCwUAA4ICAQB32dc0 +Nil3mC/yOL/+CycJttuULseT8OYvugq3wb0f3Xcf5Z92drFSqCDqEIMoHPzx4x1q +eXq8RjWX4uxJP2bCd8CEC85oi5VOMPj6JlUWSv4PuBl3SWpS17ZWUooDD6eNoXDu +nmVnAuQ28HE9gn7MeOfArEqPxyt+ZV+vD5CXw37We/csTqR+wOrKWci66wUh6MAn +fQmTcvhh/Gkh/yGoT41P2rjDdcI10na3wRUUCNBM9qa/+gZOCr6AizJYw2tk5D1q +CQwdbFLIucXnvbf1M8VEZIN8PtlVn+UzHRY2AX9aHmehBUOnKVNO8Rzo0lMH2QvW +VYMm28zZFU9Vj/yyOXEwmrNEsbN6lH7vrrNpglk79z1tYVI2OFGCy76GdxFtM+pN +K0N8+QZ/02Aco+KqgQXW6ztTZMk52R/60owF1Qufrlk87zIzX1lcqnOCja5f1/1j +QQrtVWQ7z9ZbBo79ppOCmf9vsn4onb6rlr47cP69MuhWd3m19+UdTMzUzWcQuDVv +eOXZU1jZC+DclkxNJXJrh4MD4TGiUfp2cbliTiP+oxqg7fv4bKaVFONPfCb5thqe +MXSze4K//546XZeU32h4fJKz7v1pbFiD1TRisA/ScH/tsVRBWdiWNpMHIjcM9ZAl +Y9xuHIQRvS3B+Vs+VEow7u9sql1BW5ls43WVmQ== +-----END CERTIFICATE----- diff --git a/cfg/keystore/public/jvet_example_provider.crt b/cfg/keystore/public/jvet_example_provider.crt new file mode 100644 index 0000000000..d52b22d3e2 --- /dev/null +++ b/cfg/keystore/public/jvet_example_provider.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFjjCCA3agAwIBAgIUPHb0Ymtt23LsKEaj4cLPxOOm7tEwDQYJKoZIhvcNAQEL +BQAwWDELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBkdlbmV2YTEPMA0GA1UEBwwGR2Vu +ZXZhMQ0wCwYDVQQKDARKVkVUMRgwFgYDVQQDDA9KVkVUIEV4YW1wbGUgQ0EwHhcN +MjQxMTAxMTI1NTAwWhcNMjYxMTAxMTI1NTAwWjBmMQswCQYDVQQGEwJDSDEPMA0G +A1UECAwGR2VuZXZhMQ8wDQYDVQQHDAZHZW5ldmExDTALBgNVBAoMBEpWRVQxJjAk +BgNVBAMMHUpWRVQgZXhhbXBsZSBjb250ZW50IHByb3ZpZGVyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEA81zCeHZNKHY2IsXUeSRXwAi5n2P1LC8Gn5F0 +ZPxEfCnmhBdcg9hMLhlDGZl2LK3zlo4vqFY2WPN+DFDgskLIo6Ch+TjPIsS2C26J +LiM5A4f75SUY1/+8QqleiRdF8mM+SWl3ujDwnJFusmQ9zKDpFfe4ac5OW3kq/zPs +SSD9NE6baX7cO7V8u7i0vR4/OzLE8SZo6OZeyX1TTbxG7ISEDE1N7gYhmLAcBTS7 +W/l6vqW/Rhc59miXyvGV9ynXzCpoqhy79PG0EOqWfR3pd4L57g+3WPgB8k9R1oG3 +yqFbnic/U83ygrI4ewfK3qC/doCWaTRvYWtWHHhQGGREKFy2gqWQXf4kNJecl2Ga ++ch9SWmuVtu4X0xU5oxUfEYn1WlY+x385mR5s8yTNSaDfuLTwRf6QhBb+9uFiQs7 +WyEX2BMOqpcUvZH2425NAv0Mq3uzlLrv4KnTl/QXb3e77zUMuuAD9wHpWjoDUT8w +h+NOKDe2CNyGEm4/EdhvHeUHNBn4gi5Ch+a239RFS3soZxpkBWB+8U99WMRRlc4y +Gfr+MeZlYqwu29ELxLZXJuP/mmwi9RrpiPqjzDkptkReWLtYoz0yPCqlrcBqc7TE +ce/GxOIqvtFhHnRwJpjgeEsBBHcL0JgEh+PW1n0N4RaEothGZHDfQv0ekqXoSr/G +aKFOVqcCAwEAAaNCMEAwHQYDVR0OBBYEFNt0O0zrfYC91RkvIfia0zWJ8dyjMB8G +A1UdIwQYMBaAFB6JYdS3IB8G/BOXOPGECsQ0gqo2MA0GCSqGSIb3DQEBCwUAA4IC +AQA6XF5pY/5VuuUviemcot6UHDlysS6c04fOShvwdTj0Bg8fpXHkA9R3vXUYVRuU +bUg4iheKcA7pHMQKy+WsKT30eU/ZNGryIA5d1gDBCXMsCofv5S6U1UASSwCr/+ut +mKhK81exVN37O9Wd14frXSYQJdxxOJIArRucjJmZcks2bQl1I1IjQJj5AdFoymQh +CPLFjEAM3yiCR5+ONFByqJ0eTxZvl3z7fTwb1sFRSAw86nRF/WUHsGCxn/9zApeI +SPY9/nSwhhmln5/KZBrAXmUH7+jCfpCr2WOTK5v/a0Ab3Im4Ua/LPxOL2FsCGcxw +0XkPcpTIL97sOywFGMF1IBACvwd11LsucHO4SKsAiDCgOvw9iYvpMjS0W2IgLOqH +cla02pqoH3zmdnt9WgetkvWT0oPueZkY1SuNF7VZ0clSIlxnXFyHja9VxgOm5iVy +qrbBzLTAa8t2ULT29t69ymJnTwuai6qRYi3FAz+iYElmd+MVuEiJkSm35a05HVmR +EGpvMLK5patRnpWacOL0RjlNWgWRMBlFP9Hemy8reaGsl85JR8Er5O5bTANz7v2J +Ft9ZsyKjmt3bBqgSv+3WAcJEbha1O+5esDBwX104c180ljtrhOwffJpQoX2l7tZh +4WpS2nqyLlkrXqbFXtHv3nmwNEd9o2HbB0yKEFhf70bYfA== +-----END CERTIFICATE----- diff --git a/cfg/sei_vui/digially_signed_content.cfg b/cfg/sei_vui/digially_signed_content.cfg new file mode 100644 index 0000000000..cc5fde812e --- /dev/null +++ b/cfg/sei_vui/digially_signed_content.cfg @@ -0,0 +1,7 @@ +SEIDSCEnabled : 1 +SEIDSCHashMethod : 4 +SEIDSCSigningKeyFile : ../cfg/keystore/private/jvet_example_provider.key +SEIDSCVerificationKeyURI : file://somepath/jvet_example_provider.crt +SEIDSCKeyIDEnabled : 0 +SEIDSCKeyID : 0 + diff --git a/doc/software-manual.tex b/doc/software-manual.tex index ca56529a49..ea5cc3a0c1 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -4039,6 +4039,7 @@ The table below lists the SEI messages defined for Version 1 and Range-Extension 213 & Processing order SEI messages & Table \ref{tab:sei-processing order}\\ 216 & Source Picture Timing Information & Table \ref{tab:sei-source-picture-timing-info}\\ 218 & Modality Information SEI messages & Table \ref{tab:sei-modality-info}\\ + 220/221/222 & Digitally Signed Content SEI messages & Table \ref{tab:sei-dsc}\\ \end{SEIListTable} %% %% SEI messages @@ -6328,6 +6329,43 @@ Specifies the exponent part of the maximum wavelength indicating the spectral ba %When true, generate time code SEI messages. %\\ +\begin{OptionTableNoShorthand}{Digitally Signed Content SEI messages encoder parameters}{tab:sei-dsc} +\Option{SEIDSCEnabled} & +\Default{false} & +Enables (true) or disables (false) the insertion of Digitally Signed Content Initialisation, Selection and Verification SEI message. +\\ +\Option{SEIDSCHashMethod} & +\Default{0} & +Hash method to be used . +\par + \begin{tabular}{cp{0.46\textwidth}} + 0 & SHA-1 \\ + 1 & SHA-224 \\ + 2 & SHA-256 \\ + 3 & SHA-384 \\ + 4 & SHA-512 \\ + 5 & SHA-512/224 \\ + 6 & SHA-512/256 \\ + \end{tabular} +\\ +\Option{SEIDSCSigningKeyFile} & +\Default{(empty)} & +Location of the private key file to be used for signing. +\\ +\Option{SEIDSCVerificationKeyURI} & +\Default{(empty)} & +Certificate URI to be signalled to the decoder. Note, the decoder currently only supports "file://" URIs. +\\ +\Option{SEIDSCKeyIDEnabled} & +\Default{0} & +Indicated whether a key ID is signalled. +\\ +\Option{SEIDSCKeyID} & +\Default{0} & +If SEIDSCKeyIDEnabled is enabled, the value of the key ID. +\\ +\end{OptionTableNoShorthand} + \begin{OptionTableNoShorthand}{Object Mask Information SEI message encoder parameters}{tab:sei-object-mask-information} \Option{SEIObjectMaskFileRoot (-omi)} & \Default{\NotSet} & @@ -6768,6 +6806,17 @@ When true, do not output frames for which there is an SEI NoDisplay message. If 1 then clip output video to the Rec. 709 Range on saving when OutputBitDepth is less than InternalBitDepth. \\ +\Option{KeyStoreDir} & +%\ShortOption{\None} & +\Default{"keystore/pub"} & +If Digitally Signed Content SEIs are present in the bitstream and support for verifying digital signatures is enabled in the software, KeyStoreDir specifies the directory for pre-stored content provider certificates. When a "file://" URI is provided, the decoder searches for the specifies file name in this directory. +\\ + +\Option{TrustStoreDir} & +%\ShortOption{\None} & +\Default{"keystore/ca"} & +If Digitally Signed Content SEIs are present in the bitstream and support for verifying digital signatures is enabled in the software, KeyStoreDir specifies the directory for pre-stored content provider certificates. The content provider certificate is verified against all CA certificated in this folder. Note, when adding new CA certificates, run "openssl rehash <directory>" to create the necessary hash links.\\ + \end{OptionTableNoShorthand} diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index ff74e02c4c..a9f4fcb0af 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -928,6 +928,9 @@ void DecApp::xCreateDecLib() ); m_cDecLib.setDecodedPictureHashSEIEnabled(m_decodedPictureHashSEIEnabled); +#if JVET_AJ0151_DSC_SEI + m_cDecLib.setKeyStoreParameters(m_keyStoreDir, m_trustStoreDir); +#endif if (!m_outputDecodedSEIMessagesFilename.empty()) { diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index c4e611a687..1555a8ae4d 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -132,6 +132,10 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("UpscaledOutputWidth", m_upscaledOutputWidth, 0, "Forced upscaled output width (override SPS)" ) ("UpscaledOutputHeight", m_upscaledOutputHeight, 0, "Forced upscaled output height (override SPS)" ) ("UpscaleFilterForDisplay", m_upscaleFilterForDisplay, 1, "Filters used for upscaling reconstruction to full resolution (2: ECM 12 - tap luma and 6 - tap chroma MC filters, 1 : Alternative 12 - tap luma and 6 - tap chroma filters, 0 : VVC 8 - tap luma and 4 - tap chroma MC filters)") +#if JVET_AJ0151_DSC_SEI + ("KeyStoreDir", m_keyStoreDir, std::string("keystore/pub"), "Directory for locally stored public keys for verifying digitally signed content") + ("TrustStoreDir", m_trustStoreDir, std::string("keystore/ca"), "Directory for locally stored trusted CA certificates") +#endif #if GDR_LEAK_TEST ("RandomAccessPos", m_gdrPocRandomAccess, 0, "POC of GDR Random access picture\n") #endif // GDR_LEAK_TEST diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index c2c4cc3642..0fd74e381e 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -102,6 +102,10 @@ protected: int m_upscaledOutputHeight; int m_upscaleFilterForDisplay; int m_targetSubPicIdx; ///< Specify which subpicture shall be write to output, using subpicture index +#if JVET_AJ0151_DSC_SEI + std::string m_keyStoreDir; + std::string m_trustStoreDir; +#endif #if GDR_LEAK_TEST int m_gdrPocRandomAccess; ///< #endif // GDR_LEAK_TEST diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index dd1f9bbe71..0ac645489d 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -1042,6 +1042,9 @@ void EncApp::xInitLibCfg( int layerIdx ) m_cEncLib.setGcmpSEIGuardBandBoundaryExteriorFlag ( m_gcmpSEIGuardBandBoundaryExteriorFlag ); m_cEncLib.setGcmpSEIGuardBandSamplesMinus1 ( (uint8_t)m_gcmpSEIGuardBandSamplesMinus1 ); m_cEncLib.setSubpicureLevelInfoSEICfg (m_cfgSubpictureLevelInfoSEI); +#if JVET_AJ0151_DSC_SEI + m_cEncLib.setDigitallySignedContentSEICfg (m_cfgDigitallySignedContentSEI); +#endif m_cEncLib.setSampleAspectRatioInfoSEIEnabled (m_sampleAspectRatioInfoSEIEnabled); m_cEncLib.setSariCancelFlag (m_sariCancelFlag); m_cEncLib.setSariPersistenceFlag (m_sariPersistenceFlag); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 8e3ec11782..c26ba3ccdb 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1529,6 +1529,21 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("SEISPTISourceType", m_sptiSourceType, 0u, "Indicates the timing relationship between source pictures and corresponding decoded output pictures.") ("SEISPTITimeScale", m_sptiTimeScale, 27000000u, "Specifies the number of time units that pass in one second.") ("SEISPTINumUnitsInElementalInterval", m_sptiNumUnitsInElementalInterval, 1080000u, "Specifies the number of time units of a clock operating at the frequency spti_time_scale Hz that corresponds to the indicated elemental source picture interval of consecutive pictures in output order in the CLVS.") +#if JVET_AJ0151_DSC_SEI +("SEIDSCEnabled", m_cfgDigitallySignedContentSEI.enabled, false, "Control generation of Digitally Signed Content SEI messages") +("SEIDSCHashMethod", m_cfgDigitallySignedContentSEI.hashMethod, 0 , "Hash type to be used:\n" + "\t0: SHA-1 (default)\n" + "\t1: SHA-224\n" + "\t2: SHA-256\n" + "\t3: SHA-384\n" + "\t4: SHA-512\n" + "\t5: SHA-512/224\n" + "\t6: SHA-512/256") +("SEIDSCSigningKeyFile", m_cfgDigitallySignedContentSEI.privateKeyFile, std::string("") , "(Private) signing key location for Digitally Signed Content SEI messages") +("SEIDSCVerificationKeyURI", m_cfgDigitallySignedContentSEI.publicKeyUri, std::string("") , "(Public) verification key URI for Digitally Signed Content SEI messages") +("SEIDSCKeyIDEnabled", m_cfgDigitallySignedContentSEI.keyIdEnabled, false, "Enable using a key ID addition to URI of public key of Digitally Signed Content SEI messages") +("SEIDSCKeyID", m_cfgDigitallySignedContentSEI.keyId, 0 , "Public Key ID for Digitally Signed Content SEI messages (if enabled)") +#endif #if ENABLE_TRACING ("TraceChannelsList", bTracingChannelsList, false, "List all available tracing channels") ("TraceRule", sTracingRule, std::string(""), "Tracing rule (ex: \"D_CABAC:poc==8\" or \"D_REC_CB_LUMA:poc==8\")") diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 71566661f0..d723ce181c 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -762,6 +762,9 @@ protected: uint32_t m_gcmpSEIGuardBandSamplesMinus1; EncCfgParam::CfgSEISubpictureLevel m_cfgSubpictureLevelInfoSEI; +#if JVET_AJ0151_DSC_SEI + EncCfgParam::CfgSEIDigitallySignedContent m_cfgDigitallySignedContentSEI; +#endif bool m_nnPostFilterSEICharacteristicsEnabled; bool m_nnPostFilterSEICharacteristicsUseSuffixSEI; diff --git a/source/Lib/CommonAnalyserLib/CMakeLists.txt b/source/Lib/CommonAnalyserLib/CMakeLists.txt index 3b8197ffc8..103975ca53 100644 --- a/source/Lib/CommonAnalyserLib/CMakeLists.txt +++ b/source/Lib/CommonAnalyserLib/CMakeLists.txt @@ -75,8 +75,17 @@ if( DEFINED ENABLE_HIGH_BITDEPTH ) endif() endif() -target_include_directories( ${LIB_NAME} PUBLIC ../CommonLib/. ../CommonLib/.. ../CommonLib/x86 ../libmd5 ) -target_link_libraries( ${LIB_NAME} ) +find_package(OpenSSL) + +if (NOT OPENSSL_FOUND) + message ("OpenSSL not available. Compiling with parsing only support for Digitally Signed Content SEIs") + target_compile_definitions( ${LIB_NAME} PUBLIC JVET_AJ0151_DSC_SEI=0 ) + target_include_directories( ${LIB_NAME} PUBLIC ../CommonLib/. ../CommonLib/.. ../CommonLib/x86 ../libmd5 ) + target_link_libraries( ${LIB_NAME} ) +else() + target_include_directories( ${LIB_NAME} PUBLIC ../CommonLib/. ../CommonLib/.. ../CommonLib/x86 ../libmd5 ${OPENSSL_INCLUDE_DIR} ) + target_link_libraries( ${LIB_NAME} OpenSSL::SSL OpenSSL::Crypto ) +endif() if (NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") ) # set needed compile definitions diff --git a/source/Lib/CommonLib/BitStream.h b/source/Lib/CommonLib/BitStream.h index 47eacf86c0..d94b5dc187 100644 --- a/source/Lib/CommonLib/BitStream.h +++ b/source/Lib/CommonLib/BitStream.h @@ -152,6 +152,9 @@ class InputBitstream protected: std::vector<uint8_t> m_fifo; /// FIFO for storage of complete bytes std::vector<uint32_t> m_emulationPreventionByteLocation; +#if JVET_AJ0151_DSC_SEI + std::vector<uint8_t> m_origFifo; /// for calculation of hash +#endif uint32_t m_fifoIdx; /// Read index into m_fifo @@ -218,6 +221,12 @@ public: const std::vector<uint8_t> &getFifo() const { return m_fifo; } std::vector<uint8_t> &getFifo() { return m_fifo; } + +#if JVET_AJ0151_DSC_SEI + const std::vector<uint8_t> &getOrigFifo() const { return m_origFifo; } + void clearOrigFifo() { m_origFifo.clear(); } + void copyToOrigFifo() { m_origFifo = m_fifo; } +#endif }; //! \} diff --git a/source/Lib/CommonLib/CMakeLists.txt b/source/Lib/CommonLib/CMakeLists.txt index 3352a666e9..669e631e9d 100644 --- a/source/Lib/CommonLib/CMakeLists.txt +++ b/source/Lib/CommonLib/CMakeLists.txt @@ -73,8 +73,17 @@ if( DEFINED ENABLE_HIGH_BITDEPTH ) endif() endif() -target_include_directories( ${LIB_NAME} PUBLIC . .. ./x86 ../libmd5 ) -target_link_libraries( ${LIB_NAME} ) +find_package(OpenSSL) + +if (NOT OPENSSL_FOUND) + message ("OpenSSL not available. Compiling with parsing only support for Digitally Signed Content SEIs") + target_compile_definitions( ${LIB_NAME} PUBLIC JVET_AJ0151_DSC_SEI=0 ) + target_include_directories( ${LIB_NAME} PUBLIC . .. ./x86 ../libmd5 ) + target_link_libraries( ${LIB_NAME} ) +else() + target_include_directories( ${LIB_NAME} PUBLIC . .. ./x86 ../libmd5 ${OPENSSL_INCLUDE_DIR} ) + target_link_libraries( ${LIB_NAME} OpenSSL::SSL OpenSSL::Crypto ) +endif () if (NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") ) # set needed compile definitions diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp index 6f3d73392f..73ac4439c2 100644 --- a/source/Lib/CommonLib/SEI.cpp +++ b/source/Lib/CommonLib/SEI.cpp @@ -487,6 +487,11 @@ static const std::map<SEI::PayloadType, const char *> payloadTypeStrings = { #if JVET_AG0322_MODALITY_INFORMATION { SEI::PayloadType::MODALITY_INFORMATION, "Modality information" }, #endif +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + { SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION, "Digitally Signed Content Initialization" }, + { SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION, "Digitally Signed Content Selection" }, + { SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_VERIFICATION, "Digitally Signed Content Verification" }, +#endif #if JVET_AJ0207_GFV { SEI::PayloadType::GENERATIVE_FACE_VIDEO, "Generative face video" } #endif diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h index ad19197b56..b354cedda0 100644 --- a/source/Lib/CommonLib/SEI.h +++ b/source/Lib/CommonLib/SEI.h @@ -112,6 +112,11 @@ public: #if JVET_AH2006_TXTDESCRINFO_SEI SEI_TEXT_DESCRIPTION = 219, #endif +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + DIGITALLY_SIGNED_CONTENT_INITIALIZATION = 220, + DIGITALLY_SIGNED_CONTENT_SELECTION = 221, + DIGITALLY_SIGNED_CONTENT_VERIFICATION = 222, +#endif #if JVET_AJ0207_GFV GENERATIVE_FACE_VIDEO = 223, #endif diff --git a/source/Lib/CommonLib/SEIDigitallySignedContent.cpp b/source/Lib/CommonLib/SEIDigitallySignedContent.cpp new file mode 100644 index 0000000000..b40f886e4a --- /dev/null +++ b/source/Lib/CommonLib/SEIDigitallySignedContent.cpp @@ -0,0 +1,601 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2024, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SEI.h" +#include "SEIDigitallySignedContent.h" + +#include <cctype> + +#if JVET_AJ0151_DSC_SEI + +const EVP_MD* getHashFunction(int hashMethod) +{ + switch (hashMethod) + { + case 0: + return EVP_sha1(); + break; + case 1: + return EVP_sha224(); + break; + case 2: + return EVP_sha256(); + break; + case 3: + return EVP_sha384(); + break; + case 4: + return EVP_sha512(); + break; + case 5: + return EVP_sha512_224(); + break; + case 6: + return EVP_sha512_256(); + break; + default: + THROW ("unknown hash function"); + } +} + +void DscSubstream::initSubstream(int hashMethod) +{ + if (m_currentDigest.size()) + { + m_lastDigest=m_currentDigest; + m_currentDigest.clear(); + } + + if (m_ctx != nullptr) + { + printf ("DSC warning: initializing substream that was not signed or verified\n"); + EVP_MD_CTX_free(m_ctx); + } + + m_ctx = EVP_MD_CTX_new(); + CHECK (m_ctx == nullptr, "Failed to create EVP_MD_CTX"); + + if (EVP_DigestInit_ex(m_ctx, getHashFunction(hashMethod), nullptr) != 1) + { + THROW( "EVP_DigestInit_ex failed" ); + EVP_MD_CTX_free(m_ctx); + exit(1); + } + m_streamStatus = DSC_Initialized; + m_dataAdded = false; +} +bool DscSubstream::addDatapacket(const char *data, size_t length) +{ + CHECK(m_streamStatus == DSC_Uninitalized, "substream is not initialized"); + + if (m_streamStatus == DSC_Verified) + { + printf ("Stream already verified, cannot add data.\n"); + return false; + } + + if (!EVP_DigestUpdate(m_ctx, data, length)) + { + THROW("Message digest update failed."); + EVP_MD_CTX_free(m_ctx); + exit(1); + } + m_dataAdded = true; + + return true; +} + +bool DscSubstream::calculateHash() +{ + CHECK(m_streamStatus == DSC_Uninitalized, "substream is not initialized"); + + if (m_streamStatus == DSC_Verified) + { + printf ("Stream already verified, cannot calculate hash again\n"); + return false; + } + + if (m_dataAdded == false) + { + return false; + } + + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int lengthOfHash = 0; + + if (EVP_DigestFinal_ex(m_ctx, hash, &lengthOfHash) != 1) + { + THROW ("EVP_DigestFinal_ex failed"); + EVP_MD_CTX_free(m_ctx); + exit(1); + } + + EVP_MD_CTX_free(m_ctx); + m_ctx = nullptr; + + m_currentDigest.resize(lengthOfHash); + std::memcpy(m_currentDigest.data(), hash, lengthOfHash); + + return true; +} + + +void DscSubstreamManager::initDscSubstreamManager (int numSubstreams, int hashMethodType, const std::string &certUri, bool hasContentUuid, std::array<uint8_t,16> &contentUuid) +{ + if (!m_isInitialized) + { + m_substream.resize(numSubstreams); + for (auto &substream: m_substream) + { + substream.initSubstream(hashMethodType); + } + m_hashMethodType = hashMethodType; + m_certUri = certUri; + m_hasContentUuid = hasContentUuid; + if (hasContentUuid) + { + // always 16 bytes (128 bit) + m_contentUuid.resize(16); + std::memcpy(m_contentUuid.data(), contentUuid.data(), 16); + } + + m_isInitialized = true; + m_isFirstSubstream = true; + + printf ("DSC: initializing %d substreams\n", numSubstreams); + } + else + { + printf ("DSC: re-initializing %d substreams\n", numSubstreams); + if (numSubstreams != m_substream.size()) + { + printf ("DSC Warning: re-initializing with different number of substream, starting a new signed segment\n"); + uninitDscSubstreamManager(); + initDscSubstreamManager(numSubstreams, hashMethodType, certUri, hasContentUuid, contentUuid); + return; + } + if (hashMethodType != m_hashMethodType) + { + printf ("DSC Warning: re-initializing with different hash method type, starting a new signed segment\n"); + uninitDscSubstreamManager(); + initDscSubstreamManager(numSubstreams, hashMethodType, certUri, hasContentUuid, contentUuid); + return; + } + if (certUri != m_certUri) + { + printf ("DSC Warning: re-initializing with different certificate URI, starting a new signed segment\n"); + uninitDscSubstreamManager(); + initDscSubstreamManager(numSubstreams, hashMethodType, certUri, hasContentUuid, contentUuid); + return; + } + if (hasContentUuid != m_hasContentUuid) + { + printf ("DSC Warning: re-initializing with different presence of content UUID, starting a new signed segment\n"); + uninitDscSubstreamManager(); + initDscSubstreamManager(numSubstreams, hashMethodType, certUri, hasContentUuid, contentUuid); + return; + } + for (auto &substream: m_substream) + { + substream.initSubstream(hashMethodType); + } + // update content UUID + if (hasContentUuid) + { + // always 16 bytes (128 bit) + m_contentUuid.resize(16); + std::memcpy(m_contentUuid.data(), contentUuid.data(), 16); + } + m_isFirstSubstream = false; + } +} + +void DscSubstreamManager::initSignature(const std::string &privKeyFile) +{ + if (!m_sigInitialized) + { + m_dscSign.initDscSignature(privKeyFile, m_hashMethodType); + m_sigInitialized = true; + } +} + +bool DscSubstreamManager::initVerificator (const std::string &keyStoreDir, const std::string &trustStoreDir) +{ + if (!m_dscVerify.initDscVerificator (m_certUri, keyStoreDir, trustStoreDir, m_hashMethodType)) + { + return false; + } + + return true; +} + +void DscSubstreamManager::addToSubstream (int substreamId, const char *data, size_t length) +{ + CHECK(substreamId >= m_substream.size(), "Invalid substream"); + if (!m_substream[substreamId].addDatapacket(data, length)) + { + printf ("Trying to add NAL unit to substream %d, which was already verified.\n", substreamId); + } +} + + +void DscSubstreamManager::createDatapacket (int substreamId, std::vector<uint8_t> &dataPacket) +{ + std::vector<uint8_t> refDigest; + std::vector<uint8_t> curDigest; + + m_substream[substreamId].getCurrentDigest(curDigest); + + if (substreamId == 0) + { + if (m_isFirstSubstream) + { + refDigest.resize(curDigest.size()); + std::memset(refDigest.data(), 0, refDigest.size()); + } + else + { + m_substream[substreamId].getLastDigest(refDigest); + } + } + else + { + m_substream[substreamId - 1].getCurrentDigest(refDigest); + } + dataPacket.insert(dataPacket.end(), refDigest.begin(), refDigest.end()); + dataPacket.insert(dataPacket.end(), curDigest.begin(), curDigest.end()); + dataPacket.insert(dataPacket.end(), m_hashMethodType); + if (m_hasContentUuid) + { + dataPacket.insert(dataPacket.end(), m_contentUuid.begin(), m_contentUuid.end()); + } + +}; + +void DscSubstreamManager::signSubstream (int substreamId, std::vector<uint8_t> &signature) +{ + printf ("DSC: signing substream %d\n", substreamId); + CHECK(substreamId >= m_substream.size(), "Invalid substream"); + + if (! m_substream[substreamId].calculateHash()) + { + THROW("Cannot create signature, because no data was added into substream"); + } + + std::vector<uint8_t> dataPacket; + createDatapacket (substreamId, dataPacket); + + m_dscSign.signPacket(dataPacket, signature); +} + +bool DscSubstreamManager::verifySubstream (int substreamId, std::vector<uint8_t> &signature) +{ + printf ("DSC: verifying substream %d\n", substreamId); + CHECK(substreamId >= m_substream.size(), "Invalid substream"); + if (! m_substream[substreamId].calculateHash()) + { + std::cout << "Cannot verify signature for substream " << substreamId << " because no NAL units are present in that substream." << std::endl; + return false; + } + std::vector<uint8_t> dataPacket; + createDatapacket (substreamId, dataPacket); + + return m_dscVerify.verifyPacket(dataPacket, signature); +} + + +void DscSubstreamManager::uninitDscSubstreamManager() +{ + CHECK(m_isInitialized == false, "substream manager is not initialized"); + m_substream.clear(); + m_isInitialized = false; +} + +bool DscSignature::initDscSignature (const std::string &keyfile, int hashMethod) +{ + CHECK(m_isInitialized == true, "Signature is already initialized"); + // Read private key + FILE *pkeyFile = fopen(keyfile.c_str(), "r"); + if (!pkeyFile) + { + std::cerr << "Error opening private key file: " << keyfile << std::endl; + return false; + } + m_privKey = PEM_read_PrivateKey(pkeyFile, nullptr, nullptr, nullptr); + fclose(pkeyFile); + if (!m_privKey) + { + std::cerr << "Error reading private key: " << keyfile << std::endl; + return false; + } + + m_hashMethodType = hashMethod; + m_isInitialized = true; + return true; +} + +bool DscSignature::signPacket (std::vector<uint8_t> &packet, std::vector<uint8_t> &signature) +{ + CHECK(m_isInitialized == false, "Signature is not initialized"); + +#if 0 + if (std::rand() > (RAND_MAX / 2) ) + { + std::cout << "\033[1;31mTest mode: invalid signature\033[0m\n"; + packet[0] = 0; + } +#endif + + // Create signature + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); + EVP_SignInit(mdctx, getHashFunction(m_hashMethodType)); + EVP_SignUpdate(mdctx, packet.data(), packet.size()); + unsigned int sig_len; + // resize the maximum lenght of the signature + signature.resize(EVP_PKEY_size(m_privKey)); + EVP_SignFinal(mdctx, signature.data(), &sig_len, m_privKey); + // resize to the actual length of the signature + signature.resize(sig_len); + EVP_MD_CTX_free(mdctx); + return true; +} + +void DscSignature::uninitDscSignature () +{ + if (m_isInitialized) + { + if (m_privKey) + { + EVP_PKEY_free(m_privKey); + m_privKey = nullptr; + } + m_isInitialized = false; + } +} + + +// Verify a certificate against trusted certificate storage +// Directory needs to contain hash links as created by 'openssl rehash <dir>' +// returns +// DSCStatus::DSCError - in case of error +// DSCStatus::DSC_Untrusted - if the verification fails +// DSCStatus::DSC_Verified - if the verificatoion is successfull +DSCStatus DscVerificator::verifyCert (const std::string &certFile, const std::string &trustStoreDir) +{ + BIO *certbio = NULL; + X509 *cert = NULL; + + // Create a new BIO object for reading the certificate + certbio = BIO_new(BIO_s_file()); + + // Load the certificate from file + if (BIO_read_filename(certbio, certFile.c_str()) <= 0) + { + printf("Error loading cert PEM file\n"); + return DSCStatus::DSC_Error; + } + cert = PEM_read_bio_X509(certbio, NULL, 0, NULL); + if (!cert) + { + printf("Error loading cert into memory\n"); + return DSCStatus::DSC_Error; + } + + // Print the certificate's subject name + char *subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + printf("Certificate Subject: %s\n", subject); + + // The trusted store is the set of CA certificates that are trusted + X509_STORE *store = X509_STORE_new(); + + // Load all CA certificates from the specified directory + if (!X509_STORE_load_locations(store, NULL, trustStoreDir.c_str())) + { + printf("Error loading CA certs from directory\n"); + return DSCStatus::DSC_Error; + } + + // The context holds the validation parameters and results + X509_STORE_CTX *ctx = X509_STORE_CTX_new(); + + // Initialize the context for the validation operation + if (!X509_STORE_CTX_init(ctx, store, cert, NULL)) + { + printf("Error initializing validation context\n"); + return DSCStatus::DSC_Error; + } + + // Perform the validation + int result = X509_verify_cert(ctx); + if (result != 1) + { + printf("\033[1;31mCertificate validation failed\033[0m\n"); + m_certVerificationStatus = DSCStatus::DSC_Untrusted; + return DSCStatus::DSC_Untrusted; + } + else + { + // Print the certificate's issuer name + char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + printf("Certificate Issuer (CA): %s\n", issuer); + printf("\033[1;32mCertificate validation passed.\033[0m\n"); + m_certVerificationStatus = DSCStatus::DSC_Verified; + } + + // Clean up + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + X509_free(cert); + BIO_free_all(certbio); + + return DSCStatus::DSC_Verified; +} + +// Convert a URI to a local storage location +// Works only for file:// URIs at the moment, but could easily be extended to other sources +// Paths in the URI are ignored +bool DscVerificator::xLocateCertificate (const std::string &certificateURI, const std::string &keyStoreDir, std::string &targetPath) +{ + // we currently support only "FILE://" URIs + std::string uri = certificateURI; + std::string lowercaseURI = uri; + std::transform(lowercaseURI.begin(), lowercaseURI.end(), lowercaseURI.begin(), [](unsigned char c){ return std::tolower(c); }); + if (lowercaseURI.rfind("file://", 0) == std::string::npos) + { + printf ("This software currently only supports FILE:// URIs\n"); + return false; + } + + std::size_t found = uri.rfind("/"); + + if ((found + 1) == uri.size()) + { + // "/" character found at the end of URI -> remove and find again + uri.pop_back(); + found = uri.rfind("/"); + } + + CHECK (found==std::string::npos, "no / character found in URI. This should not happen after previous prefix check.") + + targetPath = keyStoreDir + "/" + uri.substr(found + 1); + + std::cout << "Using certificate file: " << targetPath << std::endl; + + return true; +} + +DSCStatus DscVerificator::initDscVerificator (const std::string &certificateURI, const std::string &keyStoreDir, const std::string &trustStoreDir, int hashMethod) +{ + m_certVerificationStatus = DSCStatus::DSC_Uninitalized; + + // sanitize certificate URI and redirect to key store + std::string certificatePath; + + if (!xLocateCertificate(certificateURI, keyStoreDir, certificatePath)) + { + return DSCStatus::DSC_Error; + } + + // verify certificate + m_certVerificationStatus = verifyCert(certificatePath, trustStoreDir); + if (m_certVerificationStatus == DSCStatus::DSC_Error ) + { + return m_certVerificationStatus; + } + + // Read certificate + FILE *certFile = fopen(certificatePath.c_str(), "r"); + if (!certFile) + { + std::cerr << "Error opening certificate file\n"; + return DSCStatus::DSC_Error; + } + + X509 *cert = PEM_read_X509(certFile, nullptr, nullptr, nullptr); + fclose(certFile); + + if (!cert) + { + std::cerr << "Error reading certificate\n"; + return DSCStatus::DSC_Error; + } + + // Get public key from certificate + m_pubKey = X509_get_pubkey(cert); + if (!m_pubKey) + { + std::cerr << "Error getting public key from certificate\n"; + return DSCStatus::DSC_Error; + } + + m_hashMethodType = hashMethod; + m_isInitialized = true; + + return DSCStatus::DSC_Initialized; +} + +DSCStatus DscVerificator::verifyPacket (std::vector<uint8_t> &packet, std::vector<uint8_t> &signature) +{ + if (!m_isInitialized) + { + return DSCStatus::DSC_Uninitalized; + } + // Verify signature + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); + EVP_VerifyInit(mdctx, getHashFunction(m_hashMethodType)); + EVP_VerifyUpdate(mdctx, packet.data(), packet.size()); + int verify_result = EVP_VerifyFinal(mdctx, signature.data(), (unsigned int) signature.size(), m_pubKey); + EVP_MD_CTX_free(mdctx); + + if (verify_result == 1) + { + if ( m_certVerificationStatus != DSCStatus::DSC_Verified ) + { + std::cout << "\033[1;31mSignature is valid, but CA is untrusted.\033[0m\n"; + return DSCStatus::DSC_Untrusted; + } + std::cout << "\033[1;32mSignature is valid.\033[0m\n"; + return DSCStatus::DSC_Verified; + } else if (verify_result == 0) + { + std::cout << "\033[1;31mSignature is invalid.\033[0m\n"; + return DSCStatus::DSC_Invalid; + } else + { + std::cout << "Error occurred during verification.\n"; + } + + if (verify_result == -1) + { + unsigned long err = ERR_get_error(); + char err_msg[120]; + ERR_error_string_n(err, err_msg, sizeof(err_msg)); + std::cout << "Verification error: " << err_msg << "\n"; + } + return DSCStatus::DSC_Error; +} + +void DscVerificator::uninitDscVerificator () +{ + if (m_isInitialized) + { + if (m_pubKey) + { + EVP_PKEY_free(m_pubKey); + m_pubKey = nullptr; + } + m_isInitialized = false; + } +} + +#endif diff --git a/source/Lib/CommonLib/SEIDigitallySignedContent.h b/source/Lib/CommonLib/SEIDigitallySignedContent.h new file mode 100644 index 0000000000..0c149430a2 --- /dev/null +++ b/source/Lib/CommonLib/SEIDigitallySignedContent.h @@ -0,0 +1,218 @@ +/* The copyright in this software is being made available under the BSD + * License, included below. This software may be subject to other third party + * and contributor rights, including patent rights, and no such rights are + * granted under this license. + * + * Copyright (c) 2010-2024, ITU/ISO/IEC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + +#include "CommonDef.h" +#include "SEI.h" + +#endif + +#if JVET_AJ0151_DSC_SEI + +#include <openssl/evp.h> +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/x509.h> +#include <openssl/x509_vfy.h> + +struct PelStorage; + +typedef enum : uint32_t +{ + DSC_Uninitalized, + DSC_Initialized, + DSC_Error, + DSC_Untrusted, + DSC_Verified, + DSC_Invalid, +} DSCStatus; + +#endif + +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + +class SEIDigitallySignedContentInitialization: public SEI +{ +public: + int8_t dsciHashMethodType = 0; + std::string dsciKeySourceUri; + int8_t dsciNumVerificationSubstreams = 0; + int8_t dsciKeyRetrievalModeIdc = 0; + bool dsciUseKeyRegisterIdxFlag = false; + int32_t dsciKeyRegisterIdx = 0; + bool dsciContentUuidPresentFlag = false; + std::array<uint8_t, 16> dsciContentUuid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +public: + SEIDigitallySignedContentInitialization() + {}; + + virtual ~SEIDigitallySignedContentInitialization() + {}; + + PayloadType payloadType() const { return PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION; } +}; + +class SEIDigitallySignedContentSelection: public SEI +{ +public: + int32_t dscsVerificationSubstreamId = 0; + +public: + SEIDigitallySignedContentSelection() + {}; + + virtual ~SEIDigitallySignedContentSelection() + {}; + + PayloadType payloadType() const { return PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION; } +}; + +class SEIDigitallySignedContentVerification: public SEI +{ +public: + int32_t dscvVerificationSubstreamId = 0; + int32_t dscvSignatureLengthInOctets = 0; + std::vector<uint8_t> dscvSignature; + +public: + SEIDigitallySignedContentVerification() + {}; + + virtual ~SEIDigitallySignedContentVerification() + {}; + + PayloadType payloadType() const { return PayloadType::DIGITALLY_SIGNED_CONTENT_VERIFICATION; } +}; + +#endif + +#if JVET_AJ0151_DSC_SEI + +class DscSignature +{ +private: + bool m_isInitialized = false; + int m_hashMethodType = -1; + EVP_PKEY *m_privKey = nullptr; + +public: + ~DscSignature() + { + uninitDscSignature(); + }; + bool initDscSignature (const std::string &keyfile, int hashMethodType); + bool signPacket (std::vector<uint8_t> &packet, std::vector<uint8_t> &signature); + void uninitDscSignature (); +}; + +class DscVerificator +{ +private: + bool m_isInitialized = false; + int m_hashMethodType = -1; + EVP_PKEY *m_pubKey = nullptr; + DSCStatus m_certVerificationStatus = DSCStatus::DSC_Uninitalized; +public: +~DscVerificator() + { + uninitDscVerificator(); + }; + DSCStatus initDscVerificator (const std::string &pubKeyUri, const std::string &keyStoreDir, const std::string &trustStoreDir, int hashMethodType); + DSCStatus verifyCert (const std::string &certFile, const std::string &trustStoreDir); + DSCStatus verifyPacket (std::vector<uint8_t> &packet, std::vector<uint8_t> &signature); + void uninitDscVerificator (); +protected: + bool xLocateCertificate (const std::string &certificateURI, const std::string &keyStoreDir, std::string &targetPath); + +}; + + +class DscSubstream +{ +private: + DSCStatus m_streamStatus = DSC_Uninitalized; + bool m_dataAdded = false; + EVP_MD_CTX* m_ctx = nullptr; + + std::vector<uint8_t> m_lastDigest; + std::vector<uint8_t> m_currentDigest; + +public: + void initSubstream(int hashMethod); + bool addDatapacket(const char *data, size_t length); + bool calculateHash(); + void getCurrentDigest (std::vector<uint8_t> &digest) { digest= m_currentDigest; }; + void getLastDigest (std::vector<uint8_t> &digest) { digest= m_lastDigest; }; +}; + +class DscSubstreamManager +{ +private: + DscSignature m_dscSign; + DscVerificator m_dscVerify; + + std::vector<DscSubstream> m_substream; + + uint8_t m_hashMethodType = 0; + bool m_hasContentUuid = false; + std::vector<uint8_t> m_contentUuid; + + std::string m_certUri; + + bool m_isFirstSubstream = true; + + bool m_isInitialized = false; + + bool m_sigInitialized = false; + +public: + void initDscSubstreamManager (int numSubstreams, int hashMethodType, const std::string &certUri, bool hasContentUuid, std::array<uint8_t,16> &contentUuid); + + void initSignature (const std::string &privKeyFile); + bool initVerificator (const std::string &keyStoreDir, const std::string &trustStoreDir); + + void addToSubstream (int substreamId, const char *data, size_t lenght); + void signSubstream (int substreamId, std::vector<uint8_t> &signature); + bool verifySubstream (int substreamId, std::vector<uint8_t> &signature); + void uninitDscSubstreamManager(); +protected: + void createDatapacket (int substreamId, std::vector<uint8_t> &dataPacket); + +}; + +#endif diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index f93b63af93..b00d49a79e 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -54,14 +54,23 @@ // clang-format off + //########### place macros to be removed in next cycle below this line ############### #define JVET_AJ0129_SPO_SEI_LIST 1 // Update SeiProcessingOrderSeiList with all supported SEI message types -#define JVET_AJ0207_GFV 1 //generative face video (GFV) SEI +#define JVET_AJ0207_GFV 1 // generative face video (GFV) SEI + +#define JVET_AJ0151_DSC_SEI_DECODER_SYNTAX 1 // read the Digitally Signed Content SEIs at the decoder //########### place macros to be be kept below this line ############### +#ifndef JVET_AJ0151_DSC_SEI + +#define JVET_AJ0151_DSC_SEI 1 // Digitally signed content signing and verification (requires OpenSSL v3) + +#endif + #define GDR_ENABLED 1 #if GDR_ENABLED diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 1396a10a6c..ab807fc4c8 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -58,6 +58,10 @@ #include "CommonLib/CodingStatistics.h" #endif +#if JVET_AJ0151_DSC_SEI || JVET_AJ0151_DSC_SEI_DECODER_SYNTAX +#include "SEIDigitallySignedContent.h" +#endif + bool tryDecodePicture(Picture *pcEncPic, const int expectedPoc, const std::string &bitstreamFileName, const int layerIdx, EnumArray<ParameterSetMap<APS>, ApsType> *apsMap, bool bDecodeUntilPocFound, int debugCTU, int debugPOC) @@ -708,6 +712,31 @@ Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_ return pcPic; } +#if JVET_AJ0151_DSC_SEI +void DecLib::xStoreNALUnitForSignature(InputNALUnit &nalu) +{ + std::ostringstream rbspPayload; + binNalUnit binNalu; + binNalu.nalUnitType = nalu.m_nalUnitType; + binNalu.length = nalu.getBitstream().getOrigFifo().size(); + binNalu.data = new uint8_t [binNalu.length]; + + std::memcpy(binNalu.data, nalu.getBitstream().getOrigFifo().data(), binNalu.length); + + m_signedContentNalUnitBuffer.push_back(binNalu); + nalu.getBitstream().clearOrigFifo(); +} + +void DecLib::xProcessStoredNALUnitsForSignature(int substreamId) +{ + for (auto nalu: m_signedContentNalUnitBuffer) + { + m_dscSubstreamManager.addToSubstream(substreamId, (char*)nalu.data, nalu.length); + free (nalu.data); + } + m_signedContentNalUnitBuffer.clear(); +} +#endif void DecLib::executeLoopFilters() { @@ -3169,6 +3198,39 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl // actual decoding starts here xActivateParameterSets( nalu ); +#if JVET_AJ0151_DSC_SEI + SEIMessages dscInitSEIs = getSeisByType( m_pcPic->SEIs, SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION); + if (!dscInitSEIs.empty()) + { + if (dscInitSEIs.size()>1) + { + printf ("Warming: received more than one Digitally Signed Content Initialization SEI message at a time. Using first only.\n"); + } + SEIDigitallySignedContentInitialization* dsci = (SEIDigitallySignedContentInitialization*) dscInitSEIs.front(); + m_dscSubstreamManager.initDscSubstreamManager(dsci->dsciNumVerificationSubstreams, dsci->dsciHashMethodType, dsci->dsciKeySourceUri, + dsci->dsciContentUuidPresentFlag, dsci->dsciContentUuid); + if (!m_dscSubstreamManager.initVerificator(m_keyStoreDir, m_trustStoreDir)) + { + printf("Error: Cannot initialize Digitally Signed Content verification\n"); + } + } + SEIMessages dscSelectionSEIs = getSeisByType(m_pcPic->SEIs, SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION); + if (!dscSelectionSEIs.empty()) + { + if (dscSelectionSEIs.size()>1) + { + printf ("Warming: received more than one Digitally Signed Content Selection SEI message at a time. Using first only.\n"); + } + SEIDigitallySignedContentSelection* dscs = (SEIDigitallySignedContentSelection*) dscSelectionSEIs.front(); + xProcessStoredNALUnitsForSignature(dscs->dscsVerificationSubstreamId); + } + else + { + // process as substream 0, when no selection SEI is received + // todo: multiples slices + xProcessStoredNALUnitsForSignature(0); + } +#endif m_firstSliceInSequence[nalu.m_nuhLayerId] = false; m_firstSliceInBitstream = false; @@ -3806,15 +3868,38 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i return false; case NAL_UNIT_OPI: xDecodeOPI(nalu); return false; case NAL_UNIT_DCI: xDecodeDCI(nalu); return false; - case NAL_UNIT_SPS: xDecodeSPS(nalu); return false; + case NAL_UNIT_SPS: +#if JVET_AJ0151_DSC_SEI + xStoreNALUnitForSignature(nalu); +#endif + xDecodeSPS(nalu); + return false; - case NAL_UNIT_PPS: xDecodePPS(nalu); return false; + case NAL_UNIT_PPS: +#if JVET_AJ0151_DSC_SEI + xStoreNALUnitForSignature(nalu); +#endif + xDecodePPS(nalu); + return false; - case NAL_UNIT_PH: xDecodePicHeader(nalu); return !m_bFirstSliceInPicture; + case NAL_UNIT_PH: +#if JVET_AJ0151_DSC_SEI + xStoreNALUnitForSignature(nalu); +#endif + xDecodePicHeader(nalu); + return !m_bFirstSliceInPicture; - case NAL_UNIT_PREFIX_APS: xDecodeAPS(nalu); return false; + case NAL_UNIT_PREFIX_APS: +#if JVET_AJ0151_DSC_SEI + xStoreNALUnitForSignature(nalu); +#endif + xDecodeAPS(nalu); + return false; case NAL_UNIT_SUFFIX_APS: +#if JVET_AJ0151_DSC_SEI + xStoreNALUnitForSignature(nalu); +#endif if (m_prevSliceSkipped) { xDecodeAPS(nalu); @@ -3854,6 +3939,18 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i m_accessUnitSeiPayLoadTypes.push_back(std::tuple<NalUnitType, int, SEI::PayloadType>( nalu.m_nalUnitType, nalu.m_nuhLayerId, (*newSEI)->payloadType())); } +#if JVET_AJ0151_DSC_SEI + SEIMessages dscVerifySEIs = getSeisByType( m_pcPic->SEIs, SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_VERIFICATION); + if (!dscVerifySEIs.empty()) + { + for (auto dscvsei:dscVerifySEIs) + { + SEIDigitallySignedContentVerification *sei = (SEIDigitallySignedContentVerification*) dscvsei; + m_dscSubstreamManager.verifySubstream(sei->dscvVerificationSubstreamId, sei->dscvSignature ); + } + } + +#endif } else { @@ -3868,7 +3965,12 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i case NAL_UNIT_CODED_SLICE_CRA: case NAL_UNIT_CODED_SLICE_GDR: case NAL_UNIT_CODED_SLICE_RADL: - case NAL_UNIT_CODED_SLICE_RASL: ret = xDecodeSlice(nalu, iSkipFrame, iPOCLastDisplay); return ret; + case NAL_UNIT_CODED_SLICE_RASL: +#if JVET_AJ0151_DSC_SEI + xStoreNALUnitForSignature(nalu); +#endif + ret = xDecodeSlice(nalu, iSkipFrame, iPOCLastDisplay); + return ret; case NAL_UNIT_EOS: m_associatedIRAPType[nalu.m_nuhLayerId] = NAL_UNIT_INVALID; diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 1476f73901..94dd1f5d31 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -56,6 +56,19 @@ #include "CommonLib/Reshape.h" #include "CommonLib/SEINeuralNetworkPostFiltering.h" +#if JVET_AJ0151_DSC_SEI +#include "SEIDigitallySignedContent.h" +#endif + +#if JVET_AJ0151_DSC_SEI +struct binNalUnit +{ + NalUnitType nalUnitType = NAL_UNIT_INVALID; + size_t length = 0; + uint8_t *data = nullptr; +}; +#endif + class InputNALUnit; //! \ingroup DecoderLib @@ -223,6 +236,11 @@ private: int m_maxDecSliceAddrInSubPic; int m_clsVPSid; +#if JVET_AJ0151_DSC_SEI + std::string m_keyStoreDir; + std::string m_trustStoreDir; +#endif + #if GDR_ENABLED int m_lastGdrPoc; int m_lastGdrRecoveryPocCnt; @@ -239,6 +257,14 @@ public: int m_gdrPocRandomAccess; #endif // GDR_LEAK_TEST +#if JVET_AJ0151_DSC_SEI + void xStoreNALUnitForSignature(InputNALUnit &nalu); + void xProcessStoredNALUnitsForSignature(int substream_id); + + std::list<binNalUnit> m_signedContentNalUnitBuffer; + DscSubstreamManager m_dscSubstreamManager; +#endif + public: DecLib(); virtual ~DecLib(); @@ -362,6 +388,14 @@ public: void applyNnPostFilter(); void setPrevPicPOC(const int prevPicPoc) { m_prevPicPOC = prevPicPoc;} +#if JVET_AJ0151_DSC_SEI + void setKeyStoreParameters(const std::string &keyStoreDir, const std::string &trustStoreDir) + { + m_keyStoreDir = keyStoreDir; + m_trustStoreDir = trustStoreDir; + } +#endif + protected: void xUpdateRasInit(Slice* slice); diff --git a/source/Lib/DecoderLib/NALread.cpp b/source/Lib/DecoderLib/NALread.cpp index 811f1880b2..be508eb51a 100644 --- a/source/Lib/DecoderLib/NALread.cpp +++ b/source/Lib/DecoderLib/NALread.cpp @@ -163,6 +163,12 @@ void read(InputNALUnit& nalu) std::vector<uint8_t> &nalUnitBuf = bitstream.getFifo(); // perform anti-emulation prevention const NalUnitType nut = (NalUnitType)(nalUnitBuf[1] >> 3); +#if JVET_AJ0151_DSC_SEI + if (nut == NAL_UNIT_SPS || nut == NAL_UNIT_PPS || nut == NAL_UNIT_PREFIX_APS || nut == NAL_UNIT_SUFFIX_APS || nut == NAL_UNIT_PH || NALUnit::isVclNalUnitType(nut) ) + { + bitstream.copyToOrigFifo(); + } +#endif convertPayloadToRBSP(nalUnitBuf, &bitstream, nut <= NAL_UNIT_RESERVED_IRAP_VCL_11); bitstream.resetToStart(); readNalUnitHeader(nalu); diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp index 500e9554f3..aae58f6a87 100644 --- a/source/Lib/DecoderLib/SEIread.cpp +++ b/source/Lib/DecoderLib/SEIread.cpp @@ -570,6 +570,16 @@ bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType sei = new SEIModalityInfo; xParseSEIModalityInfo((SEIModalityInfo &) *sei, payloadSize, pDecodedMessageOutputStream); break; +#endif +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION: + sei = new SEIDigitallySignedContentInitialization; + xParseSEIDigitallySignedContentInitialization((SEIDigitallySignedContentInitialization &) *sei, payloadSize, pDecodedMessageOutputStream); + break; + case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION: + sei = new SEIDigitallySignedContentSelection; + xParseSEIDigitallySignedContentSelection((SEIDigitallySignedContentSelection &) *sei, payloadSize, pDecodedMessageOutputStream); + break; #endif default: for (uint32_t i = 0; i < payloadSize; i++) @@ -644,11 +654,17 @@ bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType xParseSEIProcessingOrderNesting((SEIProcessingOrderNesting&)*sei, nalUnitType, nuh_layer_id, payloadSize, vps, sps, hrd, pDecodedMessageOutputStream); break; -#if JVET_AJ0207_GFV +#if JVET_AJ0207_GFV case SEI::PayloadType::GENERATIVE_FACE_VIDEO: sei = new SEIGenerativeFaceVideo; xParseSEIGenerativeFaceVideo((SEIGenerativeFaceVideo &)*sei, payloadSize, pDecodedMessageOutputStream); break; +#endif +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_VERIFICATION: + sei = new SEIDigitallySignedContentVerification; + xParseSEIDigitallySignedContentVerification((SEIDigitallySignedContentVerification &) *sei, payloadSize, pDecodedMessageOutputStream); + break; #endif default: for (uint32_t i = 0; i < payloadSize; i++) @@ -4598,4 +4614,60 @@ void SEIReader::xParseSEIGenerativeFaceVideo(SEIGenerativeFaceVideo & sei, uint3 } #endif -//! \} \ No newline at end of file +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX +void SEIReader::xParseSEIDigitallySignedContentInitialization(SEIDigitallySignedContentInitialization &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) +{ + unsigned int val; + sei_read_code(pDecodedMessageOutputStream, 8, val, "dsci_hash_method_type"); + sei.dsciHashMethodType = val; + sei_read_string(pDecodedMessageOutputStream, sei.dsciKeySourceUri, "twci_key_source_uri"); + sei_read_uvlc(pDecodedMessageOutputStream, val, "dsci_num_verification_substreams_minus1"); + sei.dsciNumVerificationSubstreams = val + 1; + sei_read_uvlc(pDecodedMessageOutputStream, val, "dsci_key_retrieval_mode_idc"); + sei.dsciKeyRetrievalModeIdc = val; + if (sei.dsciKeyRetrievalModeIdc == 1) + { + sei_read_flag(pDecodedMessageOutputStream, val, "dsci_use_key_register_idx_flag"); + sei.dsciUseKeyRegisterIdxFlag = (val!=0); + if( sei.dsciUseKeyRegisterIdxFlag ) + { + sei_read_uvlc(pDecodedMessageOutputStream, val, "dsci_key_register_idx"); + sei.dsciKeyRegisterIdx = val; + } + } + sei_read_flag(pDecodedMessageOutputStream, val, "dsci_content_uuid_present_flag"); + sei.dsciContentUuidPresentFlag = (val!=0); + if (sei.dsciContentUuidPresentFlag) + { + for (int i=0; i<16; i++) + { + sei_read_code(pDecodedMessageOutputStream, 8, val, "dsci_content_uuid"); + sei.dsciContentUuid[i] = val; + } + + } +} + +void SEIReader::xParseSEIDigitallySignedContentSelection(SEIDigitallySignedContentSelection &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) +{ + unsigned int val; + sei_read_uvlc(pDecodedMessageOutputStream, val, "dscs_verification_substream_id"); + sei.dscsVerificationSubstreamId = val; +} + +void SEIReader::xParseSEIDigitallySignedContentVerification(SEIDigitallySignedContentVerification &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream) +{ + unsigned int val; + sei_read_uvlc(pDecodedMessageOutputStream, val, "dscv_verification_substream_id"); + sei.dscvVerificationSubstreamId = val; + sei_read_uvlc(pDecodedMessageOutputStream, val, "dscv_signature_length_in_octets_minus1"); + sei.dscvSignatureLengthInOctets = val + 1; + sei.dscvSignature.resize(sei.dscvSignatureLengthInOctets); + for (int i=0; i< sei.dscvSignature.size(); i++) + { + sei_read_code(pDecodedMessageOutputStream, 8, val, "dscv_signature"); + sei.dscvSignature[i] = val; + } +} +#endif +//! \} diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h index 6838b757bd..55376dd59d 100644 --- a/source/Lib/DecoderLib/SEIread.h +++ b/source/Lib/DecoderLib/SEIread.h @@ -46,8 +46,12 @@ //! \{ #include "CommonLib/SEI.h" -class InputBitstream; +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX +#include "CommonLib/SEIDigitallySignedContent.h" +#endif + +class InputBitstream; class SEIReader: public VLCReader { @@ -134,6 +138,11 @@ protected: #if JVET_AH2006_TXTDESCRINFO_SEI void xParseSEITextDescription(SEITextDescription &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); #endif +#if JVET_AJ0151_DSC_SEI_DECODER_SYNTAX + void xParseSEIDigitallySignedContentInitialization(SEIDigitallySignedContentInitialization &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); + void xParseSEIDigitallySignedContentSelection (SEIDigitallySignedContentSelection &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); + void xParseSEIDigitallySignedContentVerification (SEIDigitallySignedContentVerification &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream); +#endif void sei_read_scode(std::ostream *pOS, uint32_t length, int& code, const char *pSymbolName); void sei_read_code(std::ostream *pOS, uint32_t length, uint32_t &ruiCode, const char *pSymbolName); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 08a923c8e0..73c2bb20a6 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -675,6 +675,9 @@ protected: bool m_gcmpSEIGuardBandBoundaryExteriorFlag; uint8_t m_gcmpSEIGuardBandSamplesMinus1; EncCfgParam::CfgSEISubpictureLevel m_cfgSubpictureLevelInfoSEI; +#if JVET_AJ0151_DSC_SEI + EncCfgParam::CfgSEIDigitallySignedContent m_cfgDigitallySignedContentSEI; +#endif bool m_sampleAspectRatioInfoSEIEnabled; bool m_sariCancelFlag; bool m_sariPersistenceFlag; @@ -2447,6 +2450,16 @@ public: { m_cfgSubpictureLevelInfoSEI = cfg; } +#if JVET_AJ0151_DSC_SEI + const EncCfgParam::CfgSEIDigitallySignedContent &getDigitallySignedContentSEICfg() const + { + return m_cfgDigitallySignedContentSEI; + } + void setDigitallySignedContentSEICfg(const EncCfgParam::CfgSEIDigitallySignedContent &cfg) + { + m_cfgDigitallySignedContentSEI = cfg; + } +#endif bool getSampleAspectRatioInfoSEIEnabled() const { return m_sampleAspectRatioInfoSEIEnabled; } void setSampleAspectRatioInfoSEIEnabled(const bool val) { m_sampleAspectRatioInfoSEIEnabled = val; } bool getSariCancelFlag() const { return m_sariCancelFlag; } diff --git a/source/Lib/EncoderLib/EncCfgParam.h b/source/Lib/EncoderLib/EncCfgParam.h index 9644544aeb..b3540855d0 100644 --- a/source/Lib/EncoderLib/EncCfgParam.h +++ b/source/Lib/EncoderLib/EncCfgParam.h @@ -72,7 +72,21 @@ public: bool hasSublayerInfo; }; -} +#if JVET_AJ0151_DSC_SEI +class CfgSEIDigitallySignedContent +{ +public: + CfgSEIDigitallySignedContent(){}; + virtual ~CfgSEIDigitallySignedContent(){}; + bool enabled = false; + std::string privateKeyFile; + std::string publicKeyUri; + bool keyIdEnabled = false; + int keyId = 0; + int hashMethod = 0; +}; +#endif +} #endif // __ENCCFGPARAMS__ diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index bb5ca0a658..828d2afe9a 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -323,6 +323,24 @@ void EncGOP::init ( EncLib* pcEncLib ) #endif } +#if JVET_AJ0151_DSC_SEI +void EncGOP::xAddToSubstream(int substreamId, OutputNALUnit &nalu) +{ + // exit, if digitally signed content is not active + if (!m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + return; + } + std::ostringstream rbspPayload; + + // add emultaion prevention + writeNaluWithHeader(rbspPayload, nalu); + + // store NAL unit + m_dscSubstreamManager.addToSubstream(substreamId, rbspPayload.str().c_str(), rbspPayload.str().size()); +} +#endif + int EncGOP::xWriteOPI (AccessUnit &accessUnit, const OPI *opi) { OutputNALUnit nalu(NAL_UNIT_OPI); @@ -360,6 +378,9 @@ int EncGOP::xWriteSPS( AccessUnit &accessUnit, const SPS *sps, const int layerId nalu.m_nuhLayerId = layerId; CHECK( nalu.m_temporalId, "The value of TemporalId of SPS NAL units shall be equal to 0" ); m_HLSWriter->codeSPS( sps ); +#if JVET_AJ0151_DSC_SEI + xAddToSubstream(0, nalu); +#endif accessUnit.push_back(new NALUnitEBSP(nalu)); return (int) (accessUnit.back()->m_nalUnitData.str().size()) * 8; } @@ -372,6 +393,9 @@ int EncGOP::xWritePPS( AccessUnit &accessUnit, const PPS *pps, const int layerId nalu.m_temporalId = accessUnit.temporalId; CHECK( nalu.m_temporalId < accessUnit.temporalId, "TemporalId shall be greater than or equal to the TemporalId of the layer access unit containing the NAL unit" ); m_HLSWriter->codePPS( pps ); +#if JVET_AJ0151_DSC_SEI + xAddToSubstream(0, nalu); +#endif accessUnit.push_back(new NALUnitEBSP(nalu)); return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8; } @@ -393,6 +417,9 @@ int EncGOP::xWriteAPS( AccessUnit &accessUnit, APS *aps, const int layerId, cons #endif m_HLSWriter->codeAPS(aps); +#if JVET_AJ0151_DSC_SEI + xAddToSubstream(0, nalu); +#endif accessUnit.push_back(new NALUnitEBSP(nalu)); return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8; } @@ -474,6 +501,9 @@ int EncGOP::xWritePicHeader( AccessUnit &accessUnit, PicHeader *picHeader ) nalu.m_temporalId = accessUnit.temporalId; nalu.m_nuhLayerId = m_pcEncLib->getLayerId(); m_HLSWriter->codePictureHeader( picHeader, true ); +#if JVET_AJ0151_DSC_SEI + xAddToSubstream(0, nalu); +#endif accessUnit.push_back(new NALUnitEBSP(nalu)); return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8; } @@ -567,6 +597,36 @@ void EncGOP::xWriteLeadingSEIOrdered (SEIMessages& seiMessages, SEIMessages& duI { AccessUnit::iterator itNalu = accessUnit.begin(); +#if JVET_AJ0151_DSC_SEI + SEIMessages currentMessages; + SEIMessages localMessages = seiMessages; + +#if ENABLE_TRACING + g_HLSTraceEnable = !testWrite; +#endif + + // skip over AUD or any Trailing SEIs, which belong to previous AU + while ((itNalu != accessUnit.end()) && + ((*itNalu)->m_nalUnitType == NAL_UNIT_ACCESS_UNIT_DELIMITER + || (*itNalu)->m_nalUnitType == NAL_UNIT_SUFFIX_SEI + )) + { + itNalu++; + } + if (m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + currentMessages = extractSeisByType(localMessages, SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION); + CHECK( (currentMessages.size() > 1), "too many Digitally Signed Content Initialization SEI messages found"); + xWriteSEI(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId); + xClearSEIs(currentMessages, !testWrite); + + currentMessages = extractSeisByType(localMessages, SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION); + CHECK( (currentMessages.size() > 1), "too many Digitally Signed Content Selection SEI messages found"); + xWriteSEI(NAL_UNIT_PREFIX_SEI, currentMessages, accessUnit, itNalu, temporalId); + xClearSEIs(currentMessages, !testWrite); + } +#endif + while ((itNalu != accessUnit.end()) && ((*itNalu)->m_nalUnitType == NAL_UNIT_ACCESS_UNIT_DELIMITER || (*itNalu)->m_nalUnitType == NAL_UNIT_OPI @@ -579,11 +639,13 @@ void EncGOP::xWriteLeadingSEIOrdered (SEIMessages& seiMessages, SEIMessages& duI itNalu++; } +#if !JVET_AJ0151_DSC_SEI SEIMessages localMessages = seiMessages; SEIMessages currentMessages; #if ENABLE_TRACING g_HLSTraceEnable = !testWrite; +#endif #endif // The case that a specific SEI is not present is handled in xWriteSEI (empty list) @@ -937,6 +999,14 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS seiMessages.push_back(seiProcessingOrder); seiMessages.push_back(seiProcessingOrderNesting); } +#if JVET_AJ0151_DSC_SEI + if (m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + SEIDigitallySignedContentInitialization *sei = new SEIDigitallySignedContentInitialization; + m_seiEncoder.initSEIDigitallySignedContentInitialization(sei); + seiMessages.push_back(sei); + } +#endif } void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice) @@ -1066,6 +1136,15 @@ void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessage m_seiEncoder.initSEIPostFilterHint(postFilterHintSEI); seiMessages.push_back(postFilterHintSEI); } +#if JVET_AJ0151_DSC_SEI + + if (m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + SEIDigitallySignedContentSelection *sei = new SEIDigitallySignedContentSelection; + m_seiEncoder.initSEIDigitallySignedContentSelection(sei, 0); + seiMessages.push_back(sei); + } +#endif } #if JVET_AJ0207_GFV @@ -3971,6 +4050,34 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l { m_pcEncLib->setParamSetChanged(pcSlice->getSPS()->getSPSId(), pcSlice->getPPS()->getPPSId()); } +#if JVET_AJ0151_DSC_SEI + + // Before writing the NAL units of an RAP, write trailing TWC verification SEIs of previous picture + const bool writeDSCverification = !m_seqFirst && pcSlice->isIRAP(); + if (writeDSCverification) + { + if (m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + SEIMessages twcSeiMessages; + std::vector<uint8_t> signature; + m_dscSubstreamManager.signSubstream(0, signature); + SEIDigitallySignedContentVerification *sei = new SEIDigitallySignedContentVerification; + m_seiEncoder.initSEIDigitallySignedContentVerification(sei, 0, signature); + twcSeiMessages.push_back(sei); + xWriteTrailingSEIMessages(twcSeiMessages, accessUnit, m_prevPicTemporalId); + } + } + m_prevPicTemporalId = pcSlice->getTLayer(); + if (writePS && m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + std::array<uint8_t,16> contentUuid = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + const EncCfgParam::CfgSEIDigitallySignedContent &dscCfg = m_pcCfg->getDigitallySignedContentSEICfg(); + m_dscSubstreamManager.initDscSubstreamManager(1, dscCfg.hashMethod, dscCfg.publicKeyUri , false, contentUuid); + m_dscSubstreamManager.initSignature(dscCfg.privateKeyFile); + } +#endif int layerIdx = m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx( m_pcEncLib->getLayerId() ); @@ -4350,6 +4457,9 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l bool naluAlignedWrittenToList = false; // used to ensure current NALU is not written more than once to the NALU list. xAttachSliceDataToNalUnit(nalu, pcBitstreamRedirect); +#if JVET_AJ0151_DSC_SEI + xAddToSubstream(0, nalu); +#endif accessUnit.push_back(new NALUnitEBSP(nalu)); actualTotalBits += uint32_t(accessUnit.back()->m_nalUnitData.str().size()) * 8; numBytesInVclNalUnits += (std::size_t)(accessUnit.back()->m_nalUnitData.str().size()); @@ -4529,6 +4639,27 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l #endif xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer()); +#if JVET_AJ0151_DSC_SEI + + m_totalPicsCoded++; + const int skip = m_pcCfg->getFrameSkip() ? m_pcCfg->getFrameSkip() : 1; + const int lastPic =(m_pcCfg->getFramesToBeEncoded() / skip) - 1; + const bool isLastPicture = ( m_totalPicsCoded > lastPic); + if (isLastPicture) + { + if (m_pcCfg->getDigitallySignedContentSEICfg().enabled) + { + SEIMessages twcSeiMessages; + std::vector<uint8_t> signature; + m_dscSubstreamManager.signSubstream(0, signature); + SEIDigitallySignedContentVerification *sei = new SEIDigitallySignedContentVerification; + m_seiEncoder.initSEIDigitallySignedContentVerification(sei, 0, signature); + twcSeiMessages.push_back(sei); + xWriteTrailingSEIMessages(twcSeiMessages, accessUnit, pcSlice->getTLayer()); + m_dscSubstreamManager.uninitDscSubstreamManager(); + } + } +#endif #if GDR_ENABLED if (!(m_pcCfg->getGdrNoHash() && pcSlice->getPic()->gdrParam.inGdrInterval)) diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index a031a157c9..ea14187b08 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -63,6 +63,10 @@ #include <vector> #include "EncHRD.h" +#if JVET_AJ0151_DSC_SEI +#include "SEIDigitallySignedContent.h" +#endif + #if JVET_O0756_CALCULATE_HDRMETRICS #include "HDRLib/inc/ConvertColorFormat.H" #include "HDRLib/inc/Convert.H" @@ -232,6 +236,14 @@ private: SEIComplexityMetrics m_SEIGreenComplexityMetrics; #endif +#if JVET_AJ0151_DSC_SEI + void xAddToSubstream(int substreamId, OutputNALUnit &nalu); + + DscSubstreamManager m_dscSubstreamManager; + int m_totalPicsCoded = 0; + int m_prevPicTemporalId = 0; +#endif + public: EncGOP(); virtual ~EncGOP(); diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index 1ba0706950..bad78540aa 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -33,6 +33,9 @@ #include "CommonLib/CommonDef.h" #include "CommonLib/SEI.h" +#if JVET_AJ0151_DSC_SEI +#include "CommonLib/SEIDigitallySignedContent.h" +#endif #include "EncGOP.h" #include "EncLib.h" #include <fstream> @@ -2128,4 +2131,26 @@ void SEIEncoder::initSEIGenerativeFaceVideo(SEIGenerativeFaceVideo *sei, int cur } } #endif + +#if JVET_AJ0151_DSC_SEI +void SEIEncoder::initSEIDigitallySignedContentInitialization(SEIDigitallySignedContentInitialization *sei) +{ + sei->dsciNumVerificationSubstreams = 1; //m_pcCfg->getMaxTempLayer(); + sei->dsciHashMethodType = m_pcCfg->getDigitallySignedContentSEICfg().hashMethod; + sei->dsciKeySourceUri = m_pcCfg->getDigitallySignedContentSEICfg().publicKeyUri; + sei->dsciUseKeyRegisterIdxFlag = m_pcCfg->getDigitallySignedContentSEICfg().keyIdEnabled; + sei->dsciKeyRegisterIdx = m_pcCfg->getDigitallySignedContentSEICfg().keyId; +} +void SEIEncoder::initSEIDigitallySignedContentSelection(SEIDigitallySignedContentSelection *sei, int substream) +{ + sei->dscsVerificationSubstreamId = substream; +} +void SEIEncoder::initSEIDigitallySignedContentVerification(SEIDigitallySignedContentVerification *sei, int32_t substream, const std::vector<uint8_t> &signature) +{ + sei->dscvVerificationSubstreamId = substream; + sei->dscvSignatureLengthInOctets = (int32_t) signature.size(); + sei->dscvSignature = signature; +} +#endif + //! \} diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h index 0d4e83f8db..e721b6bb9a 100644 --- a/source/Lib/EncoderLib/SEIEncoder.h +++ b/source/Lib/EncoderLib/SEIEncoder.h @@ -112,6 +112,11 @@ public: #if JVET_AH2006_TXTDESCRINFO_SEI void initSEITextDescription(SEITextDescription *sei); #endif +#if JVET_AJ0151_DSC_SEI + void initSEIDigitallySignedContentInitialization(SEIDigitallySignedContentInitialization *sei); + void initSEIDigitallySignedContentSelection(SEIDigitallySignedContentSelection *sei, int substream); + void initSEIDigitallySignedContentVerification(SEIDigitallySignedContentVerification *sei, int32_t substream, const std::vector<uint8_t> &signature); +#endif #if GREEN_METADATA_SEI_ENABLED void initSEIGreenMetadataInfo(SEIGreenMetadataInfo *sei, FeatureCounterStruct featureCounter, SEIQualityMetrics metrics, SEIComplexityMetrics greenMetadata); #endif diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp index 2cef552adb..4ebb972850 100644 --- a/source/Lib/EncoderLib/SEIwrite.cpp +++ b/source/Lib/EncoderLib/SEIwrite.cpp @@ -216,6 +216,17 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI &sei, HRD &h case SEI::PayloadType::GENERATIVE_FACE_VIDEO: xWriteSEIGenerativeFaceVideo(*static_cast<const SEIGenerativeFaceVideo*>(&sei)); break; +#endif +#if JVET_AJ0151_DSC_SEI + case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_INITIALIZATION: + xWriteSEIDigitallySignedContentInitialization(*static_cast<const SEIDigitallySignedContentInitialization *>(&sei)); + break; + case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_SELECTION: + xWriteSEIDigitallySignedContentSelection(*static_cast<const SEIDigitallySignedContentSelection *>(&sei)); + break; + case SEI::PayloadType::DIGITALLY_SIGNED_CONTENT_VERIFICATION: + xWriteSEIDigitallySignedContentVerification(*static_cast<const SEIDigitallySignedContentVerification *>(&sei)); + break; #endif default: THROW("Trying to write unhandled SEI message"); @@ -2276,7 +2287,6 @@ void SEIWriter::xWriteSEIModalityInfo(const SEIModalityInfo& sei) } #endif - #if JVET_AJ0207_GFV void SEIWriter::xWriteSEIGenerativeFaceVideo(const SEIGenerativeFaceVideo &sei) { @@ -2493,7 +2503,7 @@ void SEIWriter::xWriteSEIGenerativeFaceVideo(const SEIGenerativeFaceVideo &sei) // Matrix Parameters CHECK((!sei.m_coordinatePresentFlag) && (!sei.m_matrixPresentFlag), "When gfv_coordinate_present_flag is equal to 0, gfv_matrix_present_flag shall be equal to 1"); xWriteFlag(sei.m_matrixPresentFlag, "gfv_matrix_present_flag"); - + if (sei.m_matrixPresentFlag) { std::vector<uint32_t> matrixWidthVec; @@ -2650,4 +2660,48 @@ void SEIWriter::xWriteSEIGenerativeFaceVideo(const SEIGenerativeFaceVideo &sei) } #endif +#if JVET_AJ0151_DSC_SEI +void SEIWriter::xWriteSEIDigitallySignedContentInitialization(const SEIDigitallySignedContentInitialization &sei) +{ + xWriteCode(sei.dsciHashMethodType, 8, "dsci_hash_method_type"); + xWriteString(sei.dsciKeySourceUri, "dsci_key_source_uri"); + CHECK (sei.dsciNumVerificationSubstreams < 1, "Number of DSC verification substreams has to be greater than zero"); + xWriteUvlc(sei.dsciNumVerificationSubstreams - 1, "dsci_num_verification_substreams_minus1"); + xWriteUvlc(sei.dsciKeyRetrievalModeIdc, "dsci_key_retrieval_mode_idc"); + if (sei.dsciKeyRetrievalModeIdc == 1) + { + xWriteFlag(sei.dsciUseKeyRegisterIdxFlag, "dsci_use_key_register_idx_flag"); + if( sei.dsciUseKeyRegisterIdxFlag ) + { + xWriteUvlc(sei.dsciKeyRegisterIdx, "dsci_key_register_idx"); + } + } + xWriteFlag(sei.dsciContentUuidPresentFlag, "dsci_content_uuid_present_flag"); + if (sei.dsciContentUuidPresentFlag) + { + for (int i=0; i<16; i++) + { + xWriteCode(sei.dsciContentUuid[i], 8, "dsci_content_uuid"); + } + } +} + +void SEIWriter::xWriteSEIDigitallySignedContentSelection(const SEIDigitallySignedContentSelection &sei) +{ + xWriteUvlc(sei.dscsVerificationSubstreamId, "dscs_verification_substream_id"); +} + +void SEIWriter::xWriteSEIDigitallySignedContentVerification(const SEIDigitallySignedContentVerification &sei) +{ + xWriteUvlc(sei.dscvVerificationSubstreamId, "dscv_verification_substream_id"); + CHECK (sei.dscvSignatureLengthInOctets < 1, "Length of signature has to be greater than zero"); + xWriteUvlc(sei.dscvSignatureLengthInOctets - 1, "dscv_signature_length_in_octets_minus1"); + CHECK (sei.dscvSignatureLengthInOctets != sei.dscvSignature.size(), "Signature length incosistent"); + for (int i=0; i< sei.dscvSignature.size(); i++) + { + xWriteCode(sei.dscvSignature[i], 8, "dscv_signature"); + } +} +#endif + //! \} diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h index 25839669be..f3352b2ed1 100644 --- a/source/Lib/EncoderLib/SEIwrite.h +++ b/source/Lib/EncoderLib/SEIwrite.h @@ -41,6 +41,10 @@ #include "VLCWriter.h" #include "CommonLib/SEI.h" +#if JVET_AJ0151_DSC_SEI +#include "CommonLib/SEIDigitallySignedContent.h" +#endif + class OutputBitstream; //! \ingroup EncoderLib @@ -126,6 +130,7 @@ protected: #if JVET_AG0322_MODALITY_INFORMATION void xWriteSEIModalityInfo(const SEIModalityInfo &sei); #endif + #if JVET_AJ0207_GFV void xWriteSEIGenerativeFaceVideo(const SEIGenerativeFaceVideo& sei); std::vector<double> prevcoordinateXRec; @@ -138,6 +143,12 @@ protected: bool doUpdateGFVcoordinate= false; bool doUpdateGFVmatrix= false; #endif + +#if JVET_AJ0151_DSC_SEI + void xWriteSEIDigitallySignedContentInitialization(const SEIDigitallySignedContentInitialization &sei); + void xWriteSEIDigitallySignedContentSelection(const SEIDigitallySignedContentSelection &sei); + void xWriteSEIDigitallySignedContentVerification(const SEIDigitallySignedContentVerification &sei); +#endif protected: HRD m_nestingHrd; }; -- GitLab