From 31f24774e8f69d56b4fd51e2b3cb8fe8f3fbcbfa Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Thu, 7 Sep 2023 13:32:55 -0700 Subject: [PATCH] OEMCrypto v17.2 Version 17.2 includes udpates to support MediaCAS. See the CHANGELOG for full details. --- CHANGELOG.md | 41 + oem_certificate_generator/README.md | 6 +- oem_certificate_generator/oem_certificate.py | 6 +- oemcrypto/include/OEMCryptoCENC.h | 655 ++++++++------ oemcrypto/include/OEMCryptoCENCCommon.h | 2 +- oemcrypto/odk/include/OEMCryptoCENCCommon.h | 6 +- oemcrypto/odk/include/core_message_features.h | 5 +- oemcrypto/odk/include/odk_message.h | 7 +- oemcrypto/odk/include/odk_structs.h | 4 +- oemcrypto/odk/src/core_message_features.cpp | 2 +- oemcrypto/odk/src/odk.gyp | 1 + oemcrypto/odk/src/odk_endian.h | 8 + oemcrypto/odk/src/odk_serialize.c | 6 +- oemcrypto/odk/src/odk_timer.c | 17 +- oemcrypto/odk/src/serialization_base.c | 24 +- oemcrypto/odk/src/serialization_base.h | 5 +- oemcrypto/odk/test/odk_test.cpp | 1 + oemcrypto/odk/test/odk_test.gypi | 2 + oemcrypto/oemcrypto_unittests.gyp | 3 +- oemcrypto/opk/build/ree-sources.mk | 61 +- oemcrypto/opk/build/tee-sources.mk | 2 +- oemcrypto/opk/oemcrypto_ta/oemcrypto.c | 444 ++++++++-- .../opk/oemcrypto_ta/oemcrypto_api_macros.h | 8 +- .../oemcrypto_entitled_key_session.c | 18 + .../oemcrypto_entitled_key_session.h | 5 + oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c | 3 + oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h | 4 + oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c | 1 - .../opk/oemcrypto_ta/oemcrypto_overflow.c | 10 + .../opk/oemcrypto_ta/oemcrypto_overflow.h | 8 + .../oemcrypto_serialized_usage_table.c | 2 +- .../opk/oemcrypto_ta/oemcrypto_session.c | 112 +-- .../opk/oemcrypto_ta/oemcrypto_session.h | 11 + .../oemcrypto_session_key_table.c | 47 +- .../opk/oemcrypto_ta/oemcrypto_usage_table.c | 24 +- ...ypto_and_key_management_interface_layer1.h | 6 + .../wtpi/wtpi_crypto_asymmetric_interface.h | 35 + .../wtpi_root_of_trust_interface_layer1.h | 6 +- .../oemcrypto_ta/wtpi_reference/cose_util.c | 227 +++-- .../oemcrypto_ta/wtpi_reference/cose_util.h | 22 +- .../wtpi_reference/wtpi_clock_and_gn_layer1.c | 46 +- .../wtpi_reference/wtpi_config_macros.h | 3 + ...wtpi_crypto_and_key_management_layer1_hw.c | 10 + ...crypto_and_key_management_layer1_openssl.c | 29 +- .../wtpi_reference/wtpi_crypto_asymmetric.c | 39 +- .../wtpi_reference/wtpi_decrypt_sample.c | 7 +- .../wtpi_reference/wtpi_device_key.c | 9 +- .../oemcrypto_ta/wtpi_reference/wtpi_idle.c | 5 +- .../wtpi_reference/wtpi_reference.gyp | 15 +- .../wtpi_root_of_trust_layer1.c | 46 +- .../wtpi_test/common/common_special_cases.c | 7 +- .../oemcrypto_ta/wtpi_test/crypto_test.cpp | 449 +++++++--- .../ree/GEN_oemcrypto_tee_test_api.c | 340 +++++++- .../wtpi_test/ree/GEN_ree_serializer.c | 116 ++- .../wtpi_test/ree/GEN_ree_serializer.h | 10 + .../opk/oemcrypto_ta/wtpi_test/ree/ree.gyp | 2 +- .../wtpi_test/tee/GEN_dispatcher.c | 54 +- .../wtpi_test/tee/GEN_tee_serializer.c | 102 ++- .../wtpi_test/tee/GEN_tee_serializer.h | 8 + .../opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp | 6 + .../wtpi_useless/wtpi_secure_buffer_access.c | 3 +- oemcrypto/opk/ports/optee/Makefile | 22 +- oemcrypto/opk/ports/optee/README.md | 18 +- .../optee/host/common/tos/optee_ree_tos.c | 11 +- .../host/common/tos/optee_secure_buffers.c | 5 +- .../ports/optee/host/wtpi_unittests/Makefile | 8 + oemcrypto/opk/ports/optee/install_ta.sh | 46 - oemcrypto/opk/ports/optee/push.sh | 26 - .../optee/ta/common/wtpi_impl/sources.mk | 17 + .../ta/common/wtpi_impl/util/der_parse.c | 162 +++- .../ta/common/wtpi_impl/util/der_parse.h | 11 + .../optee/ta/common/wtpi_impl/wtpi_config.c | 8 +- .../ta/common/wtpi_impl/wtpi_config_macros.h | 3 + .../wtpi_crypto_and_key_management_layer1.c | 268 +++--- .../common/wtpi_impl/wtpi_crypto_asymmetric.c | 402 +++++++-- .../ta/common/wtpi_impl/wtpi_decrypt_sample.c | 60 +- .../wtpi_persistent_storage_layer2.c | 2 +- .../wtpi_impl/wtpi_root_of_trust_layer1.c | 57 +- .../opk/ports/optee/ta/oemcrypto_ta/Makefile | 2 +- .../optee/ta/oemcrypto_ta/oemcrypto_ta.c | 6 +- .../opk/ports/optee/ta/oemcrypto_ta/sub.mk | 11 +- .../opk/ports/optee/ta/wtpi_test_ta/Makefile | 2 +- .../opk/ports/optee/ta/wtpi_test_ta/sub.mk | 11 + .../optee/ta/wtpi_test_ta/wtpi_test_ta.c | 8 +- ...crypto_and_key_management_layer1_openssl.c | 8 +- oemcrypto/opk/ports/trusty/ta/rules.mk | 1 + .../common/GEN_common_serializer.c | 40 +- .../common/GEN_common_serializer.h | 9 +- .../opk/serialization/common/bump_allocator.c | 29 +- .../common/common_special_cases.c | 13 +- .../common/include/length_types.h | 2 +- .../common/include/shared_buffer_allocator.h | 8 +- .../opk/serialization/common/log_macros.c | 2 + oemcrypto/opk/serialization/common/opk_init.c | 14 +- .../common/opk_serialization_base.c | 25 +- .../common/shared_buffer_allocator.c | 23 +- .../opk/serialization/ree/GEN_oemcrypto_api.c | 824 ++++++++++++------ .../serialization/ree/GEN_ree_serializer.c | 438 +++++----- .../serialization/ree/GEN_ree_serializer.h | 59 +- .../opk/serialization/ree/ree_special_cases.c | 37 + .../opk/serialization/ree/ree_special_cases.h | 6 + .../opk/serialization/ree/special_case_apis.c | 34 + .../opk/serialization/tee/GEN_dispatcher.c | 242 +++-- .../serialization/tee/GEN_tee_serializer.c | 392 +++++---- .../serialization/tee/GEN_tee_serializer.h | 58 +- oemcrypto/opk/serialization/tee/tee.gyp | 1 + .../opk/serialization/tee/tee_special_cases.c | 36 +- .../opk/serialization/tee/tee_special_cases.h | 5 + oemcrypto/opk/serialization/tee/tee_version.c | 26 +- oemcrypto/test/common.mk | 1 + oemcrypto/test/fuzz_tests/README.md | 3 +- .../test/fuzz_tests/build_oemcrypto_fuzztests | 15 +- .../1970fbbb5d20902996167f3309fbd38a6850b147 | Bin 296 -> 0 bytes .../5812ad7753622d9177a1b3dd71c6c4a008ff54eb | Bin 296 -> 0 bytes .../10da8c370429a6a450d5ad0ee563653d18dbfeb8 | Bin 140 -> 0 bytes .../1ae600c50a9a0bca685d7b83004fa3135901ded2 | Bin 204 -> 0 bytes .../21d16dc13d2b8103c7943a5bd960ebc77dfefde4 | Bin 204 -> 0 bytes .../38d4821122ddf0e84dba312f444bfbef5b81cc9d | Bin 204 -> 0 bytes .../3cdf5d3cd5937b78d2560970a0ccce14fb0d0230 | Bin 588 -> 0 bytes .../3cf22dc963d6705061004cb0fad32bdebc86ffc9 | Bin 140 -> 0 bytes .../3d891464eace6f7d3c716830e6051f7e90b90610 | Bin 140 -> 0 bytes .../6f65463040c50e026e252e7544dff41babbc4604 | Bin 140 -> 0 bytes .../737cd5853708e2d2732e4c54dc944bc54d522406 | Bin 428 -> 0 bytes .../d775f9b5597e76cbf380ad74fea86c307c224309 | Bin 140 -> 0 bytes .../e9c4232d40cbc76f71220641ea9f8740bfedd306 | Bin 204 -> 0 bytes .../eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce | Bin 140 -> 0 bytes .../f6c28150e2e1a1390516a09d453d33cb9a1337b4 | Bin 204 -> 0 bytes .../6c6a072aa58399454ee759bac539109a20f7e97f | Bin 188 -> 0 bytes .../75ae4c5769c9568d631452df3b3702d876e4863a | Bin 178 -> 0 bytes .../9bdb356ec50807b86c807c09c780267101fd1a0b | Bin 178 -> 0 bytes .../374d2a1ab0be81451653b26a0ff99c2f20351700 | Bin 176 -> 0 bytes .../7a883f7628e57eb5fe48d660fed48ac5da2f5d21 | Bin 176 -> 0 bytes .../a591b11c7ff1f45e8edb1a055a3255edb247576d | Bin 176 -> 0 bytes .../c182ac7556d1cd1ed73da74882dee807381f3ee0 | Bin 176 -> 0 bytes .../6f8b954fb7f8be2c3632f931aaf55e3d1a6c58d8 | Bin 676 -> 0 bytes .../7997b5673d5a9402b2f8acc43f92cdf6ad1f913d | Bin 676 -> 0 bytes .../8196b2365ca56224853dfeeddde216b4f467f0dd | Bin 676 -> 0 bytes .../81ac6d013d80da7f67fe6fbb5e8c15a35a0d8134 | Bin 676 -> 0 bytes .../fuzz_tests/oemcrypto_copy_buffer_fuzz.cc | 139 ++- .../oemcrypto_deactivate_usage_entry_fuzz.cc | 27 +- .../fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc | 292 +++---- .../test/fuzz_tests/oemcrypto_fuzz_helper.cc | 74 +- .../test/fuzz_tests/oemcrypto_fuzz_helper.h | 174 +++- .../test/fuzz_tests/oemcrypto_fuzz_structs.h | 35 +- .../test/fuzz_tests/oemcrypto_fuzztests.gyp | 129 --- .../test/fuzz_tests/oemcrypto_fuzztests.gypi | 10 +- .../oemcrypto_generate_rsa_signature_fuzz.cc | 40 +- .../oemcrypto_generate_signature.cc | 36 - .../oemcrypto_generic_decrypt_fuzz.cc | 76 +- .../oemcrypto_generic_encrypt_fuzz.cc | 78 +- .../fuzz_tests/oemcrypto_generic_sign_fuzz.cc | 68 +- .../oemcrypto_generic_verify_fuzz.cc | 99 +-- .../oemcrypto_license_request_fuzz.cc | 23 +- ...mcrypto_load_entitled_content_keys_fuzz.cc | 68 +- .../fuzz_tests/oemcrypto_load_license_fuzz.cc | 17 +- .../oemcrypto_load_provisioning_fuzz.cc | 15 +- .../fuzz_tests/oemcrypto_load_renewal_fuzz.cc | 36 +- .../oemcrypto_load_usage_entry_fuzz.cc | 87 +- .../oemcrypto_load_usage_table_header_fuzz.cc | 20 +- .../oemcrypto_opk_dispatcher_fuzz.cc | 63 +- .../fuzz_tests/oemcrypto_opk_fuzztests.gyp | 274 +++--- .../oemcrypto_provisioning_request_fuzz.cc | 23 +- .../oemcrypto_renewal_request_fuzz.cc | 22 +- .../fuzz_tests/oemcrypto_report_usage_fuzz.cc | 65 +- .../partner_oemcrypto_fuzztests.gyp | 254 ++++-- .../partner_oemcrypto_fuzztests.gypi | 1 + oemcrypto/test/oec_decrypt_fallback_chain.cpp | 46 +- oemcrypto/test/oec_session_util.cpp | 147 +++- oemcrypto/test/oec_session_util.h | 23 +- oemcrypto/test/oemcrypto_test.cpp | 399 ++++++--- oemcrypto/test/oemcrypto_unittests.gypi | 1 + .../util/include/oemcrypto_key_deriver.h | 5 + oemcrypto/util/include/oemcrypto_rsa_key.h | 7 + oemcrypto/util/src/oemcrypto_key_deriver.cpp | 40 + oemcrypto/util/src/oemcrypto_rsa_key.cpp | 21 + oemcrypto/util/test/oem_cert_test.cpp | 8 +- .../util/test/oemcrypto_oem_cert_unittest.cpp | 6 +- .../util/test/oemcrypto_ref_test_utils.h | 1 + util/include/file_store.h | 4 +- util/include/log.h | 33 +- util/include/platform.h | 2 +- util/include/rw_lock.h | 2 +- util/include/string_conversions.h | 49 +- util/include/util_common.h | 12 - util/libcrypto_dependency.gypi | 22 +- util/libssl_dependency.gypi | 24 +- util/test/test_clock.cpp | 4 +- util/test/test_sleep.cpp | 13 + util/test/test_sleep.h | 7 +- 189 files changed, 6390 insertions(+), 3411 deletions(-) mode change 120000 => 100644 oemcrypto/include/OEMCryptoCENCCommon.h delete mode 100755 oemcrypto/opk/ports/optee/install_ta.sh delete mode 100755 oemcrypto/opk/ports/optee/push.sh delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/1970fbbb5d20902996167f3309fbd38a6850b147 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/5812ad7753622d9177a1b3dd71c6c4a008ff54eb delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/10da8c370429a6a450d5ad0ee563653d18dbfeb8 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/1ae600c50a9a0bca685d7b83004fa3135901ded2 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/21d16dc13d2b8103c7943a5bd960ebc77dfefde4 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/38d4821122ddf0e84dba312f444bfbef5b81cc9d delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cdf5d3cd5937b78d2560970a0ccce14fb0d0230 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cf22dc963d6705061004cb0fad32bdebc86ffc9 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3d891464eace6f7d3c716830e6051f7e90b90610 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/6f65463040c50e026e252e7544dff41babbc4604 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/737cd5853708e2d2732e4c54dc944bc54d522406 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/d775f9b5597e76cbf380ad74fea86c307c224309 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e9c4232d40cbc76f71220641ea9f8740bfedd306 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/f6c28150e2e1a1390516a09d453d33cb9a1337b4 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/6c6a072aa58399454ee759bac539109a20f7e97f delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/75ae4c5769c9568d631452df3b3702d876e4863a delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/9bdb356ec50807b86c807c09c780267101fd1a0b delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/374d2a1ab0be81451653b26a0ff99c2f20351700 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/7a883f7628e57eb5fe48d660fed48ac5da2f5d21 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a591b11c7ff1f45e8edb1a055a3255edb247576d delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/c182ac7556d1cd1ed73da74882dee807381f3ee0 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/6f8b954fb7f8be2c3632f931aaf55e3d1a6c58d8 delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/7997b5673d5a9402b2f8acc43f92cdf6ad1f913d delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/8196b2365ca56224853dfeeddde216b4f467f0dd delete mode 100644 oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/81ac6d013d80da7f67fe6fbb5e8c15a35a0d8134 delete mode 100644 oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp delete mode 100644 oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc diff --git a/CHANGELOG.md b/CHANGELOG.md index 84bcc95..e14e991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,46 @@ [TOC] +## [Version 17.2][v17.2] + +This release contains the first version of OPK to support MediaCAS, an +end-to-end demo of OEMCrypto CAS functionality, several bug fixes in OPK and a +few updates to the OEMCrypto unit tests and fuzz tests. + +MediaCAS support has been added to OPK. `OPK_Pack_LoadCasECMKeys_Request()`, +`OPK_Unpack_LoadCasECMKeys_Request()`, `OPK_Pack_LoadCasECMKeys_Response()`, +`OPK_Unpack_LoadCasECMKeys_Response()` are moved out of the auto-generated +serialization code and are added to the special cases, to allow implementor to +pack customized data. CAS-specific WTPI functions along with a reference +implementation have been added. + +A new `cas` directory is added to the `ports/linux` project. This contains +an end-to-end demo of OEMCrypto CAS functionality. The OEMCrypto CAS test client +communicates with the Linux `tee_simulator_cas` via `liboemcrypto.so` and +`libtuner.so`. `tee_simulator_cas` loads CAS keys and performs descrambling. + +All CAS specific code in OPK is guarded by the compiler flag `SUPPORT_CAS`. + +Several other updates and fixes to OPK in this release include: +- `strnlen()` is removed from OPK to avoid issue caused by the terminating '\0'. +- Explicit call to `builtin_add_overflow()` is removed and `oemcrypto_overflow` + wrappers are used instead. +- Added non-NULL checks in `WTPI_UnwrapValidateAndInstallKeybox()`, + `OEMCrypto_OPK_SerializationVersion()`, and `OPKI_GetFromObjectTable()`. +- Validated the wrapped key size to be non-zero. +- Set OP-TEE serialized request size to the maximum size expected. +- HMACs are compared in constant time. +- Fixed pointer arithmetic with size_t to avoid unexpected truncation of the + calculated address. +- No-op for zero-sized subsample instead of aborting OPK. + +This release also contains a few updates to the OEMCrypto unit tests and fuzz +tests: +- Reduced clock skew in flaky duration tests. +- Removed device ID check since it is not required for v17. +- Added a test for zero subsample size. +- Cleaned up fuzz helper classes and added more fuzz test coverage. + ## [OPK Version 17.1.1][v17.1+opk-v17.1.1] This release fixes a flaw in the OPK code that could allow content that requires @@ -179,3 +219,4 @@ Public release for OEMCrypto API and ODK library version 16.4. [v17+test-updates+opk+mk]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17+test-updates+opk+mk [v17.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.1 [v17.1+opk-v17.1.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.1+opk-v17.1.1 +[v17.2]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v17.2 diff --git a/oem_certificate_generator/README.md b/oem_certificate_generator/README.md index 92b4c5e..a9fd483 100644 --- a/oem_certificate_generator/README.md +++ b/oem_certificate_generator/README.md @@ -16,7 +16,7 @@ OEM certificate generation tool ## Usage -Run `python oem_certificate.py --help` to see available commands. +Run `python3 oem_certificate.py --help` to see available commands. The arguments can be partially or fully loaded from a configuration file, for example, if file "location.cfg" is, @@ -32,14 +32,14 @@ example, if file "location.cfg" is, A command of ```bash - python oem_certificate.py generate_csr @location.cfg -CN TestDevice1 \ + python3 oem_certificate.py generate_csr @location.cfg -CN TestDevice1 \ --output_csr_file=csr.pem --output_private_key_file=key.der ``` is equivalent to ```bash - python oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA \ + python3 oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA \ -L=Kirkland -O='Some Company' -OU='Some Unit' --output_csr_file=csr.pem \ --output_private_key_file=key.der. ``` diff --git a/oem_certificate_generator/oem_certificate.py b/oem_certificate_generator/oem_certificate.py index 71e7789..cf4e9e1 100755 --- a/oem_certificate_generator/oem_certificate.py +++ b/oem_certificate_generator/oem_certificate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # Copyright 2017 Google LLC. All Rights Reserved. """OEM certificate generation tool. @@ -26,10 +26,10 @@ example, if file "location.cfg" is, -OU=Some Unit A command of - "python oem_certificate.py generate_csr @location.cfg -CN TestDevice1 " + "python3 oem_certificate.py generate_csr @location.cfg -CN TestDevice1 " "--output_csr_file=csr.pem --output_private_key_file=key.der", is equivalent to - "python oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA " + "python3 oem_certificate.py generate_csr -CN TestDevice1 -C=US -ST=CA " "-L=Kirkland -O='Some Company' -OU='Some Unit' --output_csr_file=csr.pem " "--output_private_key_file=key.der". diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index d34b309..34f0a94 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -3,7 +3,7 @@ // License Agreement. /** - * @mainpage OEMCrypto API v17 + * @mainpage OEMCrypto API v17.2 * * OEMCrypto is the low level library implemented by the OEM to provide key and * content protection, usually in a separate secure memory or process space. The @@ -121,7 +121,7 @@ * application or the license server. * * @defgroup drm_cert DRM Certificate Provisioning API - * This section of functions are used to provision the device with an DRM + * This section of functions are used to provision the device with a DRM * certificate. This certificate is obtained by a device in the field from a * Google/Widevine provisioning server, or from a third party server running the * Google/Widevine provisioning server SDK. Since the DRM certificate may be @@ -135,6 +135,14 @@ * The usage table is used to store license usage and allows a persistent * license to be reloaded. * + * @defgroup entitled Entitlement License API + * Functions that are needed for entitled and entitlement licenses. + * + * [Entitlement licensing](../../index#entitlement) is a way to provide access + * to content keys that may be stored elsewhere, such as in the content itself. + * This can be used to implement content key rotation without requiring new + * licenses, or access to multiple pieces of content with a single license. + * * @defgroup test_verify Test and Verification API * Functions that are designed to help test OEMCrypto and the device. They are * not used during normal operation. Some functions, like those that test the @@ -376,6 +384,20 @@ typedef enum OEMCryptoCipherMode { OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_ECB, } OEMCryptoCipherMode; +/** + * This is a list of valid algorithms for OEMCrypto_Generic_* functions. + * Some are valid for encryption/decryption, and some for signing/verifying. + */ +typedef enum OEMCrypto_Algorithm { + OEMCrypto_AES_CBC_128_NO_PADDING = 0, + OEMCrypto_HMAC_SHA256 = 1, + OEMCrypto_Algorithm_MaxValue = 1, +} OEMCrypto_Algorithm; + +/// @} + +/// @addtogroup entitled +/// @{ /** * Contains encrypted content key data for loading into the sessions keytable. * The content key data is encrypted using AES-256-CBC encryption, with PKCS#7 @@ -399,16 +421,6 @@ typedef struct { OEMCryptoCipherMode cipher_mode; } OEMCrypto_EntitledContentKeyObject; -/** - * This is a list of valid algorithms for OEMCrypto_Generic_* functions. - * Some are valid for encryption/decryption, and some for signing/verifying. - */ -typedef enum OEMCrypto_Algorithm { - OEMCrypto_AES_CBC_128_NO_PADDING = 0, - OEMCrypto_HMAC_SHA256 = 1, - OEMCrypto_Algorithm_MaxValue = 1, -} OEMCrypto_Algorithm; - /// @} /// @addtogroup keyladder @@ -574,6 +586,13 @@ typedef enum OEMCrypto_WatermarkingSupport { /** * Obfuscation Renames. + * + * The function signatures of each oecc obfuscated name should remain static + * across multiple versions. When we want to change the function signature of a + * function, we will give the new signature a new oecc number and keep the + * original oecc name with the original function signature. This allows us to + * maintain backwards compatibility when the CDM loads an older version of + * liboemcrypto.so using dlopen. */ // clang-format off #define OEMCrypto_Initialize _oecc01 @@ -702,6 +721,7 @@ typedef enum OEMCrypto_WatermarkingSupport { #define OEMCrypto_ReuseUsageEntry _oecc127 #define OEMCrypto_GetDTCP2Capability _oecc128 #define OEMCrypto_GetWatermarkingSupport _oecc129 +#define OEMCrypto_GetOEMKeyToken _oecc130 // clang-format on /// @addtogroup initcontrol @@ -915,39 +935,6 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session); */ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); -/** - * This method creates an entitled key session. - * - * @param[in] oec_session: handle for the OEMCrypto session to be associated - * with the created entitled key session. - * @param[out] key_session: id of the created entitled key session. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_INVALID_SESSION - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_CreateEntitledKeySession( - OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session); - -/** - * This method which removes an entitled key session. - * - * @param[in] key_session: id of the entitled key session to be removed. - * - * Returns: - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( - OEMCrypto_SESSION key_session); - /** * Generates three secondary keys, mac_key[server], mac_key[client], and * encrypt_key, for handling signing and content key decryption under the @@ -1795,67 +1782,6 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, const uint8_t* signature, size_t signature_length); -/** - * Load content keys into a session which already has entitlement keys - * loaded. This function will only be called for a session after a call to - * OEMCrypto_LoadKeys() with the parameter type license_type equal to - * OEMCrypto_EntitlementLicense. This function may be called multiple times - * for the same session. - * - * If the session does not have license_type equal to - * OEMCrypto_EntitlementLicense, return OEMCrypto_ERROR_INVALID_CONTEXT and - * perform no work. - * - * For each key object in key_array, OEMCrypto shall look up the entry in the - * key table with the corresponding entitlement_key_id. - * - * 1. If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. - * 2. If the entry already has a content_key_id and content_key_data, that - * id and data are erased. - * 3. The content_key_id from the key_array is copied to the entry's - * content_key_id. - * 4. The content_key_data decrypted using the entitlement_key_data as a - * key for AES-256-CBC with an IV of content_key_data_iv. Notice that - * the entitlement key will be an AES 256 bit key. The clear content key - * data will be stored in the entry's content_key_data. - * Entries in the key table that do not correspond to anything in the - * key_array are not modified or removed. - * - * For devices that use a hardware key ladder, it may be more convenient to - * store the encrypted content key data in the key table, and decrypt it when - * the function SelectKey is called. - * - * @param[in] session: handle for the entitled key session to be used. - * @param[in] message: pointer to memory containing message to be verified. - * @param[in] message_length: length of the message, in bytes. - * @param[in] key_array_length: number of keys present. - * @param[in] key_array: set of key updates. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_KEY_NOT_ENTITLED - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method changed in API version 17. - */ -OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array); - /** * NOTE: OEMCrypto_RefreshKeys() is only used to load a v15 license or renewal. * Because there are no longer any active v15 servers, this function is only @@ -2091,6 +2017,245 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, /// @} +/// @addtogroup entitled +/// @{ + +/** + * This method creates an entitled key session. + * OEMCrypto is required to support at least one entitled key session per + * license. For CAS support, we also require that OEMCrypto support at least + * six entitled key sessions per license. + * + * @param[in] oec_session: handle for the OEMCrypto session to be associated + * with the created entitled key session. + * @param[out] key_session: id of the created entitled key session. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_TOO_MANY_SESSIONS + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this oec_session. It will not be called simultaneously with + * initialization or usage table functions. It is as if the CDM holds a write + * lock for this session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_CreateEntitledKeySession( + OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session); + +/** + * This method which removes an entitled key session. + * + * @param[in] key_session: id of the entitled key session to be removed. + * + * Returns: + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( + OEMCrypto_SESSION key_session); + +/** + * Load content keys into an entitled session which is associated with an + * entitlement sessions. This function will only be called for an entitled + * session after a call to OEMCrypto_LoadLicense() has been called on the + * associated entitlement session. This function may be called multiple times + * for the same session. + * + * If the session is not an entitled session, return + * OEMCrypto_ERROR_INVALID_CONTEXT and perform no work. + * + * For each key object in key_array, OEMCrypto shall look up the entry in the + * key table for the entitlement session with the corresponding + * entitlement_key_id. + * + * 1. If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2. If the entry already has a content_key_id and content_key_data, that + * id and data are erased. + * 3. The content_key_id from the key_array is copied to the entry's + * content_key_id. + * 4. The content_key_data decrypted using the entitlement_key_data as a + * key for AES-256-CBC with an IV of content_key_data_iv. Notice that + * the entitlement key will be an AES 256 bit key. The clear content key + * data will be stored in the entry's content_key_data. + * Entries in the key table that do not correspond to anything in the + * key_array are not modified or removed. + * + * For devices that use a hardware key ladder, it may be more convenient to + * store the encrypted content key data in the key table, and decrypt it when + * the function SelectKey is called. + * + * @param[in] session: handle for the entitled key session to be used. + * @param[in] message: pointer to memory containing message to be verified. + * @param[in] message_length: length of the message, in bytes. + * @param[in] key_array_length: number of keys present. + * @param[in] key_array: set of key updates. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_KEY_NOT_ENTITLED + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * + * @buffer_size + * OEMCrypto shall support message sizes as described in the section + * OEMCrypto_ResourceRatingTier(). + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session, or its entitlement session. It will not be called + * simultaneously with initialization or usage table functions. It is as if + * the CDM holds a write lock for this session, and a read lock on the + * OEMCrypto system. + * + * @version + * This method changed in API version 17. + */ +OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); + +/** + * This method associates an existing entitled key session to the specified + * OEMCrypto session. + * + * @param[in] key_session: id of the entitled key session. + * @param[in] oec_session: handle for the OEMCrypto session to be associated + * with the entitled key session. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_INVALID_SESSION + * + * @threading + * This is a "Session Initialization Function" and will not be called + * simultaneously with any other function, as if the CDM holds a write lock + * on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); + +/** + * The OEMCrypto_LoadCasECMKeys method is added to load content keys into an + * entitled key session, which already has entitlement keys loaded. Used only by + * CAS. + * + * This function will only be called for a session after a call to + * OEMCrypto_LoadKeys with the license_type equal to + * OEMCrypto_EntitlementLicense, and a call to + * OEMCrypto_CreateEntitledKeySession initializing the entitled key session. + * This function may be called multiple times for the same session. + * + * For each key object, odd and even, OEMCrypto shall look up the entry in the + * key table with the corresponding entitlement_key_id. Before the + * entitlement_key is used: + * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2) Check the entitlement key’s key control block use. If failed, return + * corresponding error code such as OEMCrypto_ERROR_ANALOG_OUTPUT, + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 3) If the entitlement key’s control block has a nonzero Duration field, + * then the API shall verify that the duration is greater than the + * session’s elapsed time clock before the key is used. OEMCrypto will + * return OEMCrypto_ERROR_KEY_EXPIRED. + * 4) The content_key_data decrypted using the entitlement_key_data as a key + * for AES-256-CBC with an IV of content_key_data_iv. Wrapped content is + * padded using PKCS#7 padding. Notice that the entitlement key will be an + * AES 256 bit key. The clear content key data will be stored in the + * entry’s content_key_data. + * 5) The decrypted content key data may be set in a hardware KeySlot, + * together with content iv and cipher mode information, which can be used + * by the Descrambler in TunerHal. The entitled key session ID may be used + * as the key token to uniquely identify the content key in KeySlot. + * + * @param[in] session: handle for the entitled key session to be used. + * @param[in] message: pointer to memory containing message to be verified. + * @param[in] message_length: length of the message, in bytes. + * @param[in] even_key: key update for the even ecm key. May be null if the key + * does not change. + * @param[in] odd_key: key update for the odd ecm key. May be null if the key + * does not change. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_KEY_NOT_ENTITLED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_KEY_EXPIRED + * @retval OEMCrypto_ERROR_ANALOG_OUTPUT + * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); + +/** + * Retrieves the key token associated with the input entitled key session. This + * method is currently used only by CAS, where key token is a means to share + * vendor specific crypto info with other frameworks (e.g. Descrambler in + * Android TunerHAL) that are also under control of the vendor. + * + * @param[in] key_session: handle for the entitled key session to be used. + * @param[out] key_token: where the key token is stored. + * @param[in,out] key_token_length: length of the key token, in bytes. + * + * @retval OEMCrypto_SUCCESS on success + * @retval OEMCrypto_ERROR_SHORT_BUFFER if buffer_length is too small. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * + * @threading + * This is an "Initialization and Termination Function" and will not be called + * simultaneously with any other function, as if the CDM holds a write lock on + * the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session, + uint8_t* key_token, + size_t* key_token_length); +/// @} + /// @addtogroup decryption /// @{ @@ -3868,11 +4033,14 @@ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void); * key and signing key generated using an algorithm at least as strong as * that in GenerateDerivedKeys. * - * First, OEMCrypto shall verify the signature of the message using - * HMAC-SHA256 with the derived mac_key[server]. The signature verification - * shall use a constant-time algorithm (a signature mismatch will always take - * the same time as a successful comparison). The signature is over the - * entire message buffer starting at message with length message_length. If + * First, OEMCrypto shall verify the signature of the message using the correct + * algorithm depending on if the device supports Provisioning 2.0, 3.0 or 4.0. + * + * For Provisioning 2.0, OEMCrypto shall verify the signature of the message + * using HMAC-SHA256 with the derived mac_key[server]. The signature + * verification shall use a constant-time algorithm (a signature mismatch will + * always take the same time as a successful comparison). The signature is over + * the entire message buffer starting at message with length message_length. If * the signature verification fails, ignore all other arguments and return * OEMCrypto_ERROR_SIGNATURE_FAILURE. * @@ -3880,7 +4048,10 @@ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void); * and encrypt_key with a call to OEMCrypto_DeriveKeysFromSessionKey() or * OEMCrypto_GenerateDerivedKeys(). * - * The function ODK_ParseProvisioning is called to parse the message. If it + * For Provisioning 3.0 and 4.0, the signature is not verified. + * + * After the signature is verified, + * the function ODK_ParseProvisioning is called to parse the message. If it * returns an error, OEMCrypto shall return that error to the CDM layer. The * function ODK_ParseProvisioning is described in the document "Widevine Core * Message Serialization". @@ -4157,7 +4328,7 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( RSA_Padding_Scheme padding_scheme); /** - * OEMCrypto will use OEMCrypto_PrepAndSignProvisioningRequest(), as described + * OEMCrypto will use ODK_PrepareCoreProvisioningRequest(), as described * in the document "Widevine Core Message Serialization", to prepare the core * message. If it returns an error, the error should be returned by OEMCrypto * to the CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall @@ -4168,11 +4339,17 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( * the request with the session's derived client mac key from the previous * call to OEMCrypto_GenerateDerivedKeys(). * - * For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto - * will sign the request with the private key associated with the OEM + * For Provisioning 3.0, i.e. a device that has a baked in OEM Certificate, + * OEMCrypto will sign the request with the private key associated with the OEM * Certificate. The key shall have been loaded by a previous call to * OEMCrypto_LoadDRMPrivateKey(). * + * For Provisioning 4.0, i.e. a device that uses a Boot Chain Certificate to + * request and OEM cert, a request for an OEM cert is signed by the OEM private + * key. A request for a DRM cert is signed by the DRM private key. The DRM cert + * that was generated on the device in OEMCrypto_GenerateCertificateKeyPair() is + * signed by the OEM cert private key. + * * Refer to the Signing Messages Sent to a Server section above for more * details. * @@ -4799,11 +4976,71 @@ OEMCryptoResult OEMCrypto_GetBootCertificateChain( * key is supposed to be certified by the server. The private key is wrapped * with the encryption key so it can be stored in the file system. * - * If an OEM private key is unavailable, the request is assumed for OEM + * The |public_key_signature| output is formatted differently depending + * on whether or not an OEM private key has been loaded. + * + * If an OEM private key is unavailable, the request is assumed to be for OEM * certificate provisioning. In this case, the public key is signed by the - * device private key. If an OEM private key is available, the request is - * assumed for DRM certificate provisioning and the public key is signed by the - * OEM private key. + * device private key. The format of |public_key_signature| in this case is a + * COSE_Sign1 CBOR array. The format is described in RFC 8152 Section 4.2 and + * 4.4, as well as Android IRemotelyProvisionedComponent.aidl (under + * "SignedData") + * + * ~~~ + * |public_key_signature|: COSE_Sign1 CBOR array + * [ + * protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / + * AlgorithmES384 }, + * unprotected: {}, + * payload: bstr .cbor Data / nil, + * signature: bstr ; PureEd25519(priv_key, Sig_structure) / + * ; ECDSA(priv_key, Sig_structure) + * ] + * ~~~ + * + * Notes: + * 1. The payload field in the COSE_Sign1 struct is the public key generated + * by OEMCrypto_GenerateCertificateKeyPair + * 2. The signature field in the COSE_Sign1 struct is the concatenation of the + * (R,S) values from the EC/Ed signature. If either R or S is smaller than + * the key size, it is left-padded with 0 to match the key size as + * described in RFC 8152. This signature is not DER encoded. + * 3. The signature is generated by calling the selected EC signing function + * (PureEd25519 or one of the supported ECDSA algorithms) on + * `Sig_structure`, which is a CBOR array described below. The payload + * field in Sig_structure is the same as the payload in the above + * COSE_Sign1 CBOR array. + * + * ~~~ + * Sig_structure: CBOR array + * [ + * context: "Signature1", + * protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / + * AlgorithmES384 }, + * external_aad: bstr .size 0, + * payload: bstr .cbor Data / nil, + * ] + * ~~~ + * + * If an OEM private key is available, the request is assumed to be for DRM + * certificate provisioning and the public key is signed by the OEM private key. + * If the OEM private key is an RSA key, then |public_key_signature| is the raw + * output of the RSA sign operation with RSASSA-PSS padding. If the OEM private + * key is an ECC key, then |public_key_signature| is the ASN.1 DER-encoded (R,S) + * signature as specified in RFC 3279 2.2.3. + * + * After this function completes successfully, the session will hold a private + * key and will be ready for a call to + * OEMCrypto_PrepAndSignProvisioningRequest(). In particular, when this + * function is used to generate a DRM Certificate key pair, the session will be + * ready to sign a provisioning request with the DRM Cert private key. When this + * function is used to generate an OEM Certificate key pair, the session will be + * ready to sign a provisioning request with the OEM Cert private key. + * + * The public key shall be an ASN.1 DER-encoded SubjectPublicKeyInfo as + * specified in RFC 5280. Widevine recommends ECC keys for Provisioning 4.0, but + * an RSA key may also be used. If the key is an RSA key, then the encoding + * should use "rsaEncryption" (OID 1.2.840.113549.1.1.1), and not RSASSA-PSS. * * @param[in] session: session id. * @param[out] public_key: pointer to the buffer that receives the public key @@ -4812,11 +5049,8 @@ OEMCryptoResult OEMCrypto_GetBootCertificateChain( * @param[in,out] public_key_length: on input, size of the caller's public_key * buffer. On output, the number of bytes written into the buffer. * @param[out] public_key_signature: pointer to the buffer that receives the - * signature of the public key. - * If an OEM private key is unavailable: it is signed by the device private - * key. The signature must be in COSE_SIGN1 format as specified in RFC 8152. - * If an OEM private key is available: it is signed by the OEM private key. - * The signature must be raw signature bytes. + * signature of the public key. The format depends on whether an OEM private + * key has been loaded. * @param[in,out] public_key_signature_length: on input, size of the caller's * public_key_signature buffer. On output, the number of bytes written into * the buffer. @@ -4850,6 +5084,44 @@ OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, OEMCrypto_PrivateKeyType* key_type); +/** + * Loads an OEM private key to a session. The key will be used in signing DRM + * certificate request, or the public key generated by calling + * OEMCrypto_GenerateCertificateKeyPair. + * + * @param[in] session: session id. + * @param[in] key_type: type of the leaf key (RSA or ECC). + * @param[in] wrapped_private_key: the encrypted private key. This is the + * wrapped key generated by OEMCrypto_GenerateCertificateKeyPair. + * @param[in] wrapped_private_key_length: length of |wrapped_private_key| in + * bytes. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_NO_DEVICE_KEY + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_KEY + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_InstallOemPrivateKey( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); + /// @} /// @addtogroup test_verify @@ -5060,140 +5332,15 @@ OEMCryptoResult OEMCrypto_FreeSecureBuffer( OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor, int secure_fd); -/** - * Loads an OEM private key to a session. The key will be used in signing DRM - * certificate request, or the public key generated by calling - * OEMCrypto_GenerateCertificateKeyPair. - * - * @param[in] session: session id. - * @param[in] key_type: type of the leaf key (RSA or ECC). - * @param[in] wrapped_private_key: the encrypted private key. This is the - * wrapped key generated by OEMCrypto_GenerateCertificateKeyPair. - * @param[in] wrapped_private_key_length: length of |wrapped_private_key| in - * bytes. - * - * @retval OEMCrypto_SUCCESS - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_NO_DEVICE_KEY - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_KEY - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_InstallOemPrivateKey( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); - /// @} -/** - * This method associates an existing entitled key session to the specified - * OEMCrypto session. - * - * @param[in] key_session: id of the entitled key session. - * @param[in] oec_session: handle for the OEMCrypto session to be associated - * with the entitled key session. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * @retval OEMCrypto_ERROR_INVALID_SESSION - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); - -/** - * The OEMCrypto_LoadCasECMKeys method is added to load content keys into an - * entitled key session, which already has entitlement keys loaded. Used only by - * CAS. - * - * This function will only be called for a session after a call to - * OEMCrypto_LoadKeys with the license_type equal to - * OEMCrypto_EntitlementLicense, and a call to - * OEMCrypto_CreateEntitledKeySession initializing the entitled key session. - * This function may be called multiple times for the same session. - * - * For each key object, odd and even, OEMCrypto shall look up the entry in the - * key table with the corresponding entitlement_key_id. Before the - * entitlement_key is used: - * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. - * 2) Check the entitlement key’s key control block use. If failed, return - * corresponding error code such as OEMCrypto_ERROR_ANALOG_OUTPUT, - * OEMCrypto_ERROR_INSUFFICIENT_HDCP. - * 3) If the entitlement key’s control block has a nonzero Duration field, - * then the API shall verify that the duration is greater than the - * session’s elapsed time clock before the key is used. OEMCrypto will - * return OEMCrypto_ERROR_KEY_EXPIRED. - * 4) The content_key_data decrypted using the entitlement_key_data as a key - * for AES-256-CBC with an IV of content_key_data_iv. Wrapped content is - * padded using PKCS#7 padding. Notice that the entitlement key will be an - * AES 256 bit key. The clear content key data will be stored in the - * entry’s content_key_data. - * 5) The decrypted content key data may be set in a hardware KeySlot, - * together with content iv and cipher mode information, which can be used - * by the Descrambler in TunerHal. The entitled key session ID may be used - * as the key token to uniquely identify the content key in KeySlot. - * - * @param[in] session: handle for the entitled key session to be used. - * @param[in] message: pointer to memory containing message to be verified. - * @param[in] message_length: length of the message, in bytes. - * @param[in] even_key: key update for the even ecm key. May be null if the key - * does not change. - * @param[in] odd_key: key update for the odd ecm key. May be null if the key - * does not change. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_INVALID_CONTEXT - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_KEY_NOT_ENTITLED - * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION - * @retval OEMCrypto_ERROR_KEY_EXPIRED - * @retval OEMCrypto_ERROR_ANALOG_OUTPUT - * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method is new in API version 17. - */ -OEMCryptoResult OEMCrypto_LoadCasECMKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key); - /* * OEMCrypto_OPK_SerializationVersion + * + * Note: This is an undocumented function. It is only required and used by the + * OPK implementation of OEMCrypto. It is not in a documentation group and does + * not show up on the devsite documentation page. + * * Check the serialization protocol version used by the OEMCrypto Porting Kit * (OPK). If the OPK is not used, this function must return * OEMCrypto_ERROR_NOT_IMPLEMENTED. The serialization version is expressed as diff --git a/oemcrypto/include/OEMCryptoCENCCommon.h b/oemcrypto/include/OEMCryptoCENCCommon.h deleted file mode 120000 index dd92964..0000000 --- a/oemcrypto/include/OEMCryptoCENCCommon.h +++ /dev/null @@ -1 +0,0 @@ -../../oemcrypto/odk/include/OEMCryptoCENCCommon.h \ No newline at end of file diff --git a/oemcrypto/include/OEMCryptoCENCCommon.h b/oemcrypto/include/OEMCryptoCENCCommon.h new file mode 100644 index 0000000..da01169 --- /dev/null +++ b/oemcrypto/include/OEMCryptoCENCCommon.h @@ -0,0 +1 @@ +#include "../../oemcrypto/odk/include/OEMCryptoCENCCommon.h" diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h index ce51b8d..841a731 100644 --- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -120,6 +120,7 @@ typedef enum OEMCrypto_Usage_Entry_Status { kInactiveUnused = 4, } OEMCrypto_Usage_Entry_Status; +/* Not used publicly. Not documented with Doxygen. */ typedef enum OEMCrypto_ProvisioningRenewalType { OEMCrypto_NoRenewal = 0, OEMCrypto_RenewalACert = 1, @@ -135,10 +136,13 @@ typedef enum OEMCrypto_LicenseType { OEMCrypto_LicenseType_MaxValue = OEMCrypto_EntitlementLicense, } OEMCrypto_LicenseType; -/* Private key type used in the provisioning response. */ +/** + * Private key type used in the provisioning response. + */ typedef enum OEMCrypto_PrivateKeyType { OEMCrypto_RSA_Private_Key = 0, OEMCrypto_ECC_Private_Key = 1, + OEMCrypto_PrivateKeyType_MaxValue = OEMCrypto_ECC_Private_Key, } OEMCrypto_PrivateKeyType; /** diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h index 181f452..42c41ba 100644 --- a/oemcrypto/odk/include/core_message_features.h +++ b/oemcrypto/odk/include/core_message_features.h @@ -25,10 +25,9 @@ struct CoreMessageFeatures { // This is the published version of the ODK Core Message library. The default // behavior is for the server to restrict messages to at most this version - // number. The default is 16.5, the last version used by Chrome. This will - // change to 17.0 when v17 has been released. + // number. The default is 17.2. uint32_t maximum_major_version = 17; - uint32_t maximum_minor_version = 1; + uint32_t maximum_minor_version = 2; bool operator==(const CoreMessageFeatures &other) const; bool operator!=(const CoreMessageFeatures &other) const { diff --git a/oemcrypto/odk/include/odk_message.h b/oemcrypto/odk/include/odk_message.h index 075f28c..cdbf26b 100644 --- a/oemcrypto/odk/include/odk_message.h +++ b/oemcrypto/odk/include/odk_message.h @@ -36,10 +36,12 @@ extern "C" { #if defined(__GNUC__) || defined(__clang__) #define ALIGNED __attribute__((aligned)) +#elif _MSC_VER +#define ALIGNED __declspec(align(8)) #else #define ALIGNED #error ODK_Message must be aligned to the maximum useful alignment of the \ - machine you are compiling for. Define the ALIGNED macro accordingly. + machine you are compiling for. Define the ALIGNED macro accordingly. #endif typedef struct { @@ -61,7 +63,8 @@ typedef enum { MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6, MESSAGE_STATUS_OUT_OF_MEMORY = 0x7c5c64cc, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0x7afecacf, - MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873 + MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873, + MESSAGE_STATUS_BUFFER_TOO_LARGE = 0x5bfcfb21 } ODK_MessageStatus; /* diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index fba3c3a..78e8b6a 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -16,10 +16,10 @@ extern "C" { /* The version of this library. */ #define ODK_MAJOR_VERSION 17 -#define ODK_MINOR_VERSION 1 +#define ODK_MINOR_VERSION 2 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v17.1 2022-06-17" +#define ODK_RELEASE_DATE "ODK v17.2 2022-11-21" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp index 615e477..60431f7 100644 --- a/oemcrypto/odk/src/core_message_features.cpp +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -23,7 +23,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures( features.maximum_minor_version = 5; // 16.5 break; case 17: - features.maximum_minor_version = 1; // 17.1 + features.maximum_minor_version = 2; // 17.2 break; default: features.maximum_minor_version = 0; diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp index b874247..4aa79a4 100644 --- a/oemcrypto/odk/src/odk.gyp +++ b/oemcrypto/odk/src/odk.gyp @@ -9,6 +9,7 @@ 'target_name': 'odk', 'type': 'static_library', 'standalone_static_library' : 1, + 'hard_dependency': 1, 'include_dirs': [ '../include', '../../include', diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h index 1e9f50d..58a2fd7 100644 --- a/oemcrypto/odk/src/odk_endian.h +++ b/oemcrypto/odk/src/odk_endian.h @@ -25,6 +25,14 @@ extern "C" { #define oemcrypto_be32toh OSSwapBigToHostInt32 #define oemcrypto_htobe64 OSSwapHostToBigInt64 #define oemcrypto_be64toh OSSwapBigToHostInt64 +#elif defined(_WIN32) +#include +#define oemcrypto_htobe16 htons +#define oemcrypto_be16toh ntohs +#define oemcrypto_htobe32 htonl +#define oemcrypto_be32toh ntohl +#define oemcrypto_htobe64 htonll +#define oemcrypto_be64toh ntohll #else /* defined(__linux__) || defined(__ANDROID__) */ uint32_t oemcrypto_htobe16(uint16_t u16); uint32_t oemcrypto_be16toh(uint16_t u16); diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c index 5c58200..537eefe 100644 --- a/oemcrypto/odk/src/odk_serialize.c +++ b/oemcrypto/odk/src/odk_serialize.c @@ -212,7 +212,7 @@ static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) { Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); Unpack_OEMCrypto_Substring(msg, &obj->pst); Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); - obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg); + Unpack_OEMCrypto_LicenseType(msg, &obj->license_type); Unpack_bool(msg, &obj->nonce_required); Unpack_ODK_TimerLimits(msg, &obj->timer_limits); Unpack_uint32_t(msg, &obj->watermarking); @@ -270,7 +270,7 @@ static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg, Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); Unpack_OEMCrypto_Substring(msg, &obj->pst); Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); - obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg); + Unpack_OEMCrypto_LicenseType(msg, &obj->license_type); Unpack_bool(msg, &obj->nonce_required); Unpack_ODK_TimerLimits(msg, &obj->timer_limits); Unpack_uint32_t(msg, &obj->key_array_length); @@ -286,7 +286,7 @@ static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg, static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg, ODK_ParsedProvisioning* obj) { - obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg); + Unpack_OEMCrypto_PrivateKeyType(msg, &obj->key_type); Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key); Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key_iv); Unpack_OEMCrypto_Substring(msg, &obj->encrypted_message_key); diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index 1b09551..e811d78 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -268,8 +268,21 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits, ODK_InitializeClockValues(clock_values, 0); - nonce_values->api_major_version = ODK_MAJOR_VERSION; - nonce_values->api_minor_version = ODK_MINOR_VERSION; + nonce_values->api_major_version = api_major_version; + switch (nonce_values->api_major_version) { + case 16: + nonce_values->api_minor_version = 5; + break; + case 17: + nonce_values->api_minor_version = 2; + break; + case 18: + nonce_values->api_minor_version = 3; + break; + default: + nonce_values->api_minor_version = 0; + break; + } nonce_values->nonce = 0; nonce_values->session_id = session_id; diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index 30af34c..2ea3065 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -108,10 +108,28 @@ static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) { } } -int Unpack_enum(ODK_Message* message) { - uint32_t v32; +void Unpack_OEMCrypto_LicenseType(ODK_Message* message, + OEMCrypto_LicenseType* value) { + assert(value); + uint32_t v32 = 0; Unpack_uint32_t(message, &v32); - return (int)v32; + if (v32 <= OEMCrypto_LicenseType_MaxValue) { + *value = (OEMCrypto_LicenseType)v32; + } else { + ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); + } +} + +void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message, + OEMCrypto_PrivateKeyType* value) { + assert(value); + uint32_t v32 = 0; + Unpack_uint32_t(message, &v32); + if (v32 <= OEMCrypto_PrivateKeyType_MaxValue) { + *value = (OEMCrypto_PrivateKeyType)v32; + } else { + ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); + } } void Unpack_bool(ODK_Message* message, bool* value) { diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h index 7b69e11..f397937 100644 --- a/oemcrypto/odk/src/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -25,7 +25,10 @@ void PackArray(ODK_Message* message, const uint8_t* base, size_t size); void Pack_OEMCrypto_Substring(ODK_Message* message, const OEMCrypto_Substring* obj); -int Unpack_enum(ODK_Message* message); +void Unpack_OEMCrypto_LicenseType(ODK_Message* message, + OEMCrypto_LicenseType* value); +void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message, + OEMCrypto_PrivateKeyType* value); void Unpack_bool(ODK_Message* message, bool* value); void Unpack_uint8_t(ODK_Message* message, uint8_t* value); void Unpack_uint16_t(ODK_Message* message, uint16_t* value); diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index a244d25..5fafb07 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -872,6 +872,7 @@ std::vector TestCases() { {17, 16, 5, 16, 5}, {17, 17, 0, 17, 0}, {17, 17, 1, 17, 1}, + {17, 17, 2, 17, 2}, }; return test_cases; } diff --git a/oemcrypto/odk/test/odk_test.gypi b/oemcrypto/odk/test/odk_test.gypi index 0cb8a00..4eb3b18 100644 --- a/oemcrypto/odk/test/odk_test.gypi +++ b/oemcrypto/odk/test/odk_test.gypi @@ -4,6 +4,8 @@ { 'sources': [ + 'odk_golden_v16.cpp', + 'odk_golden_v17.cpp', 'odk_test.cpp', 'odk_test_helper.cpp', 'odk_test_helper.h', diff --git a/oemcrypto/oemcrypto_unittests.gyp b/oemcrypto/oemcrypto_unittests.gyp index f6a41ee..fd0b27e 100644 --- a/oemcrypto/oemcrypto_unittests.gyp +++ b/oemcrypto/oemcrypto_unittests.gyp @@ -12,7 +12,7 @@ 'gmock_dependency': 'drm_private_key); - if (result == OEMCrypto_SUCCESS) result = free_key_result; + // TODO(b/225216277): When result is not OEMCrypto_ERROR_NOT_IMPLEMENTED + // above, uncomment this check + // if (result == OEMCrypto_SUCCESS) + result = free_key_result; free_key_result = FreeMacAndEncryptionKeys(session_context); - if (result == OEMCrypto_SUCCESS) result = free_key_result; + // TODO(b/225216277): When result is not OEMCrypto_ERROR_NOT_IMPLEMENTED + // above, uncomment this check + // if (result == OEMCrypto_SUCCESS) + result = free_key_result; if (result != OEMCrypto_SUCCESS) session_context->state = SESSION_INVALID; return result; } @@ -464,6 +473,13 @@ OEMCryptoResult OEMCrypto_Initialize(void) { goto cleanup; } +#ifdef SUPPORT_CAS + result = WTPI_InitializeCas(); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to initialize CAS with result: %u", result); + goto cleanup; + } +#endif g_opk_system_state = SYSTEM_INITIALIZED; result = OEMCrypto_SUCCESS; @@ -484,6 +500,9 @@ OEMCryptoResult OEMCrypto_Terminate(void) { OEMCryptoResult keybox_result = WTPI_TerminateKeybox(); OEMCryptoResult clock_result = WTPI_TerminateClock(); OEMCryptoResult key_management_result = WTPI_K1_TerminateKeyManagement(); +#ifdef SUPPORT_CAS + OEMCryptoResult cas_terminate_result = WTPI_TerminateCas(); +#endif OEMCryptoResult tee_result = WTPI_Terminate(); g_opk_system_state = SYSTEM_NOT_INITIALIZED; if (tee_result != OEMCrypto_SUCCESS) { @@ -511,6 +530,11 @@ OEMCryptoResult OEMCrypto_Terminate(void) { if (asymmetric_key_terminate_result != OEMCrypto_SUCCESS) { return asymmetric_key_terminate_result; } +#ifdef SUPPORT_CAS + if (cas_terminate_result != OEMCrypto_SUCCESS) { + return cas_terminate_result; + } +#endif return key_terminate_result; } @@ -621,7 +645,7 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session, LOGE("Failed to derive mac and encryption keys from keybox with result: %u", result); } -cleanup : { +cleanup: { OEMCryptoResult free_key_result = WTPI_K1_FreeKeyHandle(keybox_key); if (result == OEMCrypto_SUCCESS) result = free_key_result; if (result != OEMCrypto_SUCCESS) { @@ -673,10 +697,11 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( size_t session_key_length = sizeof(session_key); size_t expected_session_key_length = 0; result = OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED; - if (session_context->drm_private_key == NULL) goto cleanup; WTPI_AsymmetricKey_Handle private_key_handle; uint32_t allowed_schemes; - AsymmetricKey* private_key = session_context->drm_private_key; + AsymmetricKey* private_key; + if (session_context->drm_private_key == NULL) goto cleanup; + private_key = session_context->drm_private_key; result = WTPI_UnwrapIntoAsymmetricKeyHandle( private_key->wrapped_key, private_key->wrapped_key_length, private_key->key_type, &private_key_handle, &allowed_schemes); @@ -790,10 +815,11 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, /* last_nonce_time should only be initialized once. */ static uint64_t last_nonce_time = 0; static int nonce_count = 0; - const int nonce_flood_count = 200; + const int kNonceFloodCount = 200; if (last_nonce_time == now) { - nonce_count++; - if (nonce_count > nonce_flood_count) { + if (nonce_count < kNonceFloodCount) { + nonce_count++; + } else { LOGE("Nonce flood detected: now = %" PRIu64, now); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1529,7 +1555,6 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( LOGE("Not a entitlement license or no keys found"); return OEMCrypto_ERROR_INVALID_CONTEXT; } - for (size_t i = 0; i < key_array_length; i++) { if (!IsSubstrInRange(message_length, key_array[i].entitlement_key_id, false) || @@ -1546,8 +1571,6 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( return OEMCrypto_ERROR_INVALID_CONTEXT; } } - - result = OEMCrypto_SUCCESS; for (size_t i = 0; i < key_array_length; i++) { const OEMCrypto_EntitledContentKeyObject key_object = key_array[i]; SymmetricKey* entitlement_key = OPKI_FindKeyFromTable( @@ -1937,42 +1960,6 @@ static OEMCryptoResult DecryptCENCInternal( RETURN_INVALID_CONTEXT_IF_ZERO(samples_length); RETURN_INVALID_CONTEXT_IF_NULL(pattern); - const size_t max_length = WTPI_MaxSampleSize(); - /* Iterate through all the samples and validate them before doing any decrypt. - */ - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - const OEMCrypto_SampleDescription* const sample = &(samples[sample_index]); - if (sample->buffers.input_data == NULL || - sample->buffers.input_data_length == 0) { - LOGE("Sample %zu has invalid input data.", sample_index); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - /* Iterate through all the subsamples and sum their lengths. */ - size_t subsample_length_tally = 0; - for (size_t subsample_index = 0; - subsample_index < sample->subsamples_length; ++subsample_index) { - const OEMCrypto_SubSampleDescription* const subsample = - &(sample->subsamples[subsample_index]); - size_t length; - if (OPK_AddOverflowUX(subsample->num_bytes_clear, - subsample->num_bytes_encrypted, &length)) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - if (OPK_AddOverflowUX(subsample_length_tally, length, - &subsample_length_tally)) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - } - if (max_length != 0 && subsample_length_tally > max_length) { - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - if (subsample_length_tally != sample->buffers.input_data_length) { - LOGE("Sample %zu's length and subsample lengths do not match.", - sample_index); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } - result = OPKI_DecryptSamples(session_context, key_session, samples, samples_length, pattern); if (result == OEMCrypto_ERROR_SHORT_BUFFER) { @@ -1999,43 +1986,60 @@ OEMCryptoResult OEMCrypto_DecryptCENC( RETURN_INVALID_CONTEXT_IF_NULL(samples); RETURN_INVALID_CONTEXT_IF_ZERO(samples_length); RETURN_INVALID_CONTEXT_IF_NULL(pattern); - /* DecryptCENC may be called for calls that could go through CopyBuffer. We - separate those calls out here so that the decrypt code path only has to - handle cases where a key is expected. */ - bool has_encrypted_data = false; - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - if (samples[sample_index].subsamples_length != 1 || - samples[sample_index].subsamples[0].num_bytes_encrypted > 0) { - has_encrypted_data = true; - break; - } - } - if (has_encrypted_data) - return DecryptCENCInternal(session, samples, samples_length, pattern); + bool has_encrypted_data = false; const size_t max_length = WTPI_MaxSampleSize(); + /* Iterate through all the samples and validate them before doing any decrypt + * or copy over. Also it checks whether there is any encrypted data in the + * samples. */ for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { const OEMCrypto_SampleDescription* const sample = &(samples[sample_index]); - ABORT_IF(sample->subsamples_length != 1, - "Sample %zu with multiple subsamples was somehow not treated as " - "encrypted.", - sample_index); - const OEMCrypto_SubSampleDescription* const subsample = - &(sample->subsamples[0]); - if (max_length != 0 && subsample->num_bytes_clear > max_length) { - LOGE("Sample size too large: %zu bytes. Max allowed: %zu", - subsample->num_bytes_clear, max_length); + if (sample->buffers.input_data == NULL || + sample->buffers.input_data_length == 0) { + LOGE("Sample %zu has invalid input data.", sample_index); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + /* Iterate through all the subsamples and sum their lengths. */ + size_t subsample_length_tally = 0; + for (size_t subsample_index = 0; + subsample_index < sample->subsamples_length; ++subsample_index) { + const OEMCrypto_SubSampleDescription* const subsample = + &(sample->subsamples[subsample_index]); + size_t length; + if (OPK_AddOverflowUX(subsample->num_bytes_clear, + subsample->num_bytes_encrypted, &length)) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + if (OPK_AddOverflowUX(subsample_length_tally, length, + &subsample_length_tally)) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + if (subsample->num_bytes_encrypted > 0) has_encrypted_data = true; + } + if (max_length != 0 && subsample_length_tally > max_length) { return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } - if (subsample->num_bytes_clear != sample->buffers.input_data_length) { - LOGE("Sample %zu's length and subsample length do not match.", + if (subsample_length_tally != sample->buffers.input_data_length) { + LOGE("Sample %zu's length and subsample lengths do not match.", sample_index); return OEMCrypto_ERROR_INVALID_CONTEXT; } + } + /* DecryptCENC may be called for calls that could go through CopyBuffer. We + separate those calls out here so that the decrypt code path only has to + handle cases where a key is expected. */ + if (has_encrypted_data) + return DecryptCENCInternal(session, samples, samples_length, pattern); + + /* Handle clear samples. */ + for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { + const OEMCrypto_SampleDescription* const sample = &(samples[sample_index]); + /* Copy the consecutive subsamples all at once. */ OEMCryptoResult result = OEMCrypto_CopyBuffer( session, sample->buffers.input_data, sample->buffers.input_data_length, - &sample->buffers.output_descriptor, subsample->subsample_flags); + &sample->buffers.output_descriptor, /*subsample_flags=*/ + (OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to copy buffer with result: %u", result); return result; @@ -2052,10 +2056,10 @@ OEMCryptoResult OEMCrypto_CopyBuffer( LOGE("OEMCrypto is not yet initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + if (data_length == 0) return OEMCrypto_SUCCESS; /* We don't need to check the session, CopyBuffer should be allowed for all session states since it doesn't access any state data. */ RETURN_INVALID_CONTEXT_IF_NULL(data_addr); - RETURN_INVALID_CONTEXT_IF_ZERO(data_length); RETURN_INVALID_CONTEXT_IF_NULL(dest_buffer_desc); OEMCryptoResult result; @@ -2371,8 +2375,9 @@ OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { } else if (provisioning_method == OEMCrypto_Keybox) { return WTPI_ValidateKeybox(); } else if (provisioning_method == OEMCrypto_BootCertificateChain) { - // Provisioning 4 does not use keybox or OEM cert as root. - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + // Although provisioning 4 does not use keybox as root, a keybox can still + // be present as a backup of root of trust, which can be validated as well. + return WTPI_ValidateKeybox(); } else { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } @@ -2480,7 +2485,10 @@ uint32_t OEMCrypto_MinorAPIVersion(void) { return API_MINOR_VERSION; } OEMCryptoResult OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length) { RETURN_INVALID_CONTEXT_IF_NULL(buffer_length); - const size_t max_length = strnlen(BUILD_INFO(), 128); + const size_t current_size = sizeof(BUILD_INFO()); + const size_t build_info_limit = 128; + const size_t max_length = + current_size > build_info_limit ? build_info_limit : current_size; if (*buffer_length < max_length) { *buffer_length = max_length; return OEMCrypto_ERROR_SHORT_BUFFER; @@ -2676,21 +2684,17 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(signature_length); - if (padding_scheme == kSign_PKCS1_Block1 && message_length > 83) { + if (padding_scheme != kSign_PKCS1_Block1) { + LOGE("Only PKCS1 block1 padding scheme allowed"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + if (message_length > 83) { LOGE("message_length is too long for the given padding_scheme."); return OEMCrypto_ERROR_SIGNATURE_FAILURE; } - if (session_context->state == SESSION_LOAD_OEM_RSA_KEY && - padding_scheme == kSign_RSASSA_PSS) { - // SignMessageWithOEMPrivateKey handles signature being NULL, so we - // intentionally do not check it here. - result = OEMCrypto_ERROR_NOT_IMPLEMENTED; - // TODO(b/225216277): implement this. - // SignMessageWithOEMPrivateKey(message, message_length, signature, - // signature_length); - if (result != OEMCrypto_SUCCESS) return result; - } else if (session_context->state == SESSION_LOAD_DRM_RSA_KEY) { + if (session_context->state == SESSION_LOAD_DRM_RSA_KEY) { if ((session_context->allowed_schemes & padding_scheme) != padding_scheme) { LOGE("Invalid padding scheme: %u", session_context->allowed_schemes); return OEMCrypto_ERROR_INVALID_KEY; @@ -2787,6 +2791,10 @@ OEMCryptoResult OEMCrypto_LoadProvisioning( LOGE("Encrypted private key length is too large to handle."); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (parsed_response.enc_private_key.length == 0) { + LOGE("Encrypted private key length is zero."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } if (parsed_response.enc_private_key_iv.length != KEY_IV_SIZE) { LOGE("Encrypted private key iv has invalid length: %zu", parsed_response.enc_private_key_iv.length); @@ -3308,7 +3316,16 @@ OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( if (result != OEMCrypto_SUCCESS) return result; // Generate the key pair and fill the key type. - const size_t required_signature_size = 1024; + size_t required_signature_size = MAX_ASYMMETRIC_SIGNATURE_SIZE; + if (session_context->prov40_oem_private_key == NULL) { + // This is for obtaining an OEM leaf cert. The signature is a COSE_SIGN1 + // format. Adjust the required signature size. + result = WTPI_GetMaxDeviceKeyCoseSign1Size(&required_signature_size); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get max COSE_SIGN1 size: %u", result); + return result; + } + } AsymmetricKeyType generated_key_type; result = WTPI_GenerateRandomCertificateKeyPair( &generated_key_type, wrapped_private_key, wrapped_private_key_size, @@ -3487,6 +3504,217 @@ OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( return OEMCrypto_SUCCESS; } +#ifdef SUPPORT_CAS +OEMCryptoResult OEMCrypto_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key) { + if (g_opk_system_state != SYSTEM_INITIALIZED) { + LOGE("OEMCrypto is not yet initialized"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (OPKI_GetSessionType(session) != SESSION_TYPE_ENTITLED_KEY) { + LOGE("Unexpected session type."); + return OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION; + } + OEMCryptoSession* session_context = NULL; + OEMCryptoEntitledKeySession* key_session = NULL; + OEMCryptoResult result = + GetSessionContext(session, &session_context, &key_session); + if (result != OEMCrypto_SUCCESS) return result; + ABORT_IF(session_context == NULL, + "Failed to get the entitlement session context."); + ABORT_IF(key_session == NULL, + "Failed to get the entitled key session context."); + result = OPKI_CheckStatePreCall(session_context, API_LOADENTITLEDCONTENTKEYS); + if (result != OEMCrypto_SUCCESS) return result; + + RETURN_INVALID_CONTEXT_IF_NULL(message); + RETURN_INVALID_CONTEXT_IF_ZERO(message_length); + + if (!even_key && !odd_key) { + LOGD("No even or odd keys found"); + return OEMCrypto_SUCCESS; + } + OEMCrypto_EntitledContentKeyObject key_array[2]; + memset(key_array, 0, sizeof(OEMCrypto_EntitledContentKeyObject) * 2); + if (even_key && odd_key) { + memcpy(&key_array[0], even_key, sizeof(OEMCrypto_EntitledContentKeyObject)); + memcpy(&key_array[1], odd_key, sizeof(OEMCrypto_EntitledContentKeyObject)); + } else { + if (even_key) { + memcpy(&key_array[0], even_key, + sizeof(OEMCrypto_EntitledContentKeyObject)); + } else if (odd_key) { + memcpy(&key_array[1], odd_key, + sizeof(OEMCrypto_EntitledContentKeyObject)); + } + } + + /* Validate entitled content keys. */ + if (session_context->license_type != OEMCrypto_EntitlementLicense || + session_context->num_entitlement_keys == 0) { + LOGE("Not an entitlement license or no keys found"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + static const size_t kKeyCount = 2; + OEMCrypto_EntitledContentKeyObject empty_key = {0}; + for (size_t i = 0; i < kKeyCount; i++) { + if (memcmp(&key_array[i], &empty_key, sizeof(empty_key)) == 0) continue; + if (!IsSubstrInRange(message_length, key_array[i].entitlement_key_id, + false) || + !IsSubstrInRange(message_length, key_array[i].content_key_id, false) || + !IsSubstrInRange(message_length, key_array[i].content_key_data, + false) || + !IsSubstrInRange(message_length, key_array[i].content_key_data_iv, + false) || + !IsSubstrInRange(message_length, key_array[i].content_iv, true) || + key_array[i].entitlement_key_id.length > KEY_ID_MAX_SIZE || + key_array[i].content_key_id.length > KEY_ID_MAX_SIZE || + key_array[i].content_key_data.length != KEY_SIZE_128 || + key_array[i].content_key_data_iv.length != KEY_IV_SIZE) { + LOGE("Invalid substring range for key index: %zu", i); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + + /* Load entitled content keys. */ + for (size_t i = 0; i < kKeyCount; i++) { + /* Skips NULL key. */ + if (memcmp(&key_array[i], &empty_key, sizeof(empty_key)) == 0) continue; + const bool is_even = (i % 2 == 0); + const OEMCrypto_EntitledContentKeyObject key_object = key_array[i]; + SymmetricKey* entitlement_key = OPKI_FindKeyFromTable( + session_context, false, message + key_object.entitlement_key_id.offset, + key_object.entitlement_key_id.length); + if (!OPKI_CheckKey(entitlement_key, ENTITLEMENT_KEY)) { + result = OEMCrypto_KEY_NOT_ENTITLED; + goto cleanup; + } + + /* Initialized the index to which the entitled content key to be loaded. */ + uint32_t entitled_content_key_index = + key_session->num_entitled_content_keys; + /* It prefers to reuse an existing content key index that is entitled by the + * same entitlement key if one exists already, but will allocate a new index + * if there are none that can be reused. + * The block below searches whether there is an existing content key + * entitled by the same entitlement key, with the same parity as the key to + * be loaded, and will reuse the index to load the new content key if there + * is one. */ + for (uint32_t k = 0; k < key_session->num_entitled_content_keys; k++) { + const EntitlementKeyInfo* key_info = &key_session->entitlement_keys[k]; + if (key_info->entitlement_key_id_size == entitlement_key->key_id_size && + memcmp(key_info->entitlement_key_id, entitlement_key->key_id, + key_info->entitlement_key_id_size) == 0 && + is_even == key_session->entitled_content_keys[k]->is_even_key) { + entitled_content_key_index = k; + result = OPKI_FreeKeyFromTable( + &key_session->entitled_content_keys[entitled_content_key_index]); + if (result != OEMCrypto_SUCCESS) goto cleanup; + break; + } + } + + const bool adding_new_content_key = + entitled_content_key_index == key_session->num_entitled_content_keys; + if (adding_new_content_key && + key_session->num_entitled_content_keys == CONTENT_KEYS_PER_SESSION) { + result = OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + goto cleanup; + } + SymmetricKey** content_key_ptr = + &key_session->entitled_content_keys[entitled_content_key_index]; + result = OPKI_CreateKey(content_key_ptr, CONTENT_KEY, + (KeySize)key_object.content_key_data.length); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to create CONTENT_KEY with result: %u", result); + goto cleanup; + } + SymmetricKey* content_key = *content_key_ptr; + + content_key->cipher_mode = key_object.cipher_mode; + content_key->is_even_key = is_even; + memcpy(content_key->key_id, message + key_object.content_key_id.offset, + key_object.content_key_id.length); + content_key->key_id_size = key_object.content_key_id.length; + content_key->session_key_index = entitled_content_key_index; + content_key->is_entitled_content_key = true; + + /* Associate the new content key with its entitlement key. Fill out + * entitlement key info of the new content key in key session. */ + memcpy(key_session->entitlement_keys[entitled_content_key_index] + .entitlement_key_id, + entitlement_key->key_id, entitlement_key->key_id_size); + key_session->entitlement_keys[entitled_content_key_index] + .entitlement_key_id_size = entitlement_key->key_id_size; + + if (adding_new_content_key) { + key_session->num_entitled_content_keys++; + } + + /* Check key usage before the key is consumed by descrambler. */ + result = + OPKI_CheckKeyControlBlock(&entitlement_key->key_control_block, + /*use_type=*/0, OPK_SECURE_OUTPUT_BUFFER); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = WTPI_K1_AESDecryptAndCreateKeyHandle( + entitlement_key->key_handle, + message + key_object.content_key_data.offset, + key_object.content_key_data.length, + message + key_object.content_key_data_iv.offset, CONTENT_KEY, + &content_key->key_handle); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to decrypt and create content key handle with result %u", + result); + goto cleanup; + } + result = WTPI_InstallContentKey(key_session->key_slot_descriptor, + content_key->key_handle, + content_key->cipher_mode, is_even); + /* No need to keep the content key handle since the key is loaded in key + * slot. */ + WTPI_K1_FreeKeyHandle(content_key->key_handle); + content_key->key_handle = NULL; + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to install entitled content key with result %d", result); + goto cleanup; + } + + uint8_t content_iv[KEY_IV_SIZE] = {0}; + const size_t content_iv_length = key_object.content_iv.length > KEY_IV_SIZE + ? KEY_IV_SIZE + : key_object.content_iv.length; + memcpy(content_iv, message + key_object.content_iv.offset, + content_iv_length); + if (content_key->cipher_mode == OEMCrypto_CipherMode_CBC || + content_key->cipher_mode == OEMCrypto_CipherMode_CTR || + content_key->cipher_mode == OEMCrypto_CipherMode_OFB || + content_key->cipher_mode == OEMCrypto_CipherMode_SCTE) { + result = + WTPI_InstallContentIV(key_session->key_slot_descriptor, + &content_iv[0], content_iv_length, is_even); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to install entitled content IV with result %d", result); + goto cleanup; + } + } + } // for loop over key_array + result = OPKI_UpdatePlaybackTimeAndUsageEntryStatus(session_context); + if (result != OEMCrypto_SUCCESS) goto cleanup; + + result = OPKI_SetStatePostCall(session_context, API_LOADENTITLEDCONTENTKEYS); + +cleanup: + if (result != OEMCrypto_SUCCESS) { + FreeEntitledContentKeys(key_session); + FreeContentAndEntitlementKeys(session_context); + session_context->state = SESSION_INVALID; + } + return result; +} +#else OEMCryptoResult OEMCrypto_LoadCasECMKeys( OEMCrypto_SESSION session UNUSED, const uint8_t* message UNUSED, size_t message_length UNUSED, @@ -3494,6 +3722,7 @@ OEMCryptoResult OEMCrypto_LoadCasECMKeys( const OEMCrypto_EntitledContentKeyObject* odd_key UNUSED) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } +#endif OEMCryptoResult OEMCrypto_ProductionReady(void) { if (g_opk_system_state != SYSTEM_INITIALIZED) { @@ -3601,3 +3830,42 @@ OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void) { } return WTPI_GetWatermarkingSupport(); } + +#ifdef SUPPORT_CAS +OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session, + uint8_t* key_token, + size_t* key_token_length) { + if (g_opk_system_state != SYSTEM_INITIALIZED) { + LOGE("OEMCrypto is not yet initialized"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (OPKI_GetSessionType(key_session) != SESSION_TYPE_ENTITLED_KEY) { + LOGE("Unexpected session type."); + return OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION; + } + OEMCryptoEntitledKeySession* key_session_context = NULL; + OEMCryptoResult result = + OPKI_GetEntitledKeySession(key_session, &key_session_context); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get entitled key session with result: %u, session = %u", + result, key_session); + return result; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_token_length); + const size_t required_length = WTPI_GetKeyTokenSize(); + if (*key_token_length < required_length) { + *key_token_length = required_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + RETURN_INVALID_CONTEXT_IF_NULL(key_token); + *key_token_length = required_length; + return WTPI_GetKeyToken(key_session_context->key_slot_descriptor, key_token, + key_token_length); +} +#else +OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session UNUSED, + uint8_t* key_token UNUSED, + size_t* key_token_length UNUSED) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} +#endif diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index 829a969..46a38b7 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -11,9 +11,9 @@ // values that are conventionally defined to indicate debug/non-debug. #if !defined(OPK_IS_DEBUG) # if !defined(NDEBUG) && defined(_DEBUG) -# define OPK_IS_DEBUG true +# define OPK_IS_DEBUG 1 # else -# define OPK_IS_DEBUG false +# define OPK_IS_DEBUG 0 # endif #endif @@ -31,7 +31,7 @@ // version bumps to v17.1, the first released OPK implementation would be // v17.1.0 #define API_MAJOR_VERSION 17 -#define API_MINOR_VERSION 0 -#define OPK_PATCH_VERSION 2 +#define API_MINOR_VERSION 2 +#define OPK_PATCH_VERSION 0 #endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.c index c0d9036..e451801 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.c @@ -9,6 +9,9 @@ #include "odk_util.h" #include "oemcrypto_check_macros.h" #include "oemcrypto_key_table.h" +#ifdef SUPPORT_CAS +# include "wtpi_cas_interface.h" +#endif OEMCryptoResult OPKI_InitializeEntitledKeySession( OEMCryptoEntitledKeySession* session, OEMCrypto_SESSION key_session_id, @@ -22,7 +25,17 @@ OEMCryptoResult OPKI_InitializeEntitledKeySession( (DecryptHash){ .hash_error = OEMCrypto_SUCCESS, }, +#ifdef SUPPORT_CAS + .key_slot_descriptor = NULL, +#endif }; +#ifdef SUPPORT_CAS + OEMCryptoResult result = WTPI_AllocateKeySlotDescriptor( + key_session_id, &session->key_slot_descriptor); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to allocate key slot descriptor with result: %u", result); + } +#endif return OEMCrypto_SUCCESS; } @@ -35,6 +48,11 @@ OEMCryptoResult OPKI_TerminateEntitledKeySession( OPKI_FreeKeyFromTable(&session->entitled_content_keys[i]); if (result == OEMCrypto_SUCCESS) result = free_key_result; } +#ifdef SUPPORT_CAS + OEMCryptoResult free_key_slot_result = + WTPI_FreeKeySlotDescriptor(session->key_slot_descriptor); + if (result == OEMCrypto_SUCCESS) result = free_key_slot_result; +#endif *session = (OEMCryptoEntitledKeySession){0}; return result; } diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.h index e61462e..d44b94f 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_entitled_key_session.h @@ -35,6 +35,11 @@ typedef struct OEMCryptoEntitledKeySession { /* the OEMCrypto session that this entitled key session is associated with. */ OEMCrypto_SESSION entitlement_session_id; DecryptHash decrypt_hash; +#ifdef SUPPORT_CAS + /* CAS only. Contains info of the key slot associated to this key session. The + * interpretation of key slot descriptor can be vendor-specific. */ + void* key_slot_descriptor; +#endif } OEMCryptoEntitledKeySession; /* Initializes entitled key session |session| with id |key_session_id| and the diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c index 2b8304d..e7b518e 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.c @@ -19,6 +19,9 @@ OEMCryptoResult OPKI_InitializeSymmetricKey(SymmetricKey* key, key->key_size = key_size; memset(&key->key_control_block, 0, sizeof(key->key_control_block)); key->is_entitled_content_key = false; +#ifdef SUPPORT_CAS + key->is_even_key = false; +#endif return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h index 57d3d67..d22c078 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.h @@ -25,6 +25,10 @@ typedef struct SymmetricKey { uint32_t session_key_index; bool is_entitled_content_key; OEMCryptoCipherMode cipher_mode; +#ifdef SUPPORT_CAS + /* Key parity. CAS only. */ + bool is_even_key; +#endif } SymmetricKey; typedef struct AsymmetricKey { diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c index 623a36a..d0153de 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.c @@ -50,7 +50,6 @@ OEMCryptoResult OPK_ParseDestBufferDesc( OEMCryptoResult OPK_CheckOutputBounds(const OPK_OutputBuffer* output_buffer, size_t offset, size_t size) { ABORT_IF_NULL(output_buffer); - ABORT_IF_ZERO(size); ABORT_IF(!OPK_IsOutputBufferValid(output_buffer), "Invalid output buffer."); const size_t max_allowed = WTPI_MaxOutputSizeForDecrypt(); diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.c index 251ed2e..27d2511 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.c @@ -60,4 +60,14 @@ bool OPK_SubOverflowUX(size_t a, size_t b, size_t* c) { return true; } +bool OPK_AddOverflowUintptr(uintptr_t a, uintptr_t b, uintptr_t* c) { + if (UINTPTR_MAX - a >= b) { + if (c) { + *c = a + b; + } + return false; + } + return true; +} + #endif diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.h index ab0b98c..2912678 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.h @@ -48,6 +48,12 @@ NO_IGNORE_RESULT static inline bool OPK_SubOverflowUX(size_t a, size_t b, return __builtin_sub_overflow(a, b, c); } +NO_IGNORE_RESULT static inline bool OPK_AddOverflowUintptr(uintptr_t a, + uintptr_t b, + uintptr_t* c) { + return __builtin_add_overflow(a, b, c); +} + #else /* The builtins are not available, so use our implementations. */ @@ -56,6 +62,8 @@ NO_IGNORE_RESULT bool OPK_SubOverflowU32(uint32_t a, uint32_t b, uint32_t* c); NO_IGNORE_RESULT bool OPK_SubOverflowU64(uint64_t a, uint64_t b, uint64_t* c); NO_IGNORE_RESULT bool OPK_AddOverflowUX(size_t a, size_t b, size_t* c); NO_IGNORE_RESULT bool OPK_SubOverflowUX(size_t a, size_t b, size_t* c); +NO_IGNORE_RESULT bool OPK_AddOverflowUintptr(uintptr_t a, uintptr_t b, + uintptr_t* c); #endif /* __has_builtin(__builtin_add_overflow) || COMPATIBLE_WITH_GCC(5) */ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c index 84545fa..e42f276 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.c @@ -20,7 +20,7 @@ size_t OPKI_SignedHeaderSize(int table_size UNUSED) { return sizeof(SignedSavedUsageHeader); } -size_t OPKI_SignedEntrySize() { return sizeof(SignedSavedUsageEntry); } +size_t OPKI_SignedEntrySize(void) { return sizeof(SignedSavedUsageEntry); } OEMCryptoResult OPKI_PackSignedUsageHeader( uint8_t* buffer, size_t buffer_size, const SignedSavedUsageHeader* header) { diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c index 2f6b46a..59f981b 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.c @@ -637,7 +637,7 @@ OEMCryptoResult OPKI_GenerateCertSignature(OEMCryptoSession* session, } NO_IGNORE_RESULT static OEMCryptoResult CheckStatusOnline( - OEMCryptoSession* session, uint32_t nonce, uint32_t control) { + OEMCryptoSession* session, uint32_t nonce, uint32_t control UNUSED) { if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; if (session->nonce_values.nonce != nonce) { return OEMCrypto_ERROR_INVALID_NONCE; @@ -655,7 +655,7 @@ NO_IGNORE_RESULT static OEMCryptoResult CheckStatusOnline( } NO_IGNORE_RESULT static OEMCryptoResult CheckStatusOffline( - OEMCryptoSession* session, uint32_t nonce, uint32_t control) { + OEMCryptoSession* session, uint32_t nonce, uint32_t control UNUSED) { if (!session) return OEMCrypto_ERROR_UNKNOWN_FAILURE; switch (OPKI_GetUsageEntryStatus(session->session_id)) { default: /* Invalid status. */ @@ -713,6 +713,7 @@ OEMCryptoResult OPKI_InstallKey(OEMCryptoSession* session, SymmetricKey** current_key_ptr; uint32_t current_key_index = 0; SymmetricKeyType key_type; + uint8_t minimum_patch_level = 0; if (session->license_type == OEMCrypto_ContentLicense) { if (key_data_length != KEY_SIZE_128 && key_data_length != KEY_SIZE_256) { /* Generic crypto allows both key sizes. */ @@ -815,9 +816,9 @@ OEMCryptoResult OPKI_InstallKey(OEMCryptoSession* session, result = OEMCrypto_ERROR_UNKNOWN_FAILURE; goto cleanup; } - uint8_t minimum_patch_level = (current_key->key_control_block.control_bits & - CONTROL_SECURITY_PATCH_LEVEL_MASK) >> - CONTROL_SECURITY_PATCH_LEVEL_SHIFT; + minimum_patch_level = (current_key->key_control_block.control_bits & + CONTROL_SECURITY_PATCH_LEVEL_MASK) >> + CONTROL_SECURITY_PATCH_LEVEL_SHIFT; if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) { LOGE( "Security patch level doesn't meet the minimum requirement. Current: " @@ -1093,6 +1094,52 @@ static bool IsHdcpLevelSufficient(OEMCrypto_HDCP_Capability required, return current_priority >= required_priority; } +OEMCryptoResult OPKI_CheckKeyControlBlock(const KeyControlBlock* control, + uint32_t use_type, + OPK_OutputBuffer_Type buffer_type) { + RETURN_INVALID_CONTEXT_IF_NULL(control); + if (use_type && (!(control->control_bits & use_type))) { + /* Could not use this key for the given use type. */ + LOGE("Could not use this key for the given use type: %u", use_type); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (control->control_bits & CONTROL_DATA_PATH_SECURE) { + if (!WTPI_IsClosedPlatform() && + buffer_type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + return OEMCrypto_ERROR_DECRYPT_FAILED; + } + } + const OEMCrypto_HDCP_Capability capability = WTPI_CurrentHDCPCapability(); + if (capability != HDCP_NO_DIGITAL_OUTPUT && + (control->control_bits & CONTROL_HDCP_REQUIRED)) { + /* Check to see if HDCP requirements are satisfied. */ + const uint8_t required_hdcp = + (control->control_bits & CONTROL_HDCP_VERSION_MASK) >> + CONTROL_HDCP_VERSION_SHIFT; + if (!IsHdcpLevelSufficient(required_hdcp, capability) || + capability == HDCP_NONE) { + return OEMCrypto_ERROR_INSUFFICIENT_HDCP; + } + } + /* Disable the analog outputs, if required. */ + if (control->control_bits & CONTROL_DISABLE_ANALOG_OUTPUT) { + if (WTPI_IsAnalogDisplayActive() && !WTPI_DisableAnalogDisplay()) { + LOGE("Analog output could not be disabled"); + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } + /* If CGMS-A is required, either it must be active or analog output must be + disabled. */ + if (control->control_bits & CONTROL_CGMS_MASK) { + if (!WTPI_IsCGMS_AActive() && WTPI_IsAnalogDisplayActive() && + !WTPI_DisableAnalogDisplay()) { + LOGE("CGMS must be active if analog output is active"); + return OEMCrypto_ERROR_ANALOG_OUTPUT; + } + } + return OEMCrypto_SUCCESS; +} + OEMCryptoResult OPKI_CheckCurrentContentKeyUsage( OEMCryptoSession* session, OEMCryptoEntitledKeySession* key_session, uint32_t use_type, OPK_OutputBuffer_Type buffer_type) { @@ -1118,46 +1165,7 @@ OEMCryptoResult OPKI_CheckCurrentContentKeyUsage( result = OPKI_GetKeyControlBlock(current_content_key, session, key_session, &control); if (result != OEMCrypto_SUCCESS) return result; - if (use_type && (!(control.control_bits & use_type))) { - /* Could not use this key for the given use type. */ - LOGE("Could not use this key for the given use type: %u", use_type); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (control.control_bits & CONTROL_DATA_PATH_SECURE) { - if (!WTPI_IsClosedPlatform() && - buffer_type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - } - const OEMCrypto_HDCP_Capability capability = WTPI_CurrentHDCPCapability(); - if (capability != HDCP_NO_DIGITAL_OUTPUT && - (control.control_bits & CONTROL_HDCP_REQUIRED)) { - /* Check to see if HDCP requirements are satisfied. */ - const uint8_t required_hdcp = - (control.control_bits & CONTROL_HDCP_VERSION_MASK) >> - CONTROL_HDCP_VERSION_SHIFT; - if (!IsHdcpLevelSufficient(required_hdcp, capability) || - capability == HDCP_NONE) { - return OEMCrypto_ERROR_INSUFFICIENT_HDCP; - } - } - /* Disable the analog outputs, if required. */ - if (control.control_bits & CONTROL_DISABLE_ANALOG_OUTPUT) { - if (WTPI_IsAnalogDisplayActive() && !WTPI_DisableAnalogDisplay()) { - LOGE("Analog output could not be disabled"); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - } - /* If CGMS-A is required, either it must be active or analog output must be - disabled. */ - if (control.control_bits & CONTROL_CGMS_MASK) { - if (!WTPI_IsCGMS_AActive() && WTPI_IsAnalogDisplayActive() && - !WTPI_DisableAnalogDisplay()) { - LOGE("CGMS must be active if analog output is active"); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - } - return OEMCrypto_SUCCESS; + return OPKI_CheckKeyControlBlock(&control, use_type, buffer_type); } OEMCryptoResult OPKI_UpdatePlaybackTimeAndUsageEntryStatus( @@ -1271,12 +1279,14 @@ NO_IGNORE_RESULT static OEMCryptoResult ComputeDecryptHash( return result; } } - result = WTPI_Crc32Cont_OutputBuffer( - output_buffer, current_offset, subsample_length, - decrypt_hash->current_hash, &decrypt_hash->current_hash); - if (result != OEMCrypto_SUCCESS) { - LOGE("Failed to compute CRC32 with result: %u", result); - return result; + if (subsample_length > 0) { + result = WTPI_Crc32Cont_OutputBuffer( + output_buffer, current_offset, subsample_length, + decrypt_hash->current_hash, &decrypt_hash->current_hash); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to compute CRC32 with result: %u", result); + return result; + } } if (OEMCrypto_LastSubsample & subsample->subsample_flags) { if (decrypt_hash->current_hash != decrypt_hash->given_hash) { diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h index 7f243a6..51cc73c 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.h @@ -305,6 +305,17 @@ NO_IGNORE_RESULT OEMCryptoResult OPKI_GetKeyControlBlock( SymmetricKey* content_key, OEMCryptoSession* session, OEMCryptoEntitledKeySession* key_session, KeyControlBlock* control_block); +/* Checks whether |use_type| and |buffer_type| is allowed by the key control block. Returns OEMCrypto_ERROR_INVALID_CONTEXT if |control| is NULL, or |use_type| is not allowed by the + key control block or if the replay mask is set in the key control block, or + if the license type doesn't match the one in |key_session|. Returns + OEMCrypto_DECRYPT_FAILED if the |buffer_type| is not allowed on the device, + OEMCrypto_ERROR_KEY_EXPIRED if the duration in the key control block has + passed, OEMCrypto_ERROR_INSUFFICIENT_HDCP if the HDCP requirements are not + met, OEMCrypto_ERROR_ANALOG_OUTPUT if the analog display requirements are not + met, and OEMCrypto_SUCCESS otherwise. + Caller retains ownership of |control|. */ +NO_IGNORE_RESULT OEMCryptoResult OPKI_CheckKeyControlBlock(const KeyControlBlock* control, uint32_t use_type, OPK_OutputBuffer_Type buffer_type); + /* Checks whether the current content key selected in the |session|, or the current entitled content key selected in the |key_session| can be used in the operation given by |use_type| and with the given |buffer_type|. diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c index d1535c0..8ac0c2e 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.c @@ -4,32 +4,9 @@ #include "oemcrypto_session_key_table.h" -#include - #include "odk_util.h" #include "wtpi_abort_interface.h" -NO_IGNORE_RESULT static SymmetricKey** get_key_table( - OEMCryptoSession* session, OEMCrypto_LicenseType license_type, - uint32_t* num_keys) { - if (session == NULL || num_keys == NULL) { - return NULL; - } - - switch (license_type) { - case OEMCrypto_ContentLicense: - *num_keys = session->num_content_keys; - return session->content_keys; - case OEMCrypto_EntitlementLicense: - *num_keys = session->num_entitlement_keys; - return session->entitlement_keys; - } - - // Execution can only reach this point if license_type was not a valid member - // of the enumeration. - return NULL; -} - SymmetricKey* OPKI_FindKeyFromTable(OEMCryptoSession* session, bool is_content_key, const uint8_t* key_id, size_t key_id_length) { @@ -41,16 +18,20 @@ SymmetricKey* OPKI_FindKeyFromTable(OEMCryptoSession* session, LOGE("Cannot get entitlement key for content license"); return NULL; } - uint32_t num_keys; - OEMCrypto_LicenseType license_type = - is_content_key ? OEMCrypto_ContentLicense : OEMCrypto_EntitlementLicense; - SymmetricKey** key_table = get_key_table(session, license_type, &num_keys); - for (size_t i = 0; i < num_keys; i++) { - SymmetricKey* key = key_table[i]; - ABORT_IF(key == NULL, "Key at index %zu is NULL", i); - if (key_id_length == key->key_id_size && - crypto_memcmp(key->key_id, key_id, key_id_length) == 0) { - return key; + SymmetricKey** keys = NULL; + uint32_t num_keys = 0; + if (is_content_key) { + keys = session->content_keys; + num_keys = session->num_content_keys; + } else { + keys = session->entitlement_keys; + num_keys = session->num_entitlement_keys; + } + for (uint32_t i = 0; i < num_keys; i++) { + ABORT_IF(keys[i] == NULL, "Key at index %u is NULL", i); + if (key_id_length == keys[i]->key_id_size && + crypto_memcmp(keys[i]->key_id, key_id, key_id_length) == 0) { + return keys[i]; } } return NULL; diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c index 136a1bf..52d8fb0 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.c @@ -11,6 +11,7 @@ #include "odk_endian.h" #include "odk_util.h" #include "oemcrypto_check_macros.h" +#include "oemcrypto_compiler_detection.h" #include "oemcrypto_object_table.h" #include "oemcrypto_serialized_usage_table.h" #include "wtpi_clock_interface_layer1.h" @@ -82,6 +83,17 @@ static UsageTableState g_usage_table_state = USAGE_TABLE_NOT_INITIALIZED; * valid if |g_usage_table_state| is USAGE_TABLE_ACTIVE. */ static UsageTable g_usage_table; +#if __has_attribute(packed) || COMPATIBLE_WITH_GCC(3) || \ + COMPATIBLE_WITH_CLANG(3) +# define PACKED __attribute__((packed)) +#elif defined(_WIN32) +# define PACKED +# pragma pack(push) +# pragma pack(1) +#else +# define PACKED +#endif + /* TODO(b/158720996): figure out a way to avoid __attribute__(packed). */ typedef struct { uint8_t signature[20]; // -- HMAC SHA1 of the rest of the report. @@ -93,7 +105,11 @@ typedef struct { int64_t seconds_since_first_decrypt; // now - time_of_first_decrypt int64_t seconds_since_last_decrypt; // now - time_of_last_decrypt uint8_t pst[]; -} __attribute__((packed)) OEMCrypto_PST_Report; +} PACKED OEMCrypto_PST_Report; + +#if defined(_WIN32) +# pragma pack(pop) +#endif static void ClearTable(void) { g_usage_table.table_size = 0; @@ -141,7 +157,7 @@ NO_IGNORE_RESULT static OEMCryptoResult EncryptAndSignHeader( .buffer_size = sizeof(signed_header.buffer), .buffer = {0}, }; - uint8_t temp_buffer[PADDED_HEADER_BUFFER_SIZE]; + uint8_t temp_buffer[PADDED_HEADER_BUFFER_SIZE] = {0}; OEMCryptoResult result = OPKI_PackUsageHeader(temp_buffer, sizeof(temp_buffer), &header); if (result != OEMCrypto_SUCCESS) return result; @@ -297,7 +313,7 @@ NO_IGNORE_RESULT static OEMCryptoResult EncryptAndSignEntry( .buffer_size = sizeof(signed_entry.buffer), .buffer = {0}, }; - uint8_t temp_buffer[PADDED_ENTRY_BUFFER_SIZE]; + uint8_t temp_buffer[PADDED_ENTRY_BUFFER_SIZE] = {0}; OEMCryptoResult result = OPKI_PackUsageEntry(temp_buffer, sizeof(temp_buffer), entry); if (result != OEMCrypto_SUCCESS) return result; @@ -911,7 +927,7 @@ OEMCryptoResult OPKI_VerfiyUsageEntryPST(OEMCrypto_SESSION session_id, } OEMCryptoResult OPKI_SetUsageEntryMacKeys( - const OEMCrypto_SESSION session_id, + OEMCrypto_SESSION session_id, WTPI_K1_SymmetricKey_Handle mac_key_server, WTPI_K1_SymmetricKey_Handle mac_key_client) { if (g_usage_table_state != USAGE_TABLE_ACTIVE_STATE) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h index d1ec19f..83f8056 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h @@ -138,6 +138,8 @@ OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_SymmetricKey_Handle key_handle, * hash function and places the result in |out_buffer|. |key_handle| is a handle * to the key used in the derivation. |out_buffer| must be >= 20 bytes. * + * Can be called with key handles of length KEY_SIZE_128 and KEY_SIZE_256 + * * Caller retains ownership of all pointers. * * @param[in] key_handle: key handle for the crypto operation @@ -177,6 +179,8 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length, * the hash function and places the result in |out_buffer|. |key_handle| is a * handle to the key used in the derivation. |out_buffer| must be >= 32 bytes. * + * Can be called with key handles of length KEY_SIZE_128 and KEY_SIZE_256 + * * Caller retains ownership of all pointers. * * @param[in] key_handle: key handle for HMAC operation @@ -198,6 +202,8 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key_handle, * |signature| using SHA256 as the hash function. |key_handle| is a handle to * the key used in the derivation. * + * Can be called with key handles of length KEY_SIZE_128 and KEY_SIZE_256 + * * Caller retains ownership of all pointers. * * @param[in] key_handle: key handle for HMAC operation diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h index fe8b9ee..04c6f57 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h @@ -156,6 +156,13 @@ OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length, * the given |padding scheme| and place the result in |signature|. * |key| is a handle to the RSA key used for signing. * + * If |padding_scheme| is kSign_RSASSA_PSS, this function should hash the + * message with SHA1, then sign the result with RSASSA-PSS. + * + * If |padding_scheme| is kSign_PKCS1_Block1, this function should pad the + * message with PKCS1 v1.5 block1, then perform a raw private key RSA operation + * on the result. + * * Caller retains ownership of all pointers. * * @param[in] key: handle with RSA key required to sign @@ -298,6 +305,20 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key, */ OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length); +/** + * Writes the maximum possible size of the boot certificate chain (BCC) in + * provisioning 4.0 to |out_length|. + * + * Caller retains ownership of all pointers. + * + * @param[out] out_length: max size of the BCC + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length); + /** * Generate a pair of RSA or ECC key pair, which will be used in the certificate * signing request as specified in provisioning 4. The output key type must be @@ -363,6 +384,20 @@ OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, uint8_t* signature, size_t* signature_length); +/** + * Writes the maximum possible size of the COSE_SIGN1 format signature generated + * by the device key to |out_length|. + * + * Caller retains ownership of all pointers. + * + * @param[out] out_length: max size of the COSE_SIGN1 format signature + * + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if any of the pointers are NULL + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if there are any other failures + * @retval OEMCrypto_SUCCESS otherwise + */ +OEMCryptoResult WTPI_GetMaxDeviceKeyCoseSign1Size(size_t* out_length); + /// @} #ifdef __cplusplus diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h index 71fdfa1..d7d7078 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_root_of_trust_interface_layer1.h @@ -51,12 +51,16 @@ OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input, size_t length); /** - * Attempt to validate the current keybox loaded. + * Attempt to validate the current keybox loaded. When provisioning 4.0 is + * enabled, this function can be also used to validate the backup keybox if + * the installation of a backup keybox is supported. * * @retval OEMCrypto_SUCCESS success * @retval OEMCrypto_ERROR_BAD_MAGIC if magic field is not "kbox" * @retval OEMCrypto_ERROR_BAD_CRC if computed CRC is not equivalent to stored * CRC + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4.0 is enabled and + * backup keybox is not supported */ OEMCryptoResult WTPI_ValidateKeybox(void); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c index 0fde11a..ece0bc7 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c @@ -10,27 +10,34 @@ #include "dice/cbor_writer.h" #include "dice/config.h" #include "dice/dice.h" -#include "ecc_util.h" #include "oemcrypto_check_macros.h" +#include "wtpi_crypto_asymmetric_interface.h" /****************************************************************************** The following are copied from open-dice library cbor_cert_op.c *******************************************************************************/ -#if DICE_PUBLIC_KEY_SIZE != 32 -# error "Only Ed25519 is supported; 32 bytes needed to store the public key." -#endif -#if DICE_SIGNATURE_SIZE != 64 -# error "Only Ed25519 is supported; 64 bytes needed to store the signature." -#endif +#define DICE_PUBLIC_KEY_SIZE_ED25519 32 +#define DICE_SIGNATURE_SIZE_ED25519 64 + +#define DICE_SIGNATURE_SIZE_P256 64 +#define DICE_PUBLIC_KEY_SIZE_P256 64 // Max size of the COSE_Sign1 protected attributes. #define DICE_MAX_PROTECTED_ATTRIBUTES_SIZE 16 -static DiceResult DiceCoseEncodePublicKey( - void* context_not_used, const uint8_t public_key[DICE_PUBLIC_KEY_SIZE], - size_t buffer_size, uint8_t* buffer, size_t* encoded_size) { - (void)context_not_used; +static DiceResult DiceCoseEncodePublicKeyEd25519(const uint8_t* public_key, + size_t public_key_size, + size_t buffer_size, + uint8_t* buffer, + size_t* encoded_size) { + ABORT_IF_NULL(public_key); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + + if (public_key_size != DICE_PUBLIC_KEY_SIZE_ED25519) { + return kDiceResultInvalidInput; + } // Constants per RFC 8152. const int64_t kCoseKeyKtyLabel = 1; @@ -61,7 +68,7 @@ static DiceResult DiceCoseEncodePublicKey( CborWriteInt(kCoseCrvEd25519, &out); // Add the public key. CborWriteInt(kCoseOkpXLabel, &out); - CborWriteBstr(/*data_size=*/DICE_PUBLIC_KEY_SIZE, public_key, &out); + CborWriteBstr(/*data_size=*/public_key_size, public_key, &out); if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } @@ -69,18 +76,112 @@ static DiceResult DiceCoseEncodePublicKey( return kDiceResultOk; } +static DiceResult DiceCoseEncodePublicKeyECDSA(const uint8_t* public_key, + size_t public_key_size, + size_t buffer_size, + uint8_t* buffer, + size_t* encoded_size) { + ABORT_IF_NULL(public_key); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + + if (public_key_size != DICE_PUBLIC_KEY_SIZE_P256) { + return kDiceResultInvalidInput; + } + + // Constants per RFC 8152. + const int64_t kCoseKeyKtyLabel = 1; + const int64_t kCoseKeyAlgLabel = 3; + const int64_t kCoseKeyOpsLabel = 4; + const int64_t kCoseEc2CrvLabel = -1; + const int64_t kCoseEc2XLabel = -2; + const int64_t kCoseEc2YLabel = -3; + const int64_t kCoseKeyTypeEc2 = 2; + const int64_t kCoseAlgES256 = -7; + const int64_t kCoseKeyOpsVerify = 2; + const int64_t kCoseCrvP256 = 1; + + struct CborOut out; + CborOutInit(buffer, buffer_size, &out); + CborWriteMap(/*num_pairs=*/6, &out); + // Add the key type. + CborWriteInt(kCoseKeyKtyLabel, &out); + CborWriteInt(kCoseKeyTypeEc2, &out); + // Add the algorithm. + CborWriteInt(kCoseKeyAlgLabel, &out); + CborWriteInt(kCoseAlgES256, &out); + // Add the KeyOps. + CborWriteInt(kCoseKeyOpsLabel, &out); + CborWriteArray(/*num_elements=*/1, &out); + CborWriteInt(kCoseKeyOpsVerify, &out); + // Add the curve. + CborWriteInt(kCoseEc2CrvLabel, &out); + CborWriteInt(kCoseCrvP256, &out); + // Add the public key. + CborWriteInt(kCoseEc2XLabel, &out); + CborWriteBstr(/*data_size=*/public_key_size / 2, public_key, &out); + CborWriteInt(kCoseEc2YLabel, &out); + CborWriteBstr(/*data_size=*/public_key_size / 2, + public_key + (public_key_size / 2), &out); + if (CborOutOverflowed(&out)) { + return kDiceResultBufferTooSmall; + } + *encoded_size = CborOutSize(&out); + return kDiceResultOk; +} + +static DiceResult DiceCoseEncodePublicKey(const uint8_t* public_key, + size_t public_key_size, + size_t buffer_size, uint8_t* buffer, + size_t* encoded_size, + AsymmetricKeyType key_type) { + ABORT_IF_NULL(public_key); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + + switch (key_type) { + case PROV40_ED25519_PRIVATE_KEY: + return DiceCoseEncodePublicKeyEd25519(public_key, public_key_size, + buffer_size, buffer, encoded_size); + + case DRM_ECC_PRIVATE_KEY: + return DiceCoseEncodePublicKeyECDSA(public_key, public_key_size, + buffer_size, buffer, encoded_size); + default: + return kDiceResultInvalidInput; + } + return kDiceResultInvalidInput; +} + static DiceResult EncodeProtectedAttributes(size_t buffer_size, uint8_t* buffer, - size_t* encoded_size) { + size_t* encoded_size, + AsymmetricKeyType key_type) { + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + // Constants per RFC 8152. const int64_t kCoseHeaderAlgLabel = 1; const int64_t kCoseAlgEdDSA = -8; + const int64_t kCoseAlgES256 = -7; + + int64_t coseAlg = kCoseAlgEdDSA; + switch (key_type) { + case PROV40_ED25519_PRIVATE_KEY: + coseAlg = kCoseAlgEdDSA; + break; + case DRM_ECC_PRIVATE_KEY: + coseAlg = kCoseAlgES256; + break; + default: + return kDiceResultInvalidInput; + } struct CborOut out; CborOutInit(buffer, buffer_size, &out); CborWriteMap(/*num_pairs=*/1, &out); // Add the algorithm. CborWriteInt(kCoseHeaderAlgLabel, &out); - CborWriteInt(kCoseAlgEdDSA, &out); + CborWriteInt(coseAlg, &out); if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } @@ -94,6 +195,12 @@ static DiceResult EncodeCoseTbs(const uint8_t* protected_attributes, const uint8_t* aad, size_t aad_size, size_t buffer_size, uint8_t* buffer, size_t* encoded_size) { + ABORT_IF_NULL(protected_attributes); + ABORT_IF_NULL(payload); + ABORT_IF_NULL(buffer); + ABORT_IF_NULL(encoded_size); + // aad is specifically allowed to be null + struct CborOut out; CborOutInit(buffer, buffer_size, &out); // TBS is an array of four elements. @@ -116,9 +223,14 @@ static DiceResult EncodeCoseTbs(const uint8_t* protected_attributes, static DiceResult EncodeCoseSign1(const uint8_t* protected_attributes, size_t protected_attributes_size, const uint8_t* payload, size_t payload_size, - const uint8_t signature[DICE_SIGNATURE_SIZE], - size_t buffer_size, uint8_t* buffer, - size_t* encoded_size) { + const uint8_t* signature, + size_t signature_size, size_t buffer_size, + uint8_t* buffer, size_t* encoded_size) { + if (signature_size != DICE_SIGNATURE_SIZE_ED25519 || + signature_size != DICE_SIGNATURE_SIZE_P256) { + return kDiceResultInvalidInput; + } + struct CborOut out; CborOutInit(buffer, buffer_size, &out); // COSE_Sign1 is an array of four elements. @@ -130,26 +242,26 @@ static DiceResult EncodeCoseSign1(const uint8_t* protected_attributes, // Payload. CborWriteBstr(payload_size, payload, &out); // Signature. - CborWriteBstr(/*num_elements=*/DICE_SIGNATURE_SIZE, signature, &out); + CborWriteBstr(/*num_elements=*/signature_size, signature, &out); if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } *encoded_size = CborOutSize(&out); return kDiceResultOk; } -/****************************************************************************** - The codes above are copied from open-dice library cbor_cert_op.c -*******************************************************************************/ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, size_t payload_size, - const uint8_t* ed25519_key, + AsymmetricKeyType key_type, + WTPI_AsymmetricKey_Handle key, size_t buffer_size, uint8_t* buffer, size_t* encoded_size) { - if (payload == NULL || payload_size == 0 || ed25519_key == NULL || - buffer_size == 0 || buffer == NULL || encoded_size == NULL) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } + RETURN_INVALID_CONTEXT_IF_NULL(payload); + RETURN_INVALID_CONTEXT_IF_ZERO(payload_size); + RETURN_INVALID_CONTEXT_IF_NULL(key); + RETURN_INVALID_CONTEXT_IF_ZERO(buffer_size); + RETURN_INVALID_CONTEXT_IF_NULL(buffer); + RETURN_INVALID_CONTEXT_IF_NULL(encoded_size); *encoded_size = 0; // The encoded protected attributes are used in the TBS and the final @@ -158,7 +270,7 @@ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, size_t protected_attributes_size = 0; DiceResult dice_result = EncodeProtectedAttributes( sizeof(protected_attributes), protected_attributes, - &protected_attributes_size); + &protected_attributes_size, key_type); if (dice_result != kDiceResultOk) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -173,18 +285,18 @@ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, } // Sign the TBS with the authority key. - uint8_t signature[DICE_SIGNATURE_SIZE]; + uint8_t signature[DICE_SIGNATURE_SIZE_P256]; // P256 is largest supported so size_t signature_length = sizeof(signature); - OEMCryptoResult result = ED25519Sign(ed25519_key, buffer, *encoded_size, - signature, &signature_length); + OEMCryptoResult result = CoseSignOp(key, key_type, buffer, *encoded_size, + signature, &signature_length); if (result != OEMCrypto_SUCCESS) { return result; } // The final certificate is an untagged COSE_Sign1 structure. - dice_result = EncodeCoseSign1(protected_attributes, protected_attributes_size, - payload, payload_size, signature, buffer_size, - buffer, encoded_size); + dice_result = EncodeCoseSign1( + protected_attributes, protected_attributes_size, payload, payload_size, + signature, signature_length, buffer_size, buffer, encoded_size); if (dice_result != kDiceResultOk) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -221,26 +333,43 @@ static OEMCryptoResult GenerateEncodedBccPayload( } // The minimum buffer length required to hold the generated BCC. The generated -// BCC should have a fixed size in phase 1. In this implementation, it happens -// to be 180 bytes. -#define BCC_TOTAL_LENGTH 180 +// BCC should have a fixed size in phase 1. +#define BCC_TOTAL_LENGTH_ED25519 180 +#define BCC_TOTAL_LENGTH_P256 250 + +#if BCC_TOTAL_LENGTH_ED25519 >= BCC_TOTAL_LENGTH_P256 +# define BCC_MAX_LENGTH BCC_TOTAL_LENGTH_ED25519 +#else +# define BCC_MAX_LENGTH BCC_TOTAL_LENGTH_P256 +#endif OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, size_t public_key_length, AsymmetricKeyType key_type, - const uint8_t* ed25519_key, + WTPI_AsymmetricKey_Handle key, uint8_t* out, size_t* out_length) { - if (public_key == NULL || out_length == NULL || ed25519_key == NULL) { + if (public_key == NULL || out_length == NULL || key == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (out == NULL || *out_length < BCC_TOTAL_LENGTH) { - *out_length = BCC_TOTAL_LENGTH; - return OEMCrypto_ERROR_SHORT_BUFFER; + + size_t required_buffer_length = BCC_MAX_LENGTH; + // Can only support ED25519 and ECDSA P256 + switch (key_type) { + case PROV40_ED25519_PRIVATE_KEY: + if (public_key_length != DICE_PUBLIC_KEY_SIZE_ED25519) + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + break; + case DRM_ECC_PRIVATE_KEY: + if (public_key_length != DICE_PUBLIC_KEY_SIZE_P256) + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + break; + default: + return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - // Can only support ED25519 key. - if (key_type != PROV40_ED25519_PRIVATE_KEY || - public_key_length != DICE_PUBLIC_KEY_SIZE) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + + if (out == NULL || *out_length < required_buffer_length) { + *out_length = required_buffer_length; + return OEMCrypto_ERROR_SHORT_BUFFER; } // Bcc = [ @@ -261,8 +390,8 @@ OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, const uint8_t* encoded_public_key = out + out_cursor; size_t encoded_public_key_size = 0; DiceResult dice_result = DiceCoseEncodePublicKey( - /*context_not_used=*/NULL, public_key, *out_length - out_cursor, - out + out_cursor, &encoded_public_key_size); + public_key, public_key_length, *out_length - out_cursor, out + out_cursor, + &encoded_public_key_size, key_type); if (dice_result != kDiceResultOk) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -270,7 +399,7 @@ OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, // Encode second entry in the array which is a COSE_Sign1. // The payload can not exceed total length. - uint8_t bcc_payload[BCC_TOTAL_LENGTH]; + uint8_t bcc_payload[BCC_MAX_LENGTH]; size_t bcc_payload_size = sizeof(bcc_payload); OEMCryptoResult result = GenerateEncodedBccPayload(encoded_public_key, encoded_public_key_size, @@ -279,7 +408,7 @@ OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, size_t encoded_cose_sign1_size = 0; result = DiceCoseSignAndEncodeSign1( - bcc_payload, bcc_payload_size, ed25519_key, *out_length - out_cursor, + bcc_payload, bcc_payload_size, key_type, key, *out_length - out_cursor, out + out_cursor, &encoded_cose_sign1_size); if (result != OEMCrypto_SUCCESS) return result; out_cursor += encoded_cose_sign1_size; diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h index d573abe..258b71f 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.h @@ -7,16 +7,18 @@ #include "OEMCryptoCENCCommon.h" #include "oemcrypto_key_types.h" +#include "wtpi_crypto_asymmetric_interface.h" /** - * Generate a COSE_SIGN1 format signature of |payload| with |ed25519_key| and - * wirte the signature to |buffer|. Only ED25519 key is currently supported. + * Generate a COSE_SIGN1 format signature of |payload| with |key| and + * wirte the signature to |buffer|. + * * Caller retains ownership of all pointers and they must not be NULL. - * |ed25519_key| is expected to be size ED25519_PRIVATE_KEY_LEN. */ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, size_t payload_size, - const uint8_t* ed25519_key, + AsymmetricKeyType key_type, + WTPI_AsymmetricKey_Handle key, size_t buffer_size, uint8_t* buffer, size_t* encoded_size); @@ -30,8 +32,9 @@ OEMCryptoResult DiceCoseSignAndEncodeSign1(const uint8_t* payload, OEMCryptoResult BuildBootCertificateChain(const uint8_t* public_key, size_t public_key_length, AsymmetricKeyType key_type, - const uint8_t* ed25519_key, + WTPI_AsymmetricKey_Handle key, uint8_t* out, size_t* out_length); + /** * Parse the input BCC and retrieve the encoded device public key (COSE_key). */ @@ -39,4 +42,13 @@ OEMCryptoResult GetDevicePublicKeyFromBcc(const uint8_t* bcc, size_t bcc_length, uint8_t* dk_pub, size_t* dk_pub_length); +/** + * Sign |message| with |key| and place the result in |signature|. Update + * |signature_length| to reflect the bytes written to |signature|. + */ +OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, + AsymmetricKeyType key_type, const uint8_t* message, + size_t message_size, uint8_t* signature, + size_t* signature_length); + #endif /* OEMCRYPTO_TA_COSE_UTIL_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c index 4169d2c..59dcdce 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c @@ -13,6 +13,7 @@ #include "oemcrypto_wall_clock.h" #include "wtpi_clock_interface_layer2.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_generation_number_interface.h" #include "wtpi_logging_interface.h" #include "wtpi_persistent_storage.h" @@ -56,23 +57,21 @@ static OEMCryptoResult InitializeDelta(void) { wall_clock > gSavedWallClock) { uint64_t sleep_time = wall_clock - gSavedWallClock; gLastTime += sleep_time; - LOGD("Init clock from sleep time = %" PRIu64 " = %" PRIu64 " - %" PRIu64, - sleep_time, wall_clock, gSavedWallClock); } // After that onetime increment, we should advance the clock in sync with the // hardware clock. Here we compute the delta between our system clock and the // hardware clock. gClockDelta = gLastTime - hw_timer; - LOGD("Init clock with new delta: %" PRId64 " = %" PRIu64 " - %" PRIu64, - gClockDelta, gLastTime, hw_timer); return OEMCrypto_SUCCESS; } static OEMCryptoResult InitializeData(void) { - gInitialized = true; size_t data_length = PERSISTENT_DATA_SIZE; uint8_t buffer[PERSISTENT_DATA_SIZE]; OEMCryptoResult status = WTPI_LoadPersistentData(buffer, &data_length); + if (status != OEMCrypto_SUCCESS && status != OPK_ERROR_NO_PERSISTENT_DATA) { + return status; + } uint8_t version_number = buffer[0]; if (status == OPK_ERROR_NO_PERSISTENT_DATA || data_length != PERSISTENT_DATA_SIZE || @@ -80,15 +79,22 @@ static OEMCryptoResult InitializeData(void) { // Note: In the future, we may wish to handle older version numbers. // This is the first initialization. Start the generation number at random // value and the clock at 0. + LOGD("New random generation number."); status = WTPI_C1_RandomBytes((uint8_t*)(&gSavedGenerationNumber), sizeof(uint64_t)); - LOGD("New random generation number."); if (status != OEMCrypto_SUCCESS) return status; gClockDelta = 0; gLastSaveTime = 0; status = WTPI_GetSecureTimer(&gLastTime); - LOGD("Initializing new clock delta = 0, last = %" PRIu64, gLastTime); - return status; + if (status != OEMCrypto_SUCCESS) return status; + // Some duration logic assumes a clock value of 0 can never happen, so let's + // pick a minimum clock value. + const uint64_t kMinimumClock = 10; + if (gLastTime < kMinimumClock) { + gLastTime += kMinimumClock; + gClockDelta += kMinimumClock; + gLastSaveTime += kMinimumClock; + } } else { WTPI_PersistentData data; memcpy(&data, buffer + 1, sizeof(data)); @@ -97,12 +103,10 @@ static OEMCryptoResult InitializeData(void) { gSavedWallClock = data.previous_wall_clock; gLastSaveTime = gLastTime; status = InitializeDelta(); - LOGD("Loading saved generation: %" PRIu64, gSavedGenerationNumber); - LOGD("Initializing clock w/last = %" PRIu64 ", last wall = %" PRIu64 - ", delta = %" PRId64, - gLastTime, gSavedWallClock, gClockDelta); - return status; + if (status != OEMCrypto_SUCCESS) return status; } + gInitialized = true; + return OEMCrypto_SUCCESS; } static OEMCryptoResult SaveData(void) { @@ -117,10 +121,7 @@ static OEMCryptoResult SaveData(void) { wall_clock > EARLIEST_REASONABLE_TIME ? wall_clock : gSavedWallClock; data.previous_trusted_time = gLastTime; data.generation_number = gSavedGenerationNumber; - LOGD("Store generation number = %" PRIu64, gSavedGenerationNumber); gLastSaveTime = gLastTime; - LOGD("Saving wall clock = %" PRIu64 ", system time = %" PRId64 ".", - data.previous_wall_clock, data.previous_trusted_time); size_t data_length = PERSISTENT_DATA_SIZE; uint8_t buffer[PERSISTENT_DATA_SIZE]; buffer[0] = PERSISTENT_FORMAT_VERSION_NUMBER; @@ -136,7 +137,6 @@ OEMCryptoResult WTPI_PrepareGenerationNumber(void) { } OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) { - LOGD("Load generation number."); if (!gInitialized) { OEMCryptoResult status = InitializeData(); if (status != OEMCrypto_SUCCESS) return status; @@ -147,7 +147,6 @@ OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) { } OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) { - LOGD("Save generation number."); if (!gInitialized) { // This is only done in the tests. In real life, we attempt to load the old // GN before we ever save a new one. @@ -162,7 +161,6 @@ OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) { The following implement the clock interface. *******************************************************************************/ OEMCryptoResult WTPI_InitializeClock(void) { - LOGD("Initialize clock."); gInitialized = false; gLastTime = 0; gSavedWallClock = EARLIEST_REASONABLE_TIME; @@ -172,7 +170,6 @@ OEMCryptoResult WTPI_InitializeClock(void) { } OEMCryptoResult WTPI_TerminateClock(void) { - LOGD("Terminate clock."); if (!gInitialized) return OEMCrypto_SUCCESS; return SaveData(); } @@ -183,12 +180,12 @@ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { RETURN_INVALID_CONTEXT_IF_NULL(time_in_s); OEMCryptoResult status = OEMCrypto_SUCCESS; if (!gInitialized) { - LOGD("Clock needs to initialize."); status = InitializeData(); if (status != OEMCrypto_SUCCESS) return status; } uint64_t hw_timer = 0; status = WTPI_GetSecureTimer(&hw_timer); + if (status != OEMCrypto_SUCCESS) return status; uint64_t now = hw_timer + gClockDelta; // If the hardware clock goes backwards, or the clock delta has not been // initialized by the saved wall clock, then now might be less than the last @@ -205,9 +202,8 @@ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { } *time_in_s = now; if (now > gLastSaveTime + PERIODIC_SAVE_TIME) { - LOGD("Periodic clock save. now = %" PRIu64 ", last save = %" PRIu64, now, - gLastSaveTime); - SaveData(); + status = SaveData(); + if (status != OEMCrypto_SUCCESS) return status; } - return status; + return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h index 343a779..b67c29a 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_config_macros.h @@ -51,6 +51,9 @@ verification information to the key. */ #define MAX_WRAPPED_ASYMMETRIC_KEY_SIZE \ (PKCS8_DRM_KEY_MAX_SIZE + ENCRYPT_AND_SIGN_EXTRA) +/** Maximum size of the signature generated by an asymmetric key (ECC or RSA). + */ +#define MAX_ASYMMETRIC_SIGNATURE_SIZE 1024 /// @} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c index cd15399..df8f3e7 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c @@ -10,6 +10,7 @@ #include "OEMCryptoCENCCommon.h" #include "key_mapping_interface.h" +#include "oemcrypto_check_macros.h" #include "oemcrypto_compiler_attributes.h" #include "oemcrypto_object_table.h" #include "oemcrypto_overflow.h" @@ -132,6 +133,10 @@ static OEMCryptoResult VerifyAndDecryptKey( static bool IsKeyValid(uint32_t index) { WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, index); + if (key == NULL) { + LOGE("Key at index %u is null", index); + return false; + } switch (key->key_type) { case CONTENT_KEY: // We cheat a little here. We also call generic crypto keys "content @@ -163,6 +168,7 @@ static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle, } WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, key_handle->index); + ABORT_IF_NULL(key); *type = key->key_type; return OEMCrypto_SUCCESS; } @@ -177,6 +183,7 @@ OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle, } WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, key_handle->index); + ABORT_IF_NULL(key); *size = key->key_size; return OEMCrypto_SUCCESS; } @@ -203,6 +210,7 @@ WTPI_K2_SymmetricKey_Handle KM_LookupKeyHandle( WTPI_K2_SymmetricKey_Handle k2_key_handle = NULL; uint32_t k1_index = k1_key_handle->index; WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, k1_index); + ABORT_IF_NULL(key); if (key->is_loaded) { uint32_t k2_index = key->index_loaded; k2_key_handle = gHandlePairTable[k2_index].k2_key_handle; @@ -236,6 +244,7 @@ OEMCryptoResult KM_PairKeyHandle(WTPI_K1_SymmetricKey_Handle k1_key_handle, if (result != OEMCrypto_SUCCESS) return result; WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, k1_key_handle->index); + ABORT_IF_NULL(key); key->is_loaded = true; key->index_loaded = k2_index; gHandlePairTable[k2_index].k2_key_handle = k2_key_handle; @@ -250,6 +259,7 @@ static void UnpairKeyHandle(uint32_t k2_index) { if (IsKeyHandleValid(k1_key_handle)) { WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, k1_key_handle->index); + ABORT_IF_NULL(key); key->is_loaded = false; key->index_loaded = MAX_NUMBER_OF_LAYER2_KEY_TABLE_ENTRIES; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c index 12b5bf3..7af7bac 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c @@ -10,6 +10,8 @@ #include "OEMCryptoCENCCommon.h" #include "crypto_util.h" +#include "odk_util.h" +#include "oemcrypto_check_macros.h" #include "oemcrypto_compiler_attributes.h" #include "oemcrypto_object_table.h" #include "oemcrypto_overflow.h" @@ -79,6 +81,7 @@ static bool IsKeyValid(uint32_t index) { case DERIVING_KEY: return key->key_size == KEY_SIZE_128 || key->key_size == KEY_SIZE_256; } + return false; } static bool IsKeyHandleValid(WTPI_K1_SymmetricKey_Handle key_handle) { @@ -107,6 +110,7 @@ static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle, } WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, key_handle->index); + ABORT_IF_NULL(key); *type = key->key_type; return OEMCrypto_SUCCESS; } @@ -191,7 +195,7 @@ static OEMCryptoResult VerifyAndDecryptKey( ABORT_IF(out_key == NULL, "Parameters are NULL or 0"); WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, key_handle->index); - if (key == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + ABORT_IF_NULL(key); ABORT_IF(out_size < (size_t)(key->key_size), "Invalid output buffer size"); const uint8_t* wrapped_data = (const uint8_t*)(&key->key_data); @@ -213,8 +217,8 @@ static OEMCryptoResult VerifyAndDecryptKey( sizeof(signing_key), computed_signature)) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (memcmp(wrapped->signature, computed_signature, SHA256_DIGEST_LENGTH) != - 0) { + if (crypto_memcmp(wrapped->signature, computed_signature, + SHA256_DIGEST_LENGTH) != 0) { return OEMCrypto_ERROR_SIGNATURE_FAILURE; } @@ -256,6 +260,7 @@ OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle, } WTPI_K1_SymmetricKey* key = OPKI_GetFromObjectTable(&key_table, key_handle->index); + ABORT_IF_NULL(key); *size = key->key_size; return OEMCrypto_SUCCESS; } @@ -401,7 +406,7 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify( OEMCryptoResult result = WTPI_C1_HMAC_SHA256( key_handle, message, message_length, computed_signature); if (result != OEMCrypto_SUCCESS) return result; - if (memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) { + if (crypto_memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) { return OEMCrypto_ERROR_SIGNATURE_FAILURE; } return OEMCrypto_SUCCESS; @@ -661,3 +666,19 @@ OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) { if (RAND_bytes(out, size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_SUCCESS; } + +OEMCryptoResult WTPI_K1_CopyKeyHandle(WTPI_K1_SymmetricKey_Handle key, + WTPI_K1_SymmetricKey_Handle* out) { + if (!IsKeyHandleValid(key)) return OEMCrypto_ERROR_INVALID_CONTEXT; + OEMCryptoResult result = PrepareCachedKey(key); + if (result != OEMCrypto_SUCCESS) return result; + SymmetricKeyType type; + result = GetKeyType(key, &type); + if (result != OEMCrypto_SUCCESS) return result; + KeySize key_size; + result = WTPI_K1_GetKeySize(key, &key_size); + if (result != OEMCrypto_SUCCESS) return result; + return WTPI_K1_CreateKeyHandle(key->cached_key, key_size, type, + out); + +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c index 1937cc6..d6ec4dc 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c @@ -25,6 +25,9 @@ #include "wtpi_device_key_interface.h" #include "wtpi_logging_interface.h" +#define MAX_BCC_PAYLOAD_SIZE 2048 +#define MAX_COSE_SIGN1_SIZE 2048 + typedef struct tee_asymmetric_key_handle { AsymmetricKeyType key_type; RSA* rsa_key; @@ -394,12 +397,19 @@ OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { } result = BuildBootCertificateChain(public_key, public_key_length, key_type, - private_key_handle->ed25519_key, out, - out_length); + private_key_handle, out, out_length); WTPI_FreeAsymmetricKeyHandle(private_key_handle); return result; } +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = MAX_BCC_PAYLOAD_SIZE; + return OEMCrypto_SUCCESS; +} + OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, uint8_t* public_key, @@ -467,7 +477,7 @@ OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, if (message_length > 500) { return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } - const size_t kRequiredSignatureBufferSize = 1024; + const size_t kRequiredSignatureBufferSize = MAX_COSE_SIGN1_SIZE; if (signature == NULL || *signature_length < kRequiredSignatureBufferSize) { *signature_length = kRequiredSignatureBufferSize; return OEMCrypto_ERROR_SHORT_BUFFER; @@ -488,12 +498,29 @@ OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, } size_t encoded_size = 0; - result = DiceCoseSignAndEncodeSign1( - message, message_length, private_key_handle->ed25519_key, - *signature_length, signature, &encoded_size); + result = DiceCoseSignAndEncodeSign1(message, message_length, key_type, + private_key_handle, *signature_length, + signature, &encoded_size); WTPI_FreeAsymmetricKeyHandle(private_key_handle); if (result != OEMCrypto_SUCCESS) return result; *signature_length = encoded_size; return OEMCrypto_SUCCESS; } + +OEMCryptoResult WTPI_GetMaxDeviceKeyCoseSign1Size(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = MAX_COSE_SIGN1_SIZE; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, + AsymmetricKeyType key_type, const uint8_t* message, + size_t message_size, uint8_t* signature, + size_t* signature_length) { + (void)key_type; + return ED25519Sign(key->ed25519_key, message, message_size, signature, + signature_length); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.c index 1ce44a9..62b1143 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.c @@ -27,8 +27,9 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptToOutputBuffer_CBC( const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, size_t cipher_data_length, const OPK_OutputBuffer* output_buffer, size_t output_offset) { + if (cipher_data_length == 0) return OEMCrypto_SUCCESS; if (key_handle == NULL || initial_iv == NULL || pattern == NULL || - cipher_data == NULL || cipher_data_length == 0 || output_buffer == NULL) { + cipher_data == NULL || output_buffer == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } OEMCryptoResult result = @@ -94,9 +95,10 @@ NO_IGNORE_RESULT static OEMCryptoResult DecryptToOutputBuffer_CTR( WTPI_K1_SymmetricKey_Handle key_handle, const uint8_t* initial_iv, size_t block_offset, const uint8_t* cipher_data, size_t cipher_data_length, const OPK_OutputBuffer* output_buffer, size_t output_offset) { + if (cipher_data_length == 0) return OEMCrypto_SUCCESS; if (key_handle == NULL || initial_iv == NULL || block_offset >= AES_BLOCK_SIZE || cipher_data == NULL || - cipher_data_length == 0 || output_buffer == NULL) { + output_buffer == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } OEMCryptoResult result = @@ -231,6 +233,7 @@ OEMCryptoResult WTPI_DecryptSample( subsample->num_bytes_encrypted, &subsample_length)) { return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (subsample_length == 0) continue; size_t current_offset; if (OPK_AddOverflowUX(starting_output_offset, offset, ¤t_offset)) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c index a774bf4..79ae974 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c @@ -171,10 +171,9 @@ OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, const uint8_t* data, return VerifyAndDecrypt_V1(context, data, data_size, out, out_size); } -OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy(const uint8_t* wrapped, - size_t wrapped_size, - const uint8_t* signature, - const uint8_t* iv, - uint8_t* out) { +OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy( + const uint8_t* wrapped UNUSED, size_t wrapped_size UNUSED, + const uint8_t* signature UNUSED, const uint8_t* iv UNUSED, + uint8_t* out UNUSED) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c index 5e57bcf..732e22c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_idle.c @@ -2,10 +2,11 @@ source code may only be used and distributed under the Widevine License Agreement. */ +#include "odk_attributes.h" #include "wtpi_idle_interface.h" -OEMCryptoResult WTPI_Idle(OEMCrypto_IdleState state, - uint32_t os_specific_code) { +OEMCryptoResult WTPI_Idle(OEMCrypto_IdleState state UNUSED, + uint32_t os_specific_code UNUSED) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp index 54ff484..239daea 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp @@ -21,15 +21,6 @@ ], }, 'targets': [ - { - 'target_name': 'oemcrypto_ta_reference_cose_util', - 'sources': [ - 'cose_util.c', - ], - 'dependencies': [ - '../../../../third_party/open-dice.gyp:cbor', - ], - }, { 'target_name': 'oemcrypto_ta_reference_root_of_trust', 'sources': [ @@ -43,8 +34,8 @@ ], 'dependencies': [ '../../../odk/src/odk.gyp:odk', + 'oemcrypto_ta_reference_crypto', 'oemcrypto_ta_reference_renewal', - 'oemcrypto_ta_reference_cose_util', '../../../../third_party/open-dice.gyp:cbor', ], }, @@ -91,6 +82,9 @@ 'sources': [ 'wtpi_idle.c', ], + 'include_dirs': [ + '../../../odk/include', + ], }, { 'target_name': 'oemcrypto_ta_reference_crypto', @@ -144,7 +138,6 @@ ], 'dependencies': [ '../../../odk/src/odk.gyp:odk', - 'oemcrypto_ta_reference_cose_util', '../../../../third_party/open-dice.gyp:cbor', ], }, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c index 258056e..97f7a31 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "cose_util.h" @@ -121,6 +122,10 @@ OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input, result = OEMCrypto_ERROR_SHORT_BUFFER; goto cleanup; } + if (input == NULL) { + result = OEMCrypto_ERROR_INVALID_CONTEXT; + goto cleanup; + } // First, try the buffer as if is a clear keybox. memcpy(&gKeybox, input, output_length); result = WTPI_ValidateKeybox(); @@ -136,7 +141,6 @@ OEMCryptoResult WTPI_UnwrapValidateAndInstallKeybox(const uint8_t* input, result = OEMCrypto_ERROR_SHORT_BUFFER; goto cleanup; } - if (result != OEMCrypto_SUCCESS) goto cleanup; // Use the layer above to validate the keybox. result = WTPI_ValidateKeybox(); if (result != OEMCrypto_SUCCESS) goto cleanup; @@ -187,20 +191,44 @@ static OEMCryptoResult GetProv4DeviceID(uint8_t* device_id, return OEMCrypto_ERROR_INVALID_CONTEXT; } + size_t required_bcc_payload_size = 0; + OEMCryptoResult result = + WTPI_GetMaxBootCertificateChainSize(&required_bcc_payload_size); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get max bcc size: %u", result); + return result; + } + // Device ID with provisioning 4 in this reference implementation is hash of // (encoded) device public key from BCC. - uint8_t bcc_buffer[1024]; // Make sure this is large enough to hold BCC. - size_t bcc_size = sizeof(bcc_buffer); - OEMCryptoResult result = WTPI_GetBootCertificateChain(bcc_buffer, &bcc_size); - if (result != OEMCrypto_SUCCESS) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + uint8_t* bcc_buffer = (uint8_t*)malloc(required_bcc_payload_size); + if (bcc_buffer == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + memset(bcc_buffer, 0, required_bcc_payload_size); + size_t bcc_size = required_bcc_payload_size; + result = WTPI_GetBootCertificateChain(bcc_buffer, &bcc_size); + if (result != OEMCrypto_SUCCESS) { + free(bcc_buffer); + return result; + } - uint8_t dk_pub_buffer[1024]; - size_t dk_pub_size = sizeof(dk_pub_buffer); + uint8_t* dk_pub_buffer = (uint8_t*)malloc(required_bcc_payload_size); + if (dk_pub_buffer == NULL) { + free(bcc_buffer); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memset(dk_pub_buffer, 0, required_bcc_payload_size); + size_t dk_pub_size = required_bcc_payload_size; result = GetDevicePublicKeyFromBcc(bcc_buffer, bcc_size, dk_pub_buffer, &dk_pub_size); - if (result != OEMCrypto_SUCCESS) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + free(bcc_buffer); + if (result != OEMCrypto_SUCCESS) { + free(dk_pub_buffer); + return result; + } - return WTPI_C1_SHA256(dk_pub_buffer, dk_pub_size, device_id); + result = WTPI_C1_SHA256(dk_pub_buffer, dk_pub_size, device_id); + free(dk_pub_buffer); + return result; } OEMCryptoResult WTPI_GetDeviceID(uint8_t* device_id, size_t device_id_length) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c index d53728e..ae713f7 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c @@ -6,6 +6,7 @@ #include "common_special_cases.h" #include "log_macros.h" +#include "odk_attributes.h" #include "opk_serialization_base.h" void OPK_Pack_WTPI_K1_SymmetricKey_Handle( @@ -98,9 +99,11 @@ void OPK_Unpack_OPK_OutputBuffer(ODK_Message* message, } void OPK_Pack_OEMCrypto_CENCEncryptPatternDesc( - ODK_Message* message, const OEMCrypto_CENCEncryptPatternDesc* value) {} + ODK_Message* message UNUSED, + const OEMCrypto_CENCEncryptPatternDesc* value UNUSED) {} void OPK_Unpack_OEMCrypto_CENCEncryptPatternDesc( - ODK_Message* message, OEMCrypto_CENCEncryptPatternDesc* value) {} + ODK_Message* message UNUSED, + OEMCrypto_CENCEncryptPatternDesc* value UNUSED) {} void OPK_Pack_SymmetricKeyType(ODK_Message* message, const SymmetricKeyType* value) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp index 2327a08..6d86d0d 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp @@ -5,6 +5,7 @@ #include #include "OEMCryptoCENC.h" +#include "cose_util.h" #include "log.h" #include "oemcrypto_key_types.h" #include "openssl/curve25519.h" @@ -12,6 +13,7 @@ #include "openssl/sha.h" #include "opk_init.h" #include "ssl_util.h" +#include "string_conversions.h" #include "tos_shared_memory_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" @@ -28,6 +30,9 @@ using wtpi_test::MakeEccPublicKey; using wtpi_test::NewEccPrivateKey; using wtpi_test::SerializeEccPrivateKey; using wtpi_test::SerializeEccPublicKey; + +using wtpi_test::ExtractPublicKeyFromBcc; +using wtpi_test::ScopedCbor; // // Pre-define some types to help with key clean up. using WtpiAsymmetircKeyType = @@ -473,156 +478,158 @@ TEST_F(CryptoTest, HMAC_SHA256FailsWithBadInput) { WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(), NULL)); } -TEST_F(CryptoTest, HMAC_SHA256Basic) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +// Values passed to test suites represent indices of hmac_test_cases[] +class HmacTest : public CryptoTest, public testing::WithParamInterface {}; + +// Copied and slightly modified from RFC 4231 +static struct hmac_sha256_test_case { + std::string key; + std::string data; + std::string expected; +} const hmac_sha256_test_cases[] = { + { + // 128-bit key, modified from RFC 4231 test case 2 + .key = "4a656665000000000000000000000000", + .data = "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + .expected = "5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843", + }, + { + // 256-bit key, modified from RFC 4231 test case 1 + .key = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b000000000000000000000" + "000", + .data = "4869205468657265", + .expected = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c" + "2e32cff7", + }, +}; + +// Copied and slightly modified from RFC 2202 +static struct hmac_sha1_test_case { + std::string key; + std::string data; + std::string expected; +} const hmac_sha1_test_cases[] = { + { + // 128-bit key, modified from RFC 2202 test case 1 + .key = "4a656665000000000000000000000000", + .data = "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + .expected = "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + }, + { + // 256-bit key, original test + .key = + "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + .data = "4869205468657265", + .expected = "B5A023B7CAC1A26C9139B9C2136EA3C3FAC5D349", + }, +}; + +INSTANTIATE_TEST_SUITE_P(HmacTests, HmacTest, testing::Values(0, 1)); + +TEST_P(HmacTest, HMAC_SHA256Basic) { + struct hmac_sha256_test_case const* t = &hmac_sha256_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } std::vector output(32, 0); - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(), - output.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA256(key_handle, data.data(), + data.size(), output.data())); - std::vector expected = {232, 73, 155, 228, 241, 152, 13, 104, - 241, 50, 34, 164, 24, 223, 92, 189, - 151, 213, 63, 221, 245, 144, 194, 16, - 142, 34, 212, 0, 5, 183, 7, 19}; - for (int i = 0; i < 32; i++) { - ASSERT_EQ(expected[i], output[i]); - } + EXPECT_EQ(expected, output); } -TEST_F(CryptoTest, HMAC_SHA256_VerifyBasic) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA256_VerifyBasic) { + struct hmac_sha256_test_case const* t = &hmac_sha256_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } - std::vector signature = {232, 73, 155, 228, 241, 152, 13, 104, - 241, 50, 34, 164, 24, 223, 92, 189, - 151, 213, 63, 221, 245, 144, 194, 16, - 142, 34, 212, 0, 5, 183, 7, 19}; - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), 32, - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), data.size(), + expected.data())); - signature[0] = 0xFF; + expected[0] = 0xFF; ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), input.size(), - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), data.size(), + expected.data())); } -TEST_F(CryptoTest, HMAC_SHA256_VerifyFailsWithBadInput) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA256_VerifyFailsWithBadInput) { + struct hmac_sha256_test_case const* t = &hmac_sha256_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } - std::vector signature = {70, 189, 50, 6, 5, 197, 166, 182, - 22, 58, 183, 11, 198, 52, 91, 146, - 165, 249, 8, 231, 159, 229, 137, 121, - 194, 62, 187, 71, 209, 165, 227, 7}; - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(NULL, input.data(), input.size(), - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(NULL, data.data(), data.size(), + expected.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(key_handle, NULL, input.size(), - signature.data())); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), 0, - signature.data())); + WTPI_C1_HMAC_SHA256_Verify(key_handle, NULL, data.size(), + expected.data())); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), 0, expected.data())); ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA256_Verify(key_handle, input.data(), input.size(), NULL)); + WTPI_C1_HMAC_SHA256_Verify(key_handle, data.data(), data.size(), NULL)); } -TEST_F(CryptoTest, HMAC_SHA1Basic) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA1Basic) { + struct hmac_sha1_test_case const* t = &hmac_sha1_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } std::vector output(20, 0); - ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(key_handle, input.data(), - input.size(), output.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(key_handle, data.data(), + data.size(), output.data())); - std::vector expected = {106, 229, 208, 106, 97, 2, 39, - 252, 78, 167, 85, 132, 70, 103, - 130, 238, 157, 20, 201, 141}; - for (int i = 0; i < 20; i++) { - ASSERT_EQ(expected[i], output[i]); - } + ASSERT_EQ(expected, output); } -TEST_F(CryptoTest, HMAC_SHA1FailsWithBadInput) { - std::vector key; - for (int i = 0; i < 32; i++) { - key.push_back(i); - } +TEST_P(HmacTest, HMAC_SHA1FailsWithBadInput) { + struct hmac_sha1_test_case const* t = &hmac_sha1_test_cases[GetParam()]; + std::vector key = wvutil::a2b_hex(t->key); + std::vector data = wvutil::a2b_hex(t->data); + std::vector expected = wvutil::a2b_hex(t->expected); WTPI_K1_SymmetricKey_Handle key_handle; - - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + EXPECT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, &key_handle)); - std::vector input; - for (int i = 0; i < 32; i++) { - input.push_back(i); - } std::vector output(20, 0); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(NULL, input.data(), input.size(), output.data())); + WTPI_C1_HMAC_SHA1(NULL, data.data(), data.size(), output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(key_handle, NULL, input.size(), output.data())); + WTPI_C1_HMAC_SHA1(key_handle, NULL, data.size(), output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(key_handle, input.data(), 0, output.data())); + WTPI_C1_HMAC_SHA1(key_handle, data.data(), 0, output.data())); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_C1_HMAC_SHA1(key_handle, input.data(), input.size(), NULL)); + WTPI_C1_HMAC_SHA1(key_handle, data.data(), data.size(), NULL)); } TEST_F(CryptoTest, CopyToOutputBufferBasicInsecure) { @@ -971,8 +978,8 @@ TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks) { WTPI_K1_CreateKeyHandle(expected_derived_key, KEY_SIZE_256, MAC_KEY_CLIENT, &expected_derived_key_handle)); - // perform an operation with out_key_handle and expected_derived_key_handle to - // prove they are using the same underlying key data + // perform an operation with out_key_handle and expected_derived_key_handle + // to prove they are using the same underlying key data std::vector input; for (int i = 0; i < 32; i++) { input.push_back(i); @@ -992,6 +999,56 @@ TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks) { } } +TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks256BitDerivingKey) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, DERIVING_KEY, + &key_handle)); + + const uint8_t context[4] = {'T', 'E', 'S', 'T'}; + + WTPI_K1_SymmetricKey_Handle out_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_DeriveKeyFromKeyHandle(key_handle, 1, context, + sizeof(context), ENCRYPTION_KEY, + KEY_SIZE_128, &out_key_handle)); + + const uint8_t expected_derived_key[] = {124, 186, 187, 120, 87, 47, + 248, 173, 91, 134, 226, 18, + 145, 223, 106, 64}; + + WTPI_K1_SymmetricKey_Handle expected_derived_key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(expected_derived_key, KEY_SIZE_128, + ENCRYPTION_KEY, &expected_derived_key_handle)); + + // perform an operation with out_key_handle and expected_derived_key_handle + // to prove they are using the same underlying key data + std::vector input; + for (int i = 0; i < 32; i++) { + input.push_back(i); + } + std::vector output1(20, 1); + std::vector output2(20, 2); + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_C1_HMAC_SHA1(out_key_handle, input.data(), + input.size(), output1.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA1(expected_derived_key_handle, input.data(), + input.size(), output2.data())); + + for (int i = 0; i < 20; i++) { + ASSERT_EQ(output1[i], output2[i]); + } +} + TEST_F(CryptoTest, WrapKeyFailsForBadInputs) { std::vector key; for (int i = 0; i < 32; i++) { @@ -1082,10 +1139,10 @@ TEST_F(CryptoTest, WrapAndUnwrapKeyWorks) { } TEST_F(CryptoTest, WrapAsymmetricKeyFailsForBadInputs) { - uint8_t output[4000]; + uint8_t output[4000] = {0}; size_t output_length = 4000; AsymmetricKeyType key_type = DRM_RSA_PRIVATE_KEY; - uint8_t clear_key[256]; + uint8_t clear_key[256] = {0}; size_t clear_key_length = 256; ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, @@ -1233,8 +1290,8 @@ TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleFailsForBadInput) { decrypt_key_handle, enc_key.data(), 7, iv.data(), MAC_KEY_CLIENT, &out_key_handle)); - // TODO(b/205751866): serializer allocates iv array on TEE side regardless if - // REE iv ptr is NULL, so the NULL never propagates to the TEE + // TODO(b/205751866): serializer allocates iv array on TEE side regardless + // if REE iv ptr is NULL, so the NULL never propagates to the TEE // // ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, // WTPI_K1_AESDecryptAndCreateKeyHandle( @@ -1747,33 +1804,115 @@ TEST_F(CryptoTest, ECCDeriveSessionKeyFailsForBadInput) { } TEST_F(CryptoTest, GetBootCertificateChainSuccess) { - const size_t kExpectedBccSize = 180; - std::vector buffer; - buffer.resize(kExpectedBccSize); - size_t buffer_size = buffer.size(); + std::vector buffer(0); + size_t buffer_size = 0; - OEMCryptoResult result = + OEMCryptoResult res = WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); - if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + // TODO: change to use wtpi config + if (res == OEMCrypto_ERROR_NOT_IMPLEMENTED) { GTEST_SKIP() << "BCC not supported"; } - ASSERT_EQ(result, OEMCrypto_SUCCESS); - EXPECT_EQ(buffer_size, kExpectedBccSize); + + EXPECT_EQ(res, OEMCrypto_ERROR_SHORT_BUFFER); + buffer.resize(buffer_size); + + res = WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + + ASSERT_EQ(res, OEMCrypto_SUCCESS); + + // Get public key to validate CoseSign1 signature + ScopedCbor public_key_cbor = + ExtractPublicKeyFromBcc(buffer.data(), buffer_size); + ASSERT_NE(public_key_cbor, nullptr); + + size_t offset = 0; + size_t len = 0; + res = GetCoseSign1OffsetInBcc(buffer.data(), buffer_size, &offset, &len); + ASSERT_EQ(OEMCrypto_SUCCESS, res); + + cose_errback error; + int struct_type = 0; + HCOSE_SIGN1 sign1 = (HCOSE_SIGN1)COSE_Decode( + buffer.data() + offset, len, &struct_type, COSE_sign1_object, &error); + ASSERT_NE(sign1, nullptr); + + bool result = COSE_Sign1_validate(sign1, public_key_cbor.get(), &error); + COSE_Sign1_Free(sign1); + ASSERT_TRUE(result); +} + +TEST_F(CryptoTest, UseBootCertificateChainToValidateCoseSign1) { + std::vector buffer(0); + size_t buffer_size = 0; + + OEMCryptoResult res = + WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + + // TODO: change to use wtpi config + if (res == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + GTEST_SKIP() << "BCC not supported"; + } + + EXPECT_EQ(res, OEMCrypto_ERROR_SHORT_BUFFER); + buffer.resize(buffer_size); + + res = WTPI_GetBootCertificateChain(buffer.data(), &buffer_size); + ASSERT_EQ(res, OEMCrypto_SUCCESS); + + // Validate twice to verify that WTPI_DeviceKeyCoseSign1() is + // deterministically using the same private key to sign, and the BCC pub key + // is still usable to verify + for (int i = 0; i < 2; i++) { + const uint8_t message[3] = {'m', 's', 'g'}; + std::vector cosesign1(0); + size_t cosesign1_len = 0; + ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), + cosesign1.data(), &cosesign1_len), + OEMCrypto_ERROR_SHORT_BUFFER); + cosesign1.resize(cosesign1_len); + ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), + cosesign1.data(), &cosesign1_len), + OEMCrypto_SUCCESS); + + // Get public key to validate CoseSign1 signature + ScopedCbor public_key_cbor = + ExtractPublicKeyFromBcc(buffer.data(), buffer_size); + ASSERT_NE(public_key_cbor, nullptr); + + cose_errback error; + int struct_type = 0; + HCOSE_SIGN1 sign1 = + (HCOSE_SIGN1)COSE_Decode(cosesign1.data(), cosesign1_len, &struct_type, + COSE_sign1_object, &error); + ASSERT_NE(sign1, nullptr); + + bool result = COSE_Sign1_validate(sign1, public_key_cbor.get(), &error); + COSE_Sign1_Free(sign1); + ASSERT_TRUE(result); + } } TEST_F(CryptoTest, GenerateRandomCertificateKeyPairSuccess) { const size_t kBufferSize = 2000; AsymmetricKeyType type; - uint8_t public_key[kBufferSize]; - size_t public_key_length = sizeof(public_key); + std::vector public_key; + size_t public_key_length = 0; uint8_t wrapped_private_key[kBufferSize]; size_t wrapped_private_key_length = sizeof(wrapped_private_key); ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( &type, wrapped_private_key, &wrapped_private_key_length, - public_key, &public_key_length), + public_key.data(), &public_key_length), + OEMCrypto_ERROR_SHORT_BUFFER); + public_key.resize(public_key_length); + + ASSERT_EQ(WTPI_GenerateRandomCertificateKeyPair( + &type, wrapped_private_key, &wrapped_private_key_length, + public_key.data(), &public_key_length), OEMCrypto_SUCCESS); + EXPECT_TRUE(type == DRM_ECC_PRIVATE_KEY || type == DRM_RSA_PRIVATE_KEY); EXPECT_GT(public_key_length, size_t(0)); EXPECT_LT(public_key_length, kBufferSize); @@ -1807,7 +1946,7 @@ TEST_F(CryptoTest, GenerateRandomCertificateKeyPairSuccess) { // Verify with generated public key boringssl_ptr pkey(EVP_PKEY_new()); - const uint8_t* pos = public_key; + const uint8_t* pos = public_key.data(); RSA* decoded_rsa = d2i_RSA_PUBKEY(NULL, &pos, public_key_length); ASSERT_NE(nullptr, decoded_rsa) << "RSA pub key failed to decode"; ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), decoded_rsa)); @@ -1826,7 +1965,7 @@ TEST_F(CryptoTest, GenerateRandomCertificateKeyPairSuccess) { // Verify with generated public key EcKeyPtr ec_pub_key; - const uint8_t* pos = public_key; + const uint8_t* pos = public_key.data(); EC_KEY* decoded_pub_key = d2i_EC_PUBKEY(NULL, &pos, public_key_length); ASSERT_NE(nullptr, decoded_pub_key) << "ECC pub key failed to decode"; ec_pub_key.reset(decoded_pub_key); @@ -1900,10 +2039,62 @@ TEST_F(CryptoTest, GenerateRandomCertificateKeyPairFailsForBadInput) { TEST_F(CryptoTest, WTPI_DeviceKeyCoseSign1Success) { const uint8_t message[3] = {'m', 's', 'g'}; - uint8_t signature_buffer[1024]; - size_t signature_buffer_size = sizeof(signature_buffer); + std::vector signature_buffer(0); + size_t signature_buffer_size = 0; + ASSERT_EQ( + WTPI_DeviceKeyCoseSign1(message, sizeof(message), signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_SHORT_BUFFER); + signature_buffer.resize(signature_buffer_size); + ASSERT_EQ( + WTPI_DeviceKeyCoseSign1(message, sizeof(message), signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_SUCCESS); - ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), signature_buffer, - &signature_buffer_size), - OEMCrypto_SUCCESS); + // Use the COSE-C library to decode and validate as a COSE_sign1 struct + cose_errback error; + int struct_type = 0; + HCOSE_SIGN1 sign1 = + (HCOSE_SIGN1)COSE_Decode(signature_buffer.data(), signature_buffer_size, + &struct_type, COSE_sign1_object, &error); + if (!sign1) { + FAIL() << "COSE_Decode failed"; + } + // Cannot validate signature because we cannot access the public key. + // A separate test uses the BCC to validate WTPI_DeviceKeyCoseSign1() +} + +TEST_F(CryptoTest, WTPI_DeviceKeyCoseSign1FailsForBadInput) { + const uint8_t message[3] = {'m', 's', 'g'}; + std::vector signature_buffer(0); + size_t signature_buffer_size = 0; + + ASSERT_EQ( + WTPI_DeviceKeyCoseSign1(NULL, sizeof(message), signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_INVALID_CONTEXT); + + ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, 0, signature_buffer.data(), + &signature_buffer_size), + OEMCrypto_ERROR_INVALID_CONTEXT); + + ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), NULL, + &signature_buffer_size), + OEMCrypto_ERROR_SHORT_BUFFER); + + ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), + signature_buffer.data(), NULL), + OEMCrypto_ERROR_INVALID_CONTEXT); + + size_t bad_size = 0; + ASSERT_EQ(WTPI_DeviceKeyCoseSign1(message, sizeof(message), + signature_buffer.data(), &bad_size), + OEMCrypto_ERROR_SHORT_BUFFER); + ASSERT_GT(bad_size, size_t(0)); + + size_t bad_message_length = 1500; + ASSERT_EQ( + WTPI_DeviceKeyCoseSign1(message, bad_message_length, + signature_buffer.data(), &signature_buffer_size), + OEMCrypto_ERROR_BUFFER_TOO_LARGE); } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c index 362d118..7a68cc0 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c @@ -35,7 +35,11 @@ OEMCryptoResult WTPI_PrepareGenerationNumber(void) { API_Initialize(); request = OPK_Pack_PrepareGenerationNumber_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -62,7 +66,11 @@ OEMCryptoResult WTPI_LoadGenerationNumber(uint64_t* value) { API_Initialize(); request = OPK_Pack_LoadGenerationNumber_Request(value); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -89,7 +97,11 @@ OEMCryptoResult WTPI_SaveGenerationNumber(uint64_t value) { API_Initialize(); request = OPK_Pack_SaveGenerationNumber_Request(value); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -117,7 +129,11 @@ OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key_handle, API_Initialize(); request = OPK_Pack_K1_GetKeySize_Request(key_handle, size); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -149,7 +165,11 @@ OEMCryptoResult WTPI_C1_AESCBCDecrypt(WTPI_K1_SymmetricKey_Handle key_handle, request = OPK_Pack_C1_AESCBCDecrypt_Request(key_handle, key_length, in_buffer, in_buffer_length, iv, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -181,7 +201,11 @@ OEMCryptoResult WTPI_C1_AESCBCEncrypt(WTPI_K1_SymmetricKey_Handle key_handle, request = OPK_Pack_C1_AESCBCEncrypt_Request(key_handle, in_buffer, in_buffer_length, iv, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -212,7 +236,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key_handle, request = OPK_Pack_C1_HMAC_SHA1_Request(key_handle, input, input_length, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -240,7 +268,11 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* input, size_t input_length, API_Initialize(); request = OPK_Pack_C1_SHA256_Request(input, input_length, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -270,7 +302,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key_handle, request = OPK_Pack_C1_HMAC_SHA256_Request(key_handle, input, input_length, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -300,7 +336,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify( request = OPK_Pack_C1_HMAC_SHA256_Verify_Request(key_handle, input, input_length, signature); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -331,7 +371,11 @@ OEMCryptoResult WTPI_C1_CopyToOutputBuffer(const uint8_t* input, request = OPK_Pack_C1_CopyToOutputBuffer_Request(input, input_length, out, output_offset); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -358,7 +402,11 @@ OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t out_length) { API_Initialize(); request = OPK_Pack_C1_RandomBytes_Request(out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -385,7 +433,11 @@ OEMCryptoResult WTPI_K1_InitializeKeyManagement(void) { API_Initialize(); request = OPK_Pack_K1_InitializeKeyManagement_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -412,7 +464,11 @@ OEMCryptoResult WTPI_K1_TerminateKeyManagement(void) { API_Initialize(); request = OPK_Pack_K1_TerminateKeyManagement_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -442,7 +498,11 @@ OEMCryptoResult WTPI_K1_CreateKeyHandle( request = OPK_Pack_K1_CreateKeyHandle_Request(input, input_length, key_type, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -472,7 +532,11 @@ OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle( request = OPK_Pack_K1_DeriveDeviceKeyIntoHandle_Request( context, out_key_type, out_key_handle, out_key_size); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -505,7 +569,11 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandle( decrypt_key_handle, enc_key, enc_key_length, iv, key_type, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -539,7 +607,11 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( decrypt_key_handle, enc_mac_keys, enc_mac_keys_length, iv, out_mac_key_server, out_mac_key_client); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -573,7 +645,11 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( key_handle, counter, context, context_length, out_key_type, out_key_size, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -605,7 +681,11 @@ OEMCryptoResult WTPI_K1_WrapKey(uint32_t context, request = OPK_Pack_K1_WrapKey_Request(context, key_handle, key_type, wrapped_key, wrapped_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -636,7 +716,11 @@ OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle( request = OPK_Pack_K1_UnwrapIntoKeyHandle_Request( context, wrapped_key, wrapped_key_length, key_type, out_key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -664,7 +748,11 @@ OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) { API_Initialize(); request = OPK_Pack_K1_FreeKeyHandle_Request(key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -694,7 +782,11 @@ OEMCryptoResult WTPI_CreateAsymmetricKeyHandle( request = OPK_Pack_CreateAsymmetricKeyHandle_Request(input, input_length, key_type, key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -725,7 +817,11 @@ OEMCryptoResult WTPI_UnwrapIntoAsymmetricKeyHandle( request = OPK_Pack_UnwrapIntoAsymmetricKeyHandle_Request( input, input_length, key_type, key_handle, allowed_schemes); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -754,7 +850,11 @@ OEMCryptoResult WTPI_FreeAsymmetricKeyHandle( API_Initialize(); request = OPK_Pack_FreeAsymmetricKeyHandle_Request(key_handle); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -784,7 +884,11 @@ OEMCryptoResult WTPI_GetWrappedAsymmetricKeySize(size_t enc_private_key_length, request = OPK_Pack_GetWrappedAsymmetricKeySize_Request(enc_private_key_length, key_type, buffer_size); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -816,7 +920,11 @@ OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length, request = OPK_Pack_WrapAsymmetricKey_Request(output, output_length, key_type, clear_key, clear_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -848,7 +956,11 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, request = OPK_Pack_RSASign_Request(key, message, message_length, signature, signature_length, padding_scheme); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -879,7 +991,11 @@ OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key, request = OPK_Pack_RSADecrypt_Request(key, input, input_length, out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -909,7 +1025,11 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, request = OPK_Pack_ECCSign_Request(key, message, message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -942,7 +1062,11 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, request = OPK_Pack_ECCDeriveSessionKey_Request( key, key_source, key_source_length, session_key, session_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -971,7 +1095,11 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key, API_Initialize(); request = OPK_Pack_GetSignatureSize_Request(key, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -998,7 +1126,11 @@ OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { API_Initialize(); request = OPK_Pack_GetBootCertificateChain_Request(out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1018,6 +1150,38 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_GetMaxBootCertificateChainSize_Request(out_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetMaxBootCertificateChainSize_Response(&response, &result, + &out_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, uint8_t* public_key, @@ -1031,7 +1195,11 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( key_type, wrapped_private_key, wrapped_private_key_length, public_key, public_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1064,7 +1232,11 @@ OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, request = OPK_Pack_DeviceKeyCoseSign1_Request(message, message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1084,6 +1256,38 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_GetMaxDeviceKeyCoseSign1Size(size_t* out_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_GetMaxDeviceKeyCoseSign1Size_Request(out_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetMaxDeviceKeyCoseSign1Size_Response(&response, &result, + &out_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCryptoResult WTPI_Crc32Init(uint32_t* initial_hash) { pthread_mutex_lock(&api_lock); OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1092,7 +1296,11 @@ OEMCryptoResult WTPI_Crc32Init(uint32_t* initial_hash) { API_Initialize(); request = OPK_Pack_Crc32Init_Request(initial_hash); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1120,7 +1328,11 @@ OEMCryptoResult WTPI_Crc32Cont(const uint8_t* in, size_t in_length, API_Initialize(); request = OPK_Pack_Crc32Cont_Request(in, in_length, prev_crc, new_crc); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1151,7 +1363,11 @@ OEMCryptoResult WTPI_Crc32Cont_OutputBuffer(const OPK_OutputBuffer* in, request = OPK_Pack_Crc32Cont_OutputBuffer_Request(in, in_offset, in_length, prev_crc, new_crc); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1178,7 +1394,11 @@ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { API_Initialize(); request = OPK_Pack_GetTrustedTime_Request(time_in_s); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1205,7 +1425,11 @@ OEMCryptoResult WTPI_InitializeClock(void) { API_Initialize(); request = OPK_Pack_InitializeClock_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1232,7 +1456,11 @@ OEMCryptoResult WTPI_TerminateClock(void) { API_Initialize(); request = OPK_Pack_TerminateClock_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1259,7 +1487,11 @@ OEMCrypto_Clock_Security_Level WTPI_GetClockType(void) { API_Initialize(); request = OPK_Pack_GetClockType_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1287,7 +1519,11 @@ OEMCryptoResult WTPI_GetEncryptAndSignSize(uint32_t context, size_t in_length, request = OPK_Pack_GetEncryptAndSignSize_Request(context, in_length, wrapped_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1318,7 +1554,11 @@ OEMCryptoResult WTPI_EncryptAndSign(uint32_t context, const uint8_t* data, request = OPK_Pack_EncryptAndSign_Request(context, data, data_length, out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1348,7 +1588,11 @@ OEMCryptoResult WTPI_VerifyAndDecrypt(uint32_t context, const uint8_t* wrapped, request = OPK_Pack_VerifyAndDecrypt_Request(context, wrapped, wrapped_length, out, out_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1380,7 +1624,11 @@ OEMCryptoResult WTPI_VerifyAndDecryptUsageData_Legacy(const uint8_t* wrapped, request = OPK_Pack_VerifyAndDecryptUsageData_Legacy_Request( wrapped, wrapped_length, signature, iv, out); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c index 7d36e31..41bad6d 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c @@ -1150,11 +1150,43 @@ void OPK_Unpack_GetBootCertificateChain_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Request( + const size_t* out_length) { + uint32_t api_value = 10033; /* from _tee10033 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackIsNull(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetMaxBootCertificateChainSize_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10033) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_size_t(msg, out_length); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Request( const AsymmetricKeyType* key_type, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, const size_t* public_key_length) { - uint32_t api_value = 10033; /* from _tee10033 */ + uint32_t api_value = 10034; /* from _tee10034 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1175,7 +1207,7 @@ void OPK_Unpack_GenerateRandomCertificateKeyPair_Response( uint8_t** public_key, size_t** public_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10033) + if (api_value != 10034) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, wrapped_private_key_length); OPK_UnpackNullable_size_t(msg, public_key_length); @@ -1209,7 +1241,7 @@ void OPK_Unpack_GenerateRandomCertificateKeyPair_Response( ODK_Message OPK_Pack_DeviceKeyCoseSign1_Request( const uint8_t* message, size_t message_length, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10034; /* from _tee10034 */ + uint32_t api_value = 10035; /* from _tee10035 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1230,7 +1262,7 @@ void OPK_Unpack_DeviceKeyCoseSign1_Response(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10034) + if (api_value != 10035) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -1251,8 +1283,40 @@ void OPK_Unpack_DeviceKeyCoseSign1_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_GetMaxDeviceKeyCoseSign1Size_Request( + const size_t* out_length) { + uint32_t api_value = 10036; /* from _tee10036 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackIsNull(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetMaxDeviceKeyCoseSign1Size_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10036) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_size_t(msg, out_length); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash) { - uint32_t api_value = 10035; /* from _tee10035 */ + uint32_t api_value = 10037; /* from _tee10037 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1267,7 +1331,7 @@ void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** initial_hash) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10035) + if (api_value != 10037) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1284,7 +1348,7 @@ void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, ODK_Message OPK_Pack_Crc32Cont_Request(const uint8_t* in, size_t in_length, uint32_t prev_crc, const uint32_t* new_crc) { - uint32_t api_value = 10036; /* from _tee10036 */ + uint32_t api_value = 10038; /* from _tee10038 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1302,7 +1366,7 @@ void OPK_Unpack_Crc32Cont_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10036) + if (api_value != 10038) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1321,7 +1385,7 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Request(const OPK_OutputBuffer* in, size_t in_length, uint32_t prev_crc, const uint32_t* new_crc) { - uint32_t api_value = 10037; /* from _tee10037 */ + uint32_t api_value = 10039; /* from _tee10039 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1352,7 +1416,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10037) + if (api_value != 10039) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1367,7 +1431,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, } ODK_Message OPK_Pack_GetTrustedTime_Request(const uint64_t* time_in_s) { - uint32_t api_value = 10038; /* from _tee10038 */ + uint32_t api_value = 10040; /* from _tee10040 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1383,7 +1447,7 @@ void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, uint64_t** time_in_s) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10038) + if (api_value != 10040) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1398,7 +1462,7 @@ void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, } ODK_Message OPK_Pack_InitializeClock_Request(void) { - uint32_t api_value = 10039; /* from _tee10039 */ + uint32_t api_value = 10041; /* from _tee10041 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1412,7 +1476,7 @@ void OPK_Unpack_InitializeClock_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10039) + if (api_value != 10041) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1426,7 +1490,7 @@ void OPK_Unpack_InitializeClock_Response(ODK_Message* msg, } ODK_Message OPK_Pack_TerminateClock_Request(void) { - uint32_t api_value = 10040; /* from _tee10040 */ + uint32_t api_value = 10042; /* from _tee10042 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1440,7 +1504,7 @@ void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, OEMCryptoResult* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10040) + if (api_value != 10042) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1454,7 +1518,7 @@ void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, } ODK_Message OPK_Pack_GetClockType_Request(void) { - uint32_t api_value = 10041; /* from _tee10041 */ + uint32_t api_value = 10043; /* from _tee10043 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1468,7 +1532,7 @@ void OPK_Unpack_GetClockType_Response(ODK_Message* msg, OEMCrypto_Clock_Security_Level* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10041) + if (api_value != 10043) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_OEMCrypto_Clock_Security_Level(msg, result); OPK_UnpackEOM(msg); @@ -1477,7 +1541,7 @@ void OPK_Unpack_GetClockType_Response(ODK_Message* msg, ODK_Message OPK_Pack_GetEncryptAndSignSize_Request( uint32_t context, size_t in_length, const size_t* wrapped_length) { - uint32_t api_value = 10042; /* from _tee10042 */ + uint32_t api_value = 10044; /* from _tee10044 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1495,7 +1559,7 @@ void OPK_Unpack_GetEncryptAndSignSize_Response(ODK_Message* msg, size_t** wrapped_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10042) + if (api_value != 10044) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1514,7 +1578,7 @@ ODK_Message OPK_Pack_EncryptAndSign_Request(uint32_t context, size_t data_length, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10043; /* from _tee10043 */ + uint32_t api_value = 10045; /* from _tee10045 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1534,7 +1598,7 @@ void OPK_Unpack_EncryptAndSign_Response(ODK_Message* msg, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10043) + if (api_value != 10045) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -1560,7 +1624,7 @@ ODK_Message OPK_Pack_VerifyAndDecrypt_Request(uint32_t context, size_t wrapped_length, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10044; /* from _tee10044 */ + uint32_t api_value = 10046; /* from _tee10046 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1581,7 +1645,7 @@ void OPK_Unpack_VerifyAndDecrypt_Response(ODK_Message* msg, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10044) + if (api_value != 10046) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -1605,7 +1669,7 @@ void OPK_Unpack_VerifyAndDecrypt_Response(ODK_Message* msg, ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Request( const uint8_t* wrapped, size_t wrapped_length, const uint8_t* signature, const uint8_t* iv, const uint8_t* out) { - uint32_t api_value = 10045; /* from _tee10045 */ + uint32_t api_value = 10047; /* from _tee10047 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1625,7 +1689,7 @@ void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Response( ODK_Message* msg, OEMCryptoResult* result, uint8_t** out) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10045) + if (api_value != 10047) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h index b28fc05..423282b 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h @@ -197,6 +197,11 @@ void OPK_Unpack_GetBootCertificateChain_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** out, size_t** out_length); +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Request( + const size_t* out_length); +void OPK_Unpack_GetMaxBootCertificateChainSize_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length); ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Request( const AsymmetricKeyType* key_type, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, @@ -213,6 +218,11 @@ void OPK_Unpack_DeviceKeyCoseSign1_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** signature, size_t** signature_length); +ODK_Message OPK_Pack_GetMaxDeviceKeyCoseSign1Size_Request( + const size_t* out_length); +void OPK_Unpack_GetMaxDeviceKeyCoseSign1Size_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length); ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash); void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** initial_hash); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp index 5df1c6d..8ad229c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree.gyp @@ -10,7 +10,7 @@ '../settings.gypi', ], 'variables': { - 'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/ipc-test/serialization_adapter', + 'serialization_adapter_dir' : '<(oemcrypto_dir)/opk/ports/linux/common', }, 'targets' : [ { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c index 8102d89..d961831 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c @@ -776,7 +776,21 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetBootCertificateChain_Response(result, out, out_length); break; } - case 10033: /* WTPI_GenerateRandomCertificateKeyPair */ + case 10033: /* WTPI_GetMaxBootCertificateChainSize */ + { + size_t* out_length; + OPK_InitPointer((uint8_t**)&out_length); + OPK_Unpack_GetMaxBootCertificateChainSize_Request(request, &out_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetMaxBootCertificateChainSize"); + result = WTPI_GetMaxBootCertificateChainSize(out_length); + *response = + OPK_Pack_GetMaxBootCertificateChainSize_Response(result, out_length); + break; + } + case 10034: /* WTPI_GenerateRandomCertificateKeyPair */ { size_t* wrapped_private_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); @@ -804,7 +818,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, public_key, public_key_length); break; } - case 10034: /* WTPI_DeviceKeyCoseSign1 */ + case 10035: /* WTPI_DeviceKeyCoseSign1 */ { size_t message_length; OPK_Init_size_t((size_t*)&message_length); @@ -826,7 +840,21 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, signature_length); break; } - case 10035: /* WTPI_Crc32Init */ + case 10036: /* WTPI_GetMaxDeviceKeyCoseSign1Size */ + { + size_t* out_length; + OPK_InitPointer((uint8_t**)&out_length); + OPK_Unpack_GetMaxDeviceKeyCoseSign1Size_Request(request, &out_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetMaxDeviceKeyCoseSign1Size"); + result = WTPI_GetMaxDeviceKeyCoseSign1Size(out_length); + *response = + OPK_Pack_GetMaxDeviceKeyCoseSign1Size_Response(result, out_length); + break; + } + case 10037: /* WTPI_Crc32Init */ { uint32_t* initial_hash; OPK_InitPointer((uint8_t**)&initial_hash); @@ -839,7 +867,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Init_Response(result, initial_hash); break; } - case 10036: /* WTPI_Crc32Cont */ + case 10038: /* WTPI_Crc32Cont */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -859,7 +887,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_Response(result, new_crc); break; } - case 10037: /* WTPI_Crc32Cont_OutputBuffer */ + case 10039: /* WTPI_Crc32Cont_OutputBuffer */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -882,7 +910,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_OutputBuffer_Response(result, new_crc); break; } - case 10038: /* WTPI_GetTrustedTime */ + case 10040: /* WTPI_GetTrustedTime */ { uint64_t* time_in_s; OPK_InitPointer((uint8_t**)&time_in_s); @@ -895,7 +923,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetTrustedTime_Response(result, time_in_s); break; } - case 10039: /* WTPI_InitializeClock */ + case 10041: /* WTPI_InitializeClock */ { OPK_Unpack_InitializeClock_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -906,7 +934,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_InitializeClock_Response(result); break; } - case 10040: /* WTPI_TerminateClock */ + case 10042: /* WTPI_TerminateClock */ { OPK_Unpack_TerminateClock_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -917,7 +945,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_TerminateClock_Response(result); break; } - case 10041: /* WTPI_GetClockType */ + case 10043: /* WTPI_GetClockType */ { OPK_Unpack_GetClockType_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -929,7 +957,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetClockType_Response(result); break; } - case 10042: /* WTPI_GetEncryptAndSignSize */ + case 10044: /* WTPI_GetEncryptAndSignSize */ { uint32_t context; OPK_Init_uint32_t((uint32_t*)&context); @@ -948,7 +976,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetEncryptAndSignSize_Response(result, wrapped_length); break; } - case 10043: /* WTPI_EncryptAndSign */ + case 10045: /* WTPI_EncryptAndSign */ { size_t data_length; OPK_Init_size_t((size_t*)&data_length); @@ -970,7 +998,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_EncryptAndSign_Response(result, out, out_length); break; } - case 10044: /* WTPI_VerifyAndDecrypt */ + case 10046: /* WTPI_VerifyAndDecrypt */ { size_t wrapped_length; OPK_Init_size_t((size_t*)&wrapped_length); @@ -993,7 +1021,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_VerifyAndDecrypt_Response(result, out, out_length); break; } - case 10045: /* WTPI_VerifyAndDecryptUsageData_Legacy */ + case 10047: /* WTPI_VerifyAndDecryptUsageData_Legacy */ { size_t wrapped_length; OPK_Init_size_t((size_t*)&wrapped_length); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c index 5019d6a..c818d97 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c @@ -936,13 +936,38 @@ ODK_Message OPK_Pack_GetBootCertificateChain_Response( return msg; } +void OPK_Unpack_GetMaxBootCertificateChainSize_Request(ODK_Message* msg, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10033) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *out_length = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Response( + OEMCryptoResult result, const size_t* out_length) { + uint32_t api_value = 10033; /* from _tee10033 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_size_t(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_GenerateRandomCertificateKeyPair_Request( ODK_Message* msg, AsymmetricKeyType** key_type, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, uint8_t** public_key, size_t** public_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10033) + if (api_value != 10034) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -963,7 +988,7 @@ ODK_Message OPK_Pack_GenerateRandomCertificateKeyPair_Response( const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const uint8_t* public_key, const size_t* public_key_length) { - uint32_t api_value = 10033; /* from _tee10033 */ + uint32_t api_value = 10034; /* from _tee10034 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, wrapped_private_key_length); @@ -989,7 +1014,7 @@ void OPK_Unpack_DeviceKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10034) + if (api_value != 10035) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1005,7 +1030,7 @@ void OPK_Unpack_DeviceKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, ODK_Message OPK_Pack_DeviceKeyCoseSign1_Response( OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10034; /* from _tee10034 */ + uint32_t api_value = 10035; /* from _tee10035 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -1019,10 +1044,35 @@ ODK_Message OPK_Pack_DeviceKeyCoseSign1_Response( return msg; } +void OPK_Unpack_GetMaxDeviceKeyCoseSign1Size_Request(ODK_Message* msg, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10036) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *out_length = (size_t*)OPK_UnpackAlloc(msg, sizeof(size_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetMaxDeviceKeyCoseSign1Size_Response( + OEMCryptoResult result, const size_t* out_length) { + uint32_t api_value = 10036; /* from _tee10036 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_size_t(&msg, out_length); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10035) + if (api_value != 10037) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1033,7 +1083,7 @@ void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) { ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result, const uint32_t* initial_hash) { - uint32_t api_value = 10035; /* from _tee10035 */ + uint32_t api_value = 10037; /* from _tee10037 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1048,7 +1098,7 @@ void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10036) + if (api_value != 10038) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1062,7 +1112,7 @@ void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in, ODK_Message OPK_Pack_Crc32Cont_Response(OEMCryptoResult result, const uint32_t* new_crc) { - uint32_t api_value = 10036; /* from _tee10036 */ + uint32_t api_value = 10038; /* from _tee10038 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1077,7 +1127,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( size_t* in_length, uint32_t* prev_crc, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10037) + if (api_value != 10039) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1117,7 +1167,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, const uint32_t* new_crc) { - uint32_t api_value = 10037; /* from _tee10037 */ + uint32_t api_value = 10039; /* from _tee10039 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1130,7 +1180,7 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, void OPK_Unpack_GetTrustedTime_Request(ODK_Message* msg, uint64_t** time_in_s) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10038) + if (api_value != 10040) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1141,7 +1191,7 @@ void OPK_Unpack_GetTrustedTime_Request(ODK_Message* msg, uint64_t** time_in_s) { ODK_Message OPK_Pack_GetTrustedTime_Response(OEMCryptoResult result, const uint64_t* time_in_s) { - uint32_t api_value = 10038; /* from _tee10038 */ + uint32_t api_value = 10040; /* from _tee10040 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1154,7 +1204,7 @@ ODK_Message OPK_Pack_GetTrustedTime_Response(OEMCryptoResult result, void OPK_Unpack_InitializeClock_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10039) + if (api_value != 10041) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1163,7 +1213,7 @@ void OPK_Unpack_InitializeClock_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result) { - uint32_t api_value = 10039; /* from _tee10039 */ + uint32_t api_value = 10041; /* from _tee10041 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1175,7 +1225,7 @@ ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result) { void OPK_Unpack_TerminateClock_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10040) + if (api_value != 10042) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1184,7 +1234,7 @@ void OPK_Unpack_TerminateClock_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result) { - uint32_t api_value = 10040; /* from _tee10040 */ + uint32_t api_value = 10042; /* from _tee10042 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1196,7 +1246,7 @@ ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result) { void OPK_Unpack_GetClockType_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10041) + if (api_value != 10043) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1206,7 +1256,7 @@ void OPK_Unpack_GetClockType_Request(ODK_Message* msg) { ODK_Message OPK_Pack_GetClockType_Response( OEMCrypto_Clock_Security_Level result) { - uint32_t api_value = 10041; /* from _tee10041 */ + uint32_t api_value = 10043; /* from _tee10043 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_OEMCrypto_Clock_Security_Level(&msg, &result); @@ -1221,7 +1271,7 @@ void OPK_Unpack_GetEncryptAndSignSize_Request(ODK_Message* msg, size_t** wrapped_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10042) + if (api_value != 10044) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1234,7 +1284,7 @@ void OPK_Unpack_GetEncryptAndSignSize_Request(ODK_Message* msg, ODK_Message OPK_Pack_GetEncryptAndSignSize_Response( OEMCryptoResult result, const size_t* wrapped_length) { - uint32_t api_value = 10042; /* from _tee10042 */ + uint32_t api_value = 10044; /* from _tee10044 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1249,7 +1299,7 @@ void OPK_Unpack_EncryptAndSign_Request(ODK_Message* msg, uint32_t* context, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10043) + if (api_value != 10045) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1266,7 +1316,7 @@ void OPK_Unpack_EncryptAndSign_Request(ODK_Message* msg, uint32_t* context, ODK_Message OPK_Pack_EncryptAndSign_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10043; /* from _tee10043 */ + uint32_t api_value = 10045; /* from _tee10045 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -1285,7 +1335,7 @@ void OPK_Unpack_VerifyAndDecrypt_Request(ODK_Message* msg, uint32_t* context, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10044) + if (api_value != 10046) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1302,7 +1352,7 @@ void OPK_Unpack_VerifyAndDecrypt_Request(ODK_Message* msg, uint32_t* context, ODK_Message OPK_Pack_VerifyAndDecrypt_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10044; /* from _tee10044 */ + uint32_t api_value = 10046; /* from _tee10046 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -1320,7 +1370,7 @@ void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( uint8_t** signature, uint8_t* iv, uint8_t** out) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10045) + if (api_value != 10047) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1335,7 +1385,7 @@ void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Response( OEMCryptoResult result, const uint8_t* out) { - uint32_t api_value = 10045; /* from _tee10045 */ + uint32_t api_value = 10047; /* from _tee10047 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h index 065215a..0b6463d 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h @@ -180,6 +180,10 @@ void OPK_Unpack_GetBootCertificateChain_Request(ODK_Message* msg, uint8_t** out, ODK_Message OPK_Pack_GetBootCertificateChain_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length); +void OPK_Unpack_GetMaxBootCertificateChainSize_Request(ODK_Message* msg, + size_t** out_length); +ODK_Message OPK_Pack_GetMaxBootCertificateChainSize_Response( + OEMCryptoResult result, const size_t* out_length); void OPK_Unpack_GenerateRandomCertificateKeyPair_Request( ODK_Message* msg, AsymmetricKeyType** key_type, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, @@ -196,6 +200,10 @@ void OPK_Unpack_DeviceKeyCoseSign1_Request(ODK_Message* msg, uint8_t** message, ODK_Message OPK_Pack_DeviceKeyCoseSign1_Response( OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length); +void OPK_Unpack_GetMaxDeviceKeyCoseSign1Size_Request(ODK_Message* msg, + size_t** out_length); +ODK_Message OPK_Pack_GetMaxDeviceKeyCoseSign1Size_Response( + OEMCryptoResult result, const size_t* out_length); void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash); ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result, const uint32_t* initial_hash); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp index 0063652..19ba604 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp @@ -54,12 +54,18 @@ 'crypto_test.cpp', 'generation_number_interface_test.cpp', 'ssl_util.cpp', + 'cose_util.cpp', 'test_rsa_key.cpp', '<(DEPTH)/linux/src/log.cpp', + '<(DEPTH)/util/src/string_conversions.cpp', ], 'includes': [ '../../../../util/libcrypto_dependency.gypi', ], + 'dependencies': [ + '../../../../third_party/cose-c.gyp:cose-c', + '../../../../third_party/open-dice.gyp:cbor', + ], }, ] } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c index a9cc59b..892eed9 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c @@ -2,10 +2,11 @@ source code may only be used and distributed under the Widevine License Agreement. */ +#include "odk_attributes.h" #include "wtpi_secure_buffer_access_interface.h" /* Secure buffers are not supported by the test build. */ -OEMCryptoResult WTPI_GetSecureBufferAddress(void* secure, size_t offset, +OEMCryptoResult WTPI_GetSecureBufferAddress(void* secure, size_t offset UNUSED, uint8_t** out_addr) { if (secure == NULL || out_addr == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; diff --git a/oemcrypto/opk/ports/optee/Makefile b/oemcrypto/opk/ports/optee/Makefile index 7285563..fa0bc3a 100644 --- a/oemcrypto/opk/ports/optee/Makefile +++ b/oemcrypto/opk/ports/optee/Makefile @@ -27,10 +27,17 @@ endif # Default is QEMU OPTEE_PLATFORM ?= qemu CFG_TEE_TA_MALLOC_DEBUG:=y +IS_ARM:=1 # Default toolchain dir from the optee repositories OPTEE_TOOLCHAIN_DIR ?= $(OPTEE_DIR)/toolchains +# need to undefine this to avoid looking for . Including libc in the +# compiler include paths leads to a huge amount of redundant-decl compiler +# warnings +CPPFLAGS := \ + -U__linux__ \ + ifeq ($(OPTEE_PLATFORM),qemu) PLATFORM ?= vexpress-qemu_virt ARCH := 32 @@ -39,8 +46,15 @@ OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch32 TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32 CROSS_COMPILE := arm-linux-gnueabihf- WTPI_BUILD_INFO := OPTEE_QEMU -CPPFLAGS := \ - -I$(OPTEE_TOOLCHAIN)/arm-none-linux-gnueabihf/libc/usr/include \ + +else ifeq ($(OPTEE_PLATFORM),qemuv8) +PLATFORM ?= vexpress-qemu_armv8a +ARCH := 64 +TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec +OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch64 +TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm64 +CROSS_COMPILE := aarch64-linux-gnu- +WTPI_BUILD_INFO := OPTEE_QEMUv8 else ifeq ($(OPTEE_PLATFORM),stm32mp1) PLATFORM ?= stm32mp1-157A-DK1 @@ -50,8 +64,6 @@ OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch32 TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32 CROSS_COMPILE := arm-linux-gnueabihf- WTPI_BUILD_INFO := OPTEE_STM32MP1 -CPPFLAGS := \ - -I$(OPTEE_TOOLCHAIN)/arm-none-linux-gnueabihf/libc/usr/include \ else ifeq ($(OPTEE_PLATFORM),nxpimx8m) PLATFORM ?= imx-mx8mqevk @@ -61,8 +73,6 @@ OPTEE_TOOLCHAIN := $(OPTEE_TOOLCHAIN_DIR)/aarch64 TA_DEV_KIT_DIR := $(OPTEE_DIR)/optee_os/out/arm/export-ta_arm64 CROSS_COMPILE := aarch64-linux-gnu- WTPI_BUILD_INFO := OPTEE_IMX8 -CPPFLAGS := \ - -I$(OPTEE_TOOLCHAIN)/aarch64-none-linux-gnu/libc/usr/include \ else $(error Unknown OPTEE_PLATFORM "$(OPTEE_PLATFORM)" Check makefile for possible options.) diff --git a/oemcrypto/opk/ports/optee/README.md b/oemcrypto/opk/ports/optee/README.md index 064b3ba..d4e4858 100644 --- a/oemcrypto/opk/ports/optee/README.md +++ b/oemcrypto/opk/ports/optee/README.md @@ -20,7 +20,7 @@ This is a port of the OEMCrypto Trusted App for OP-TEE using the OPK. # current OPK makefiles $ git checkout 1e15682f1a4bb64c48b84884976a2b5c4201e878 $ cd ../ - $ python ./src/util/generate_build_files.py gyp + $ python3 ./src/util/generate_build_files.py gyp ``` 2. From the top level of this repo (CDM), run `make -j32 -C ./oemcrypto/opk/ports/optee host ta` @@ -173,3 +173,19 @@ cd /mnt/host/oemcrypto/test # run OEMCrypto unit tests ./oemcrypto_unittests ``` + +### Scripts + +The `scripts` folder contains various utility scripts to help build, run, and +test OP-TEE builds. Many of them rely on the environment variable $OPTEE_DIR, +which is the location of the OP-TEE codebase. + +- `qemu-check.py`: Launch QEMU, execute commands, and extract test results. + Tuned to OP-TEE running gtest executables such as wtpi_unittests. Uses pexpect + to communicate with QEMU and parse results +- `push.sh`: Intended to be run from the compilation environment in the CDM + repo. Simply copies the build outputs from the CDM repo into $OPTEE_DIR, along + with `install_ta.sh`. Works well with 9p virtfs-enabled QEMU. +- `install_ta.sh`: Intended to be run on the target platform in the host + environment. Installs the OEMCrypto TA and WTPI Test TA into OP-TEE using + xtest diff --git a/oemcrypto/opk/ports/optee/host/common/tos/optee_ree_tos.c b/oemcrypto/opk/ports/optee/host/common/tos/optee_ree_tos.c index b71801e..57dca9a 100644 --- a/oemcrypto/opk/ports/optee/host/common/tos/optee_ree_tos.c +++ b/oemcrypto/opk/ports/optee/host/common/tos/optee_ree_tos.c @@ -140,12 +140,19 @@ OPK_TransportStatus TOS_Transport_SendMessage(ODK_Message* request, op.params[0].memref.size = opk_shared_memory_.size; op.params[1].memref.parent = &transport_shared_memory_; op.params[1].memref.offset = 0; - op.params[1].memref.size = ODK_Message_GetSize(request); + op.params[1].memref.size = transport_shared_memory_.size; + + // TEE_Param VALUE types contain two uint32_t fields. We want to store a + // size_t to represent max(request_size, response_size), but we don't ever + // expect it to realistically be larger than the max uint32_t size (4 GB) so + // we intentionally downcast from size_t to uint32_t. + op.params[2].value.a = (uint32_t)(ODK_Message_GetSize(request)); + op.params[2].value.b = 0; op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_WHOLE, /* opk_shared_memory */ TEEC_MEMREF_PARTIAL_INOUT, /* transport_shared_memory */ - TEEC_NONE, TEEC_NONE); + TEEC_VALUE_INPUT, TEEC_NONE); res = TEEC_InvokeCommand(&teec_session_, TA_SEND_REQUEST_CMD, &op, NULL); if (res != TEEC_SUCCESS) { LOGE("SendMessage failed: 0x%08x", res); diff --git a/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c b/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c index dbe8064..8aa30a6 100644 --- a/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c +++ b/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.c @@ -15,8 +15,7 @@ void TOS_SecureBuffer_Pack(ODK_Message* message, const OEMCrypto_DestBufferDesc* obj) { /* secure memory - pack handle, length, offset */ - OPK_Pack_uint64_t(message, - (const uint64_t*)&obj->buffer.secure.secure_buffer); + OPK_Pack_size_t(message, (const size_t*)&obj->buffer.secure.secure_buffer); OPK_Pack_size_t(message, &obj->buffer.secure.secure_buffer_length); OPK_Pack_size_t(message, &obj->buffer.secure.offset); } @@ -24,7 +23,7 @@ void TOS_SecureBuffer_Pack(ODK_Message* message, void TOS_SecureBuffer_Unpack(ODK_Message* message, OEMCrypto_DestBufferDesc* obj) { /* secure memory - unpack handle, length, offset */ - OPK_Unpack_uint64_t(message, (uint64_t*)&obj->buffer.secure.secure_buffer); + OPK_Unpack_size_t(message, (size_t*)&obj->buffer.secure.secure_buffer); OPK_Unpack_size_t(message, &obj->buffer.secure.secure_buffer_length); OPK_Unpack_size_t(message, &obj->buffer.secure.offset); } diff --git a/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile b/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile index 378782d..4dca131 100644 --- a/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile +++ b/oemcrypto/opk/ports/optee/host/wtpi_unittests/Makefile @@ -42,5 +42,13 @@ ldflags = \ cppflags += \ -DOPENSSL_NO_ASM \ -Wnon-virtual-dtor \ + -DCOSE_C_USE_OPENSSL \ + -include 'cstdlib' \ + '-DEVP_aes_128_ccm()=EVP_aes_128_gcm()' \ + '-DEVP_aes_256_ccm()=EVP_aes_256_gcm()' \ + '-DEVP_aes_192_ccm()=EVP_aes_192_gcm()' \ + '-DEVP_CTRL_CCM_SET_L=0x14' \ + '-DEVP_CTRL_CCM_GET_TAG=EVP_CTRL_GCM_GET_TAG' \ + '-DEVP_CTRL_CCM_SET_TAG=EVP_CTRL_GCM_SET_TAG' \ include ../rules.mk diff --git a/oemcrypto/opk/ports/optee/install_ta.sh b/oemcrypto/opk/ports/optee/install_ta.sh deleted file mode 100755 index 44fa009..0000000 --- a/oemcrypto/opk/ports/optee/install_ta.sh +++ /dev/null @@ -1,46 +0,0 @@ -# Run this script in the non-secure QEMU login shell to copy the Widevine -# OEMCrypto TA and WTPI Test TA to the directory where the TAs are located and -# set environment variables to access the liboecmrypto.so - -OEMCRYPTO_TA=a92d116c-ce27-4917-b30c-4a416e2d9351.ta -if test -f $OEMCRYPTO_TA; then - echo "Installing OEMCrypto TA" - cp $OEMCRYPTO_TA /lib/optee_armtz && rm $OEMCRYPTO_TA - xtest --install-ta /lib/optee_armtz/$OEMCRYPTO_TA -else - if test -f /lib/optee_armtz/$OEMCRYPTO_TA; then - echo "OEMCrypto TA is already installed" - else - echo "OEMCrypto TA not found, run push.sh from host" - fi -fi - -WTPI_TEST_TA=b0f42504-01ec-11ec-9a03-0242ac130003.ta -if test -f $WTPI_TEST_TA; then - echo "Installing WTPI Test TA" - cp $WTPI_TEST_TA /lib/optee_armtz && rm $WTPI_TEST_TA - xtest --install-ta /lib/optee_armtz/$WTPI_TEST_TA -else - if test -f /lib/optee_armtz/$WTPI_TEST_TA; then - echo "WTPI Test TA is already installed" - else - echo "WTPI TEST TA not found, run push.sh from host" - fi -fi - -# restart tee-supplicant -PID=$(ps | grep tee-supplicant | grep -v grep | sed 's/ tee.*//') -if test -z $PID; then - echo "tee-supplicant is not running" -else - echo "stopping tee-supplicant" - kill $PID -fi -echo "starting tee-supplicant" -su tee -c "tee-supplicant -d /dev/teepriv0" & - -# run as "source" to get this to actually propagate to the environment -# eg. `. ./install_ta.sh` instead of just `./install_ta.sh` -export LD_LIBRARY_PATH=/mnt/host/oemcrypto/test -export TOS_LOG_LEVEL=4 - diff --git a/oemcrypto/opk/ports/optee/push.sh b/oemcrypto/opk/ports/optee/push.sh deleted file mode 100755 index b5c6474..0000000 --- a/oemcrypto/opk/ports/optee/push.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -PLATFORM=vexpress-qemu_virt -[ -z "${OPTEE_DIR}" ] && echo "Set \$OPTEE_DIR to your OPTEE SDK root. See README.md" && exit -[ -z "${CDM_DIR}" ] && echo "Set \$CDM_DIR to your CDM_DIR repo root" && exit - -OUT_DIR=$CDM_DIR/out/optee/$PLATFORM -VIRTFS_DIR=$OPTEE_DIR/oemcrypto/test - -test -d $VIRTFS_DIR || mkdir -p $VIRTFS_DIR - -echo "copy oemcrypto_ta (a92d116c-ce27-4917-b30c-4a416e2d9351) to $VIRTFS_DIR" -cp $OUT_DIR/oemcrypto_ta/a92d116c-ce27-4917-b30c-4a416e2d9351.ta $VIRTFS_DIR -cp $OUT_DIR/oemcrypto_helloworld/oemcrypto_helloworld $VIRTFS_DIR - -echo "copy wtpi_test_ta (b0f42504-01ec-11ec-9a03-0242ac130003) to $VIRTFS_DIR" -cp $OUT_DIR/wtpi_test_ta/b0f42504-01ec-11ec-9a03-0242ac130003.ta $VIRTFS_DIR -cp $OUT_DIR/wtpi_unittests/wtpi_unittests $VIRTFS_DIR - -echo "copy oemcrypto unit tests to $VIRTFS_DIR" -cp $OUT_DIR/oemcrypto_unittests/oemcrypto_unittests $VIRTFS_DIR - -echo "copy liboemcrypto.so to $VIRTFS_DIR" -cp $OUT_DIR/liboemcrypto/liboemcrypto.so $VIRTFS_DIR - -echo "copy install_ta.sh to $VIRTFS_DIR" -cp ./install_ta.sh $VIRTFS_DIR diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk index 2f8336c..93e38f8 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk @@ -24,9 +24,22 @@ ifndef optee_inc_dir $(error wtpi_impl/sources.mk included without setting optee_inc_dir) endif +dice_dir ?= $(OPK_REPO_TOP)/third_party/open-dice +dice_sources += \ + $(dice_dir)/src/cbor_reader.c \ + $(dice_dir)/src/cbor_writer.c \ + $(dice_dir)/src/clear_memory.c \ + $(dice_dir)/src/utils.c \ + +dice_includes += \ + $(dice_dir)/include \ + $(dice_dir)/include/dice/config/boringssl_ed25519 \ + wtpi_impl_sources += \ $(wtpi_impl_dir)/util/ta_log.c \ $(wtpi_impl_dir)/util/der_parse.c \ + $(wtpi_ref_dir)/odk_endian.c \ + $(wtpi_ref_dir)/cose_util.c \ $(wtpi_impl_dir)/wtpi_abort.c \ $(wtpi_impl_dir)/wtpi_clock_layer2.c \ $(wtpi_impl_dir)/wtpi_config.c \ @@ -39,6 +52,8 @@ wtpi_impl_sources += \ $(wtpi_impl_dir)/wtpi_root_of_trust_layer1.c \ $(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c \ $(wtpi_stub_dir)/wtpi_secure_buffer_access.c \ + $(wtpi_stub_dir)/wtpi_cas.c \ + $(wtpi_stub_dir)/wtpi_device_key_access.c \ $(wtpi_ref_dir)/renewal_util.c \ $(wtpi_ref_dir)/wtpi_clock_and_gn_layer1.c \ $(wtpi_ref_dir)/wtpi_crc32.c \ @@ -48,6 +63,7 @@ wtpi_impl_sources += \ $(wtpi_ref_dir)/wtpi_device_renewal_layer1.c \ $(wtpi_ref_dir)/wtpi_device_renewal_layer2.c \ $(tos_impl_dir)/optee_secure_buffers.c \ + $(dice_sources) \ wtpi_impl_includes += \ $(wtpi_impl_dir) \ @@ -57,6 +73,7 @@ wtpi_impl_includes += \ $(optee_inc_dir) \ $(optee_inc_dir)/mbedtls \ $(oemcrypto_dir)/include \ + $(dice_includes) \ wtpi_impl_libs += \ mbedtls diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c index 6e82f04..42d016e 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.c @@ -12,6 +12,7 @@ #include "ecp.h" #include "pk.h" #include "rsa.h" +#include "sha256.h" // Helper for the mbedtls_asn1_write_* functions. Assumes the existence of // a variable named `ret` with type `int`. @@ -160,33 +161,37 @@ static OEMCryptoResult Helper_EncodeRSAKey( int (*mbedtls_write_fn)(mbedtls_pk_context* ctx, unsigned char* buf, size_t size)) { // import RSA data as raw values into mbedtls_rsa_context - mbedtls_rsa_context rsa_ctx; - mbedtls_rsa_init(&rsa_ctx, MBEDTLS_RSA_PKCS_V15, 0); - + mbedtls_pk_context pk_ctx; + mbedtls_pk_init(&pk_ctx); int result = - mbedtls_rsa_import_raw(&rsa_ctx, key->modulus, key->modulus_len, NULL, 0, - NULL, 0, key->private_exp, key->private_exp_len, - key->public_exp, key->public_exp_len); + mbedtls_pk_setup(&pk_ctx, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + if (result != 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + mbedtls_rsa_init(mbedtls_pk_rsa(pk_ctx), MBEDTLS_RSA_PKCS_V15, 0); + + result = mbedtls_rsa_import_raw(mbedtls_pk_rsa(pk_ctx), key->modulus, + key->modulus_len, NULL, 0, NULL, 0, + key->private_exp, key->private_exp_len, + key->public_exp, key->public_exp_len); if (result < 0) { + mbedtls_pk_free(&pk_ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } // calculate remaining RSA parameters (P, Q) - result = mbedtls_rsa_complete(&rsa_ctx); + result = mbedtls_rsa_complete(mbedtls_pk_rsa(pk_ctx)); if (result < 0) { + mbedtls_pk_free(&pk_ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - // assign RSA data to generic mbedtls_pk_context type - mbedtls_pk_context pk_ctx; - const mbedtls_pk_info_t* info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); - mbedtls_pk_setup(&pk_ctx, info); - pk_ctx.pk_ctx = &rsa_ctx; - // write RSA data in DER encoding to output size_t original_output_length = *output_length; int bytes_written = mbedtls_write_fn(&pk_ctx, output, *output_length); if (bytes_written <= 0) { + mbedtls_pk_free(&pk_ctx); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } *output_length = bytes_written; @@ -196,6 +201,7 @@ static OEMCryptoResult Helper_EncodeRSAKey( TEE_MemMove(output, output + original_output_length - *output_length, *output_length); + mbedtls_pk_free(&pk_ctx); return OEMCrypto_SUCCESS; } @@ -248,6 +254,30 @@ static uint32_t GlobalPlatformCurveId(mbedtls_ecp_group_id id) { return TEE_CRYPTO_ELEMENT_NONE; } +static mbedtls_ecp_group_id MbedTlsCurveId(uint32_t id) { + switch (id) { + case TEE_ECC_CURVE_NIST_P192: + return MBEDTLS_ECP_DP_SECP192R1; + + case TEE_ECC_CURVE_NIST_P224: + return MBEDTLS_ECP_DP_SECP224R1; + + case TEE_ECC_CURVE_NIST_P256: + return MBEDTLS_ECP_DP_SECP256R1; + + case TEE_ECC_CURVE_NIST_P384: + return MBEDTLS_ECP_DP_SECP384R1; + + case TEE_ECC_CURVE_NIST_P521: + return MBEDTLS_ECP_DP_SECP521R1; + + default: + return MBEDTLS_ECP_DP_NONE; + } + + return MBEDTLS_ECP_DP_NONE; +} + static size_t CurveNumBits(mbedtls_ecp_group_id id) { switch (id) { case MBEDTLS_ECP_DP_SECP192R1: @@ -319,6 +349,19 @@ static size_t ECCSize(size_t num_bits) { return len; } +// If src size is smaller than desired size, reallocate src and front pad with +// 0s. Set src_size to desired size if successful. +static void zero_pad_and_realloc(uint8_t** src, size_t* src_size, + size_t desired_size) { + if (*src_size >= desired_size) return; + uint8_t* const temp = TEE_Malloc(desired_size, 0); + const size_t difference = desired_size - *src_size; + TEE_MemMove(temp + difference, *src, *src_size); + TEE_Free(*src); + *src = temp; + *src_size = desired_size; +} + OEMCryptoResult DecodePKCS8ECCPrivateKey(const uint8_t* input, size_t input_length, rfc5915_eckey* output) { @@ -336,6 +379,7 @@ OEMCryptoResult DecodePKCS8ECCPrivateKey(const uint8_t* input, output->ecc_curve_type = GlobalPlatformCurveId(ec_ctx->grp.id); output->ecc_curve_bits = CurveNumBits(ec_ctx->grp.id); output->max_signature_size = ECCSize(output->ecc_curve_bits); + const size_t ecc_curve_bytes = (output->ecc_curve_bits + 7) / 8; if ((res = extract_mbedtls_mpi_param(&(ec_ctx->d), &output->private_val, &output->private_val_len)) != @@ -349,6 +393,12 @@ OEMCryptoResult DecodePKCS8ECCPrivateKey(const uint8_t* input, &output->public_y_len)) != OEMCrypto_SUCCESS) goto cleanup; + zero_pad_and_realloc(&output->private_val, &output->private_val_len, + ecc_curve_bytes); + zero_pad_and_realloc(&output->public_x, &output->public_x_len, + ecc_curve_bytes); + zero_pad_and_realloc(&output->public_y, &output->public_y_len, + ecc_curve_bytes); res = OEMCrypto_SUCCESS; @@ -373,6 +423,7 @@ OEMCryptoResult DecodeECCPublicKey(const uint8_t* input, size_t input_length, output->ecc_curve_type = GlobalPlatformCurveId(ec_ctx->grp.id); output->ecc_curve_bits = CurveNumBits(ec_ctx->grp.id); output->max_signature_size = ECCSize(output->ecc_curve_bits); + const size_t ecc_curve_bytes = (output->ecc_curve_bits + 7) / 8; if ((res = extract_mbedtls_mpi_param(&(ec_ctx->Q.X), &output->public_x, &output->public_x_len)) != @@ -383,6 +434,11 @@ OEMCryptoResult DecodeECCPublicKey(const uint8_t* input, size_t input_length, OEMCrypto_SUCCESS) goto cleanup; + zero_pad_and_realloc(&output->public_x, &output->public_x_len, + ecc_curve_bytes); + zero_pad_and_realloc(&output->public_y, &output->public_y_len, + ecc_curve_bytes); + res = OEMCrypto_SUCCESS; cleanup: @@ -447,3 +503,83 @@ OEMCryptoResult EncodeECDSASignature(const uint8_t* sig, size_t sig_length, return OEMCrypto_SUCCESS; } + +OEMCryptoResult DeriveEccKey(const uint8_t* seed, size_t seed_length, + uint32_t curve_id, rfc5915_eckey* output) { + if (seed == NULL || seed_length == 0 || output == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + OEMCryptoResult res = OEMCrypto_ERROR_UNKNOWN_FAILURE; + + // grp will contain ECC generator point G + mbedtls_ecp_group grp; + mbedtls_ecp_group_init(&grp); + + // privkey will be the hashed seed used to calculate the public key + mbedtls_mpi privkey; + mbedtls_mpi_init(&privkey); + + // pubkey will be the (X,Y) point calculated by multiplying privkey*G + mbedtls_ecp_point pubkey; + mbedtls_ecp_point_init(&pubkey); + + // Hash seed + // Not all OPTEE builds support SHA512. We still want 64 bytes of material in + // case of ECC P384 or P521, so use same SHA256 hash twice + uint8_t hash[64]; + mbedtls_sha256(seed, seed_length, hash, 0); + mbedtls_sha256(seed, seed_length, hash + 32, 0); + + // Copy hashed result into mbedtls mpi struct, treat it as the private key + mbedtls_ecp_group_id id = MbedTlsCurveId(curve_id); + size_t curve_len_bits = CurveNumBits(id); + size_t curve_len = (curve_len_bits + 7) / 8; + int mbedtls_res = mbedtls_mpi_read_binary(&privkey, hash, curve_len); + if (mbedtls_res < 0) { + goto cleanup; + } + + // Use a static generator point G for the provided curve + // mbedtls_ecp_group_load loads a known set of fields for a given curve + mbedtls_res = mbedtls_ecp_group_load(&grp, id); + if (mbedtls_res < 0) { + goto cleanup; + } + + // Multiply private val by G + mbedtls_res = mbedtls_ecp_mul(&grp, &pubkey, &privkey, &(grp.G), NULL, NULL); + if (mbedtls_res < 0) { + goto cleanup; + } + + // Copy results into output struct + output->ecc_curve_type = curve_id; + output->ecc_curve_bits = curve_len_bits; + output->max_signature_size = ECCSize(curve_len_bits); + + if ((res = extract_mbedtls_mpi_param(&privkey, &output->private_val, + &output->private_val_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + if ((res = extract_mbedtls_mpi_param(&(pubkey.X), &output->public_x, + &output->public_x_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + if ((res = extract_mbedtls_mpi_param(&(pubkey.Y), &output->public_y, + &output->public_y_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + zero_pad_and_realloc(&output->private_val, &output->private_val_len, + curve_len); + zero_pad_and_realloc(&output->public_x, &output->public_x_len, curve_len); + zero_pad_and_realloc(&output->public_y, &output->public_y_len, curve_len); + + res = OEMCrypto_SUCCESS; + +cleanup: + mbedtls_ecp_group_free(&grp); + mbedtls_ecp_point_free(&pubkey); + mbedtls_mpi_free(&privkey); + return res; +} diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h index 1e88856..b79aa19 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/util/der_parse.h @@ -114,4 +114,15 @@ OEMCryptoResult DecodeECCPublicKey(const uint8_t* input, size_t input_length, OEMCryptoResult EncodeECDSASignature(const uint8_t* sig, size_t sig_length, uint8_t* output, size_t* output_length); +/* + * Given a buffer of bytes |seed| and a curve type |curve_id|, produce a + * deterministic public and private keypair for ECC operations. + * + * |curve_id| is the GlobalPlatform enum for curve types, eg + * TEE_ECC_CURVE_NIST_P256 + * + */ +OEMCryptoResult DeriveEccKey(const uint8_t* seed, size_t seed_length, + uint32_t curve_id, rfc5915_eckey* output); + #endif diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c index 838d83b..c129e59 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c @@ -11,7 +11,11 @@ OEMCrypto_Security_Level WTPI_GetSecurityLevel(void) { } OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) { - return OEMCrypto_Keybox; + #ifdef OPTEE_PROVISIONING_METHOD + return OPTEE_PROVISIONING_METHOD; + #else + return OEMCrypto_Keybox; + #endif } uint32_t WTPI_GetResourceRatingTier(void) { return 1; } @@ -78,5 +82,5 @@ size_t WTPI_MaxSampleSize(void) { return 0; } // GlobalPlatform spec says "256, 512, 768, 1024, 1536 and 2048 bit keys SHALL // be supported." uint32_t WTPI_SupportedCertificates(void) { - return OEMCrypto_Supports_RSA_2048bit; + return OEMCrypto_Supports_RSA_CAST | OEMCrypto_Supports_RSA_2048bit; } diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h index 7750c38..0bd8b06 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_macros.h @@ -40,5 +40,8 @@ #define MAX_WRAPPED_SYMMETRIC_KEY_SIZE MAX_SYMMETRIC_KEY_SIZE #define MAX_WRAPPED_ASYMMETRIC_KEY_SIZE \ (PKCS8_DRM_KEY_MAX_SIZE + ENCRYPT_AND_SIGN_EXTRA) +/** Maximum size of the signature generated by an asymmetric key (ECC or RSA). + */ +#define MAX_ASYMMETRIC_SIGNATURE_SIZE 1024 #endif // _WTPI_CONFIG_MACROS_H_ diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c index 5ea7bd9..31136d9 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c @@ -7,6 +7,7 @@ #include #include #include +#include "crypto_common.h" #include "der_parse.h" #include "malloc.h" #include "oemcrypto_check_macros.h" @@ -18,44 +19,9 @@ #include "wtpi_abort_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_crypto_asymmetric_interface.h" +#include "wtpi_device_key_access_interface.h" #include "wtpi_device_key_interface.h" - -/* - * - * TODO(b/206651517): Replace raw key data with pre-allocated - * TEE_OperationHandle and TEE_ObjectHandle. - * - * GlobalPlatform requires that a TEE_ObjectHandle is constructed with - * a specific operation in mind. For example, if we want to construct a key - * handle for a SHA1 operation, we specify SHA1 when we assign the key to the - * handle. Similarly for SHA256, we specify SHA256 during TEE_ObjectHandle - * construction. - * - * Unfortunately, the current SymmetricKeyType enum does not have that level of - * granularity. We use MAC_KEY_CLIENT for both SHA1 and SHA256 operations, so - * a CreateKeyHandle() request does not have enough information for us to - * guarantee a valid TEE_ObjectHandle result. - * - * To get around this, we re-allocate the TEE_OperationHandle (for the crypto - * operation we want) and TEE_ObjectHandle (for the key associated with that - * crypto operation) for every symmetric key crypto function; we don't know - * enough information to do this until the actual WTPI function is called. At - * the end of the function, we free the op/key handles. - * - * Asymmetric keys still have this problem, but to a lesser degree. The - * AsymmetricKeyType enum does not specify signing vs decrypting, so we don't - * know which operation handle to generate if we're given that enum value. - * Thankfully, those are the only two operations we do, so it's not burdensome - * to pre-allocate both options. The key object is even easier, there's only one - * choice (TEE_TYPE_RSA_KEYPAIR). - * - * TODO: also maybe add key type as a member? good to check compatibility with - * desired operation, eg. don't try to AES encrypt with an HMAC key - */ -typedef struct wtpi_k1_symmetric_key_handle { - uint8_t* key; - uint32_t key_size; // TODO: change to KeySize type -} wtpi_k1_symmetric_key_handle; +#include "wtpi_secure_buffer_access_interface.h" OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key, KeySize* size) { @@ -71,60 +37,31 @@ OEMCryptoResult Helper_AESEncryptBlock_ECB(WTPI_K1_SymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_NULL(output); RETURN_INVALID_CONTEXT_IF_NULL(key); - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; - uint32_t algo = TEE_ALG_AES_ECB_NOPAD; - uint32_t mode = TEE_MODE_ENCRYPT; - uint32_t size = key->key_size * 8; - TEE_Result res = TEE_AllocateOperation(&op_handle, algo, mode, size); - if (res != TEE_SUCCESS) { - EMSG("TEE_AllocateOperation() failed with result 0x%x", res); - goto err; + TEE_OperationHandle op_handle = key->op_ecb; + if (op_handle == TEE_HANDLE_NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; } - res = TEE_AllocateTransientObject(TEE_TYPE_AES, size, &key_handle); - if (res != TEE_SUCCESS) { - EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); - goto err; - } - TEE_Attribute attr; - TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key->key_size); - - res = TEE_PopulateTransientObject(key_handle, &attr, 1); - if (res != TEE_SUCCESS) { - EMSG("TEE_PopulateTransientObject() failed with result 0x%x", res); - goto err; - } - - res = TEE_SetOperationKey(op_handle, key_handle); - if (res != TEE_SUCCESS) { - EMSG("TEE_SetOperationKey() failed with result 0x%x", res); - goto err; - } - - TEE_CipherInit(op_handle, NULL, 0); - size_t output_len = 128; size_t in_length = AES_BLOCK_SIZE; - res = TEE_CipherUpdate(op_handle, input, in_length, output, &output_len); + TEE_CipherInit(op_handle, NULL, 0); + TEE_Result res = + TEE_CipherUpdate(op_handle, input, in_length, output, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_CipherUpdate() failed with result 0x%x", res); if (output_len != 128) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } - if (op_handle != TEE_HANDLE_NULL) TEE_FreeOperation(op_handle); - if (key_handle != TEE_HANDLE_NULL) TEE_FreeTransientObject(key_handle); return OEMCrypto_SUCCESS; err: - if (op_handle != TEE_HANDLE_NULL) TEE_FreeOperation(op_handle); - if (key_handle != TEE_HANDLE_NULL) TEE_FreeTransientObject(key_handle); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, size_t key_length_to_use, const uint8_t* in, size_t in_length, @@ -133,8 +70,30 @@ static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, if (mode != TEE_MODE_ENCRYPT && mode != TEE_MODE_DECRYPT) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; + + size_t output_len = in_length; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + + // special case: CreateKey would have allocated a CBC+Decrypt key already for + // the CONTENT_KEY type, so just use it here + if (key->key_type == CONTENT_KEY && mode == TEE_MODE_DECRYPT) { + op_handle = key->op_cbc; + TEE_CipherInit(op_handle, iv, 16); + + TEE_Result res = + TEE_CipherUpdate(op_handle, in, in_length, out, &output_len); + if (res != TEE_SUCCESS) { + EMSG("TEE_CipherUpdate() failed with result 0x%x", res); + if (output_len != in_length) { + EMSG("output_len was changed to %zu", output_len); + } + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; + } + + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + TEE_Attribute attr; uint32_t algo = TEE_ALG_AES_CBC_NOPAD; uint32_t size = key_length_to_use * 8; TEE_Result res = TEE_AllocateOperation(&op_handle, algo, mode, size); @@ -149,7 +108,6 @@ static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, goto err; } - TEE_Attribute attr; TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key_length_to_use); @@ -167,12 +125,11 @@ static OEMCryptoResult Helper_AESCBC(WTPI_K1_SymmetricKey_Handle key, TEE_CipherInit(op_handle, iv, 16); - size_t output_len = in_length; res = TEE_CipherUpdate(op_handle, in, in_length, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_CipherUpdate() failed with result 0x%x", res); if (output_len != in_length) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -225,8 +182,10 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(out); - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + TEE_Attribute attr; + size_t output_len = 32; uint32_t algo = TEE_ALG_HMAC_SHA1; uint32_t mode = TEE_MODE_MAC; uint32_t size = key->key_size * 8; @@ -241,7 +200,6 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key, EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); goto err; } - TEE_Attribute attr; TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key->key_size); res = TEE_PopulateTransientObject(key_handle, &attr, 1); @@ -259,12 +217,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA1(WTPI_K1_SymmetricKey_Handle key, TEE_MACInit(op_handle, NULL, 0); TEE_MACUpdate(op_handle, message, message_length); - size_t output_len = 32; res = TEE_MACComputeFinal(op_handle, message, 0, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_MACComputeFinal() failed with result 0x%x", res); if (output_len != 32) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } @@ -287,7 +244,10 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, size_t message_length, TEE_Result res; - TEE_OperationHandle op_handle; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + size_t chunk_len = 32; + size_t remaining_len = message_length; + size_t output_len = 32; uint32_t algo = TEE_ALG_SHA256; uint32_t mode = TEE_MODE_DIGEST; res = TEE_AllocateOperation(&op_handle, algo, mode, 0); @@ -296,8 +256,6 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, size_t message_length, goto err; } - size_t chunk_len = 32; - size_t remaining_len = message_length; for (size_t i = 0; i < message_length; i += chunk_len) { if (remaining_len < chunk_len) { chunk_len = remaining_len; @@ -306,12 +264,11 @@ OEMCryptoResult WTPI_C1_SHA256(const uint8_t* message, size_t message_length, remaining_len -= chunk_len; } - size_t output_len = 32; res = TEE_DigestDoFinal(op_handle, message, 0, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_DigestDoFinal() failed with result 0x%x", res); if (output_len != 32) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } @@ -334,11 +291,28 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(out); - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; +// If the key is too small, pad it until it is at the minimum allowed by +// GlobalPlatform +#define MIN_OPTEE_HMAC_SHA256_SIZE 256 + if (key->key_size * 8 < MIN_OPTEE_HMAC_SHA256_SIZE) { + uint8_t temp[MIN_OPTEE_HMAC_SHA256_SIZE / 8]; + TEE_MemFill(temp, 0, sizeof(temp)); + TEE_MemMove(temp, key->key, key->key_size); + TEE_Free(key->key); + key->key = TEE_Malloc(sizeof(temp), TEE_MALLOC_FILL_ZERO); + TEE_MemMove(key->key, temp, sizeof(temp)); + key->key_size = sizeof(temp); + } +#undef MIN_OPTEE_HMAC_SHA256_SIZE + + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + TEE_Attribute attr; + size_t output_len = 32; uint32_t algo = TEE_ALG_HMAC_SHA256; uint32_t mode = TEE_MODE_MAC; uint32_t size = key->key_size * 8; + TEE_Result res = TEE_AllocateOperation(&op_handle, algo, mode, size); if (res != TEE_SUCCESS) { EMSG("Could not allocate op with result 0x%x, %u, %u, %u", res, algo, mode, @@ -351,7 +325,6 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key, EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); goto err; } - TEE_Attribute attr; TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key->key, key->key_size); res = TEE_PopulateTransientObject(key_handle, &attr, 1); @@ -368,12 +341,11 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256(WTPI_K1_SymmetricKey_Handle key, TEE_MACInit(op_handle, NULL, 0); TEE_MACUpdate(op_handle, message, message_length); - size_t output_len = 32; res = TEE_MACComputeFinal(op_handle, message, 0, out, &output_len); if (res != TEE_SUCCESS) { EMSG("TEE_MACComputeFinal() failed with result 0x%x", res); if (output_len != 32) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } goto err; } @@ -420,14 +392,16 @@ OEMCryptoResult WTPI_C1_CopyToOutputBuffer(const uint8_t* in, size_t size, return OEMCrypto_ERROR_INVALID_CONTEXT; } - // TODO: secure buffer + uint8_t* dest = NULL; if (out->type == OPK_SECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } else if (out->type != OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + const OEMCryptoResult result = + WTPI_GetSecureBufferAddress(out->buffer.secure, output_offset, &dest); + if (result != OEMCrypto_SUCCESS) return result; + } else if (out->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + dest = out->buffer.clear_insecure + output_offset; + } else { return OEMCrypto_ERROR_INVALID_CONTEXT; } - - uint8_t* const dest = out->buffer.clear_insecure + output_offset; TEE_MemMove(dest, in, size); return OEMCrypto_SUCCESS; @@ -479,10 +453,75 @@ OEMCryptoResult WTPI_K1_CreateKeyHandle( EMSG("Malloc failed, out of memory"); goto err; } + TEE_MemMove(key_space, serialized_bytes, size); sess->key = key_space; - sess->key_size = (uint32_t)size; + sess->key_type = key_type; + + // Special case of CONTENT_KEY type, preallocate key handle and CTR+CBC + // operation handles. Every other operation generates operation handles on the + // fly + if (key_type == CONTENT_KEY) { + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; + uint32_t key_size = size * 8; + TEE_Result res = + TEE_AllocateTransientObject(TEE_TYPE_AES, key_size, &key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); + goto err; + } + + TEE_Attribute attr; + TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, serialized_bytes, size); + res = TEE_PopulateTransientObject(key_handle, &attr, 1); + if (res != TEE_SUCCESS) { + EMSG("TEE_PopulateTransientObject() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + goto err; + } + + // CBC + TEE_OperationHandle op_handle_cbc = TEE_HANDLE_NULL; + uint32_t algo = TEE_ALG_AES_CBC_NOPAD; + uint32_t mode = TEE_MODE_DECRYPT; + res = TEE_AllocateOperation(&op_handle_cbc, algo, mode, key_size); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateOperation() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + goto err; + } + res = TEE_SetOperationKey(op_handle_cbc, key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_SetOperationKey() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + TEE_FreeOperation(op_handle_cbc); + goto err; + } + + // CTR + TEE_OperationHandle op_handle_ctr = TEE_HANDLE_NULL; + algo = TEE_ALG_AES_ECB_NOPAD; + mode = TEE_MODE_ENCRYPT; + res = TEE_AllocateOperation(&op_handle_ctr, algo, mode, key_size); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateOperation() failed with result 0x%x", res); + TEE_FreeTransientObject(key_handle); + TEE_FreeOperation(op_handle_cbc); + goto err; + } + res = TEE_SetOperationKey(op_handle_ctr, key_handle); + TEE_FreeTransientObject(key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_SetOperationKey() failed with result 0x%x", res); + TEE_FreeOperation(op_handle_cbc); + TEE_FreeOperation(op_handle_ctr); + goto err; + } + + sess->op_cbc = op_handle_cbc; + sess->op_ecb = op_handle_ctr; + } *out_key_handle = sess; return OEMCrypto_SUCCESS; @@ -496,14 +535,15 @@ err: OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle( uint32_t context, SymmetricKeyType out_key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle, KeySize out_key_size) { - // TODO (b/201702904): Use a persistent, device-unique key - const uint8_t fake_device_key[KEY_SIZE_128] = { - 0xa2, 0xe5, 0x11, 0x54, 0x12, 0x60, 0xf0, 0xe1, - 0xa8, 0x72, 0xeb, 0x15, 0x48, 0x41, 0xc7, 0x87}; + const uint8_t* device_key = WTPI_GetDeviceKey(); + const KeySize device_key_len = WTPI_GetDeviceKeySize(); + if (device_key == NULL || device_key_len != KEY_SIZE_128) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } WTPI_K1_SymmetricKey_Handle temp_key_handle; OEMCryptoResult result = WTPI_K1_CreateKeyHandle( - fake_device_key, KEY_SIZE_128, DERIVING_KEY, &temp_key_handle); + device_key, KEY_SIZE_128, DERIVING_KEY, &temp_key_handle); if (result != OEMCrypto_SUCCESS) return result; uint8_t full_context[16] = {'.', '.', '.', '.', 'W', 'i', 'd', 'e', @@ -594,8 +634,8 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( return OEMCrypto_ERROR_INVALID_CONTEXT; } - TEE_OperationHandle op_handle; - TEE_ObjectHandle key_handle; + TEE_OperationHandle op_handle = TEE_HANDLE_NULL; + TEE_ObjectHandle key_handle = TEE_HANDLE_NULL; uint32_t algo = TEE_ALG_AES_CMAC; uint32_t mode = TEE_MODE_MAC; @@ -644,7 +684,7 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( if (res != TEE_SUCCESS) { EMSG("TEE_MACComputeFinal() failed with result 0x%x", res); if (output_len != KEY_SIZE_128) { - EMSG("output_len was changed to %d", output_len); + EMSG("output_len was changed to %zu", output_len); } return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -662,9 +702,10 @@ err: return OEMCrypto_ERROR_UNKNOWN_FAILURE; } -OEMCryptoResult WTPI_K1_WrapKey(UNUSED uint32_t context, +OEMCryptoResult WTPI_K1_WrapKey(uint32_t context UNUSED, WTPI_K1_SymmetricKey_Handle key, - SymmetricKeyType key_type, uint8_t* wrapped_key, + SymmetricKeyType key_type UNUSED, + uint8_t* wrapped_key, size_t wrapped_key_length) { RETURN_INVALID_CONTEXT_IF_NULL(key); RETURN_INVALID_CONTEXT_IF_NULL(wrapped_key); @@ -682,7 +723,7 @@ OEMCryptoResult WTPI_K1_WrapKey(UNUSED uint32_t context, } OEMCryptoResult WTPI_K1_UnwrapIntoKeyHandle( - UNUSED uint32_t context, const uint8_t* wrapped_key, + uint32_t context UNUSED, const uint8_t* wrapped_key, size_t wrapped_key_length, SymmetricKeyType key_type, WTPI_K1_SymmetricKey_Handle* out_key_handle) { RETURN_INVALID_CONTEXT_IF_NULL(wrapped_key); @@ -704,6 +745,11 @@ OEMCryptoResult WTPI_K1_FreeKeyHandle(WTPI_K1_SymmetricKey_Handle key_handle) { return OEMCrypto_SUCCESS; } + if (key_handle->op_cbc != TEE_HANDLE_NULL) + TEE_FreeOperation(key_handle->op_cbc); + if (key_handle->op_ecb != TEE_HANDLE_NULL) + TEE_FreeOperation(key_handle->op_ecb); + TEE_Free(key_handle->key); TEE_Free(key_handle); diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c index df6e0f9..697c217 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c @@ -7,6 +7,7 @@ #include #include #include +#include "cose_util.h" #include "der_parse.h" #include "malloc.h" #include "oemcrypto_check_macros.h" @@ -15,13 +16,18 @@ #include "oemcrypto_math.h" #include "oemcrypto_overflow.h" #include "tos_shared_memory_interface.h" +#include "util/der_parse.h" #include "wtpi_abort_interface.h" #include "wtpi_config_macros.h" #include "wtpi_crypto_asymmetric_interface.h" +#include "wtpi_device_key_access_interface.h" #define ECC_KEY_MAX_BITS 521 #define ECC_KEY_MAX_BYTES ((ECC_KEY_MAX_BITS + 7) / 8 + 1) #define PKCS8_2048BIT_RSA_KEY_MAX_SIZE 1300 +#define BCC_PAYLOAD_MAX_SIZE 2048 +#define COSE_SIGN1_MAX_SIZE 2048 +#define RSA_PUBLIC_KEY_DER_EXTRA 38 typedef struct tee_asymmetric_key_handle { TEE_ObjectHandle key_handle; @@ -116,6 +122,8 @@ cleanup: static OEMCryptoResult Helper_CreateECCKeyHandle( const uint8_t* serialized_bytes, size_t size, WTPI_AsymmetricKey_Handle* key_handle) { + TEE_Result res = TEE_SUCCESS; + TEE_Attribute attrs[4]; WTPI_AsymmetricKey_Handle sess = TEE_Malloc(sizeof(tee_asymmetric_key_handle), TEE_MALLOC_FILL_ZERO); if (sess == NULL) { @@ -123,7 +131,6 @@ static OEMCryptoResult Helper_CreateECCKeyHandle( return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - TEE_Result res = TEE_SUCCESS; rfc5915_eckey* sess_key = TEE_Malloc(sizeof(rfc5915_eckey), TEE_MALLOC_FILL_ZERO); if (sess_key == TEE_HANDLE_NULL) { @@ -155,9 +162,6 @@ static OEMCryptoResult Helper_CreateECCKeyHandle( goto cleanup; } - DMSG("Private key length is %d", sess_key->private_val_len); - - TEE_Attribute attrs[4]; TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PRIVATE_VALUE, sess_key->private_val, sess_key->private_val_len); TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_X, @@ -216,13 +220,6 @@ OEMCryptoResult WTPI_CreateAsymmetricKeyHandle( return OEMCrypto_ERROR_NOT_IMPLEMENTED; } -OEMCryptoResult WTPI_CreateTestRSAKeyHandle( - WTPI_AsymmetricKey_Handle* key_handle UNUSED) { - // TODO: wtpi_test_impl/crypto_interface has this unimplemented. What is - // it supposed to do? - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - OEMCryptoResult WTPI_FreeAsymmetricKeyHandle( WTPI_AsymmetricKey_Handle key_handle) { if (key_handle == TEE_HANDLE_NULL) { @@ -255,7 +252,7 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, if (padding_scheme == kSign_RSASSA_PSS) { // generate SHA1 digest uint8_t digest[20]; - TEE_OperationHandle sha1_op; + TEE_OperationHandle sha1_op = TEE_HANDLE_NULL; TEE_Result res = TEE_AllocateOperation(&sha1_op, TEE_ALG_SHA1, TEE_MODE_DIGEST, 0); if (res != TEE_SUCCESS) { @@ -280,7 +277,7 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, } TEE_FreeOperation(sha1_op); - TEE_OperationHandle sign_op_handle; + TEE_OperationHandle sign_op_handle = TEE_HANDLE_NULL; res = TEE_AllocateOperation(&sign_op_handle, TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1, TEE_MODE_SIGN, key_info.keySize); @@ -306,8 +303,60 @@ OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, } TEE_FreeOperation(sign_op_handle); } else { - // TODO: add support for cast-specific RSA padding? - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + TEE_OperationHandle enc_op = TEE_HANDLE_NULL; + + // Allocate temp buffer to hold padded message. + uint8_t* temp_buf = + TEE_Malloc(key->max_signature_size, TEE_MALLOC_FILL_ZERO); + if (temp_buf == TEE_HANDLE_NULL) { + EMSG("Malloc failed, out of memory"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Pad in front of the message with block1 according to RFC 2313 + // 0x00 | 0x01 | 0xFF repeating | 0x00 | message + size_t temp_buf_len = key->max_signature_size; + temp_buf[0] = 0x00; + temp_buf[1] = 0x01; + TEE_MemFill(temp_buf + 2, 0xFF, temp_buf_len - 3 - message_length); + temp_buf[temp_buf_len - message_length - 1] = 0x00; + TEE_MemMove(temp_buf + temp_buf_len - message_length, message, + message_length); + + // Use NOPAD type, which ignores padding. Typically an operation wll either + // add padding (eg before encrypt) or expect to remove it (eg after + // decrypt). NOPAD just forces a raw RSA exponent+modulus operation. + uint32_t alg = TEE_ALG_RSA_NOPAD; + + // Using TEE_MODE_DECRYPT to use the private key in the RSA operation + TEE_Result res = TEE_AllocateOperation(&enc_op, alg, TEE_MODE_DECRYPT, + key->max_signature_size * 8); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateOperation failed with result 0x%x", res); + TEE_Free(temp_buf); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + res = TEE_SetOperationKey(enc_op, key->key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_SetOperationKey() failed with result 0x%x", res); + TEE_Free(temp_buf); + TEE_FreeOperation(enc_op); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + res = TEE_AsymmetricDecrypt(enc_op, NULL, 0, temp_buf, temp_buf_len, + signature, signature_length); + if (res != TEE_SUCCESS) { + EMSG("TEE_AsymmetricDecrypt failed with result 0x%x", res); + TEE_Free(temp_buf); + TEE_FreeOperation(enc_op); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + TEE_Free(temp_buf); + TEE_FreeOperation(enc_op); + return OEMCrypto_SUCCESS; } return OEMCrypto_SUCCESS; @@ -335,7 +384,7 @@ OEMCryptoResult WTPI_RSADecrypt(WTPI_AsymmetricKey_Handle key, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - TEE_OperationHandle decrypt_op_handle; + TEE_OperationHandle decrypt_op_handle = TEE_HANDLE_NULL; res = TEE_AllocateOperation(&decrypt_op_handle, TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1, TEE_MODE_DECRYPT, key_info.keySize); @@ -373,20 +422,16 @@ OEMCryptoResult WTPI_GetSignatureSize(WTPI_AsymmetricKey_Handle key, return OEMCrypto_SUCCESS; } -OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, - const uint8_t* message, size_t message_length, - uint8_t* signature, size_t* signature_length) { +static OEMCryptoResult Helper_ECCSign(WTPI_AsymmetricKey_Handle key, + const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length, + bool der_encode) { RETURN_INVALID_CONTEXT_IF_NULL(key); RETURN_INVALID_CONTEXT_IF_NULL(message); RETURN_INVALID_CONTEXT_IF_ZERO(message_length); RETURN_INVALID_CONTEXT_IF_NULL(signature_length); - size_t max_signature_size = key->max_signature_size; - if (signature == NULL || *signature_length < max_signature_size) { - *signature_length = max_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - uint32_t sha_algo = 0; size_t sha_length = SHA512_DIGEST_LENGTH; uint32_t sign_algo = 0; @@ -394,18 +439,22 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, case TEE_ECC_CURVE_NIST_P224: sha_algo = TEE_ALG_SHA224; sign_algo = TEE_ALG_ECDSA_P224; + sha_length = 224 / 8; break; case TEE_ECC_CURVE_NIST_P256: sha_algo = TEE_ALG_SHA256; sign_algo = TEE_ALG_ECDSA_P256; + sha_length = 256 / 8; break; case TEE_ECC_CURVE_NIST_P384: sha_algo = TEE_ALG_SHA384; sign_algo = TEE_ALG_ECDSA_P384; + sha_length = 384 / 8; break; case TEE_ECC_CURVE_NIST_P521: sha_algo = TEE_ALG_SHA512; sign_algo = TEE_ALG_ECDSA_P521; + sha_length = 512 / 8; break; default: // Other curve types are not supported at this time. @@ -414,9 +463,19 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + size_t max_signature_size = key->max_signature_size; + if (!der_encode) { + max_signature_size = sha_length * 2; + } + if (signature == NULL || *signature_length < max_signature_size) { + *signature_length = max_signature_size; + EMSG("max_signature_size is %zu", max_signature_size); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + // generate SHA digest uint8_t digest[SHA512_DIGEST_LENGTH]; - TEE_OperationHandle sha_op; + TEE_OperationHandle sha_op = TEE_HANDLE_NULL; TEE_Result res = TEE_AllocateOperation(&sha_op, sha_algo, TEE_MODE_DIGEST, 0); if (res != TEE_SUCCESS) { EMSG("TEE_AllocateOperation failed with result 0x%x", res); @@ -439,7 +498,7 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, TEE_FreeOperation(sha_op); // Sign digest - TEE_OperationHandle sign_op; + TEE_OperationHandle sign_op = TEE_HANDLE_NULL; res = TEE_AllocateOperation(&sign_op, sign_algo, TEE_MODE_SIGN, key_info.keySize); if (res != TEE_SUCCESS) { @@ -464,11 +523,24 @@ OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, } TEE_FreeOperation(sign_op); - // ASN1-encode the signature. - OEMCryptoResult encode_res = - EncodeECDSASignature(raw_sig, raw_sig_len, signature, signature_length); + OEMCryptoResult der_res = OEMCrypto_SUCCESS; + if (der_encode) { + // ASN1-encode the signature. + der_res = + EncodeECDSASignature(raw_sig, raw_sig_len, signature, signature_length); + } else { + TEE_MemMove(signature, raw_sig, raw_sig_len); + *signature_length = raw_sig_len; + } - return encode_res; + return der_res; +} + +OEMCryptoResult WTPI_ECCSign(WTPI_AsymmetricKey_Handle key, + const uint8_t* message, size_t message_length, + uint8_t* signature, size_t* signature_length) { + return Helper_ECCSign(key, message, message_length, signature, + signature_length, true); } OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, @@ -480,6 +552,13 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, RETURN_INVALID_CONTEXT_IF_NULL(key_source); RETURN_INVALID_CONTEXT_IF_NULL(session_key_length); + rfc5915_eckey ecc_key = {0}; + TEE_OperationHandle ecdh_op = TEE_HANDLE_NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + TEE_Result res = TEE_SUCCESS; + TEE_Attribute attrs[2]; + TEE_ObjectHandle derived_key = TEE_HANDLE_NULL; + // Determine algorithm type and required key size based on incoming public key // curve parameters uint32_t alg_type = 0; @@ -511,9 +590,8 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, } // Allocate operation handle for ECDH - TEE_OperationHandle ecdh_op; - TEE_Result res = TEE_AllocateOperation(&ecdh_op, alg_type, TEE_MODE_DERIVE, - key_size_bytes * 8); + res = TEE_AllocateOperation(&ecdh_op, alg_type, TEE_MODE_DERIVE, + key_size_bytes * 8); if (res != TEE_SUCCESS) { EMSG("TEE_AllocateOperation failed with result 0x%x, %d", res, alg_type); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -529,26 +607,19 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, // Decode public key data into struct object defined by der_parse.h // This step will allocate memory for public key x and y values, so be sure to // free them - rfc5915_eckey ecc_key; - OEMCryptoResult result = - DecodeECCPublicKey(key_source, key_source_length, &ecc_key); + result = DecodeECCPublicKey(key_source, key_source_length, &ecc_key); if (result != OEMCrypto_SUCCESS) { EMSG("DecodeECCPublicKey failed with result 0x%x", res); goto cleanup; } // Copy public x and y values into attribute arrays - TEE_Attribute attrs[2]; TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, ecc_key.public_x, ecc_key.public_x_len); TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, ecc_key.public_y, ecc_key.public_y_len); - TEE_Free(ecc_key.public_x); - TEE_Free(ecc_key.public_y); - // Allocate object handle for derived key - TEE_ObjectHandle derived_key; res = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, 2048, &derived_key); if (res != TEE_SUCCESS) { @@ -568,18 +639,18 @@ OEMCryptoResult WTPI_ECCDeriveSessionKey(WTPI_AsymmetricKey_Handle key, goto cleanup; } + TEE_Free(ecc_key.public_x); + TEE_Free(ecc_key.public_y); TEE_FreeOperation(ecdh_op); return OEMCrypto_SUCCESS; cleanup: + TEE_Free(ecc_key.public_x); + TEE_Free(ecc_key.public_y); TEE_FreeOperation(ecdh_op); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } -OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, uint8_t* public_key, @@ -591,6 +662,25 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( // This implementation generates RSA key. An alternative is ECC key. *key_type = DRM_RSA_PRIVATE_KEY; + // temporary buffers to hold the raw RSA data generated by GlobalPlatform + uint8_t raw_modulus[KEY_SIZE_2048]; + size_t raw_modulus_len = sizeof(raw_modulus); + uint8_t raw_pub[KEY_SIZE_2048]; + size_t raw_pub_len = sizeof(raw_pub); + uint8_t raw_priv[KEY_SIZE_2048]; + size_t raw_priv_len = sizeof(raw_priv); + + TEE_Result tee_res = TEE_SUCCESS; + TEE_ObjectHandle key = TEE_HANDLE_NULL; + + pkcs1_rsa rsa_key = {0}; + + // Encode private key to temporary buffer before wrapping + uint8_t encoded_priv[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE]; + size_t encoded_priv_len = MAX_WRAPPED_ASYMMETRIC_KEY_SIZE; + + size_t required_size = 0; + // Check buffer sizes. size_t required_wrapped_private_key_length = 0; OEMCryptoResult result = WTPI_GetWrappedAsymmetricKeySize( @@ -598,7 +688,8 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( &required_wrapped_private_key_length); if (result != OEMCrypto_SUCCESS) return result; - const size_t required_public_key_length = KEY_SIZE_2048; + const size_t required_public_key_length = + KEY_SIZE_2048 + RSA_PUBLIC_KEY_DER_EXTRA; if (wrapped_private_key == NULL || *wrapped_private_key_length < required_wrapped_private_key_length || public_key == NULL || *public_key_length < required_public_key_length) { @@ -607,8 +698,6 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( return OEMCrypto_ERROR_SHORT_BUFFER; } - TEE_Result tee_res; - TEE_ObjectHandle key; tee_res = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR, KEY_SIZE_2048 * 8, &key); if (tee_res != TEE_SUCCESS) { @@ -622,14 +711,6 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( goto cleanup; } - // temporary buffers to hold the raw RSA data generated by GlobalPlatform - uint8_t raw_modulus[KEY_SIZE_2048]; - size_t raw_modulus_len = sizeof(raw_modulus); - uint8_t raw_pub[KEY_SIZE_2048]; - size_t raw_pub_len = sizeof(raw_pub); - uint8_t raw_priv[KEY_SIZE_2048]; - size_t raw_priv_len = sizeof(raw_priv); - tee_res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_RSA_MODULUS, raw_modulus, &raw_modulus_len); if (tee_res != TEE_SUCCESS) { @@ -651,14 +732,12 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( goto cleanup; } - pkcs1_rsa rsa_key = { - .modulus = raw_modulus, - .modulus_len = raw_modulus_len, - .public_exp = raw_pub, - .public_exp_len = raw_pub_len, - .private_exp = raw_priv, - .private_exp_len = raw_priv_len, - }; + rsa_key.modulus = raw_modulus; + rsa_key.modulus_len = raw_modulus_len; + rsa_key.public_exp = raw_pub; + rsa_key.public_exp_len = raw_pub_len; + rsa_key.private_exp = raw_priv; + rsa_key.private_exp_len = raw_priv_len; // Encode public key directly to output parameters result = EncodeRSAPublicKey(&rsa_key, public_key, public_key_length); @@ -667,10 +746,6 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( goto cleanup; } - // Encode private key to temporary buffer before wrapping - uint8_t encoded_priv[MAX_WRAPPED_ASYMMETRIC_KEY_SIZE]; - size_t encoded_priv_len = MAX_WRAPPED_ASYMMETRIC_KEY_SIZE; - result = EncodeRSAPrivateKey(&rsa_key, encoded_priv, &encoded_priv_len); if (result != OEMCrypto_SUCCESS) { EMSG("EncodeRSAPrivateKey failed"); @@ -684,7 +759,6 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( encoded_priv[encoded_priv_len++] = 0; } - size_t required_size = 0; result = WTPI_GetWrappedAsymmetricKeySize( encoded_priv_len, DRM_RSA_PRIVATE_KEY, &required_size); if (result != OEMCrypto_SUCCESS) { @@ -709,9 +783,195 @@ cleanup: return OEMCrypto_ERROR_UNKNOWN_FAILURE; } +// Generate device-unique asymmetric key handle that is consistent across +// reboots. ECDSA +static OEMCryptoResult Helper_GetDeviceAsymmetricKeyIntoHandle( + AsymmetricKeyType* key_type, + WTPI_AsymmetricKey_Handle* private_key_handle) { + RETURN_INVALID_CONTEXT_IF_NULL(key_type); + RETURN_INVALID_CONTEXT_IF_NULL(private_key_handle); + + TEE_Attribute attrs[4]; + WTPI_AsymmetricKey_Handle sess = TEE_HANDLE_NULL; + TEE_Result res = TEE_SUCCESS; + OEMCryptoResult result = OEMCrypto_SUCCESS; + // Get device key + const uint8_t* device_key = WTPI_GetDeviceKey(); + const KeySize device_key_len = WTPI_GetDeviceKeySize(); + if (device_key == NULL || device_key_len == 0) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Use as seed to ECDSA + rfc5915_eckey* sess_key = + TEE_Malloc(sizeof(rfc5915_eckey), TEE_MALLOC_FILL_ZERO); + if (sess_key == TEE_HANDLE_NULL) { + EMSG("Malloc failed, out of memory"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + result = DeriveEccKey(device_key, device_key_len, TEE_ECC_CURVE_NIST_P256, + sess_key); + if (result != OEMCrypto_SUCCESS) { + goto cleanup; + } + + sess = TEE_Malloc(sizeof(tee_asymmetric_key_handle), TEE_MALLOC_FILL_ZERO); + if (sess == NULL) { + EMSG("Malloc failed, out of memory"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + sess->max_signature_size = sess_key->max_signature_size; + sess->ecc_curve_type = sess_key->ecc_curve_type; + + res = TEE_AllocateTransientObject( + TEE_TYPE_ECDSA_KEYPAIR, sess_key->private_val_len * 8, &sess->key_handle); + if (res != TEE_SUCCESS) { + EMSG("TEE_AllocateTransientObject() failed with result 0x%x", res); + goto cleanup; + } + + TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PRIVATE_VALUE, + sess_key->private_val, sess_key->private_val_len); + TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_X, + sess_key->public_x, sess_key->public_x_len); + TEE_InitRefAttribute(&attrs[2], TEE_ATTR_ECC_PUBLIC_VALUE_Y, + sess_key->public_y, sess_key->public_y_len); + TEE_InitValueAttribute(&attrs[3], TEE_ATTR_ECC_CURVE, + sess_key->ecc_curve_type, 0); + + res = TEE_PopulateTransientObject(sess->key_handle, + (const TEE_Attribute*)(&attrs), 4); + if (res != TEE_SUCCESS) { + EMSG("TEE_PopulateTransientObject() failed with result 0x%x", res); + goto cleanup; + } + + *key_type = DRM_ECC_PRIVATE_KEY; + +cleanup: + if (sess_key != TEE_HANDLE_NULL) { + TEE_Free(sess_key->private_val); + TEE_Free(sess_key->public_x); + TEE_Free(sess_key->public_y); + } + TEE_Free(sess_key); + + if (res != TEE_SUCCESS) { + WTPI_FreeAsymmetricKeyHandle(sess); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + *private_key_handle = sess; + return OEMCrypto_SUCCESS; +} + OEMCryptoResult WTPI_DeviceKeyCoseSign1(const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + RETURN_INVALID_CONTEXT_IF_NULL(message); + RETURN_INVALID_CONTEXT_IF_ZERO(message_length); + RETURN_INVALID_CONTEXT_IF_NULL(signature_length); + + if (message_length > 500) { + return OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } + + // 64 bytes for ECDSA signature, 11 bytes for CBOR fields + size_t required_signature_length = message_length + 64 + 11; + if (signature == NULL || *signature_length < required_signature_length) { + *signature_length = required_signature_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + // Generate ECDSA key, using device key as seed + AsymmetricKeyType key_type; + WTPI_AsymmetricKey_Handle private_key_handle; + OEMCryptoResult result = + Helper_GetDeviceAsymmetricKeyIntoHandle(&key_type, &private_key_handle); + if (result != OEMCrypto_SUCCESS) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // CoseSign1 message using ECDSA key + size_t encoded_size = 0; + result = DiceCoseSignAndEncodeSign1(message, message_length, key_type, + private_key_handle, *signature_length, + signature, &encoded_size); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + if (result != OEMCrypto_SUCCESS) return result; + + *signature_length = encoded_size; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetMaxDeviceKeyCoseSign1Size(size_t* out_length) { + RETURN_INVALID_CONTEXT_IF_NULL(out_length); + *out_length = COSE_SIGN1_MAX_SIZE; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // The |out| buffer length check is delegated to the BuildBootCertificateChain + // call below. + + AsymmetricKeyType key_type; + WTPI_AsymmetricKey_Handle private_key_handle; + OEMCryptoResult result = + Helper_GetDeviceAsymmetricKeyIntoHandle(&key_type, &private_key_handle); + if (result != OEMCrypto_SUCCESS) return result; + + // Only ECDSA key is expected for now. + if (key_type != DRM_ECC_PRIVATE_KEY) { + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + // extract public key, P256 hardcoded to 64 bytes long + uint8_t public_key[64]; + size_t public_key_length = sizeof(public_key); + size_t buf_size = 32; + TEE_Result tee_res = TEE_GetObjectBufferAttribute( + private_key_handle->key_handle, TEE_ATTR_ECC_PUBLIC_VALUE_X, public_key, + &buf_size); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute() failed with result 0x%x", tee_res); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + tee_res = TEE_GetObjectBufferAttribute(private_key_handle->key_handle, + TEE_ATTR_ECC_PUBLIC_VALUE_Y, + public_key + 32, &buf_size); + if (tee_res != TEE_SUCCESS) { + EMSG("TEE_GetObjectBufferAttribute() failed with result 0x%x", tee_res); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + result = BuildBootCertificateChain(public_key, public_key_length, key_type, + private_key_handle, out, out_length); + WTPI_FreeAsymmetricKeyHandle(private_key_handle); + return result; +} + +OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { + RETURN_INVALID_CONTEXT_IF_NULL(out_length); + *out_length = BCC_PAYLOAD_MAX_SIZE; + return OEMCrypto_SUCCESS; +} + +// For cose utility +// CBOR ECDSA signatures should not be DER encoded, just concatenated (R,S) +OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, + AsymmetricKeyType key_type UNUSED, + const uint8_t* message, size_t message_size, + uint8_t* signature, size_t* signature_length) { + return Helper_ECCSign(key, message, message_size, signature, signature_length, + false); } diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c index 363361d..b57ca69 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c @@ -3,11 +3,12 @@ * source code may only be used and distributed under the Widevine * License Agreement. */ -#include #include #include #include +#include "crypto_common.h" #include "malloc.h" +#include "odk_endian.h" #include "oemcrypto_check_macros.h" #include "oemcrypto_key_types.h" #include "oemcrypto_math.h" @@ -16,10 +17,7 @@ #include "wtpi_abort_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" #include "wtpi_decrypt_sample_interface.h" - -OEMCryptoResult Helper_AESEncryptBlock_ECB(WTPI_K1_SymmetricKey_Handle key, - const uint8_t* input, - uint8_t* output); +#include "wtpi_secure_buffer_access_interface.h" static OEMCryptoResult WTPI_DecryptToOutputBuffer_CTR( WTPI_K1_SymmetricKey_Handle key, const uint8_t* initial_iv, @@ -41,19 +39,25 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CTR( return OEMCrypto_ERROR_INVALID_CONTEXT; } + uint8_t* dest = NULL; if (out->type == OPK_SECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } else if (out->type != OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + const OEMCryptoResult result = + WTPI_GetSecureBufferAddress(out->buffer.secure, output_offset, &dest); + if (result != OEMCrypto_SUCCESS) return result; + } else if (out->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + dest = out->buffer.clear_insecure + output_offset; + } else { return OEMCrypto_ERROR_INVALID_CONTEXT; } - uint8_t* const dest = out->buffer.clear_insecure + output_offset; uint8_t iv[AES_BLOCK_SIZE]; TEE_MemMove(iv, &initial_iv[0], AES_BLOCK_SIZE); size_t l = 0; while (l < size) { uint8_t aes_output[AES_BLOCK_SIZE]; - Helper_AESEncryptBlock_ECB(key, iv, aes_output); + const OEMCryptoResult result = + Helper_AESEncryptBlock_ECB(key, iv, aes_output); + if (result != OEMCrypto_SUCCESS) return result; for (uint8_t n = block_offset; n < AES_BLOCK_SIZE && l < size; ++n, ++l) { dest[l] = aes_output[n] ^ in[l]; } @@ -70,6 +74,7 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CBC( WTPI_K1_SymmetricKey_Handle key, const uint8_t* initial_iv, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* in, size_t size, const OPK_OutputBuffer* out, size_t output_offset) { + if (size == 0) return OEMCrypto_SUCCESS; size_t total_size; if (OPK_AddOverflowUX(output_offset, size, &total_size)) { return OEMCrypto_ERROR_INVALID_CONTEXT; @@ -78,21 +83,27 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CBC( RETURN_INVALID_CONTEXT_IF_NULL(initial_iv); RETURN_INVALID_CONTEXT_IF_NULL(pattern); RETURN_INVALID_CONTEXT_IF_NULL(in); - RETURN_INVALID_CONTEXT_IF_ZERO(size); RETURN_INVALID_CONTEXT_IF_NULL(out); RETURN_INVALID_CONTEXT_IF_NULL(key); if (total_size > out->size) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - // TODO: somehow add support for secure buffers + // if (key->key_size != KEY_SIZE_128 || key->key_size != KEY_SIZE_256) { + // return OEMCrypto_ERROR_UNKNOWN_FAILURE; + // } + + uint8_t* dest = NULL; if (out->type == OPK_SECURE_OUTPUT_BUFFER) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } else if (out->type != OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + const OEMCryptoResult result = + WTPI_GetSecureBufferAddress(out->buffer.secure, output_offset, &dest); + if (result != OEMCrypto_SUCCESS) return result; + } else if (out->type == OPK_CLEAR_INSECURE_OUTPUT_BUFFER) { + dest = out->buffer.clear_insecure + output_offset; + } else { return OEMCrypto_ERROR_INVALID_CONTEXT; } - uint8_t* const dest = out->buffer.clear_insecure + output_offset; const size_t pattern_length = pattern->encrypt + pattern->skip; uint8_t iv[AES_BLOCK_SIZE]; @@ -110,28 +121,14 @@ static OEMCryptoResult WTPI_DecryptToOutputBuffer_CBC( TEE_MemMove(&dest[offset], &in[offset], next_block_size); } else { uint8_t aes_output[AES_BLOCK_SIZE]; - /* Save the iv for the next block, in case |in| is in the same buffer as |dest|. */ TEE_MemMove(next_iv, &in[offset], AES_BLOCK_SIZE); - // TODO: check key size - - /* NOTE: the next few lines can be used instead of WTPI_AESCBCDecrypt, - * just to show parity with wtpi_test_impl implementation - */ - // OEMCryptoResult result = - // Helper_AESEncryptBlock_ECB(key, &in[offset], aes_output); - // if (result != OEMCrypto_SUCCESS) return result; - // for (size_t n = 0; n < AES_BLOCK_SIZE; n++) { - // dest[offset + n] = aes_output[n] ^ iv[n]; - // } - OEMCryptoResult result = WTPI_C1_AESCBCDecrypt( - key, KEY_SIZE_128, &in[offset], AES_BLOCK_SIZE, iv, aes_output); + key, key->key_size, &in[offset], AES_BLOCK_SIZE, iv, aes_output); if (result != OEMCrypto_SUCCESS) return result; TEE_MemMove(&dest[offset], aes_output, AES_BLOCK_SIZE); - TEE_MemMove(iv, next_iv, AES_BLOCK_SIZE); } offset += next_block_size; @@ -153,8 +150,8 @@ UBSAN_IGNORE_UNSIGNED_OVERFLOW static void AdvanceIVandCounter( /* The truncation here is intentional. */ const size_t increment = bytes / AES_BLOCK_SIZE; /* The potential overflow here is intentional. */ - counter = be64toh(counter) + increment; - counter = htobe64(counter); + counter = oemcrypto_be64toh(counter) + increment; + counter = oemcrypto_htobe64(counter); TEE_MemMove(&(*subsample_iv)[kCounterIndex], &counter, kCounterSize); } @@ -255,6 +252,7 @@ OEMCryptoResult WTPI_DecryptSample( subsample->num_bytes_encrypted, &subsample_length)) { return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (subsample_length == 0) continue; size_t current_offset; if (OPK_AddOverflowUX(starting_output_offset, offset, ¤t_offset)) { diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c index 6d93271..1a60282 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c @@ -60,6 +60,7 @@ static TEE_Result read_raw_object(const char* obj_id, size_t obj_id_length, TEE_ObjectHandle object; TEE_ObjectInfo object_info; TEE_Result res; + size_t read_bytes = 0; uint8_t* data = TEE_Malloc(out_length, 0); if (!data) return TEE_ERROR_OUT_OF_MEMORY; @@ -85,7 +86,6 @@ static TEE_Result read_raw_object(const char* obj_id, size_t obj_id_length, goto exit; } - size_t read_bytes = 0; res = TEE_ReadObjectData(object, data, object_info.dataSize, &read_bytes); if (res == TEE_SUCCESS) TEE_MemMove(out, data, read_bytes); if (res != TEE_SUCCESS || read_bytes != object_info.dataSize) { diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c index 8ca08d5..f0322ab 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_root_of_trust_layer1.c @@ -9,7 +9,9 @@ #include #include #include +#include +#include "cose_util.h" #include "odk_endian.h" #include "oemcrypto_key_types.h" #include "renewal_util.h" @@ -178,9 +180,60 @@ OEMCryptoResult WTPI_ValidateKeybox(void) { return OEMCrypto_SUCCESS; } +static OEMCryptoResult GetProv4DeviceID(uint8_t* device_id, + size_t device_id_length) { + if (device_id == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (device_id_length < SHA256_DIGEST_LENGTH) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + size_t required_bcc_payload_size = 0; + OEMCryptoResult result = + WTPI_GetMaxBootCertificateChainSize(&required_bcc_payload_size); + if (result != OEMCrypto_SUCCESS) { + LOGE("Failed to get max bcc size: %u", result); + return result; + } + + // Device ID with provisioning 4 in this reference implementation is hash of + // (encoded) device public key from BCC. + uint8_t* bcc_buffer = (uint8_t*)TEE_Malloc(required_bcc_payload_size, 0); + if (bcc_buffer == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + memset(bcc_buffer, 0, required_bcc_payload_size); + size_t bcc_size = required_bcc_payload_size; + result = WTPI_GetBootCertificateChain(bcc_buffer, &bcc_size); + if (result != OEMCrypto_SUCCESS) { + TEE_Free(bcc_buffer); + return result; + } + + uint8_t* dk_pub_buffer = (uint8_t*)TEE_Malloc(required_bcc_payload_size, 0); + if (dk_pub_buffer == NULL) { + TEE_Free(bcc_buffer); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + memset(dk_pub_buffer, 0, required_bcc_payload_size); + size_t dk_pub_size = required_bcc_payload_size; + result = GetDevicePublicKeyFromBcc(bcc_buffer, bcc_size, dk_pub_buffer, + &dk_pub_size); + TEE_Free(bcc_buffer); + if (result != OEMCrypto_SUCCESS) { + TEE_Free(dk_pub_buffer); + return result; + } + + result = WTPI_C1_SHA256(dk_pub_buffer, dk_pub_size, device_id); + TEE_Free(dk_pub_buffer); + return result; +} + OEMCryptoResult WTPI_GetDeviceID(uint8_t* device_id, size_t device_id_length) { if (device_id == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (WTPI_GetProvisioningMethod() == OEMCrypto_BootCertificateChain) { + return GetProv4DeviceID(device_id, device_id_length); + } + if (WTPI_GetProvisioningMethod() != OEMCrypto_Keybox) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } @@ -196,7 +249,9 @@ OEMCryptoResult WTPI_GetDeviceIDLength(size_t* device_id_length) { if (device_id_length == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (WTPI_GetProvisioningMethod() == OEMCrypto_Keybox) { + if (WTPI_GetProvisioningMethod() == OEMCrypto_BootCertificateChain) { + *device_id_length = SHA256_DIGEST_LENGTH; + } else if (WTPI_GetProvisioningMethod() == OEMCrypto_Keybox) { *device_id_length = KEYBOX_DEVICE_ID_SIZE; } else { return OEMCrypto_ERROR_NOT_IMPLEMENTED; diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile index 803a114..4729e6f 100644 --- a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile @@ -35,4 +35,4 @@ endif .DEFAULT_GOAL := build_and_copy .PHONY: build_and_copy build_and_copy: all - -cp $(O)/*.{elf,ta,dmp,map} $(O_BASE)/ + cp $(O)/$(BINARY).ta $(O_BASE)/ diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c index b442337..8829d65 100644 --- a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/oemcrypto_ta.c @@ -83,7 +83,7 @@ void TA_CloseSessionEntryPoint(void __maybe_unused* session_context) { static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { uint32_t expected_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_MEMREF_INOUT, - TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE); if (param_types != expected_param_types) { DMSG("Bad parameters\n"); @@ -98,9 +98,9 @@ static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { return TEE_ERROR_BAD_PARAMETERS; } - size_t request_size = params[1].memref.size; + size_t request_size = (size_t)(params[2].value.a); if (request_size > OPK_TRANSPORT_MESSAGE_SIZE) { - DMSG("Size too large. Input is %d, limit is %d\n", request_size, + DMSG("Size too large. Input is %zu, limit is %d\n", request_size, OPK_TRANSPORT_MESSAGE_SIZE); return TEE_ERROR_BAD_PARAMETERS; } diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk index cee202f..dd013a5 100644 --- a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk @@ -25,7 +25,8 @@ include $(CDM_DIR)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/sources.mk # srcs-y, global-incdirs-y, and libnames are used by the OP-TEE TA dev kit # build system srcs-y += \ - oemcrypto_ta.c \ + oemcrypto_ta.c \ + $(serialization_dir)/tee/tee_tos_stubs.c \ $(opk_base_ta_sources) \ $(wtpi_impl_sources) \ @@ -33,8 +34,16 @@ global-incdirs-y += \ $(opk_base_ta_includes) \ $(wtpi_impl_includes) \ +# Optional provisioning method setting for pre-v18 OPK +ifdef OPTEE_PROVISIONING_METHOD +cppflags-y += \ + -DOPTEE_PROVISIONING_METHOD=$(OPTEE_PROVISIONING_METHOD) \ + +endif + cppflags-y += \ -DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \ + -Wno-switch-default \ libnames += \ $(wtpi_impl_libs) diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile index 580531b..a25f452 100644 --- a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile @@ -35,4 +35,4 @@ endif .DEFAULT_GOAL := build_and_copy .PHONY: build_and_copy build_and_copy: all - -cp $(O)/*.{elf,ta,dmp,map} $(O_BASE)/ + cp $(O)/$(BINARY).ta $(O_BASE)/ diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk index 540dcb7..4f1b525 100644 --- a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk @@ -38,3 +38,14 @@ global-incdirs-y += \ libnames += \ $(wtpi_impl_libs) + +# Optional provisioning method setting for pre-v18 OPK +ifdef OPTEE_PROVISIONING_METHOD +cppflags-y += \ + -DOPTEE_PROVISIONING_METHOD=$(OPTEE_PROVISIONING_METHOD) \ + +endif + +cppflags-y += \ + -DWTPI_BUILD_INFO=\"$(WTPI_BUILD_INFO)\" \ + -Wno-switch-default \ diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c index c13a98f..af07f79 100644 --- a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/wtpi_test_ta.c @@ -77,7 +77,7 @@ void TA_CloseSessionEntryPoint(void __maybe_unused* session_context) { static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { uint32_t expected_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_MEMREF_INOUT, - TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE); if (param_types != expected_param_types) { DMSG("Bad parameters\n"); @@ -92,9 +92,9 @@ static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { return TEE_ERROR_BAD_PARAMETERS; } - size_t request_size = params[1].memref.size; + size_t request_size = (size_t)(params[2].value.a); if (request_size > OPK_TRANSPORT_MESSAGE_SIZE) { - DMSG("Size too large. Input is %d, limit is %d\n", request_size, + DMSG("Size too large. Input is %zu, limit is %d\n", request_size, OPK_TRANSPORT_MESSAGE_SIZE); return TEE_ERROR_BAD_PARAMETERS; } @@ -106,7 +106,7 @@ static TEE_Result HandleRequest(uint32_t param_types, TEE_Param params[4]) { static uint8_t local_buffer[OPK_TRANSPORT_MESSAGE_SIZE]; memcpy(local_buffer, transport_buffer_, request_size); - DMSG("Request size is %d\n", request_size); + DMSG("Request size is %zu\n", request_size); ODK_Message request = ODK_Message_Create(local_buffer, request_size); ODK_Message_SetSize(&request, request_size); ODK_Message response; diff --git a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c b/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c index 36ce71b..8505cdb 100644 --- a/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c +++ b/oemcrypto/opk/ports/trusty/ta/interface_impls/wtpi_crypto_and_key_management_layer1_openssl.c @@ -24,6 +24,7 @@ #include "OEMCryptoCENCCommon.h" #include "crypto_util.h" +#include "odk_util.h" #include "oemcrypto_compiler_attributes.h" #include "oemcrypto_object_table.h" #include "oemcrypto_overflow.h" @@ -276,8 +277,8 @@ static OEMCryptoResult VerifyAndDecryptKey( computed_signature)) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (memcmp(wrapped->signature, computed_signature, SHA256_DIGEST_LENGTH) != - 0) { + if (crypto_memcmp(wrapped->signature, computed_signature, + SHA256_DIGEST_LENGTH) != 0) { return OEMCrypto_ERROR_SIGNATURE_FAILURE; } @@ -491,7 +492,8 @@ OEMCryptoResult WTPI_C1_HMAC_SHA256_Verify( key_handle, message, message_length, computed_signature); if (result != OEMCrypto_SUCCESS) return result; - if (memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != 0) { + if (crypto_memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH) != + 0) { return OEMCrypto_ERROR_SIGNATURE_FAILURE; } return OEMCrypto_SUCCESS; diff --git a/oemcrypto/opk/ports/trusty/ta/rules.mk b/oemcrypto/opk/ports/trusty/ta/rules.mk index eba6526..b9b6183 100644 --- a/oemcrypto/opk/ports/trusty/ta/rules.mk +++ b/oemcrypto/opk/ports/trusty/ta/rules.mk @@ -89,6 +89,7 @@ MODULE_SRCS += \ $(SERIALIZATION_DIR)/common/shared_buffer_allocator.c \ $(SERIALIZATION_DIR)/tee/GEN_dispatcher.c \ $(SERIALIZATION_DIR)/tee/GEN_tee_serializer.c \ + $(SERIALIZATION_DIR)/tee/special_case_request_handlers.c \ $(SERIALIZATION_DIR)/tee/tee_os_type.c \ $(SERIALIZATION_DIR)/tee/tee_version.c \ $(SERIALIZATION_DIR)/tee/tee_special_cases.c \ diff --git a/oemcrypto/opk/serialization/common/GEN_common_serializer.c b/oemcrypto/opk/serialization/common/GEN_common_serializer.c index 7956e1b..131ba96 100644 --- a/oemcrypto/opk/serialization/common/GEN_common_serializer.c +++ b/oemcrypto/opk/serialization/common/GEN_common_serializer.c @@ -127,6 +127,16 @@ bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value) { } } +bool Is_Valid_OEMCrypto_ProvisioningRenewalType(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_NoRenewal */ + case 1: /* OEMCrypto_RenewalACert */ + return true; + default: + return false; + } +} + bool Is_Valid_OEMCrypto_LicenseType(uint32_t value) { switch (value) { case 0: /* OEMCrypto_ContentLicense */ @@ -612,6 +622,21 @@ void OPK_UnpackNullable_OEMCrypto_KeyRefreshObject( OPK_Unpack_OEMCrypto_KeyRefreshObject(msg, *value); } } +void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value) { + OPK_PackBoolValue(msg, value == NULL); + if (value) { + OPK_Pack_OEMCrypto_EntitledContentKeyObject(msg, value); + } +} +void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value) { + if (OPK_UnpackIsNull(msg)) { + *value = NULL; + } else { + OPK_Unpack_OEMCrypto_EntitledContentKeyObject(msg, *value); + } +} void OPK_PackNullable_OEMCrypto_CENCEncryptPatternDesc( ODK_Message* msg, const OEMCrypto_CENCEncryptPatternDesc* value) { OPK_PackBoolValue(msg, value == NULL); @@ -688,18 +713,3 @@ void OPK_UnpackAlloc_int(ODK_Message* msg, int** value) { OPK_Unpack_int(msg, *value); } } -void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value) { - OPK_PackBoolValue(msg, value == NULL); - if (value) { - OPK_Pack_OEMCrypto_EntitledContentKeyObject(msg, value); - } -} -void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value) { - if (OPK_UnpackIsNull(msg)) { - *value = NULL; - } else { - OPK_Unpack_OEMCrypto_EntitledContentKeyObject(msg, *value); - } -} diff --git a/oemcrypto/opk/serialization/common/GEN_common_serializer.h b/oemcrypto/opk/serialization/common/GEN_common_serializer.h index 6146680..a29a1d1 100644 --- a/oemcrypto/opk/serialization/common/GEN_common_serializer.h +++ b/oemcrypto/opk/serialization/common/GEN_common_serializer.h @@ -20,6 +20,7 @@ extern "C" { bool SuccessResult(OEMCryptoResult result); bool Is_Valid_OEMCryptoResult(uint32_t value); bool Is_Valid_OEMCrypto_Usage_Entry_Status(uint32_t value); +bool Is_Valid_OEMCrypto_ProvisioningRenewalType(uint32_t value); bool Is_Valid_OEMCrypto_LicenseType(uint32_t value); bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value); bool Is_Valid_OEMCryptoBufferType(uint32_t value); @@ -96,6 +97,10 @@ void OPK_PackNullable_OEMCrypto_KeyRefreshObject( ODK_Message* msg, const OEMCrypto_KeyRefreshObject* value); void OPK_UnpackNullable_OEMCrypto_KeyRefreshObject( ODK_Message* msg, OEMCrypto_KeyRefreshObject** value); +void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value); +void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( + ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value); void OPK_PackNullable_OEMCrypto_CENCEncryptPatternDesc( ODK_Message* msg, const OEMCrypto_CENCEncryptPatternDesc* value); void OPK_UnpackNullable_OEMCrypto_CENCEncryptPatternDesc( @@ -112,10 +117,6 @@ void OPK_UnpackAlloc_OEMCrypto_DestBufferDesc(ODK_Message* msg, void OPK_PackNullable_int(ODK_Message* msg, const int* value); void OPK_UnpackNullable_int(ODK_Message* msg, int** value); void OPK_UnpackAlloc_int(ODK_Message* msg, int** value); -void OPK_PackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, const OEMCrypto_EntitledContentKeyObject* value); -void OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject( - ODK_Message* msg, OEMCrypto_EntitledContentKeyObject** value); #ifdef __cplusplus } // extern "C" #endif diff --git a/oemcrypto/opk/serialization/common/bump_allocator.c b/oemcrypto/opk/serialization/common/bump_allocator.c index 1ffeec5..e2ea685 100644 --- a/oemcrypto/opk/serialization/common/bump_allocator.c +++ b/oemcrypto/opk/serialization/common/bump_allocator.c @@ -26,19 +26,28 @@ static size_t buffer_offset = 0; * allocations are aligned to 16 byte boundaries */ UBSAN_IGNORE_UNSIGNED_OVERFLOW void* OPK_BumpAllocate(size_t nbytes) { - size_t alignment_pad = (ALIGN - buffer_offset) & (ALIGN - 1); - size_t new_offset = 0; - if (odk_add_overflow_ux(buffer_offset, nbytes + alignment_pad, &new_offset) || - (new_offset > BUFFER_SIZE)) { - LOGE("failed: %zu / %d bytes free, requested %zu", - BUFFER_SIZE - buffer_offset, BUFFER_SIZE, nbytes); + /* Calcuate the next aligned address to be allocated from. The ALIGN must be a + * power of two for the calculation below to work. See details at + * https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding */ + uint8_t* const next_aligned_address = + (uint8_t*)(((uintptr_t)buffer + buffer_offset + ALIGN - 1) & + ~(ALIGN - 1)); + const size_t next_aligned_offset = next_aligned_address - buffer; + if (next_aligned_offset >= BUFFER_SIZE) { + LOGE("failed: the next aligned address out of range"); return NULL; } - LOGV("allocated %zu bytes at offset %zu, %zu free", nbytes, buffer_offset, - BUFFER_SIZE - buffer_offset); - uint8_t* result = buffer + buffer_offset; + size_t new_offset = 0; + if (odk_add_overflow_ux(next_aligned_offset, nbytes, &new_offset) || + (new_offset > BUFFER_SIZE)) { + LOGE("failed: %zu / %d bytes free, requested %zu", + BUFFER_SIZE - next_aligned_offset, BUFFER_SIZE, nbytes); + return NULL; + } + LOGV("allocated %zu bytes at offset %zu, %zu free", nbytes, + next_aligned_offset, BUFFER_SIZE - new_offset); buffer_offset = new_offset; - return result; + return next_aligned_address; } void OPK_BumpAllocator_Reset(void) { diff --git a/oemcrypto/opk/serialization/common/common_special_cases.c b/oemcrypto/opk/serialization/common/common_special_cases.c index d0ea673..edd2019 100644 --- a/oemcrypto/opk/serialization/common/common_special_cases.c +++ b/oemcrypto/opk/serialization/common/common_special_cases.c @@ -47,10 +47,8 @@ void OPK_Pack_OEMCrypto_DestBufferDesc(ODK_Message* message, break; } case OEMCrypto_BufferType_Secure: - if (OPK_Get_OSType() == OPK_RICH_OS) { - /* let the secure buffer OS interface pack the buffer info as needed */ - TOS_SecureBuffer_Pack(message, obj); - } + /* let the secure buffer OS interface pack the buffer info as needed */ + TOS_SecureBuffer_Pack(message, obj); break; case OEMCrypto_BufferType_Direct: OPK_Pack_bool(message, &obj->buffer.direct.is_video); @@ -78,9 +76,9 @@ void OPK_Unpack_OEMCrypto_DestBufferDesc(ODK_Message* message, /* map */ true, /* is output */ true); break; case OEMCrypto_BufferType_Secure: + /* let the secure buffer OS interface unpack the buffer info */ + TOS_SecureBuffer_Unpack(message, obj); if (OPK_Get_OSType() == OPK_TRUSTED_OS) { - /* let the secure buffer OS interface unpack the buffer info */ - TOS_SecureBuffer_Unpack(message, obj); /* double-check the size */ if (!TOS_SecureBuffer_CheckSize( obj->buffer.secure.secure_buffer, @@ -92,5 +90,8 @@ void OPK_Unpack_OEMCrypto_DestBufferDesc(ODK_Message* message, case OEMCrypto_BufferType_Direct: OPK_Unpack_bool(message, &obj->buffer.direct.is_video); break; + default: + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_PARSE_ERROR); + break; } } diff --git a/oemcrypto/opk/serialization/common/include/length_types.h b/oemcrypto/opk/serialization/common/include/length_types.h index 3fb685b..ed68436 100644 --- a/oemcrypto/opk/serialization/common/include/length_types.h +++ b/oemcrypto/opk/serialization/common/include/length_types.h @@ -32,7 +32,7 @@ LengthType OPK_ToLengthType(size_t length); LengthType OPK_FromSizeTPtr(const size_t* length); LengthType OPK_FromU32Ptr(const uint32_t* length); LengthType OPK_FromSizeTPtrPtr(size_t* const* length); -LengthType OPK_FromUint32PtrPtr(uint32_t* const* length); +LengthType OPK_FromU32PtrPtr(uint32_t* const* length); size_t OPK_ToSizeT(LengthType length_type); bool OPK_LengthIsNull(LengthType length_type); diff --git a/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h b/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h index 24c6202..0ed30ff 100644 --- a/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h +++ b/oemcrypto/opk/serialization/common/include/shared_buffer_allocator.h @@ -15,6 +15,8 @@ extern "C" { #include #include +#include "odk_message.h" + typedef enum { SHARED_BUFFER_TYPE_INVALID, SHARED_BUFFER_TYPE_INPUT, @@ -26,8 +28,10 @@ typedef enum { */ bool OPK_SharedBuffer_Initialize(void); void OPK_SharedBuffer_Terminate(void); -uint8_t* OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, bool copy_in, - bool copy_out, bool is_output); +ODK_MessageStatus OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, + bool copy_in, bool copy_out, + bool is_output, + uint8_t** shared_address); uint8_t* OPK_SharedBuffer_NextBuffer(void); uint8_t* OPK_SharedBuffer_NextOutputBuffer(void); uint8_t* OPK_SharedBuffer_GetAddress(void); diff --git a/oemcrypto/opk/serialization/common/log_macros.c b/oemcrypto/opk/serialization/common/log_macros.c index 10e4e52..1f03e0e 100644 --- a/oemcrypto/opk/serialization/common/log_macros.c +++ b/oemcrypto/opk/serialization/common/log_macros.c @@ -45,6 +45,8 @@ const char* OPK_MessageStatus_Str(ODK_MessageStatus status) { return "MAP_SHARED_MEMORY_FAILED"; case MESSAGE_STATUS_SECURE_BUFFER_ERROR: return "SECURE_BUFFER_ERROR"; + case MESSAGE_STATUS_BUFFER_TOO_LARGE: + return "BUFFER_TOO_LARGE"; default: break; } diff --git a/oemcrypto/opk/serialization/common/opk_init.c b/oemcrypto/opk/serialization/common/opk_init.c index 8758b41..c59ef50 100644 --- a/oemcrypto/opk/serialization/common/opk_init.c +++ b/oemcrypto/opk/serialization/common/opk_init.c @@ -4,13 +4,7 @@ * License Agreement. */ -#ifndef OPK_INIT_H_ -#define OPK_INIT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - +#include "opk_init.h" #include "shared_buffer_allocator.h" #include "tos_shared_memory_interface.h" #include "tos_transport_interface.h" @@ -37,9 +31,3 @@ void OPK_Terminate(void) { OPK_SharedBuffer_Terminate(); TOS_Transport_Terminate(); } - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // OPK_INIT_H_ diff --git a/oemcrypto/opk/serialization/common/opk_serialization_base.c b/oemcrypto/opk/serialization/common/opk_serialization_base.c index 537fff1..f579a5f 100644 --- a/oemcrypto/opk/serialization/common/opk_serialization_base.c +++ b/oemcrypto/opk/serialization/common/opk_serialization_base.c @@ -191,15 +191,16 @@ void OPK_PackSharedBuffer(ODK_Message* message, const uint8_t* address, * happen is if the parameter being packed is an output and so will of * course be writeable. */ - shared_address = OPK_SharedBuffer_Allocate( - (uint8_t*)(uintptr_t)address, len, copy_in, copy_out, is_output); - if (shared_address) { + ODK_MessageStatus sts = + OPK_SharedBuffer_Allocate((uint8_t*)(uintptr_t)address, len, copy_in, + copy_out, is_output, &shared_address); + if (sts == MESSAGE_STATUS_OK) { MDBG(" -> " BLUE "new map " COLOR_OFF "%p..%p [len=%zu]", (const void*)shared_address, (const void*)(shared_address + len - 1), len); } else { MDBG(RED " -> map failed: NULL" COLOR_OFF); - ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED); + ODK_MESSAGE_SETSTATUS(message, sts); } } else { if (address) { @@ -256,7 +257,7 @@ void OPK_Unpack_bool(ODK_Message* message, bool* value) { } static uint64_t Unpack64(ODK_Message* message) { - uint8_t buf[sizeof(uint64_t)]; + uint8_t buf[sizeof(uint64_t)] = {0}; UnpackBytes(message, buf, sizeof(buf)); uint64_t u64 = buf[0]; u64 |= (uint64_t)buf[1] << 8; @@ -283,13 +284,13 @@ void OPK_Unpack_size_t(ODK_Message* message, size_t* value) { void OPK_Unpack_uint8_t(ODK_Message* message, uint8_t* value) { if (!CheckTag(message, TAG_UINT8)) return; - UnpackBytes(message, (uint8_t*)value, sizeof(*value)); + UnpackBytes(message, value, sizeof(*value)); } void OPK_Unpack_uint16_t(ODK_Message* message, uint16_t* value) { if (!CheckTag(message, TAG_UINT16)) return; assert(value); - uint8_t buf[sizeof(uint16_t)]; + uint8_t buf[sizeof(uint16_t)] = {0}; UnpackBytes(message, buf, sizeof(buf)); *value = buf[0]; *value |= (uint16_t)buf[1] << 8; @@ -298,7 +299,7 @@ void OPK_Unpack_uint16_t(ODK_Message* message, uint16_t* value) { void OPK_Unpack_uint32_t(ODK_Message* message, uint32_t* value) { if (!CheckTag(message, TAG_UINT32)) return; assert(value); - uint8_t buf[sizeof(uint32_t)]; + uint8_t buf[sizeof(uint32_t)] = {0}; UnpackBytes(message, buf, sizeof(buf)); *value = buf[0]; *value |= (uint32_t)buf[1] << 8; @@ -413,15 +414,15 @@ void OPK_UnpackSharedBuffer(ODK_Message* message, uint8_t** address, */ bool copy_in = false; bool copy_out = false; - shared_address = OPK_SharedBuffer_Allocate(*address, len, copy_in, - copy_out, is_output); - if (shared_address) { + ODK_MessageStatus sts = OPK_SharedBuffer_Allocate( + *address, len, copy_in, copy_out, is_output, &shared_address); + if (sts == MESSAGE_STATUS_OK) { MDBG(" -> " BLUE "new map " COLOR_OFF "%p..%p [len=%zu]", (const void*)shared_address, (const void*)(shared_address + len - 1), len); } else { MDBG(RED " -> map failed: NULL" COLOR_OFF); - ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED); + ODK_MESSAGE_SETSTATUS(message, sts); } *address = shared_address; } else { diff --git a/oemcrypto/opk/serialization/common/shared_buffer_allocator.c b/oemcrypto/opk/serialization/common/shared_buffer_allocator.c index 711cc23..1c0efbd 100644 --- a/oemcrypto/opk/serialization/common/shared_buffer_allocator.c +++ b/oemcrypto/opk/serialization/common/shared_buffer_allocator.c @@ -11,6 +11,7 @@ #include "oemcrypto_overflow.h" #include "shared_buffer_allocator.h" #include "tos_shared_memory_interface.h" +#include "tos_transport_interface.h" /* * The Shared Buffer Allocator provides functions for allocating and @@ -100,7 +101,7 @@ static size_t buffer_count_ = 0; /* * Initialize shared memory state variables. */ -bool OPK_SharedBuffer_Initialize() { +bool OPK_SharedBuffer_Initialize(void) { if (TOS_SharedMemory_Allocate(TOS_SharedMemory_AvailableSize())) { OPK_SharedBuffer_Reset(); return true; @@ -111,7 +112,7 @@ bool OPK_SharedBuffer_Initialize() { /* * Release shared memory resources */ -void OPK_SharedBuffer_Terminate() { +void OPK_SharedBuffer_Terminate(void) { OPK_SharedBuffer_Reset(); TOS_SharedMemory_Release(); } @@ -149,20 +150,25 @@ void OPK_SharedBuffer_Reset(void) { * Returns: * The address of the allocation or NULL if allocation fails */ -uint8_t* OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, bool copy_in, - bool copy_out, bool is_output) { +ODK_MessageStatus OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, + bool copy_in, bool copy_out, + bool is_output, + uint8_t** shared_address) { size_t index = next_buffer_index_; + if (shared_address == NULL) { + return MESSAGE_STATUS_NULL_POINTER_ERROR; + } if (index >= MAX_SHARED_BUFFERS) { LOGE("Exceeded max shared buffer allocations"); - return NULL; + return MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED; } size_t new_offset = 0; if (OPK_AddOverflowUX(next_buffer_offset_, size, &new_offset)) { - return NULL; + return MESSAGE_STATUS_OVERFLOW_ERROR; } if (new_offset > TOS_SharedMemory_GetSize()) { LOGE("Insufficient shared memory"); - return NULL; + return MESSAGE_STATUS_BUFFER_TOO_LARGE; } Allocation* alloc = &allocations_[index]; @@ -177,7 +183,8 @@ uint8_t* OPK_SharedBuffer_Allocate(uint8_t* address, size_t size, bool copy_in, next_buffer_offset_ = new_offset; next_buffer_index_++; buffer_count_++; - return buffer_address; + *shared_address = buffer_address; + return MESSAGE_STATUS_OK; } /* diff --git a/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c b/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c index 0ee5f33..fd26aca 100644 --- a/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c +++ b/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c @@ -33,7 +33,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, API_Initialize(); request = OPK_Pack_SetSandbox_Request(sandbox_id, sandbox_id_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -63,7 +67,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize(void) { } request = OPK_Pack_Initialize_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -89,7 +97,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate(void) { API_Initialize(); request = OPK_Pack_Terminate_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -117,7 +129,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Idle(OEMCrypto_IdleState state, API_Initialize(); request = OPK_Pack_Idle_Request(state, os_specific_code); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -143,7 +159,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Wake(void) { API_Initialize(); request = OPK_Pack_Wake_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -170,7 +190,11 @@ OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { API_Initialize(); request = OPK_Pack_OpenSession_Request(session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -197,7 +221,11 @@ OEMCrypto_CloseSession(OEMCrypto_SESSION session) { API_Initialize(); request = OPK_Pack_CloseSession_Request(session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -215,61 +243,6 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateEntitledKeySession( - OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_CreateEntitledKeySession_Request(oec_session, key_session); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_CreateEntitledKeySession_Response(&response, &result, - &key_session); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_RemoveEntitledKeySession(OEMCrypto_SESSION key_session) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_RemoveEntitledKeySession_Request(key_session); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_RemoveEntitledKeySession_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context, size_t mac_key_context_length, @@ -284,7 +257,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( session, mac_key_context, mac_key_context_length, enc_key_context, enc_key_context_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -317,7 +294,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( session, derivation_key, derivation_key_length, mac_key_context, mac_key_context_length, enc_key_context, enc_key_context_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -344,7 +325,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, API_Initialize(); request = OPK_Pack_GenerateNonce_Request(session, nonce); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -374,7 +359,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( session, message, message_length, core_message_size, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -406,7 +395,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( session, message, message_length, core_message_size, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -443,7 +436,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( enc_mac_keys_iv, enc_mac_keys, key_array_length, key_array, pst, srm_restriction_data, license_type); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -476,7 +473,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, core_message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -494,36 +495,6 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_LoadEntitledContentKeys_Request( - session, message, message_length, key_array_length, key_array); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_LoadEntitledContentKeys_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, size_t num_keys, @@ -537,7 +508,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys( OPK_Pack_RefreshKeys_Request(session, message, message_length, signature, signature_length, num_keys, key_array); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -570,7 +545,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, core_message_length, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -601,7 +580,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( session, content_key_id, content_key_id_length, key_control_block, key_control_block_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -620,6 +603,169 @@ cleanup_and_return: return result; } +OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateEntitledKeySession( + OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_CreateEntitledKeySession_Request(oec_session, key_session); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_CreateEntitledKeySession_Response(&response, &result, + &key_session); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_RemoveEntitledKeySession(OEMCrypto_SESSION key_session) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_RemoveEntitledKeySession_Request(key_session); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_RemoveEntitledKeySession_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_LoadEntitledContentKeys_Request( + session, message, message_length, key_array_length, key_array); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_LoadEntitledContentKeys_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = + OPK_Pack_ReassociateEntitledKeySession_Request(key_session, oec_session); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_ReassociateEntitledKeySession_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session, uint8_t* key_token, + size_t* key_token_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = + OPK_Pack_GetOEMKeyToken_Request(key_session, key_token, key_token_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetOEMKeyToken_Response(&response, &result, &key_token, + &key_token_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCRYPTO_API OEMCryptoResult OEMCrypto_SelectKey( OEMCrypto_SESSION session, const uint8_t* content_key_id, size_t content_key_id_length, OEMCryptoCipherMode cipher_mode) { @@ -631,7 +777,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_SelectKey( request = OPK_Pack_SelectKey_Request(session, content_key_id, content_key_id_length, cipher_mode); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -660,7 +810,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( request = OPK_Pack_DecryptCENC_Request(session, samples, samples_length, pattern); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -691,7 +845,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer( request = OPK_Pack_CopyBuffer_Request(session, data_addr, data_addr_length, out_buffer_descriptor, subsample_flags); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -721,7 +879,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Encrypt( request = OPK_Pack_Generic_Encrypt_Request( session, in_buffer, in_buffer_length, iv, algorithm, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -752,7 +914,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Decrypt( request = OPK_Pack_Generic_Decrypt_Request( session, in_buffer, in_buffer_length, iv, algorithm, out_buffer); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -783,7 +949,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Sign( request = OPK_Pack_Generic_Sign_Request( session, buffer, buffer_length, algorithm, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -814,7 +984,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Verify( request = OPK_Pack_Generic_Verify_Request( session, buffer, buffer_length, algorithm, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -845,7 +1019,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( keybox_or_cert, keybox_or_cert_length, wrapped_keybox_or_cert, wrapped_keybox_or_cert_length, transport_key, transport_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -875,7 +1053,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert( request = OPK_Pack_InstallKeyboxOrOEMCert_Request(keybox_or_cert, keybox_or_cert_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -902,7 +1084,11 @@ OEMCrypto_GetProvisioningMethod(void) { API_Initialize(); request = OPK_Pack_GetProvisioningMethod_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -927,7 +1113,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { API_Initialize(); request = OPK_Pack_IsKeyboxOrOEMCertValid_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -954,7 +1144,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, API_Initialize(); request = OPK_Pack_GetDeviceID_Request(device_id, device_id_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -982,7 +1176,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data, API_Initialize(); request = OPK_Pack_GetKeyData_Request(key_data, key_data_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1010,7 +1208,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, API_Initialize(); request = OPK_Pack_LoadTestKeybox_Request(buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1037,7 +1239,11 @@ OEMCrypto_LoadOEMPrivateKey(OEMCrypto_SESSION session) { API_Initialize(); request = OPK_Pack_LoadOEMPrivateKey_Request(session); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1065,7 +1271,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( request = OPK_Pack_GetOEMPublicCertificate_Request(public_cert, public_cert_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1093,7 +1303,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* random_data, API_Initialize(); request = OPK_Pack_GetRandom_Request(random_data, random_data_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1120,7 +1334,11 @@ OEMCRYPTO_API uint32_t OEMCrypto_APIVersion(void) { API_Initialize(); request = OPK_Pack_APIVersion_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1145,7 +1363,11 @@ OEMCRYPTO_API uint32_t OEMCrypto_MinorAPIVersion(void) { API_Initialize(); request = OPK_Pack_MinorAPIVersion_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1171,7 +1393,11 @@ OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length) { API_Initialize(); request = OPK_Pack_BuildInformation_Request(buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1198,7 +1424,11 @@ OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level(void) { API_Initialize(); request = OPK_Pack_Security_Patch_Level_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1223,7 +1453,11 @@ OEMCRYPTO_API OEMCrypto_Security_Level OEMCrypto_SecurityLevel(void) { API_Initialize(); request = OPK_Pack_SecurityLevel_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1249,7 +1483,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHDCPCapability( API_Initialize(); request = OPK_Pack_GetHDCPCapability_Request(current, maximum); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1276,7 +1514,11 @@ OEMCrypto_GetDTCP2Capability(OEMCrypto_DTCP2_Capability* capability) { API_Initialize(); request = OPK_Pack_GetDTCP2Capability_Request(capability); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1302,7 +1544,11 @@ OEMCRYPTO_API bool OEMCrypto_SupportsUsageTable(void) { API_Initialize(); request = OPK_Pack_SupportsUsageTable_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1327,7 +1573,11 @@ OEMCRYPTO_API size_t OEMCrypto_MaximumUsageTableHeaderSize(void) { API_Initialize(); request = OPK_Pack_MaximumUsageTableHeaderSize_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1352,7 +1602,11 @@ OEMCRYPTO_API bool OEMCrypto_IsAntiRollbackHwPresent(void) { API_Initialize(); request = OPK_Pack_IsAntiRollbackHwPresent_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1377,7 +1631,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { API_Initialize(); request = OPK_Pack_GetNumberOfOpenSessions_Request(count); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1403,7 +1661,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max) { API_Initialize(); request = OPK_Pack_GetMaxNumberOfSessions_Request(max); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1429,7 +1691,11 @@ OEMCRYPTO_API uint32_t OEMCrypto_SupportedCertificates(void) { API_Initialize(); request = OPK_Pack_SupportedCertificates_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1455,7 +1721,11 @@ OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { API_Initialize(); request = OPK_Pack_GetCurrentSRMVersion_Request(version); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1481,7 +1751,11 @@ OEMCRYPTO_API uint32_t OEMCrypto_GetAnalogOutputFlags(void) { API_Initialize(); request = OPK_Pack_GetAnalogOutputFlags_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1506,7 +1780,11 @@ OEMCRYPTO_API uint32_t OEMCrypto_ResourceRatingTier(void) { API_Initialize(); request = OPK_Pack_ResourceRatingTier_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1531,7 +1809,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ProductionReady(void) { API_Initialize(); request = OPK_Pack_ProductionReady_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1558,7 +1840,11 @@ OEMCrypto_GetWatermarkingSupport(void) { API_Initialize(); request = OPK_Pack_GetWatermarkingSupport_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1589,7 +1875,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( session, message, message_length, core_message_length, signature, signature_length, wrapped_private_key, wrapped_private_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1619,7 +1909,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey( request = OPK_Pack_LoadDRMPrivateKey_Request( session, key_type, wrapped_private_key, wrapped_private_key_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1645,7 +1939,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey(void) { API_Initialize(); request = OPK_Pack_LoadTestRSAKey_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1676,7 +1974,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( session, message, message_length, signature, signature_length, padding_scheme); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1707,7 +2009,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( session, message, message_length, core_message_size, signature, signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1737,7 +2043,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateUsageTableHeader( request = OPK_Pack_CreateUsageTableHeader_Request(header_buffer, header_buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1765,7 +2075,11 @@ OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length) { API_Initialize(); request = OPK_Pack_LoadUsageTableHeader_Request(buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1792,7 +2106,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateNewUsageEntry( API_Initialize(); request = OPK_Pack_CreateNewUsageEntry_Request(session, usage_entry_number); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1820,7 +2138,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReuseUsageEntry( API_Initialize(); request = OPK_Pack_ReuseUsageEntry_Request(session, usage_entry_number); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1849,7 +2171,11 @@ OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t usage_entry_number, request = OPK_Pack_LoadUsageEntry_Request(session, usage_entry_number, buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1880,7 +2206,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_UpdateUsageEntry( session, header_buffer, header_buffer_length, entry_buffer, entry_buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1909,7 +2239,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeactivateUsageEntry( API_Initialize(); request = OPK_Pack_DeactivateUsageEntry_Request(session, pst, pst_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1940,7 +2274,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, request = OPK_Pack_ReportUsage_Request(session, pst, pst_length, buffer, buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1967,7 +2305,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, API_Initialize(); request = OPK_Pack_MoveEntry_Request(session, new_index); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -1996,7 +2338,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader( request = OPK_Pack_ShrinkUsageTableHeader_Request( new_entry_count, header_buffer, header_buffer_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2026,7 +2372,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetBootCertificateChain( request = OPK_Pack_GetBootCertificateChain_Request( bcc, bcc_length, additional_signature, additional_signature_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2061,7 +2411,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( public_key_signature_length, wrapped_private_key, wrapped_private_key_length, key_type); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2082,6 +2436,39 @@ cleanup_and_return: return result; } +OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallOemPrivateKey( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_InstallOemPrivateKey_Request( + session, key_type, wrapped_private_key, wrapped_private_key_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_InstallOemPrivateKey_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash(void) { pthread_mutex_lock(&api_lock); uint32_t result = 0; @@ -2090,7 +2477,11 @@ OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash(void) { API_Initialize(); request = OPK_Pack_SupportsDecryptHash_Request(); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2118,7 +2509,11 @@ OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number, request = OPK_Pack_SetDecryptHash_Request(session, frame_number, hash, hash_length); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2145,7 +2540,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHashErrorCode( API_Initialize(); request = OPK_Pack_GetHashErrorCode_Request(session, failed_frame_number); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2175,7 +2574,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_AllocateSecureBuffer( request = OPK_Pack_AllocateSecureBuffer_Request(session, buffer_size, output_descriptor, secure_fd); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2205,7 +2608,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_FreeSecureBuffer( request = OPK_Pack_FreeSecureBuffer_Request(session, output_descriptor, secure_fd); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2223,93 +2630,6 @@ cleanup_and_return: return result; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_InstallOemPrivateKey( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_InstallOemPrivateKey_Request( - session, key_type, wrapped_private_key, wrapped_private_key_length); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_InstallOemPrivateKey_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = - OPK_Pack_ReassociateEntitledKeySession_Request(key_session, oec_session); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_ReassociateEntitledKeySession_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadCasECMKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key) { - pthread_mutex_lock(&api_lock); - OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - ODK_Message request = ODK_Message_Create(NULL, 0); - ODK_Message response = ODK_Message_Create(NULL, 0); - API_Initialize(); - request = OPK_Pack_LoadCasECMKeys_Request(session, message, message_length, - even_key, odd_key); - if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - goto cleanup_and_return; - } - response = API_Transact(&request); - OPK_Unpack_LoadCasECMKeys_Response(&response, &result); - - if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -cleanup_and_return: - TOS_Transport_ReleaseMessage(&request); - TOS_Transport_ReleaseMessage(&response); - - result = API_CheckResult(result); - pthread_mutex_unlock(&api_lock); - return result; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateOTARequest(OEMCrypto_SESSION session, uint8_t* buffer, size_t* buffer_length, uint32_t use_test_key) { @@ -2321,7 +2641,11 @@ OEMCrypto_GenerateOTARequest(OEMCrypto_SESSION session, uint8_t* buffer, request = OPK_Pack_GenerateOTARequest_Request(session, buffer, buffer_length, use_test_key); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); @@ -2351,7 +2675,11 @@ OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session, const uint8_t* buffer, request = OPK_Pack_ProcessOTAKeybox_Request(session, buffer, buffer_length, use_test_key); if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { - api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } goto cleanup_and_return; } response = API_Transact(&request); diff --git a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c index 9472037..448e8f4 100644 --- a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c +++ b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c @@ -224,69 +224,6 @@ void OPK_Unpack_CloseSession_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_CreateEntitledKeySession_Request( - OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session) { - uint32_t api_value = 111; /* from _oecc111 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_uint32_t(&msg, &oec_session); - OPK_PackIsNull(&msg, key_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_CreateEntitledKeySession_Response( - ODK_Message* msg, OEMCryptoResult* result, - OEMCrypto_SESSION** key_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 111) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackNullable_uint32_t(msg, key_session); - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( - OEMCrypto_SESSION key_session) { - uint32_t api_value = 112; /* from _oecc112 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_uint32_t(&msg, &key_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 112) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - ODK_Message OPK_Pack_GenerateDerivedKeys_Request( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context, size_t mac_key_context_length, @@ -619,56 +556,6 @@ void OPK_Unpack_LoadLicense_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array) { - uint32_t api_value = 121; /* from _oecc121 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &message_length); - OPK_Pack_size_t(&msg, &key_array_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)message, - OPK_ToLengthType(message_length)); - /* pack object array with packer function - * OPK_Pack_OEMCrypto_EntitledContentKeyObject */ - ODK_Message* const odk_message = &msg; - const void* const objs = (const void*)key_array; - const LengthType count = OPK_ToLengthType(key_array_length); - const size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); - const bool is_null = objs == NULL || OPK_LengthIsNull(count); - if (!OPK_PackBoolValue(odk_message, is_null)) { - for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Pack_OEMCrypto_EntitledContentKeyObject( - odk_message, - (const OEMCrypto_EntitledContentKeyObject*)(objs + i * size)); - } - } - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 121) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - ODK_Message OPK_Pack_RefreshKeys_Request( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, size_t num_keys, @@ -798,6 +685,193 @@ void OPK_Unpack_QueryKeyControl_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_CreateEntitledKeySession_Request( + OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session) { + uint32_t api_value = 111; /* from _oecc111 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &oec_session); + OPK_PackIsNull(&msg, key_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_CreateEntitledKeySession_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_SESSION** key_session) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 111) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_uint32_t(msg, key_session); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( + OEMCrypto_SESSION key_session) { + uint32_t api_value = 112; /* from _oecc112 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &key_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 112) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array) { + uint32_t api_value = 121; /* from _oecc121 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &message_length); + OPK_Pack_size_t(&msg, &key_array_length); + OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)message, + OPK_ToLengthType(message_length)); + /* pack object array with packer function + * OPK_Pack_OEMCrypto_EntitledContentKeyObject */ + ODK_Message* const odk_message = &msg; + const void* const objs = (const void*)key_array; + const LengthType count = OPK_ToLengthType(key_array_length); + const size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); + const bool is_null = objs == NULL || OPK_LengthIsNull(count); + if (!OPK_PackBoolValue(odk_message, is_null)) { + for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + OPK_Pack_OEMCrypto_EntitledContentKeyObject( + odk_message, + (const OEMCrypto_EntitledContentKeyObject*)(objs + i * size)); + } + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 121) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { + uint32_t api_value = 119; /* from _oecc119 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_uint32_t(&msg, &key_session); + OPK_Pack_uint32_t(&msg, &oec_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ReassociateEntitledKeySession_Response( + ODK_Message* msg, OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 119) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_GetOEMKeyToken_Request(OEMCrypto_SESSION key_session, + const uint8_t* key_token, + const size_t* key_token_length) { + uint32_t api_value = 130; /* from _oecc130 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackNullable_size_t(&msg, key_token_length); + OPK_Pack_uint32_t(&msg, &key_session); + OPK_PackAlloc(&msg, key_token); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetOEMKeyToken_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** key_token, + size_t** key_token_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 130) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_UnpackNullable_size_t(msg, key_token_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtrPtr(key_token_length)); + if (p && *key_token) { + memcpy(*key_token, p, OPK_SafeDerefSizeTPtrPtr(key_token_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_SelectKey_Request(OEMCrypto_SESSION session, const uint8_t* content_key_id, size_t content_key_id_length, @@ -2678,6 +2752,41 @@ void OPK_Unpack_GenerateCertificateKeyPair_Response( } } +ODK_Message OPK_Pack_InstallOemPrivateKey_Request( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { + uint32_t api_value = 118; /* from _oecc118 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &wrapped_private_key_length); + OPK_Pack_uint32_t(&msg, &session); + OPK_Pack_uint32_t(&msg, &key_type); + OPK_PackMemory(&msg, (const uint8_t*)wrapped_private_key, + OPK_ToLengthType(wrapped_private_key_length)); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 118) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_SupportsDecryptHash_Request(void) { uint32_t api_value = 86; /* from _oecc86 */ ODK_Message msg = TOS_Transport_GetRequest(); @@ -2840,109 +2949,6 @@ void OPK_Unpack_FreeSecureBuffer_Response( } } -ODK_Message OPK_Pack_InstallOemPrivateKey_Request( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) { - uint32_t api_value = 118; /* from _oecc118 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &wrapped_private_key_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_Pack_uint32_t(&msg, &key_type); - OPK_PackMemory(&msg, (const uint8_t*)wrapped_private_key, - OPK_ToLengthType(wrapped_private_key_length)); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 118) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) { - uint32_t api_value = 119; /* from _oecc119 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_uint32_t(&msg, &key_session); - OPK_Pack_uint32_t(&msg, &oec_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_ReassociateEntitledKeySession_Response( - ODK_Message* msg, OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 119) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - -ODK_Message OPK_Pack_LoadCasECMKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key) { - uint32_t api_value = 120; /* from _oecc120 */ - ODK_Message msg = TOS_Transport_GetRequest(); - OPK_Pack_uint32_t(&msg, &api_value); - uint64_t timestamp = time(0); - OPK_Pack_uint64_t(&msg, ×tamp); - OPK_Pack_size_t(&msg, &message_length); - OPK_Pack_uint32_t(&msg, &session); - OPK_PackMemory(&msg, (const uint8_t*)message, - OPK_ToLengthType(message_length)); - OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, even_key); - OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, odd_key); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, - OEMCryptoResult* result) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 120) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OEMCryptoResult(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackEOM(msg); - - if (SuccessResult(*result)) { - OPK_SharedBuffer_FinalizeUnpacking(); - } -} - ODK_Message OPK_Pack_OPK_SerializationVersion_Request( const uint32_t* ree_major, const uint32_t* ree_minor, const uint32_t* tee_major, const uint32_t* tee_minor) { diff --git a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h index 147658c..b56e27a 100644 --- a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h +++ b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h @@ -35,14 +35,6 @@ void OPK_Unpack_OpenSession_Response(ODK_Message* msg, OEMCryptoResult* result, ODK_Message OPK_Pack_CloseSession_Request(OEMCrypto_SESSION session); void OPK_Unpack_CloseSession_Response(ODK_Message* msg, OEMCryptoResult* result); -ODK_Message OPK_Pack_CreateEntitledKeySession_Request( - OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session); -void OPK_Unpack_CreateEntitledKeySession_Response( - ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_SESSION** key_session); -ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( - OEMCrypto_SESSION key_session); -void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, - OEMCryptoResult* result); ODK_Message OPK_Pack_GenerateDerivedKeys_Request( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context, size_t mac_key_context_length, @@ -94,12 +86,6 @@ ODK_Message OPK_Pack_LoadLicense_Request(OEMCrypto_SESSION session, const uint8_t* signature, size_t signature_length); void OPK_Unpack_LoadLicense_Response(ODK_Message* msg, OEMCryptoResult* result); -ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array); -void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, - OEMCryptoResult* result); ODK_Message OPK_Pack_RefreshKeys_Request( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, size_t num_keys, @@ -120,6 +106,31 @@ void OPK_Unpack_QueryKeyControl_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** key_control_block, size_t** key_control_block_length); +ODK_Message OPK_Pack_CreateEntitledKeySession_Request( + OEMCrypto_SESSION oec_session, const OEMCrypto_SESSION* key_session); +void OPK_Unpack_CreateEntitledKeySession_Response( + ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_SESSION** key_session); +ODK_Message OPK_Pack_RemoveEntitledKeySession_Request( + OEMCrypto_SESSION key_session); +void OPK_Unpack_RemoveEntitledKeySession_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_LoadEntitledContentKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); +void OPK_Unpack_LoadEntitledContentKeys_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); +void OPK_Unpack_ReassociateEntitledKeySession_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_GetOEMKeyToken_Request(OEMCrypto_SESSION key_session, + const uint8_t* key_token, + const size_t* key_token_length); +void OPK_Unpack_GetOEMKeyToken_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** key_token, + size_t** key_token_length); ODK_Message OPK_Pack_SelectKey_Request(OEMCrypto_SESSION session, const uint8_t* content_key_id, size_t content_key_id_length, @@ -380,6 +391,11 @@ void OPK_Unpack_GenerateCertificateKeyPair_Response( size_t** public_key_length, uint8_t** public_key_signature, size_t** public_key_signature_length, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length, OEMCrypto_PrivateKeyType** key_type); +ODK_Message OPK_Pack_InstallOemPrivateKey_Request( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); +void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, + OEMCryptoResult* result); ODK_Message OPK_Pack_SupportsDecryptHash_Request(void); void OPK_Unpack_SupportsDecryptHash_Response(ODK_Message* msg, uint32_t* result); @@ -406,21 +422,6 @@ ODK_Message OPK_Pack_FreeSecureBuffer_Request( void OPK_Unpack_FreeSecureBuffer_Response( ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_DestBufferDesc** output_descriptor); -ODK_Message OPK_Pack_InstallOemPrivateKey_Request( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); -void OPK_Unpack_InstallOemPrivateKey_Response(ODK_Message* msg, - OEMCryptoResult* result); -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Request( - OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); -void OPK_Unpack_ReassociateEntitledKeySession_Response(ODK_Message* msg, - OEMCryptoResult* result); -ODK_Message OPK_Pack_LoadCasECMKeys_Request( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const OEMCrypto_EntitledContentKeyObject* even_key, - const OEMCrypto_EntitledContentKeyObject* odd_key); -void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, - OEMCryptoResult* result); ODK_Message OPK_Pack_OPK_SerializationVersion_Request( const uint32_t* ree_major, const uint32_t* ree_minor, const uint32_t* tee_major, const uint32_t* tee_minor); diff --git a/oemcrypto/opk/serialization/ree/ree_special_cases.c b/oemcrypto/opk/serialization/ree/ree_special_cases.c index 434d5db..fc5fe44 100644 --- a/oemcrypto/opk/serialization/ree/ree_special_cases.c +++ b/oemcrypto/opk/serialization/ree/ree_special_cases.c @@ -74,3 +74,40 @@ void OPK_Pack_RewrapDeviceRSAKey_Request( OPK_PackEOM(msg); OPK_SharedBuffer_FinalizePacking(); } + +ODK_Message OPK_Pack_LoadCasECMKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key) { + uint32_t api_value = 120; /* from _oecc120 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &message_length); + OPK_Pack_uint32_t(&msg, &session); + OPK_PackMemory(&msg, (const uint8_t*)message, + OPK_ToLengthType(message_length)); + OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, even_key); + OPK_PackNullable_OEMCrypto_EntitledContentKeyObject(&msg, odd_key); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 120) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} diff --git a/oemcrypto/opk/serialization/ree/ree_special_cases.h b/oemcrypto/opk/serialization/ree/ree_special_cases.h index cb3580c..ce9ca65 100644 --- a/oemcrypto/opk/serialization/ree/ree_special_cases.h +++ b/oemcrypto/opk/serialization/ree/ree_special_cases.h @@ -27,6 +27,12 @@ void OPK_Pack_RewrapDeviceRSAKey_Request( const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, const uint8_t* wrapped_rsa_key, const size_t* wrapped_rsa_key_length); +ODK_Message OPK_Pack_LoadCasECMKeys_Request( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); +void OPK_Unpack_LoadCasECMKeys_Response(ODK_Message* msg, + OEMCryptoResult* result); #ifdef __cplusplus } // extern "C" diff --git a/oemcrypto/opk/serialization/ree/special_case_apis.c b/oemcrypto/opk/serialization/ree/special_case_apis.c index 593045d..3a24efa 100644 --- a/oemcrypto/opk/serialization/ree/special_case_apis.c +++ b/oemcrypto/opk/serialization/ree/special_case_apis.c @@ -38,3 +38,37 @@ OEMCrypto_OPK_SerializationVersion(uint32_t* ree_major, uint32_t* ree_minor, pthread_mutex_unlock(&api_lock); return result; } + +OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_LoadCasECMKeys_Request(session, message, message_length, + even_key, odd_key); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&request) == MESSAGE_STATUS_BUFFER_TOO_LARGE) { + api_result = OEMCrypto_ERROR_BUFFER_TOO_LARGE; + } else { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_LoadCasECMKeys_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} diff --git a/oemcrypto/opk/serialization/tee/GEN_dispatcher.c b/oemcrypto/opk/serialization/tee/GEN_dispatcher.c index e142141..02bd09e 100644 --- a/oemcrypto/opk/serialization/tee/GEN_dispatcher.c +++ b/oemcrypto/opk/serialization/tee/GEN_dispatcher.c @@ -20,6 +20,7 @@ #include "oemcrypto_wall_clock.h" #include "opk_dispatcher.h" #include "shared_buffer_allocator.h" +#include "special_case_request_handlers.h" #include "tee_special_cases.h" #include "tos_shared_memory_interface.h" #include "tos_transport_interface.h" @@ -255,36 +256,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_CloseSession_Response(result); break; } - case 111: /* OEMCrypto_CreateEntitledKeySession */ - { - OEMCrypto_SESSION oec_session; - OPK_Init_uint32_t((uint32_t*)&oec_session); - OEMCrypto_SESSION* key_session; - OPK_InitPointer((uint8_t**)&key_session); - OPK_Unpack_CreateEntitledKeySession_Request(request, &oec_session, - &key_session); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("CreateEntitledKeySession"); - result = OEMCrypto_CreateEntitledKeySession(oec_session, key_session); - *response = - OPK_Pack_CreateEntitledKeySession_Response(result, key_session); - break; - } - case 112: /* OEMCrypto_RemoveEntitledKeySession */ - { - OEMCrypto_SESSION key_session; - OPK_Init_uint32_t((uint32_t*)&key_session); - OPK_Unpack_RemoveEntitledKeySession_Request(request, &key_session); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("RemoveEntitledKeySession"); - result = OEMCrypto_RemoveEntitledKeySession(key_session); - *response = OPK_Pack_RemoveEntitledKeySession_Response(result); - break; - } case 95: /* OEMCrypto_GenerateDerivedKeys */ { size_t mac_key_context_length; @@ -481,30 +452,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_LoadLicense_Response(result); break; } - case 121: /* OEMCrypto_LoadEntitledContentKeys */ - { - size_t message_length; - OPK_Init_size_t((size_t*)&message_length); - size_t key_array_length; - OPK_Init_size_t((size_t*)&key_array_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - uint8_t* message; - OPK_InitPointer((uint8_t**)&message); - OEMCrypto_EntitledContentKeyObject* key_array; - OPK_InitPointer((uint8_t**)&key_array); - OPK_Unpack_LoadEntitledContentKeys_Request(request, &session, &message, - &message_length, - &key_array_length, &key_array); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("LoadEntitledContentKeys"); - result = OEMCrypto_LoadEntitledContentKeys( - session, message, message_length, key_array_length, key_array); - *response = OPK_Pack_LoadEntitledContentKeys_Response(result); - break; - } case 91: /* OEMCrypto_RefreshKeys */ { size_t message_length; @@ -590,6 +537,103 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, key_control_block_length); break; } + case 111: /* OEMCrypto_CreateEntitledKeySession */ + { + OEMCrypto_SESSION oec_session; + OPK_Init_uint32_t((uint32_t*)&oec_session); + OEMCrypto_SESSION* key_session; + OPK_InitPointer((uint8_t**)&key_session); + OPK_Unpack_CreateEntitledKeySession_Request(request, &oec_session, + &key_session); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("CreateEntitledKeySession"); + result = OEMCrypto_CreateEntitledKeySession(oec_session, key_session); + *response = + OPK_Pack_CreateEntitledKeySession_Response(result, key_session); + break; + } + case 112: /* OEMCrypto_RemoveEntitledKeySession */ + { + OEMCrypto_SESSION key_session; + OPK_Init_uint32_t((uint32_t*)&key_session); + OPK_Unpack_RemoveEntitledKeySession_Request(request, &key_session); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("RemoveEntitledKeySession"); + result = OEMCrypto_RemoveEntitledKeySession(key_session); + *response = OPK_Pack_RemoveEntitledKeySession_Response(result); + break; + } + case 121: /* OEMCrypto_LoadEntitledContentKeys */ + { + size_t message_length; + OPK_Init_size_t((size_t*)&message_length); + size_t key_array_length; + OPK_Init_size_t((size_t*)&key_array_length); + OEMCrypto_SESSION session; + OPK_Init_uint32_t((uint32_t*)&session); + uint8_t* message; + OPK_InitPointer((uint8_t**)&message); + OEMCrypto_EntitledContentKeyObject* key_array; + OPK_InitPointer((uint8_t**)&key_array); + OPK_Unpack_LoadEntitledContentKeys_Request(request, &session, &message, + &message_length, + &key_array_length, &key_array); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("LoadEntitledContentKeys"); + result = OEMCrypto_LoadEntitledContentKeys( + session, message, message_length, key_array_length, key_array); + *response = OPK_Pack_LoadEntitledContentKeys_Response(result); + break; + } + case 119: /* OEMCrypto_ReassociateEntitledKeySession */ + { + OEMCrypto_SESSION key_session; + OPK_Init_uint32_t((uint32_t*)&key_session); + OEMCrypto_SESSION oec_session; + OPK_Init_uint32_t((uint32_t*)&oec_session); + OPK_Unpack_ReassociateEntitledKeySession_Request(request, &key_session, + &oec_session); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("ReassociateEntitledKeySession"); + result = + OEMCrypto_ReassociateEntitledKeySession(key_session, oec_session); + *response = OPK_Pack_ReassociateEntitledKeySession_Response(result); + break; + } + case 120: /* OEMCrypto_LoadCasECMKeys */ + { + if (!Handle_OEMCrypto_LoadCasECMKeys(request, response)) + goto handle_invalid_request; + break; + } + case 130: /* OEMCrypto_GetOEMKeyToken */ + { + size_t* key_token_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + OPK_Init_size_t(key_token_length); + OEMCrypto_SESSION key_session; + OPK_Init_uint32_t((uint32_t*)&key_session); + uint8_t* key_token; + OPK_InitPointer((uint8_t**)&key_token); + OPK_Unpack_GetOEMKeyToken_Request(request, &key_session, &key_token, + &key_token_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetOEMKeyToken"); + result = + OEMCrypto_GetOEMKeyToken(key_session, key_token, key_token_length); + *response = + OPK_Pack_GetOEMKeyToken_Response(result, key_token, key_token_length); + break; + } case 81: /* OEMCrypto_SelectKey */ { size_t content_key_id_length; @@ -1520,6 +1564,28 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, wrapped_private_key_length, key_type); break; } + case 118: /* OEMCrypto_InstallOemPrivateKey */ + { + size_t wrapped_private_key_length; + OPK_Init_size_t((size_t*)&wrapped_private_key_length); + OEMCrypto_SESSION session; + OPK_Init_uint32_t((uint32_t*)&session); + OEMCrypto_PrivateKeyType key_type; + OPK_Init_uint32_t((uint32_t*)&key_type); + uint8_t* wrapped_private_key; + OPK_InitPointer((uint8_t**)&wrapped_private_key); + OPK_Unpack_InstallOemPrivateKey_Request(request, &session, &key_type, + &wrapped_private_key, + &wrapped_private_key_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("InstallOemPrivateKey"); + result = OEMCrypto_InstallOemPrivateKey( + session, key_type, wrapped_private_key, wrapped_private_key_length); + *response = OPK_Pack_InstallOemPrivateKey_Response(result); + break; + } case 86: /* OEMCrypto_SupportsDecryptHash */ { OPK_Unpack_SupportsDecryptHash_Request(request); @@ -1610,74 +1676,6 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_FreeSecureBuffer_Response(result, output_descriptor); break; } - case 118: /* OEMCrypto_InstallOemPrivateKey */ - { - size_t wrapped_private_key_length; - OPK_Init_size_t((size_t*)&wrapped_private_key_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - OEMCrypto_PrivateKeyType key_type; - OPK_Init_uint32_t((uint32_t*)&key_type); - uint8_t* wrapped_private_key; - OPK_InitPointer((uint8_t**)&wrapped_private_key); - OPK_Unpack_InstallOemPrivateKey_Request(request, &session, &key_type, - &wrapped_private_key, - &wrapped_private_key_length); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("InstallOemPrivateKey"); - result = OEMCrypto_InstallOemPrivateKey( - session, key_type, wrapped_private_key, wrapped_private_key_length); - *response = OPK_Pack_InstallOemPrivateKey_Response(result); - break; - } - case 119: /* OEMCrypto_ReassociateEntitledKeySession */ - { - OEMCrypto_SESSION key_session; - OPK_Init_uint32_t((uint32_t*)&key_session); - OEMCrypto_SESSION oec_session; - OPK_Init_uint32_t((uint32_t*)&oec_session); - OPK_Unpack_ReassociateEntitledKeySession_Request(request, &key_session, - &oec_session); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("ReassociateEntitledKeySession"); - result = - OEMCrypto_ReassociateEntitledKeySession(key_session, oec_session); - *response = OPK_Pack_ReassociateEntitledKeySession_Response(result); - break; - } - case 120: /* OEMCrypto_LoadCasECMKeys */ - { - size_t message_length; - OPK_Init_size_t((size_t*)&message_length); - OEMCrypto_SESSION session; - OPK_Init_uint32_t((uint32_t*)&session); - uint8_t* message; - OPK_InitPointer((uint8_t**)&message); - OEMCrypto_EntitledContentKeyObject* even_key = - (OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc( - sizeof(OEMCrypto_EntitledContentKeyObject)); - OPK_Init_OEMCrypto_EntitledContentKeyObject( - (OEMCrypto_EntitledContentKeyObject*)even_key); - OEMCrypto_EntitledContentKeyObject* odd_key = - (OEMCrypto_EntitledContentKeyObject*)OPK_VarAlloc( - sizeof(OEMCrypto_EntitledContentKeyObject)); - OPK_Init_OEMCrypto_EntitledContentKeyObject( - (OEMCrypto_EntitledContentKeyObject*)odd_key); - OPK_Unpack_LoadCasECMKeys_Request(request, &session, &message, - &message_length, &even_key, &odd_key); - if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OEMCryptoResult result; - OPK_Init_uint32_t((uint32_t*)&result); - LOGD("LoadCasECMKeys"); - result = OEMCrypto_LoadCasECMKeys(session, message, message_length, - even_key, odd_key); - *response = OPK_Pack_LoadCasECMKeys_Response(result); - break; - } case 115: /* OEMCrypto_OPK_SerializationVersion */ { uint32_t* ree_major = (uint32_t*)OPK_VarAlloc(sizeof(uint32_t)); diff --git a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c index d12769e..3cc1d89 100644 --- a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c +++ b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c @@ -186,56 +186,6 @@ ODK_Message OPK_Pack_CloseSession_Response(OEMCryptoResult result) { return msg; } -void OPK_Unpack_CreateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* oec_session, - OEMCrypto_SESSION** key_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 111) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_uint32_t(msg, oec_session); - *key_session = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(OEMCrypto_SESSION)); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_CreateEntitledKeySession_Response( - OEMCryptoResult result, const OEMCrypto_SESSION* key_session) { - uint32_t api_value = 111; /* from _oecc111 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackNullable_uint32_t(&msg, key_session); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_RemoveEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 112) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_uint32_t(msg, key_session); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result) { - uint32_t api_value = 112; /* from _oecc112 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_GenerateDerivedKeys_Request( ODK_Message* msg, OEMCrypto_SESSION* session, OEMCrypto_SharedMemory** mac_key_context, size_t* mac_key_context_length, @@ -525,62 +475,6 @@ ODK_Message OPK_Pack_LoadLicense_Response(OEMCryptoResult result) { return msg; } -void OPK_Unpack_LoadEntitledContentKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, size_t* key_array_length, - OEMCrypto_EntitledContentKeyObject** key_array) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 121) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, message_length); - OPK_Unpack_size_t(msg, key_array_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); - /* unpack object array with unpacker function - * OPK_Unpack_OEMCrypto_EntitledContentKeyObject */ - ODK_Message* odk_message = msg; - void** address = (void**)key_array; - LengthType count = OPK_FromSizeTPtr(key_array_length); - size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); - if (address) { - *address = NULL; - } - if (!OPK_UnpackIsNull(odk_message)) { - if (address && !OPK_LengthIsNull(count)) { - size_t bytes_to_unpack = 0; - if (odk_mul_overflow_ux(OPK_ToSizeT(count), size, &bytes_to_unpack)) { - ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_PARSE_ERROR); - } else { - *address = OPK_BumpAllocate(bytes_to_unpack); - if (!*address) { - ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); - } else { - for (size_t i = 0; i < OPK_ToSizeT(count); i++) { - OPK_Unpack_OEMCrypto_EntitledContentKeyObject( - odk_message, - (OEMCrypto_EntitledContentKeyObject*)((*address) + size * i)); - } - } - } - } - } - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result) { - uint32_t api_value = 121; /* from _oecc121 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_RefreshKeys_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, @@ -688,6 +582,173 @@ ODK_Message OPK_Pack_QueryKeyControl_Response( return msg; } +void OPK_Unpack_CreateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* oec_session, + OEMCrypto_SESSION** key_session) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 111) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, oec_session); + *key_session = (uint32_t*)OPK_UnpackAlloc(msg, sizeof(OEMCrypto_SESSION)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_CreateEntitledKeySession_Response( + OEMCryptoResult result, const OEMCrypto_SESSION* key_session) { + uint32_t api_value = 111; /* from _oecc111 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_uint32_t(&msg, key_session); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_RemoveEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 112) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, key_session); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result) { + uint32_t api_value = 112; /* from _oecc112 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_LoadEntitledContentKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, size_t* key_array_length, + OEMCrypto_EntitledContentKeyObject** key_array) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 121) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, message_length); + OPK_Unpack_size_t(msg, key_array_length); + OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); + /* unpack object array with unpacker function + * OPK_Unpack_OEMCrypto_EntitledContentKeyObject */ + ODK_Message* odk_message = msg; + void** address = (void**)key_array; + LengthType count = OPK_FromSizeTPtr(key_array_length); + size_t size = sizeof(OEMCrypto_EntitledContentKeyObject); + if (address) { + *address = NULL; + } + if (!OPK_UnpackIsNull(odk_message)) { + if (address && !OPK_LengthIsNull(count)) { + size_t bytes_to_unpack = 0; + if (odk_mul_overflow_ux(OPK_ToSizeT(count), size, &bytes_to_unpack)) { + ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_PARSE_ERROR); + } else { + *address = OPK_BumpAllocate(bytes_to_unpack); + if (!*address) { + ODK_MESSAGE_SETSTATUS(odk_message, MESSAGE_STATUS_OUT_OF_MEMORY); + } else { + for (size_t i = 0; i < OPK_ToSizeT(count); i++) { + OPK_Unpack_OEMCrypto_EntitledContentKeyObject( + odk_message, + (OEMCrypto_EntitledContentKeyObject*)((*address) + size * i)); + } + } + } + } + } + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result) { + uint32_t api_value = 121; /* from _oecc121 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_ReassociateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session, + OEMCrypto_SESSION* oec_session) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 119) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_uint32_t(msg, key_session); + OPK_Unpack_uint32_t(msg, oec_session); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( + OEMCryptoResult result) { + uint32_t api_value = 119; /* from _oecc119 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetOEMKeyToken_Request(ODK_Message* msg, + OEMCrypto_SESSION* key_session, + uint8_t** key_token, + size_t** key_token_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 130) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackNullable_size_t(msg, key_token_length); + OPK_Unpack_uint32_t(msg, key_session); + *key_token = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtrPtr(key_token_length), sizeof(uint8_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetOEMKeyToken_Response(OEMCryptoResult result, + const uint8_t* key_token, + const size_t* key_token_length) { + uint32_t api_value = 130; /* from _oecc130 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_PackNullable_size_t(&msg, key_token_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, (const uint8_t*)key_token, + OPK_FromSizeTPtr(key_token_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_SelectKey_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** content_key_id, size_t* content_key_id_length, @@ -2269,6 +2330,38 @@ ODK_Message OPK_Pack_GenerateCertificateKeyPair_Response( return msg; } +void OPK_Unpack_InstallOemPrivateKey_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, + OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, + size_t* wrapped_private_key_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 118) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, wrapped_private_key_length); + OPK_Unpack_uint32_t(msg, session); + OPK_Unpack_uint32_t(msg, key_type); + if (!Is_Valid_OEMCrypto_PrivateKeyType(*key_type)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackInPlace(msg, (uint8_t**)wrapped_private_key, + OPK_FromSizeTPtr(wrapped_private_key_length)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result) { + uint32_t api_value = 118; /* from _oecc118 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_SupportsDecryptHash_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); @@ -2406,93 +2499,6 @@ ODK_Message OPK_Pack_FreeSecureBuffer_Response( return msg; } -void OPK_Unpack_InstallOemPrivateKey_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, - OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, - size_t* wrapped_private_key_length) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 118) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, wrapped_private_key_length); - OPK_Unpack_uint32_t(msg, session); - OPK_Unpack_uint32_t(msg, key_type); - if (!Is_Valid_OEMCrypto_PrivateKeyType(*key_type)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } - OPK_UnpackInPlace(msg, (uint8_t**)wrapped_private_key, - OPK_FromSizeTPtr(wrapped_private_key_length)); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result) { - uint32_t api_value = 118; /* from _oecc118 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_ReassociateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session, - OEMCrypto_SESSION* oec_session) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 119) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_uint32_t(msg, key_session); - OPK_Unpack_uint32_t(msg, oec_session); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( - OEMCryptoResult result) { - uint32_t api_value = 119; /* from _oecc119 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -void OPK_Unpack_LoadCasECMKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, - OEMCrypto_EntitledContentKeyObject** odd_key) { - uint32_t api_value = UINT32_MAX; - OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 120) - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - uint64_t timestamp; - OPK_Unpack_uint64_t(msg, ×tamp); - OPK_Unpack_size_t(msg, message_length); - OPK_Unpack_uint32_t(msg, session); - OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); - OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, even_key); - OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, odd_key); - OPK_UnpackEOM(msg); - OPK_SharedBuffer_FinalizeUnpacking(); -} - -ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result) { - uint32_t api_value = 120; /* from _oecc120 */ - ODK_Message msg = TOS_Transport_GetResponse(); - OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); - OPK_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - void OPK_Unpack_OPK_SerializationVersion_Request(ODK_Message* msg, uint32_t** ree_major, uint32_t** ree_minor, diff --git a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h index 3bc2ccc..5737a2a 100644 --- a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h +++ b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h @@ -36,14 +36,6 @@ ODK_Message OPK_Pack_OpenSession_Response(OEMCryptoResult result, void OPK_Unpack_CloseSession_Request(ODK_Message* msg, OEMCrypto_SESSION* session); ODK_Message OPK_Pack_CloseSession_Response(OEMCryptoResult result); -void OPK_Unpack_CreateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* oec_session, - OEMCrypto_SESSION** key_session); -ODK_Message OPK_Pack_CreateEntitledKeySession_Response( - OEMCryptoResult result, const OEMCrypto_SESSION* key_session); -void OPK_Unpack_RemoveEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session); -ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result); void OPK_Unpack_GenerateDerivedKeys_Request( ODK_Message* msg, OEMCrypto_SESSION* session, OEMCrypto_SharedMemory** mac_key_context, size_t* mac_key_context_length, @@ -91,11 +83,6 @@ void OPK_Unpack_LoadLicense_Request(ODK_Message* msg, uint8_t** signature, size_t* signature_length); ODK_Message OPK_Pack_LoadLicense_Response(OEMCryptoResult result); -void OPK_Unpack_LoadEntitledContentKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, size_t* key_array_length, - OEMCrypto_EntitledContentKeyObject** key_array); -ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result); void OPK_Unpack_RefreshKeys_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, size_t* message_length, @@ -119,6 +106,31 @@ void OPK_Unpack_QueryKeyControl_Request(ODK_Message* msg, ODK_Message OPK_Pack_QueryKeyControl_Response( OEMCryptoResult result, const uint8_t* key_control_block, const size_t* key_control_block_length); +void OPK_Unpack_CreateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* oec_session, + OEMCrypto_SESSION** key_session); +ODK_Message OPK_Pack_CreateEntitledKeySession_Response( + OEMCryptoResult result, const OEMCrypto_SESSION* key_session); +void OPK_Unpack_RemoveEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session); +ODK_Message OPK_Pack_RemoveEntitledKeySession_Response(OEMCryptoResult result); +void OPK_Unpack_LoadEntitledContentKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, size_t* key_array_length, + OEMCrypto_EntitledContentKeyObject** key_array); +ODK_Message OPK_Pack_LoadEntitledContentKeys_Response(OEMCryptoResult result); +void OPK_Unpack_ReassociateEntitledKeySession_Request( + ODK_Message* msg, OEMCrypto_SESSION* key_session, + OEMCrypto_SESSION* oec_session); +ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( + OEMCryptoResult result); +void OPK_Unpack_GetOEMKeyToken_Request(ODK_Message* msg, + OEMCrypto_SESSION* key_session, + uint8_t** key_token, + size_t** key_token_length); +ODK_Message OPK_Pack_GetOEMKeyToken_Response(OEMCryptoResult result, + const uint8_t* key_token, + const size_t* key_token_length); void OPK_Unpack_SelectKey_Request(ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** content_key_id, size_t* content_key_id_length, @@ -370,6 +382,11 @@ ODK_Message OPK_Pack_GenerateCertificateKeyPair_Response( const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length, const OEMCrypto_PrivateKeyType* key_type); +void OPK_Unpack_InstallOemPrivateKey_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, + OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, + size_t* wrapped_private_key_length); +ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result); void OPK_Unpack_SupportsDecryptHash_Request(ODK_Message* msg); ODK_Message OPK_Pack_SupportsDecryptHash_Response(uint32_t result); void OPK_Unpack_SetDecryptHash_Request(ODK_Message* msg, @@ -393,21 +410,6 @@ void OPK_Unpack_FreeSecureBuffer_Request( OEMCrypto_DestBufferDesc** output_descriptor, int* secure_fd); ODK_Message OPK_Pack_FreeSecureBuffer_Response( OEMCryptoResult result, const OEMCrypto_DestBufferDesc* output_descriptor); -void OPK_Unpack_InstallOemPrivateKey_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, - OEMCrypto_PrivateKeyType* key_type, uint8_t** wrapped_private_key, - size_t* wrapped_private_key_length); -ODK_Message OPK_Pack_InstallOemPrivateKey_Response(OEMCryptoResult result); -void OPK_Unpack_ReassociateEntitledKeySession_Request( - ODK_Message* msg, OEMCrypto_SESSION* key_session, - OEMCrypto_SESSION* oec_session); -ODK_Message OPK_Pack_ReassociateEntitledKeySession_Response( - OEMCryptoResult result); -void OPK_Unpack_LoadCasECMKeys_Request( - ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, - size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, - OEMCrypto_EntitledContentKeyObject** odd_key); -ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result); void OPK_Unpack_OPK_SerializationVersion_Request(ODK_Message* msg, uint32_t** ree_major, uint32_t** ree_minor, diff --git a/oemcrypto/opk/serialization/tee/tee.gyp b/oemcrypto/opk/serialization/tee/tee.gyp index bf07781..9445a58 100644 --- a/oemcrypto/opk/serialization/tee/tee.gyp +++ b/oemcrypto/opk/serialization/tee/tee.gyp @@ -21,6 +21,7 @@ 'sources' : [ 'GEN_dispatcher.c', 'GEN_tee_serializer.c', + 'special_case_request_handlers.c', 'tee_special_cases.c', 'tee_os_type.c', 'tee_version.c', diff --git a/oemcrypto/opk/serialization/tee/tee_special_cases.c b/oemcrypto/opk/serialization/tee/tee_special_cases.c index 0fa1631..3cd6820 100644 --- a/oemcrypto/opk/serialization/tee/tee_special_cases.c +++ b/oemcrypto/opk/serialization/tee/tee_special_cases.c @@ -15,6 +15,7 @@ #include "GEN_tee_serializer.h" #include "OEMCryptoCENC.h" #include "log_macros.h" +#include "oemcrypto_overflow.h" #include "opk_serialization_base.h" #include "shared_buffer_allocator.h" #include "tos_shared_memory_interface.h" @@ -48,7 +49,7 @@ void OPK_Unpack_RewrapDeviceRSAKey_Request( size_t unaligned_nonce_offset = 0; uintptr_t unaligned_nonce_ptr = 0; OPK_Unpack_size_t(msg, &unaligned_nonce_offset); - if (__builtin_add_overflow((uintptr_t)*message, unaligned_nonce_offset, + if (OPK_AddOverflowUintptr((uintptr_t)*message, unaligned_nonce_offset, &unaligned_nonce_ptr)) { ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_PARSE_ERROR); return; @@ -58,7 +59,7 @@ void OPK_Unpack_RewrapDeviceRSAKey_Request( size_t enc_rsa_key_offset = 0; uintptr_t enc_rsa_key_ptr = 0; OPK_Unpack_size_t(msg, &enc_rsa_key_offset); - if (__builtin_add_overflow((uintptr_t)*message, enc_rsa_key_offset, + if (OPK_AddOverflowUintptr((uintptr_t)*message, enc_rsa_key_offset, &enc_rsa_key_ptr)) { ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_PARSE_ERROR); return; @@ -68,7 +69,7 @@ void OPK_Unpack_RewrapDeviceRSAKey_Request( size_t enc_rsa_key_iv_offset = 0; uintptr_t enc_rsa_key_iv_ptr = 0; OPK_Unpack_size_t(msg, &enc_rsa_key_iv_offset); - if (__builtin_add_overflow((uintptr_t)*message, enc_rsa_key_iv_offset, + if (OPK_AddOverflowUintptr((uintptr_t)*message, enc_rsa_key_iv_offset, &enc_rsa_key_iv_ptr)) { ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_PARSE_ERROR); return; @@ -79,3 +80,32 @@ void OPK_Unpack_RewrapDeviceRSAKey_Request( OPK_UnpackEOM(msg); OPK_SharedBuffer_FinalizeUnpacking(); } + +void OPK_Unpack_LoadCasECMKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, + OEMCrypto_EntitledContentKeyObject** odd_key) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 120) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, message_length); + OPK_Unpack_uint32_t(msg, session); + OPK_UnpackInPlace(msg, (uint8_t**)message, OPK_FromSizeTPtr(message_length)); + OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, even_key); + OPK_UnpackNullable_OEMCrypto_EntitledContentKeyObject(msg, odd_key); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result) { + uint32_t api_value = 120; /* from _oecc120 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} diff --git a/oemcrypto/opk/serialization/tee/tee_special_cases.h b/oemcrypto/opk/serialization/tee/tee_special_cases.h index fac7f38..30bec40 100644 --- a/oemcrypto/opk/serialization/tee/tee_special_cases.h +++ b/oemcrypto/opk/serialization/tee/tee_special_cases.h @@ -28,6 +28,11 @@ void OPK_Unpack_RewrapDeviceRSAKey_Request( uint32_t** unaligned_nonce, uint8_t** enc_rsa_key, size_t* enc_rsa_key_length, uint8_t** enc_rsa_key_iv, uint8_t** wrapped_rsa_key, size_t** wrapped_rsa_key_length); +void OPK_Unpack_LoadCasECMKeys_Request( + ODK_Message* msg, OEMCrypto_SESSION* session, uint8_t** message, + size_t* message_length, OEMCrypto_EntitledContentKeyObject** even_key, + OEMCrypto_EntitledContentKeyObject** odd_key); +ODK_Message OPK_Pack_LoadCasECMKeys_Response(OEMCryptoResult result); #ifdef __cplusplus } // extern "C" diff --git a/oemcrypto/opk/serialization/tee/tee_version.c b/oemcrypto/opk/serialization/tee/tee_version.c index 43767f4..ce8bda6 100644 --- a/oemcrypto/opk/serialization/tee/tee_version.c +++ b/oemcrypto/opk/serialization/tee/tee_version.c @@ -7,6 +7,7 @@ #include "OEMCryptoCENC.h" #include "log_macros.h" +#include "oemcrypto_api_macros.h" #include "version.h" /* @@ -24,14 +25,27 @@ OEMCryptoResult OEMCrypto_OPK_SerializationVersion(uint32_t* ree_major, if (tee_major && ree_major) { if (*tee_major != *ree_major) { - LOGE("Rejected connection from REE version %" PRIu32 ".%" PRIu32 - ". TEE version is %" PRIu32 ".%" PRIu32, - *ree_major, *ree_minor, *tee_major, *tee_minor); + if (tee_minor && ree_minor) { + LOGE("Rejected connection from REE version %" PRIu32 ".%" PRIu32 + ". TEE version is %" PRIu32 ".%" PRIu32 ".", + *ree_major, *ree_minor, *tee_major, *tee_minor); + } else { + LOGE("Rejected connection from REE version %" PRIu32 + ".x. TEE version is %" PRIu32 ".x.", + *ree_major, *tee_major); + } return OPK_ERROR_INCOMPATIBLE_VERSION; } - LOGI("Accepted connection from REE version %" PRIu32 ".%" PRIu32 - ". TEE version is %" PRIu32 ".%" PRIu32, - *ree_major, *ree_minor, *tee_major, *tee_minor); + + if (tee_minor && ree_minor) { + LOGI("Accepted connection from REE version %" PRIu32 ".%" PRIu32 + ". TEE version is %" PRIu32 ".%" PRIu32 ".", + *ree_major, *ree_minor, *tee_major, *tee_minor); + } else { + LOGI("Accepted connection from REE version %" PRIu32 + ".x. TEE version is %" PRIu32 ".x.", + *ree_major, *tee_major); + } } return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/test/common.mk b/oemcrypto/test/common.mk index bf5a1a2..d52727f 100644 --- a/oemcrypto/test/common.mk +++ b/oemcrypto/test/common.mk @@ -18,6 +18,7 @@ endif LOCAL_CFLAGS += -DTEST_OEMCRYPTO_V15 LOCAL_SRC_FILES:= \ + GEN_api_lock_file.c \ oec_device_features.cpp \ oec_decrypt_fallback_chain.cpp \ oec_key_deriver.cpp \ diff --git a/oemcrypto/test/fuzz_tests/README.md b/oemcrypto/test/fuzz_tests/README.md index 3f66444..f4e8671 100644 --- a/oemcrypto/test/fuzz_tests/README.md +++ b/oemcrypto/test/fuzz_tests/README.md @@ -127,8 +127,7 @@ OEMCrypto implementations on linux. information locally. * Build and test fuzz scripts locally using following commands. The build - script builds fuzz binaries for both oemcrypto reference implementation - as well as opk implementation. + script builds fuzz binaries for opk implementation. ```shell $ cd PATH_TO_CDM_DIR diff --git a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests index 2b8c902..e164860 100755 --- a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests +++ b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests @@ -6,18 +6,21 @@ set -ex +# CDM_DIR is used by several script, especially when there is some confusion +if [ -z "$CDM_DIR" ]; then + export CDM_DIR="$(readlink -e $(dirname $0)/../../..)" +fi +cd $CDM_DIR + export CXX=clang++ export CC=clang export GYP_DEFINES="$GYP_DEFINES clang=1" -export PATH_TO_CDM_DIR=. -export PYTHONPATH="$PYTHONPATH:$PATH_TO_CDM_DIR/third_party" +echo "CDM_DIR = $CDM_DIR" +export PYTHONPATH="$PYTHONPATH:$CDM_DIR/third_party" -python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ - --depth=$(pwd) oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp -ninja -C out/Default # oemcrypto_opk_fuzztests.gypi has flags to instrument all the gyp targets # with fuzzer flags. -python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ +python3 $CDM_DIR/third_party/gyp/__init__.py --format=ninja \ --depth=$(pwd) \ --include=oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi \ oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/1970fbbb5d20902996167f3309fbd38a6850b147 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_copy_buffer_fuzz_seed_corpus/1970fbbb5d20902996167f3309fbd38a6850b147 deleted file mode 100644 index 3c2447f9bc18bbd1d1a67eb6f627fa63d0a0bb3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 296 zcmZQzU|?7g3M62F5ypVf%#-%q|6k9*u%P=?8Au&7P`;Fzf#HJ>gx_Fv5-c7J)iw!A zBO61E`AW`=G{(TRLX!so?|>Dy diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/21d16dc13d2b8103c7943a5bd960ebc77dfefde4 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/21d16dc13d2b8103c7943a5bd960ebc77dfefde4 deleted file mode 100644 index f3c738d5c182c46c9066c79b0499ee5dec4c9436..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 zcmZQ%U|?_zV_;wf(jWk%8CuHsg2Wj%uzBnETP) Mw*V>+qtX2b04+9IT>t<8 diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cf22dc963d6705061004cb0fad32bdebc86ffc9 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3cf22dc963d6705061004cb0fad32bdebc86ffc9 deleted file mode 100644 index 30e88100f034feaf1c32bfdf2d3846267ab7bb9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmZQzU|?_z0}^P!;Cb0zkoX2P@q~Wt;ycba{9kf6_BH>;{?pYb*L61ZLew!r_3OsR U#lwt(naP|TJM&LHOq78E0Csa3rT_o{ diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3d891464eace6f7d3c716830e6051f7e90b90610 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/3d891464eace6f7d3c716830e6051f7e90b90610 deleted file mode 100644 index 66ff92c3df8a93cf6e458b560fa1356254b7919f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmZQ%U|?_zV_;wg(jdSNp%@mNE!ztcXJCX1K&ggz*v0>&f`17nBaE*@?YRFF9rjW8BRbsP?|9-cIF?D9Wa0<&oIK}nb7r;-r`G(GY{pC1CxGQ2n~` Vaq%#tU}iFB$Ikpy4-;iz002S36#xJL diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e9c4232d40cbc76f71220641ea9f8740bfedd306 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/e9c4232d40cbc76f71220641ea9f8740bfedd306 deleted file mode 100644 index d586f1009fe1439a68fbd3c2f8638df7c855adf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 zcmZQzU|?_z0}^P!!L)oYNPGzsnnW;m@yo?Y%J-S7<#v9Tvis-yP&Poe1gxJKs$Dle iE?yGKUI3*TvtnodsfTialo5={2xXwjqw8lvlLr7E-y4bm diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_decrypt_cenc_fuzz_seed_corpus/eaf3adf2980f1f1f021aafe465ec04d2bbf5d1ce deleted file mode 100644 index a7dc6140db763b9ce814b5d16502e98374a428cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmZQ%U|?_zV_@I{(#Sxep=d8ioPiNplz{=4_yhj&C~$GfZGaF^e%PcIKaY6d?!)rVd^H1XL}QWaiNmQv{JdgDw^}L`i_9y70Qq}bo79)Z?3T<3rf5n69V}LU9EP=8 qIR)tG_`iWwyDw!NymCQ`T3y1@g71D_rdQ1p6g#@B*7^1cH*s$~&ry~D diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/75ae4c5769c9568d631452df3b3702d876e4863a b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/75ae4c5769c9568d631452df3b3702d876e4863a deleted file mode 100644 index dd245f4a4ddc00b1cca222904933b0b2db4fccf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmV;j08Re@00000000000RjUA1qKHQ2?`4g4Gs@2UtV81ZJWNn?60@(_Rfmezi?9x zluA{Jv|QO|C{wh3MeG_J75+}A*O|BRh~s4{NSwpiF?h5>GW$E=wxdwv)R590me%*X zu-_V3iY5JtP^0o2Asy+uvY`HjEcth}>c7};Evn@aW4HVnI}t%I4T6gvyqUEmhkAf_ gsR)wr29dEWP(f$-0Iz6KxbVM0c%!9y;8r4t0d${H6aWAK diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/9bdb356ec50807b86c807c09c780267101fd1a0b b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_decrypt_fuzz_seed_corpus/9bdb356ec50807b86c807c09c780267101fd1a0b deleted file mode 100644 index ff53f68f159d0258d8fe2bba37ed9ba2913cb573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmV;j08Re@00000000000RjUA1qKHQ2?`4g4Gs@2UtV8_HXyT`fa^%*{7QpPTct;> zjg*qY;IF{pbl~8f7(jIOxb1rMY>C}jn>VaTJ_eul*D&hu5VaQhY;1tdsa=eqlB{i( zYG@zhx+RX}kb+gfzJS?5Vg~f)5uw6dwCEYrWdj8RV40|;A5Xscr;-Nqj@jCUR<;{A gBz%6$^aXOA%v2gJYFZ%mK!Kj-;94RS&8ga7YhK1tT>t<8 diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/374d2a1ab0be81451653b26a0ff99c2f20351700 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/374d2a1ab0be81451653b26a0ff99c2f20351700 deleted file mode 100644 index 561fce239d588473d524d83c007ec82eec9ec799..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmZQzfB*$3&B(;e!pg?Z!O6wV!^_7nASfg(A}S^>At@y-BP%Dbps1v*qN=8@p{b>< zqpPQHU}$7)Vrph?VQFP;V{2#c;OOM+;_Bw^;pye=IRvK4a#r*>mR3o4)`6vnDce diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/7a883f7628e57eb5fe48d660fed48ac5da2f5d21 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/7a883f7628e57eb5fe48d660fed48ac5da2f5d21 deleted file mode 100644 index 2f041f7076261bf210f58e1cc908fbde3a8dce64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmZQzU|?VbVtF720Y)Zf7FITP4o)s^9$r3v0YM>Q5m7O52}vnw8Cf}b1w|!g6;(BL z4NWa=9bG+r14AQY6H_yD3rj0&8(TYj2S+Do7gslT4^J;|A74NJfWV;OkkGL3h{&ku znAo`Zgv6xel+?8JjLfX;oZP(pg2JNWlG3vBipr|$n%cVhhQ_Amme#iRj?S*`p5DIx X2@@wxo-%dX^cgc}&7L!N-uwjsvnn!i diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a591b11c7ff1f45e8edb1a055a3255edb247576d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/a591b11c7ff1f45e8edb1a055a3255edb247576d deleted file mode 100644 index f5dc76e42e4ed468c4b7b003ec75455ceaebd131..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmZQzU|?VbVnrYZ0Y)Zf7FITP4o)s^9$r3v0YM>Q5m7O52}vnw8Cf}b1w|!g6;(BL z4NWa=9bG+r14AQY6H_yD3rj0&8(TYj2S+Do7gslT4^J;|A74NJfWV;OkkGL3h{&ku znAo`Zgv6xel+?8JjLfX;oZP(pg2JNWlG3vBipr|$n%cVhhQ_Amme#iRj?S*`p5DIx X2@@wxo-%dX^cgc}&7L!N-uwjsw0bgg diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/c182ac7556d1cd1ed73da74882dee807381f3ee0 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_generic_verify_fuzz_seed_corpus/c182ac7556d1cd1ed73da74882dee807381f3ee0 deleted file mode 100644 index 7a2af72516431ea8de5fcef709d3c821a3d53113..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmZQzU|?VbVg(=u0Y)Zf7FITP4o)s^9$r3v0YM>Q5m7O52}vnw8Cf}b1w|!g6;(BL z4NWa=9bG+r14AQY6H_yD3rj0&8(TYj2S+Do7gslT4^J;|A74NJfWV;OkkGL3h{&ku znAo`Zgv6xel+?8JjLfX;oZP(pg2JNWlG3vBipr|$n%cVhhQ_Amme#iRj?S*`p5DIx X2@@wxo-%dX^cgc}&7L!N-uwjsv(hqh diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/6f8b954fb7f8be2c3632f931aaf55e3d1a6c58d8 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/6f8b954fb7f8be2c3632f931aaf55e3d1a6c58d8 deleted file mode 100644 index baf0a05cde5b5839115e7a5081da7ae855f1d16d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmZQzKm`I&?m;vF6F=AN+_-!^w3?Fw+^)0L;8YXaFW|*w-?7%08nv!OM@F{`Q)oz4XObYv+#}_+}ZL zV=_25<4&rD@ZQIMOP=2^SiXZbYu!vns6|X@0A}7{GyoG{`RT(vz3`&u2+g?(zUMbP zaBoQ|dBhm>y=d+W`D%X|^`6_zt1I^375Q(>q1~Ht_6if!9%eKEGw%o*fQiTN4-;#g z5EsN!HYdyJx1zsxv1i-&xc;AviD>a|6Z8ETJid|W&% z3}I$TKm}lY12ldB8b1S#-+;!SfyUo~#=n5Ze}TqlfCfIyJql=i3p9QJ8b1S#-+{&l E0LH+VHvj+t diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/7997b5673d5a9402b2f8acc43f92cdf6ad1f913d b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/7997b5673d5a9402b2f8acc43f92cdf6ad1f913d deleted file mode 100644 index 4e600526090a3f5262c6080a76ef5d68f3965c6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmd1HkIzo6WPk%UDC-~^5P*uGO8RQ!HeL3>@uQWTQtO~nq5+tBhtL2_-2aHe)cNj42P<=~XUc~b@iB{CzWHfs zTHWKT=T6-$?0P$u-$F8C`C670PBSy@o^SPGgj&Re24LnLMguVMgJnz$D$jjVt5_HD zWqP_uY|}zN?!MT|lQfp46feDynw@K2e|p&kru@{07tL_wUmeFU3utD_2h{I(b#K&GA`Xy z{rR)i(m<}ws=u=mW;!DpfSGp)4Zy^$C0hfZp1gZ?*5%9R|4#bibyJr~cdz37d#kn! z=U@0Br@n5|7L_0D*6+iY^xa*cra6xhY7r9}fSGp~4Zy?~m#ggjx3_KLOhH*zrSFzE zyhZgxR&5MBv+kPXjU8Jb9^LdackjJRiJunc&5b?f?{tv~Y7a9SfSGp$4Zy^Ot6mBR z*(tMc70-Vtd4A(Lp~d0xhT+QDb23g!Z76?WT(b4tjlA#&6TQ|}KHw|OX=R4mqZ=O= z4+}$>SrSkI7~cSmAArWsK;t){@n@j%ccAevpz&Xz@fo0j4|9(K8s7qqAArWsK;w6y F@c|65oOA#H diff --git a/oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/81ac6d013d80da7f67fe6fbb5e8c15a35a0d8134 b/oemcrypto/test/fuzz_tests/corpus/oemcrypto_load_entitled_content_keys_fuzz_seed_corpus/81ac6d013d80da7f67fe6fbb5e8c15a35a0d8134 deleted file mode 100644 index 16a14bc7a02dc9ac8c8949f97ee1cca59b5fab1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmZQzKm`I&?m;vF6EACjEb^V9(y4aA*0+;>o47MO9#2^96`dii*mJ?~;emLiJEl`_ zHP}C!XuW(@-bKl3nCXmY0A}7HGyoG{zHEBcM&%b<+HX$Wy`bvb+$S@N?p_c+WBw-M zcK7Br!II2=|C4P}VrH#1Vw)buf1`;JY7r9}fSGp~4Zy?=W^FuODgP|5YJ0iTwEr_^ z9j@}vj9*rN<;_`d<{dBFnBK%)eJXsRZ+jkp1rukSmM9a{9%eKEGw%o*fQkPQ{2j2X zY}W&uPog)LGe>cjww)>qP}C4lYl^q{>$hX`#MOJ3sIkk5{t(evlDCe-kr`@_ZhTxk zEDT|0Nk9c)d;>Io02)67jo*OApMl2TfyTdp#(#mvXMhGi%smQdd input_buffer = + fuzzed_data.ConsumeRemainingBytes(); - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Fuzz input buffer to be copied. - size_t input_buffer_size = size - sizeof(fuzzed_structure); + const uint32_t session_id = license_api_fuzz.session().session_id(); + + // Initialize output buffer. + OEMCrypto_DestBufferDesc dest_buffer_desc; int secure_fd = 0; - // Create output buffer pointers. If secure buffer is not supported, we - // explicitly convert to clear buffer and fuzz. - if (!InitializeOutputBuffers(session->session_id(), - fuzzed_structure.dest_buffer_desc, &secure_fd, - input_buffer_size)) { - LOGI( - "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " - "clear buffer instead."); - fuzzed_structure.dest_buffer_desc.type = OEMCrypto_BufferType_Clear; - InitializeOutputBuffers(session->session_id(), - fuzzed_structure.dest_buffer_desc, &secure_fd, - input_buffer_size); + dest_buffer_desc.type = fuzzed_structure.dest_buffer_desc.type; + switch (dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + dest_buffer_desc.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[fuzzed_structure.dest_buffer_desc + .buffer_config]; + dest_buffer_desc.buffer.clear.clear_buffer_length = + fuzzed_structure.dest_buffer_desc.buffer_config; + break; + + case OEMCrypto_BufferType_Secure: + if (OEMCrypto_AllocateSecureBuffer( + session_id, fuzzed_structure.dest_buffer_desc.buffer_config, + &dest_buffer_desc, &secure_fd) != OEMCrypto_SUCCESS) { + return 0; + } + break; + + case OEMCrypto_BufferType_Direct: + dest_buffer_desc.buffer.direct.is_video = + fuzzed_structure.dest_buffer_desc.buffer_config & 1; + break; } - OEMCrypto_CopyBuffer(session->session_id(), data + sizeof(fuzzed_structure), - input_buffer_size, &fuzzed_structure.dest_buffer_desc, - subsample_flags); - FreeOutputBuffers(session->session_id(), fuzzed_structure.dest_buffer_desc, - &secure_fd); + + OEMCrypto_CopyBuffer(session_id, input_buffer.data(), input_buffer.size(), + &dest_buffer_desc, fuzzed_structure.subsample_flags); + + // Free output buffer. + switch (dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + delete[] dest_buffer_desc.buffer.clear.clear_buffer; + break; + + case OEMCrypto_BufferType_Secure: + OEMCrypto_FreeSecureBuffer(session_id, &dest_buffer_desc, secure_fd); + break; + + case OEMCrypto_BufferType_Direct: + break; + } + return 0; } -} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc index 560a172..47f39ef 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc @@ -2,29 +2,24 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" -namespace wvoec { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); - LicenseWithUsageEntryFuzz entry; + wvoec::LicenseWithUsageEntryFuzz entry; + entry.Initialize(); entry.CreateUsageTableHeader(); - // Open a session, create a usage entry. - Session* session = entry.license_messages().session(); - session->open(); - entry.InstallTestRSAKey(session); - session->GenerateNonce(); - session->CreateNewUsageEntry(); - vector encrypted_usage_header; - session->UpdateUsageEntry(&encrypted_usage_header); + entry.InstallTestRSAKey(); + entry.session().CreateNewUsageEntry(); + entry.session().GenerateNonce(); + std::vector encrypted_usage_header; + entry.session().UpdateUsageEntry(&encrypted_usage_header); // LoadLicense sets the pst for usage entry. entry.LoadLicense(); + OEMCrypto_DeactivateUsageEntry(entry.session().session_id(), data, size); + entry.Terminate(); - OEMCrypto_DeactivateUsageEntry(session->session_id(), data, size); - session->close(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc index eb1465e..d67c2b4 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc @@ -2,186 +2,178 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_overflow.h" -namespace wvoec { -const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; -// Free dynamic memory allocated by fuzzer script. -void FreeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_SampleDescription* sample_description, - size_t sample_index, int* secure_fd_array) { - for (size_t i = 0; i < sample_index; i++) { - OEMCrypto_DestBufferDesc fuzzed_output_descriptor = - sample_description[i].buffers.output_descriptor; - switch (fuzzed_output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - delete[] fuzzed_output_descriptor.buffer.clear.clear_buffer; - break; - } - case OEMCrypto_BufferType_Secure: { - OEMCrypto_FreeSecureBuffer(session_id, &fuzzed_output_descriptor, - secure_fd_array[i]); - break; - } - case OEMCrypto_BufferType_Direct: { - break; - } - } - } -} +namespace { -// Function to initialize output buffer pointers by allocating memory. -// Limiting output buffer size to 5 MB as 4 MB is maximum size specified -// by resource rating tier documentation. -bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - size_t sample_index, - vector& secure_fd_array) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - output_descriptor.buffer.clear.clear_buffer = - new OEMCrypto_SharedMemory[std::min( - MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.clear.clear_buffer_length)]; - return true; - } - case OEMCrypto_BufferType_Secure: { - int* secure_fd; - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_id, - std::min(MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.secure.secure_buffer_length), - &output_descriptor, secure_fd); - if (sts == OEMCrypto_SUCCESS) secure_fd_array[sample_index] = *secure_fd; - return sts == OEMCrypto_SUCCESS; - } - case OEMCrypto_BufferType_Direct: { - return true; - } - } +// Limit output buffer size to 5 MB as 4 MB is maximum size specified by +// resource rating tier documentation. +constexpr size_t MAX_FUZZ_SAMPLE_SIZE = 5 * wvoec::MB; + +// Avoid calling non-trivial destructor. +wvoec::OEMCryptoLicenseAPIFuzz& license_api_fuzz = + *new wvoec::OEMCryptoLicenseAPIFuzz; + +} // namespace + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + wvoec::RedirectStdoutToFile(); + license_api_fuzz.Initialize(); + license_api_fuzz.LoadLicense(); + return 0; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - size_t samples_length; - // Split data using separator. - auto inputs = SplitInput(data, size); - if (inputs.size() < 2) { + const std::vector inputs = + wvoec::SplitFuzzedData(data, size); + if (inputs.size() < 3) { return 0; } - OEMCrypto_Decrypt_Cenc_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + // Read cipher mode and pattern from fuzzed data. + wvoec::OEMCrypto_Decrypt_Cenc_Fuzz fuzzed_structure; + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } - // Copy OEMCrypto_Decrypt_Cenc_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); - ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + wvoec::ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, + fuzzed_structure.cipher_mode); - size_t remaining_size_for_samples = - inputs[0].size() - sizeof(fuzzed_structure); - // Initialize FDP structures to read data using inbuilt functions. - FuzzedDataProvider fuzzed_sample_data(data + sizeof(fuzzed_structure), - remaining_size_for_samples); - FuzzedDataProvider fuzzed_subsample_data(inputs[1].data(), inputs[1].size()); + // Allocate sample descriptions. + std::vector sample_descriptions( + fuzzed_data.remaining_bytes() / + sizeof(wvoec::OEMCrypto_SampleDescription_Fuzz)); - // Read subsamples from fuzzed data. - vector subsamples; - while (fuzzed_subsample_data.remaining_bytes() >= - sizeof(OEMCrypto_SubSampleDescription)) { - OEMCrypto_SubSampleDescription subsample; - fuzzed_subsample_data.ConsumeData(&subsample, - sizeof(OEMCrypto_SubSampleDescription)); - subsamples.push_back(subsample); - } - if (subsamples.size() == 0) { - return 0; - } + // Allocate input buffers for each sample description. + std::vector> input_buffers( + sample_descriptions.size()); - // Infer samples_length from fuzzed data. - size_t sample_description_size = sizeof(OEMCrypto_SampleDescription); - samples_length = - fuzzed_sample_data.remaining_bytes() / sample_description_size; - if (samples_length == 0) { - return 0; - } + // Allocate secure_fd values for secure buffers. + std::vector secure_fd_array(sample_descriptions.size()); - // Initialize sample_descriptions array. - vector sample_descriptions(samples_length); - // Create array to maintain secure_fd buffer values for secure buffers. - vector secure_fd_array(samples_length); + // Allocate subsamples for each sample description. + std::vector> subsamples( + sample_descriptions.size()); - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Copy samples from fuzzed data. - size_t input_subsample_index = 0; - size_t total_input_data_length = 0; - for (size_t i = 0; i < samples_length; i++) { - fuzzed_sample_data.ConsumeData(&sample_descriptions[i], - sample_description_size); - ConvertDataToValidEnum( + const uint32_t session_id = license_api_fuzz.session().session_id(); + + // Free first given number of output buffers. + const auto FreeOutputBuffers = [&sample_descriptions, session_id, + &secure_fd_array](size_t num_buffers) { + for (size_t i = 0; i < num_buffers; i++) { + OEMCrypto_DestBufferDesc& output_descriptor = + sample_descriptions[i].buffers.output_descriptor; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + delete[] output_descriptor.buffer.clear.clear_buffer; + break; + + case OEMCrypto_BufferType_Secure: + OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, + secure_fd_array[i]); + break; + + case OEMCrypto_BufferType_Direct: + break; + } + } + }; + + // Prepare each sample description. + FuzzedDataProvider& sample_description_data = fuzzed_data; + FuzzedDataProvider input_buffer_data(inputs[1].data, inputs[1].size); + FuzzedDataProvider subsample_data(inputs[2].data, inputs[2].size); + for (size_t i = 0; i < sample_descriptions.size(); i++) { + // Read and normalize sample description fuzzed properties. + wvoec::OEMCrypto_SampleDescription_Fuzz fuzzed_sample_description; + sample_description_data.ConsumeData(&fuzzed_sample_description, + sizeof(fuzzed_sample_description)); + fuzzed_sample_description.buffers.input_data_length %= + MAX_FUZZ_SAMPLE_SIZE + 1; + wvoec::ConvertDataToValidEnum( OEMCrypto_BufferType_MaxValue, - &sample_descriptions[i].buffers.output_descriptor.type); + fuzzed_sample_description.buffers.output_descriptor.type); + fuzzed_sample_description.buffers.output_descriptor.buffer_config %= + MAX_FUZZ_SAMPLE_SIZE + 1; - // Copy random data into input sample data. Cap input data length at 5 MB, - // 1 MB higher than that described by resource rating tier. - total_input_data_length += std::min( - MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length); - - // Copy sub sample data. - sample_descriptions[i].subsamples = &subsamples[input_subsample_index]; - if (OPK_AddOverflowUX(input_subsample_index, - sample_descriptions[i].subsamples_length, - &input_subsample_index)) { + // Read input data. + if (fuzzed_sample_description.buffers.input_data_length > + input_buffer_data.remaining_bytes()) { + FreeOutputBuffers(i); return 0; } - if (input_subsample_index > subsamples.size()) return 0; - } // Sample loop. + input_buffers[i] = input_buffer_data.ConsumeBytes( + fuzzed_sample_description.buffers.input_data_length); + sample_descriptions[i].buffers.input_data = input_buffers[i].data(); + sample_descriptions[i].buffers.input_data_length = input_buffers[i].size(); - // Allocate input/output buffers for each sample description. - vector input_buffer(total_input_data_length); - size_t input_buffer_index = 0; - for (size_t i = 0; i < samples_length; i++) { - sample_descriptions[i].buffers.input_data = - &input_buffer[input_buffer_index]; - input_buffer_index += std::min( - MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length); + // Set subsample data. + if (fuzzed_sample_description.subsamples_length > + subsample_data.remaining_bytes() / + sizeof(OEMCrypto_SubSampleDescription)) { + FreeOutputBuffers(i); + return 0; + } + if (fuzzed_sample_description.subsamples_length > 0) { + subsamples[i].resize(fuzzed_sample_description.subsamples_length); + subsample_data.ConsumeData( + subsamples[i].data(), + subsamples[i].size() * sizeof(OEMCrypto_SubSampleDescription)); + } + sample_descriptions[i].subsamples = subsamples[i].data(); + sample_descriptions[i].subsamples_length = subsamples[i].size(); - // Create output buffer pointers. If secure buffer is not supported, we - // explicitly convert to clear buffer and fuzz. - if (!InitializeOutputBuffers( - session->session_id(), - sample_descriptions[i].buffers.output_descriptor, i, - secure_fd_array)) { - LOGI( - "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " - "clear buffer instead."); - sample_descriptions[i].buffers.output_descriptor.type = - OEMCrypto_BufferType_Clear; - InitializeOutputBuffers(session->session_id(), - sample_descriptions[i].buffers.output_descriptor, - i, secure_fd_array); + // Set IV data. + memcpy(sample_descriptions[i].iv, fuzzed_sample_description.iv, + sizeof(sample_descriptions[i].iv)); + + // Initialize output buffer. + OEMCrypto_DestBufferDesc& output_descriptor = + sample_descriptions[i].buffers.output_descriptor; + const wvoec::OEMCrypto_DestBufferDesc_Fuzz& fuzzed_output_descriptor = + fuzzed_sample_description.buffers.output_descriptor; + output_descriptor.type = fuzzed_output_descriptor.type; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + output_descriptor.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[fuzzed_output_descriptor.buffer_config]; + output_descriptor.buffer.clear.clear_buffer_length = + fuzzed_output_descriptor.buffer_config; + break; + + case OEMCrypto_BufferType_Secure: + if (OEMCrypto_AllocateSecureBuffer( + session_id, fuzzed_output_descriptor.buffer_config, + &output_descriptor, &secure_fd_array[i]) != OEMCrypto_SUCCESS) { + FreeOutputBuffers(i); + return 0; + } + break; + + case OEMCrypto_BufferType_Direct: + output_descriptor.buffer.direct.is_video = + fuzzed_output_descriptor.buffer_config & 1; + break; } } // Load license and call decrypt_cenc API. - license_api_fuzz.LoadLicense(); - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, + const wvoec::MessageKeyData& key = + license_api_fuzz.session().license().keys[0]; + OEMCrypto_SelectKey(session_id, key.key_id, key.key_id_length, fuzzed_structure.cipher_mode); - OEMCrypto_DecryptCENC(session->session_id(), sample_descriptions.data(), - samples_length, &fuzzed_structure.pattern); - FreeOutputBuffers(session->session_id(), sample_descriptions.data(), - samples_length, secure_fd_array.data()); + OEMCrypto_DecryptCENC(session_id, sample_descriptions.data(), + sample_descriptions.size(), &fuzzed_structure.pattern); + + // Free all output buffers. + FreeOutputBuffers(sample_descriptions.size()); + return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc index f76fafa..a5d058e 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc @@ -1,36 +1,81 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine // License Agreement. + +#include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" namespace wvoec { + void RedirectStdoutToFile() { freopen("log.txt", "a", stdout); } -std::vector> SplitInput(const uint8_t* data, size_t size) { - std::vector> result; - auto current_pos = data; - auto end = data + size; - // Using memmem to find separator - while (const uint8_t* pos = reinterpret_cast( - memmem(current_pos, end - current_pos, kFuzzDataSeparator, - sizeof(kFuzzDataSeparator)))) { - result.push_back({current_pos, pos}); - current_pos = pos + sizeof(kFuzzDataSeparator); +std::vector SplitFuzzedData(const uint8_t* data, size_t size) { + std::vector result; + const uint8_t* const end = data + size; + // Using memmem to find separator. + while ( + const uint8_t* const separator = reinterpret_cast(memmem( + data, end - data, kFuzzDataSeparator, sizeof(kFuzzDataSeparator)))) { + result.push_back({data, static_cast(separator - data)}); + data = separator + sizeof(kFuzzDataSeparator); } - if (current_pos < end) { - result.push_back({current_pos, end}); + if (data < end) { + result.push_back({data, static_cast(end - data)}); } return result; } -void OEMCryptoLicenseAPIFuzz::LoadLicense() { +void InitializeFuzz(SessionUtil& session_util) { + wvoec::global_features.Initialize(); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + OEMCrypto_Initialize(); + session_util.EnsureTestKeys(); +} + +void SessionFuzz::Initialize() { + InitializeFuzz(session_util_); + session_.open(); +} + +void SessionFuzz::Terminate() { + session_.close(); + OEMCrypto_Terminate(); +} + +void OEMCryptoLicenseAPIFuzz::Initialize() { + session_fuzz_.Initialize(); + session_fuzz_.InstallTestRSAKey(); + session_fuzz_.session().GenerateNonce(); +} + +void OEMCryptoLicenseAPIFuzz::Terminate() { + session_fuzz_.Terminate(); +} + +void OEMCryptoLicenseAPIFuzz::LoadLicense(bool generic_crypto_keys) { license_messages_.SignAndVerifyRequest(); - license_messages_.CreateDefaultResponse(); + if (generic_crypto_keys) { + license_messages_.CreateResponseWithGenericCryptoKeys(); + } else { + license_messages_.CreateDefaultResponse(); + } license_messages_.EncryptAndSignResponse(); OEMCryptoResult sts = license_messages_.LoadResponse(); CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); } +void OEMCryptoProvisioningAPIFuzz::Initialize() { + InitializeFuzz(session_util_); + + // Opens a session and Generates Nonce. + provisioning_messages_.PrepareSession(session_util_.keybox_); +} + +void OEMCryptoProvisioningAPIFuzz::Terminate() { + session_.close(); + OEMCrypto_Terminate(); +} + void OEMCryptoProvisioningAPIFuzz::LoadProvisioning() { provisioning_messages_.SignAndVerifyRequest(); provisioning_messages_.CreateDefaultResponse(); @@ -63,4 +108,5 @@ void CheckStatusAndExitFuzzerOnFailure(OEMCryptoResult result, abort(); } } + } // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h index 2aa1f46..a60a9cf 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h @@ -1,134 +1,214 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine // License Agreement. + #ifndef OEMCRYPTO_FUZZ_HELPER_H_ #define OEMCRYPTO_FUZZ_HELPER_H_ +#include +#include #include #include "FuzzedDataProvider.h" -#include "OEMCryptoCENC.h" #include "oec_device_features.h" #include "oemcrypto_corpus_generator_helper.h" #include "oemcrypto_session_tests_helper.h" -namespace wvoec { // Forward-declare the libFuzzer's mutator callback. Mark it weak so that // the program links successfully even outside of --config=asan-fuzzer // (apparently the only config in which LLVM uses our custom mutator). extern "C" size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize) __attribute__((weak)); -const size_t KB = 1024; -// Maximum signature length. If fuzzed signature length is greater that this, -// this value will be used for signature length. -const size_t MAX_FUZZ_SIGNATURE_LENGTH = 5 * KB; +namespace wvoec { + +constexpr size_t KB = 1024; + +// Default maximum length of fuzzing output parameters. +constexpr size_t MAX_FUZZ_OUTPUT_LENGTH = 5 * KB; + +// Fuzzed data region. +struct FuzzedData { + const uint8_t* data; + size_t size; +}; + // Initial setup to create a valid OEMCrypto state such as initializing crypto // firmware/hardware, installing golden key box etc. in order to fuzz // OEMCrypto APIs. -class InitializeFuzz : public SessionUtil { +void InitializeFuzz(SessionUtil& session_util); + +class SessionFuzz { public: - InitializeFuzz() { - wvoec::global_features.Initialize(); - OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); - OEMCrypto_Initialize(); - EnsureTestKeys(); + void Initialize(); + + void Terminate(); + + void InstallTestRSAKey() { + session_util_.InstallTestRSAKey(&session_); } - ~InitializeFuzz() { OEMCrypto_Terminate(); } + Session& session() { return session_; } + + const Session& session() const { return session_; } + + private: + SessionUtil session_util_; + Session session_; }; -class OEMCryptoLicenseAPIFuzz : public InitializeFuzz { +class OEMCryptoLicenseAPIFuzz { public: - OEMCryptoLicenseAPIFuzz() : license_messages_(&session_) { - session_.open(); - InstallTestRSAKey(&session_); - session_.GenerateNonce(); - } + OEMCryptoLicenseAPIFuzz() : license_messages_(&session_fuzz_.session()) {} - ~OEMCryptoLicenseAPIFuzz() { session_.close(); } + void Initialize(); + + void Terminate(); + + void LoadLicense() { LoadLicense(false); } + + void LoadLicenseWithGenericCryptoKeys() { LoadLicense(true); } LicenseRoundTrip& license_messages() { return license_messages_; } - Session* session() { return &session_; } + const LicenseRoundTrip& license_messages() const { return license_messages_; } - void LoadLicense(); + Session& session() { return session_fuzz_.session(); } + + const Session& session() const { return session_fuzz_.session(); } private: - Session session_; + void LoadLicense(bool generic_crypto_keys); + + SessionFuzz session_fuzz_; LicenseRoundTrip license_messages_; }; -class OEMCryptoProvisioningAPIFuzz : public InitializeFuzz { +class OEMCryptoProvisioningAPIFuzz { public: OEMCryptoProvisioningAPIFuzz() - : provisioning_messages_(&session_, encoded_rsa_key_) { - // Opens a session and Generates Nonce. - provisioning_messages_.PrepareSession(keybox_); - } + : provisioning_messages_(&session_, session_util_.encoded_rsa_key_) {} - ~OEMCryptoProvisioningAPIFuzz() { session_.close(); } + void Initialize(); + + void Terminate(); void LoadProvisioning(); + ProvisioningRoundTrip& provisioning_messages() { return provisioning_messages_; } - Session* session() { return &session_; } + + const ProvisioningRoundTrip& provisioning_messages() const { + return provisioning_messages_; + } + + Session& session() { return session_; } + + const Session& session() const { return session_; } private: + SessionUtil session_util_; Session session_; ProvisioningRoundTrip provisioning_messages_; }; // Initial setup to create a valid state such as creating session, installing // golden key box etc. in order to fuzz Load Renewal API. -class OEMCryptoRenewalAPIFuzz : public OEMCryptoLicenseAPIFuzz { +class OEMCryptoRenewalAPIFuzz { public: - OEMCryptoRenewalAPIFuzz() : renewal_messages_(&license_messages()) {} + OEMCryptoRenewalAPIFuzz() + : renewal_messages_(&license_api_fuzz_.license_messages()) {} + + void Initialize() { license_api_fuzz_.Initialize(); } + + void Terminate() { license_api_fuzz_.Terminate(); } + + LicenseRoundTrip& license_messages() { + return license_api_fuzz_.license_messages(); + } + + const LicenseRoundTrip& license_messages() const { + return license_api_fuzz_.license_messages(); + } RenewalRoundTrip& renewal_messages() { return renewal_messages_; } + const RenewalRoundTrip& renewal_messages() const { return renewal_messages_; } + private: + OEMCryptoLicenseAPIFuzz license_api_fuzz_; RenewalRoundTrip renewal_messages_; }; -class LicenseWithUsageEntryFuzz : public InitializeFuzz { +class LicenseWithUsageEntryFuzz { public: - LicenseWithUsageEntryFuzz() : license_messages_(&session_) { + LicenseWithUsageEntryFuzz() : license_messages_(&session_fuzz_.session()) { license_messages_.set_pst("my_pst"); } + void Initialize() { session_fuzz_.Initialize(); } + + void Terminate() { session_fuzz_.Terminate(); } + void CreateUsageTableHeader(); - LicenseRoundTrip& license_messages() { return license_messages_; } - const vector& encrypted_usage_header() { - return encrypted_usage_header_; - } + + void InstallTestRSAKey() { session_fuzz_.InstallTestRSAKey(); } + void LoadLicense(); + LicenseRoundTrip& license_messages() { return license_messages_; } + + const LicenseRoundTrip& license_messages() const { return license_messages_; } + + const std::vector& encrypted_usage_header() const { + return encrypted_usage_header_; + } + + Session& session() { return session_fuzz_.session(); } + + const Session& session() const { return session_fuzz_.session(); } + private: - vector encrypted_usage_header_; + SessionFuzz session_fuzz_; LicenseRoundTrip license_messages_; - Session session_; + std::vector encrypted_usage_header_; }; -// Convert data to valid enum value. +// Convert data from FuzzedDataProvider to valid enum value. template -void ConvertDataToValidEnum(T max_enum_value, T* t) { - FuzzedDataProvider fuzzed_enum_data(reinterpret_cast(t), sizeof(T)); - *t = static_cast(fuzzed_enum_data.ConsumeIntegralInRange( - 0, static_cast(max_enum_value))); +T ConvertDataToValidEnum(FuzzedDataProvider& fuzzed_data, T max_enum_value) { + using UnsignedT = + typename std::make_unsigned::type>::type; + return static_cast(fuzzed_data.ConsumeIntegralInRange( + 0, static_cast(max_enum_value))); +} + +// Convert data to valid enum value in place. +template +void ConvertDataToValidEnum(T max_enum_value, T& enum_data) { + using UnsignedT = + typename std::make_unsigned::type>::type; + UnsignedT data; + std::memcpy(&data, &enum_data, sizeof(T)); + const auto max_value = static_cast(max_enum_value); + if (data > max_value) { + enum_data = static_cast(data % (max_value + 1)); + } } // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise void RedirectStdoutToFile(); -// Function to split fuzzer input using delimiter "-_^_". -std::vector> SplitInput(const uint8_t* data, size_t size); +// Split fuzzed data using delimiter "-_^_". +std::vector SplitFuzzedData(const uint8_t* data, size_t size); + // Check the status and exit fuzzer if arguments do not match. This is usually // called to check status of APIs which are called to setup state for fuzzers. void CheckStatusAndExitFuzzerOnFailure(OEMCryptoResult result, OEMCryptoResult expected_status); + } // namespace wvoec #endif // OEMCRYPTO_FUZZ_HELPER_H_ diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h index 37b3daf..42d077c 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h @@ -8,6 +8,26 @@ #include "odk.h" namespace wvoec { + +// OEMCrypto_DestBufferDesc fuzzed properties. +struct OEMCrypto_DestBufferDesc_Fuzz { + OEMCryptoBufferType type; + size_t buffer_config; +}; + +// OEMCrypto_InputOutputPair fuzzed properties. +struct OEMCrypto_InputOutputPair_Fuzz { + size_t input_data_length; + OEMCrypto_DestBufferDesc_Fuzz output_descriptor; +}; + +// OEMCrypto_SampleDescription fuzzed properties. +struct OEMCrypto_SampleDescription_Fuzz { + OEMCrypto_InputOutputPair_Fuzz buffers; + uint8_t iv[16]; + size_t subsamples_length; +}; + struct OEMCrypto_Renewal_Response_Fuzz { // Timer limits in core license response needs to be fuzzed as load renewal // depends on timer limits loaded from license response. @@ -50,16 +70,6 @@ struct OEMCrypto_Generic_Api_Fuzz { // this structure. }; -struct OEMCrypto_Generic_Verify_Fuzz { - // Corpus format is as belowr. - // cipher_mode + algorithm + signature_length + buffer with actual data - OEMCryptoCipherMode cipher_mode; - OEMCrypto_Algorithm algorithm; - size_t signature_length; - // Buffer data is of variable length and not included in - // this structure. -}; - struct OEMCrypto_Generate_RSA_Signature_Fuzz { // Corpus format is as below, let | be separator. // padding_scheme + signature_length + input buffer @@ -72,10 +82,11 @@ struct OEMCrypto_Generate_RSA_Signature_Fuzz { struct OEMCrypto_Copy_Buffer_Fuzz { // Corpus format is as below. // dest_buffer_desc + subsample_flags + input buffer - OEMCrypto_DestBufferDesc dest_buffer_desc; + OEMCrypto_DestBufferDesc_Fuzz dest_buffer_desc; uint8_t subsample_flags; // Input buffer of variable length is not included in this structure. }; + } // namespace wvoec -#endif // OEMCRYPTO_FUZZ_STRUCTS_H_ \ No newline at end of file +#endif // OEMCRYPTO_FUZZ_STRUCTS_H_ diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp deleted file mode 100644 index 458e3b8..0000000 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -#source code may only be used and distributed under the Widevine License -#Agreement. -# -# Builds under the CDM ./build.py (target platform) build system -# Refer to the distribution package's README for details. -{ - 'target_defaults': { - 'type': 'executable', - 'includes': [ - 'oemcrypto_fuzztests.gypi', - ], - }, - 'variables': { - # Flag to select appropriate underlying oemcrypto implementation when - # buiding fuzz binaries. - 'oemcrypto_implementation_version%': 'reference', - }, - 'targets': [ - { - 'target_name': 'oemcrypto_load_license_fuzz', - 'sources': [ - 'oemcrypto_load_license_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_provisioning_fuzz', - 'sources': [ - 'oemcrypto_load_provisioning_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_renewal_fuzz', - 'sources': [ - 'oemcrypto_load_renewal_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_license_request_fuzz', - 'sources': [ - 'oemcrypto_license_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_provisioning_request_fuzz', - 'sources': [ - 'oemcrypto_provisioning_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_renewal_request_fuzz', - 'sources': [ - 'oemcrypto_renewal_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_decrypt_cenc_fuzz', - 'sources': [ - 'oemcrypto_decrypt_cenc_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_entitled_content_keys_fuzz', - 'sources': [ - 'oemcrypto_load_entitled_content_keys_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_encrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_encrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_decrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_decrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_sign_fuzz', - 'sources': [ - 'oemcrypto_generic_sign_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_verify_fuzz', - 'sources': [ - 'oemcrypto_generic_verify_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generate_rsa_signature_fuzz', - 'sources': [ - 'oemcrypto_generate_rsa_signature_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_usage_table_header_fuzz', - 'sources': [ - 'oemcrypto_load_usage_table_header_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_load_usage_entry_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_deactivate_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_deactivate_usage_entry_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_report_usage_fuzz', - 'sources': [ - 'oemcrypto_report_usage_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_copy_buffer_fuzz', - 'sources': [ - 'oemcrypto_copy_buffer_fuzz.cc', - ], - }, - ], -} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi index cdbeadd..f8abdec 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi @@ -29,6 +29,7 @@ '<(util_dir)/src/platform.cpp', '<(util_dir)/src/rw_lock.cpp', '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', '<(util_dir)/test/test_sleep.cpp', '<(util_dir)/test/test_clock.cpp', ], @@ -102,18 +103,11 @@ '-fcoverage-mapping', ], }], - ['oemcrypto_implementation_version=="reference"', { - # Include oemcrypto reference implementation code for building reference - # implementation fuzz binaries. - 'includes': [ - '../../ref/oec_ref.gypi', - ], - }], ['oemcrypto_implementation_version=="opk"', { # Include oemcrypto opk implementation code for building opk # implementation fuzz binaries. 'dependencies': [ - '<(oemcrypto_dir)/opk/ports/linux/wtpi_test_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc', + '<(oemcrypto_dir)/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc', ], }], ], # conditions diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc index 872b302..1537323 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc @@ -2,33 +2,35 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" - -namespace wvoec { +#include "oemcrypto_fuzz_structs.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure; - if (size <= sizeof(OEMCrypto_Generate_RSA_Signature_Fuzz)) { + wvoec::RedirectStdoutToFile(); + + wvoec::OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure; + if (size < sizeof(fuzzed_structure)) { return 0; } + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + fuzzed_structure.signature_length %= wvoec::MAX_FUZZ_OUTPUT_LENGTH + 1; + const std::vector message = + fuzzed_data.ConsumeRemainingBytes(); + std::vector signature(fuzzed_structure.signature_length); - // Copy data to fuzzed structure. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); - // Creates wrapped rsa key and calls load drm private key. - static OEMCryptoLicenseAPIFuzz license_api_fuzz; - // We cannot allocate buffers of random huge lengths in memory. - // This also slows down the fuzzer. - size_t signature_length = - std::min(MAX_FUZZ_SIGNATURE_LENGTH, fuzzed_structure.signature_length); - vector signature(signature_length); + wvoec::SessionFuzz session_fuzz; + session_fuzz.Initialize(); + session_fuzz.InstallTestRSAKey(); OEMCrypto_GenerateRSASignature( - license_api_fuzz.session()->session_id(), data + sizeof(fuzzed_structure), - size - sizeof(fuzzed_structure), signature.data(), &signature_length, + session_fuzz.session().session_id(), message.data(), message.size(), + signature.data(), &fuzzed_structure.signature_length, fuzzed_structure.padding_scheme); + session_fuzz.Terminate(); + return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc deleted file mode 100644 index 19b60b7..0000000 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include "properties.h" -#include "oemcrypto_session_tests_helper.h" - -using namespace wvoec; - -static bool is_init = false; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - SessionUtil session_helper; - if (!is_init) { - wvoec::global_features.Initialize(); - wvoec::global_features.RestrictFilter("*"); - wvutil::Properties::Init(); - is_init = true; - } - - OEMCrypto_Initialize(); - session_helper.EnsureTestKeys(); - - Session s; - s.open(); - s.GenerateDerivedKeysFromKeybox(session_helper.keybox_); - - static const uint32_t SignatureBufferMaxLength = size; - vector signature(SignatureBufferMaxLength); - size_t signature_length = signature.size(); - - OEMCryptoResult sts; - sts = OEMCrypto_GenerateSignature(s.session_id(), data, size, - &signature[0], &signature_length); - - s.close(); - OEMCrypto_Terminate(); - - return 0; -} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc index e36d550..953a1d2 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc @@ -2,60 +2,64 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_types.h" -namespace wvoec { +namespace { + +// Avoid calling non-trivial destructor. +wvoec::OEMCryptoLicenseAPIFuzz& license_api_fuzz = + *new wvoec::OEMCryptoLicenseAPIFuzz; + +} // namespace + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + wvoec::RedirectStdoutToFile(); + license_api_fuzz.Initialize(); + license_api_fuzz.LoadLicenseWithGenericCryptoKeys(); + return 0; +} + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = + wvoec::SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } - OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + wvoec::OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); - ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); - ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, - &fuzzed_structure.algorithm); - + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + wvoec::ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, + fuzzed_structure.cipher_mode); + wvoec::ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, + fuzzed_structure.algorithm); // Copy iv from input data. - size_t iv_size = inputs[0].size() - sizeof(fuzzed_structure); - if (iv_size == 0) { - return 0; - } - vector iv(iv_size); - memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size); + constexpr size_t iv_length = 16; + const std::vector iv = fuzzed_data.ConsumeBytes( + fuzzed_data.remaining_bytes() < iv_length ? 0 : iv_length); - // Copy clear buffer from input data. - vector encrypted_buffer(inputs[1].size()); - vector clear_buffer(inputs[1].size()); - memcpy(encrypted_buffer.data(), inputs[1].data(), inputs[1].size()); + // Initialize encrypted and clear buffers. + const std::vector encrypted_buffer(inputs[1].data, + inputs[1].data + inputs[1].size); + std::vector clear_buffer(encrypted_buffer.size()); - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Load license and call generic_decrypt API. - license_api_fuzz.LoadLicense(); - OEMCryptoResult sts = OEMCrypto_SelectKey( - session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, fuzzed_structure.cipher_mode); - CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); - OEMCrypto_Generic_Decrypt(session->session_id(), encrypted_buffer.data(), + // Select key and decrypt. + wvoec::Session& session = license_api_fuzz.session(); + OEMCrypto_SelectKey(session.session_id(), session.license().keys[1].key_id, + session.license().keys[1].key_id_length, + fuzzed_structure.cipher_mode); + OEMCrypto_Generic_Decrypt(session.session_id(), encrypted_buffer.data(), encrypted_buffer.size(), iv.data(), fuzzed_structure.algorithm, clear_buffer.data()); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc index df0a35e..dc2632a 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc @@ -2,60 +2,64 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_types.h" -namespace wvoec { +namespace { + +// Avoid calling non-trivial destructor. +wvoec::OEMCryptoLicenseAPIFuzz& license_api_fuzz = + *new wvoec::OEMCryptoLicenseAPIFuzz; + +} // namespace + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + wvoec::RedirectStdoutToFile(); + license_api_fuzz.Initialize(); + license_api_fuzz.LoadLicenseWithGenericCryptoKeys(); + return 0; +} + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = + wvoec::SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } - OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + wvoec::OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); - ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); - ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, - &fuzzed_structure.algorithm); - + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + wvoec::ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, + fuzzed_structure.cipher_mode); + wvoec::ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, + fuzzed_structure.algorithm); // Copy iv from input data. - size_t iv_size = inputs[0].size() - sizeof(fuzzed_structure); - if (iv_size == 0) { - return 0; - } - vector iv(iv_size); - memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size); + constexpr size_t iv_length = 16; + const std::vector iv = fuzzed_data.ConsumeBytes( + fuzzed_data.remaining_bytes() < iv_length ? 0 : iv_length); - // Copy clear buffer from input data. - vector clear_buffer(inputs[1].size()); - vector encrypted_buffer(inputs[1].size()); - memcpy(clear_buffer.data(), inputs[1].data(), inputs[1].size()); + // Initialize clear and encrypted buffers. + const std::vector clear_buffer(inputs[1].data, + inputs[1].data + inputs[1].size); + std::vector encrypted_buffer(clear_buffer.size()); - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Load license and call generic_encrypt API. - license_api_fuzz.LoadLicense(); - OEMCryptoResult sts = OEMCrypto_SelectKey( - session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, fuzzed_structure.cipher_mode); - CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); + // Select key and encrypt. + wvoec::Session& session = license_api_fuzz.session(); + OEMCrypto_SelectKey(session.session_id(), session.license().keys[0].key_id, + session.license().keys[0].key_id_length, + fuzzed_structure.cipher_mode); OEMCrypto_Generic_Encrypt( - session->session_id(), clear_buffer.data(), clear_buffer.size(), - iv.data(), fuzzed_structure.algorithm, encrypted_buffer.data()); + session.session_id(), clear_buffer.data(), clear_buffer.size(), iv.data(), + fuzzed_structure.algorithm, encrypted_buffer.data()); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc index d27415d..5896212 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc @@ -2,54 +2,56 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_types.h" -namespace wvoec { +namespace { + +// Avoid calling non-trivial destructor. +wvoec::OEMCryptoLicenseAPIFuzz& license_api_fuzz = + *new wvoec::OEMCryptoLicenseAPIFuzz; + +} // namespace + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + wvoec::RedirectStdoutToFile(); + license_api_fuzz.Initialize(); + license_api_fuzz.LoadLicenseWithGenericCryptoKeys(); + return 0; +} + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - - OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + wvoec::OEMCrypto_Generic_Api_Fuzz fuzzed_structure; if (size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); - ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); - ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, - &fuzzed_structure.algorithm); - - size_t clear_buffer_size = size - sizeof(fuzzed_structure); - if (clear_buffer_size == 0) { - return 0; - } + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + wvoec::ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, + fuzzed_structure.cipher_mode); + wvoec::ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, + fuzzed_structure.algorithm); // Copy clear buffer from input data. - vector clear_buffer(clear_buffer_size); - memcpy(clear_buffer.data(), data + sizeof(fuzzed_structure), - clear_buffer_size); + const std::vector clear_buffer = + fuzzed_data.ConsumeRemainingBytes(); - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Load license and call generic_sign API. - license_api_fuzz.LoadLicense(); - OEMCryptoResult sts = OEMCrypto_SelectKey( - session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, fuzzed_structure.cipher_mode); - CheckStatusAndExitFuzzerOnFailure(sts, OEMCrypto_SUCCESS); + // Select key and sign. + wvoec::Session& session = license_api_fuzz.session(); + OEMCrypto_SelectKey(session.session_id(), session.license().keys[2].key_id, + session.license().keys[2].key_id_length, + fuzzed_structure.cipher_mode); size_t signature_length = 0; - OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(), + OEMCrypto_Generic_Sign(session.session_id(), clear_buffer.data(), clear_buffer.size(), fuzzed_structure.algorithm, nullptr, &signature_length); - vector signature(signature_length); - OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(), + std::vector signature(signature_length); + OEMCrypto_Generic_Sign(session.session_id(), clear_buffer.data(), clear_buffer.size(), fuzzed_structure.algorithm, signature.data(), &signature_length); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc index 759286d..5738334 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc @@ -2,66 +2,59 @@ // source code may only be used and distributed under the Widevine // License Agreement. -#include -#include +#include +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_types.h" -namespace wvoec { -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); +namespace { - OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; - if (size < sizeof(fuzzed_structure)) { - return 0; - } - // Copy OEMCrypto_Generic_Verify_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); - ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); - ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, - &fuzzed_structure.algorithm); +// Avoid calling non-trivial destructor. +wvoec::OEMCryptoLicenseAPIFuzz& license_api_fuzz = + *new wvoec::OEMCryptoLicenseAPIFuzz; - size_t in_buffer_size = size - sizeof(fuzzed_structure); - if (in_buffer_size == 0) { - return 0; - } - // Copy clear buffer from input data. - vector in_buffer(in_buffer_size); - memcpy(in_buffer.data(), data + sizeof(fuzzed_structure), in_buffer_size); +} // namespace - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Load license and call generic_verify API. - license_api_fuzz.LoadLicense(); - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - OEMCrypto_CipherMode_CENC); - // Calculate signature for in buffer. - size_t signature_length = 0; - OEMCrypto_Generic_Sign(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, nullptr, - &signature_length); - vector signature(signature_length); - OEMCrypto_Generic_Sign(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, - signature.data(), &signature_length); - - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - fuzzed_structure.cipher_mode); - signature_length = - std::min(MAX_FUZZ_SIGNATURE_LENGTH, fuzzed_structure.signature_length); - signature.resize(signature_length); - OEMCrypto_Generic_Verify(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, - signature.data(), signature_length); +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + wvoec::RedirectStdoutToFile(); + license_api_fuzz.Initialize(); + license_api_fuzz.LoadLicenseWithGenericCryptoKeys(); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Split data using separator. + const std::vector inputs = + wvoec::SplitFuzzedData(data, size); + if (inputs.size() < 2) { + return 0; + } + + // Deserialize fuzzed data. + wvoec::OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + if (inputs[0].size < sizeof(fuzzed_structure)) { + return 0; + } + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + wvoec::ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, + fuzzed_structure.cipher_mode); + wvoec::ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, + fuzzed_structure.algorithm); + const std::vector buffer = + fuzzed_data.ConsumeRemainingBytes(); + const std::vector signature(inputs[1].data, + inputs[1].data + inputs[1].size); + + // Select key and verify. + wvoec::Session& session = license_api_fuzz.session(); + OEMCrypto_SelectKey(session.session_id(), session.license().keys[3].key_id, + session.license().keys[3].key_id_length, + fuzzed_structure.cipher_mode); + OEMCrypto_Generic_Verify(session.session_id(), buffer.data(), buffer.size(), + fuzzed_structure.algorithm, signature.data(), + signature.size()); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_license_request_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_license_request_fuzz.cc index 52d3493..a0e5342 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_license_request_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_license_request_fuzz.cc @@ -2,27 +2,26 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -namespace wvoec { - extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); + // Reject the input if it is less than fuzz data structure size. - if (size < sizeof(OEMCrypto_Request_Fuzz)) { + if (size < sizeof(wvoec::OEMCrypto_Request_Fuzz)) { return 0; } // Input for license request API will be modified by OEMCrypto, hence it // cannot be a const. Fuzzer complains if const identifier is removed of data, // hence copying data into a non const pointer. - uint8_t* input = new uint8_t[size]; - memcpy(input, data, size); - OEMCryptoLicenseAPIFuzz license_api_fuzz; - license_api_fuzz.license_messages().InjectFuzzedRequestData(input, size); - delete[] input; + std::vector input(data, data + size); + wvoec::OEMCryptoLicenseAPIFuzz license_api_fuzz; + license_api_fuzz.Initialize(); + license_api_fuzz.license_messages().InjectFuzzedRequestData(input.data(), + input.size()); + license_api_fuzz.Terminate(); return 0; } -} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc index fbb33e6..f0a9b45 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc @@ -2,65 +2,55 @@ // source code may only be used and distributed under the Widevine // License Agreement. -#include "FuzzedDataProvider.h" -#include "oemcrypto_fuzz_helper.h" -#include "oemcrypto_fuzz_structs.h" +#include -namespace wvoec { +#include "OEMCryptoCENC.h" +#include "oemcrypto_fuzz_helper.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); // Corpus format is as below, let | be separator. // message buffer with key data | entitled content key object array with // offsets and lengths to read key data from message buffer. // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = + wvoec::SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } - FuzzedDataProvider fuzzed_entitled_content_key_array(inputs[1].data(), - inputs[1].size()); - - // Message to be verified. Return 0 if key data buffer is empty. - if (inputs[0].size() == 0) { - return 0; - } - // Copy data to OEMCrypto_EntitledContentKeyObject array. - size_t entitled_content_key_object_size = - sizeof(OEMCrypto_EntitledContentKeyObject); - size_t entitled_content_key_array_length = - fuzzed_entitled_content_key_array.remaining_bytes() / - entitled_content_key_object_size; - if (entitled_content_key_array_length == 0) { - return 0; - } - OEMCrypto_EntitledContentKeyObject* entitled_content_key_array = - new OEMCrypto_EntitledContentKeyObject[entitled_content_key_array_length]; - - for (size_t i = 0; i < entitled_content_key_array_length; i++) { - fuzzed_entitled_content_key_array.ConsumeData( - &entitled_content_key_array[i], entitled_content_key_object_size); + std::vector entitled_content_keys( + inputs[1].size / sizeof(OEMCrypto_EntitledContentKeyObject)); + if (!entitled_content_keys.empty()) { + memcpy(entitled_content_keys.data(), inputs[1].data, + entitled_content_keys.size() * + sizeof(OEMCrypto_EntitledContentKeyObject)); } - OEMCryptoLicenseAPIFuzz license_api_fuzz; + wvoec::OEMCryptoLicenseAPIFuzz license_api_fuzz; + license_api_fuzz.Initialize(); + // Setting up state. Load default entitlement license to load entitlement // keys into sessions key table. license_api_fuzz.license_messages().set_license_type( OEMCrypto_EntitlementLicense); license_api_fuzz.LoadLicense(); + + // Create entitled key session. + OEMCrypto_SESSION key_session; + const OEMCryptoResult result = OEMCrypto_CreateEntitledKeySession( + license_api_fuzz.session().session_id(), &key_session); + wvoec::CheckStatusAndExitFuzzerOnFailure(result, OEMCrypto_SUCCESS); + // Call OEMCrypto_LoadEntitledContentKeys with fuzzed buffers. - Session* session = license_api_fuzz.session(); - uint8_t* fuzzed_key_data = inputs[0].data(); - size_t fuzzed_key_data_size = inputs[0].size(); - OEMCrypto_LoadEntitledContentKeys( - session->session_id(), fuzzed_key_data, fuzzed_key_data_size, - entitled_content_key_array_length, entitled_content_key_array); - delete[] entitled_content_key_array; + const std::vector message(inputs[0].data, + inputs[0].data + inputs[0].size); + OEMCrypto_LoadEntitledContentKeys(key_session, message.data(), message.size(), + entitled_content_keys.size(), + entitled_content_keys.data()); + + license_api_fuzz.Terminate(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_license_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_license_fuzz.cc index 64f5f4b..20b16f0 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_license_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_license_fuzz.cc @@ -4,27 +4,26 @@ #include "oemcrypto_fuzz_helper.h" -namespace wvoec { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - if (size < sizeof(ODK_ParsedLicense) + sizeof(MessageData)) { + wvoec::RedirectStdoutToFile(); + + if (size < sizeof(ODK_ParsedLicense) + sizeof(wvoec::MessageData)) { return 0; } - OEMCryptoLicenseAPIFuzz license_api_fuzz; + wvoec::OEMCryptoLicenseAPIFuzz license_api_fuzz; + license_api_fuzz.Initialize(); license_api_fuzz.license_messages().SignAndVerifyRequest(); // Interpreting input fuzz data as unencrypted (core_response + license // message data) from license server. license_api_fuzz.license_messages().InjectFuzzedResponseData(data, size); // Convert OEMCrypto_LicenseType in core_response to a valid enum value. - ConvertDataToValidEnum( + wvoec::ConvertDataToValidEnum( OEMCrypto_LicenseType_MaxValue, - &license_api_fuzz.license_messages().core_response().license_type); + license_api_fuzz.license_messages().core_response().license_type); license_api_fuzz.license_messages().EncryptAndSignResponse(); license_api_fuzz.license_messages().LoadResponse(); + license_api_fuzz.Terminate(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_provisioning_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_provisioning_fuzz.cc index 757ab24..bda7ce3 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_provisioning_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_provisioning_fuzz.cc @@ -4,17 +4,16 @@ #include "oemcrypto_fuzz_helper.h" -namespace wvoec { - extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - if (size < sizeof(ODK_ParsedProvisioning) + sizeof(RSAPrivateKeyMessage)) { + wvoec::RedirectStdoutToFile(); + + if (size < + sizeof(ODK_ParsedProvisioning) + sizeof(wvoec::RSAPrivateKeyMessage)) { return 0; } - OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz; + wvoec::OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz; + provisioning_api_fuzz.Initialize(); provisioning_api_fuzz.provisioning_messages().SignAndVerifyRequest(); // Interpreting input fuzz data as unencrypted(core_response + provisioning // message data) from provisioning server. @@ -22,6 +21,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { size); provisioning_api_fuzz.provisioning_messages().EncryptAndSignResponse(); provisioning_api_fuzz.provisioning_messages().LoadResponse(); + provisioning_api_fuzz.Terminate(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_renewal_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_renewal_fuzz.cc index 1b6ecfc..8957ee0 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_renewal_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_renewal_fuzz.cc @@ -2,41 +2,41 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include "FuzzedDataProvider.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -namespace wvoec { - extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - if (size < sizeof(OEMCrypto_Renewal_Response_Fuzz)) { - return 0; - } + wvoec::RedirectStdoutToFile(); + // Copy input data to OEMCrypto_Renewal_Response_Fuzz and rest of message // into encrypted license_renewal_response. - OEMCrypto_Renewal_Response_Fuzz fuzzed_data; - memcpy(&fuzzed_data, data, sizeof(fuzzed_data)); - const uint8_t* renewal_response = - data + sizeof(OEMCrypto_Renewal_Response_Fuzz); - const size_t renewal_response_size = - size - sizeof(OEMCrypto_Renewal_Response_Fuzz); + wvoec::OEMCrypto_Renewal_Response_Fuzz fuzzed_structure; + if (size < sizeof(fuzzed_structure)) { + return 0; + } + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + const std::vector renewal_response = + fuzzed_data.ConsumeRemainingBytes(); - OEMCryptoRenewalAPIFuzz renewal_response_fuzz; + wvoec::OEMCryptoRenewalAPIFuzz renewal_response_fuzz; + renewal_response_fuzz.Initialize(); renewal_response_fuzz.license_messages().SignAndVerifyRequest(); renewal_response_fuzz.license_messages().CreateDefaultResponse(); + // Inject timer limits from fuzzed input to timer_limits field from // core license response. - renewal_response_fuzz.license_messages().InjectFuzzedTimerLimits(fuzzed_data); + renewal_response_fuzz.license_messages().InjectFuzzedTimerLimits( + fuzzed_structure); renewal_response_fuzz.license_messages().EncryptAndSignResponse(); renewal_response_fuzz.license_messages().LoadResponse(); // Call renewal response API using fuzzed data. renewal_response_fuzz.renewal_messages().SignAndVerifyRequest(); renewal_response_fuzz.renewal_messages().InjectFuzzedResponseData( - fuzzed_data, renewal_response, renewal_response_size); + fuzzed_structure, renewal_response.data(), renewal_response.size()); renewal_response_fuzz.renewal_messages().LoadResponse(); + renewal_response_fuzz.Terminate(); return 0; } -} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc index ed47b0b..de64eb1 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc @@ -5,57 +5,62 @@ #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" -namespace wvoec { -LicenseWithUsageEntryFuzz entry; +namespace { + +// Avoid calling non-trivial destructor. +wvoec::LicenseWithUsageEntryFuzz& entry = *new wvoec::LicenseWithUsageEntryFuzz; + +OEMCryptoResult LoadUsageEntryWithFuzzedData(OEMCrypto_SESSION session, + const uint8_t* data, size_t size) { + uint32_t usage_entry_number; + if (size < sizeof(usage_entry_number)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(&usage_entry_number, data, sizeof(usage_entry_number)); + const std::vector buffer(data + sizeof(usage_entry_number), + data + size); + return OEMCrypto_LoadUsageEntry(session, usage_entry_number, buffer.data(), + buffer.size()); +} + +} // namespace + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + wvoec::RedirectStdoutToFile(); + entry.Initialize(); + return 0; +} + // The custom mutator to mutate created encrypted usage entry. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned int seed) { entry.CreateUsageTableHeader(); - Session* s = entry.license_messages().session(); - s->open(); - entry.InstallTestRSAKey(s); - uint32_t usage_entry_number = 0; - memcpy(&usage_entry_number, data, sizeof(uint32_t)); - if (OEMCrypto_LoadUsageEntry(s->session_id(), usage_entry_number, - data + sizeof(uint32_t), - size - sizeof(uint32_t)) != OEMCrypto_SUCCESS) { - s->CreateNewUsageEntry(); - vector encrypted_usage_header; - s->UpdateUsageEntry(&encrypted_usage_header); - vector encrypted_usage_entry = s->encrypted_usage_entry(); - usage_entry_number = s->usage_entry_number(); + entry.session().open(); + entry.InstallTestRSAKey(); + if (LoadUsageEntryWithFuzzedData(entry.session().session_id(), data, size) != + OEMCrypto_SUCCESS) { + entry.session().CreateNewUsageEntry(); + std::vector encrypted_usage_header; + entry.session().UpdateUsageEntry(&encrypted_usage_header); + const uint32_t usage_entry_number = entry.session().usage_entry_number(); + const std::vector& encrypted_usage_entry = + entry.session().encrypted_usage_entry(); + size = sizeof(usage_entry_number) + encrypted_usage_entry.size(); + if (size > max_size) { + return 0; + } // Copy created usage entry number and usage entry to data and mutate it. - memcpy(data, &usage_entry_number, sizeof(uint32_t)); - memcpy(data + sizeof(uint32_t), encrypted_usage_entry.data(), + memcpy(data, &usage_entry_number, sizeof(usage_entry_number)); + memcpy(data + sizeof(usage_entry_number), encrypted_usage_entry.data(), encrypted_usage_entry.size()); - size = sizeof(uint32_t) + encrypted_usage_entry.size(); } - s->close(); + entry.session().close(); return LLVMFuzzerMutate(data, size, max_size); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - - uint32_t usage_entry_number = 0; - if (size < sizeof(usage_entry_number)) { - return 0; - } - - memcpy(&usage_entry_number, data, sizeof(usage_entry_number)); - const uint8_t* extra_data = data + sizeof(usage_entry_number); - size_t extra_data_size = size - sizeof(usage_entry_number); - if (extra_data_size == 0) { - return 0; - } - - Session s; - s.open(); - OEMCrypto_LoadUsageEntry(s.session_id(), usage_entry_number, extra_data, - extra_data_size); - s.close(); + entry.session().open(); + LoadUsageEntryWithFuzzedData(entry.session().session_id(), data, size); + entry.session().close(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc index 8d3000a..ebf92fa 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc @@ -5,32 +5,32 @@ #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" -namespace wvoec { - // The custom mutator to mutate created encrypted usage table header. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned int seed) { - LicenseWithUsageEntryFuzz entry; + wvoec::LicenseWithUsageEntryFuzz entry; + entry.Initialize(); if (OEMCrypto_LoadUsageTableHeader(data, size) != OEMCrypto_SUCCESS) { entry.CreateUsageTableHeader(); - if (size < entry.encrypted_usage_header().size()) { + size = entry.encrypted_usage_header().size(); + if (size > max_size) { return 0; } // Copy created usage table header to data and mutate it. memcpy(data, entry.encrypted_usage_header().data(), entry.encrypted_usage_header().size()); - size = entry.encrypted_usage_header().size(); } + entry.Terminate(); return LLVMFuzzerMutate(data, size, max_size); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); + // Initialize OEMCrypto and call API. - InitializeFuzz initialize_fuzz; + wvoec::SessionUtil session_util; + InitializeFuzz(session_util); OEMCrypto_LoadUsageTableHeader(data, size); + OEMCrypto_Terminate(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc index 3fae8e6..231cf40 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc @@ -1,42 +1,42 @@ -#include -#include +#include #include "opk_dispatcher.h" #include "opk_init.h" -#include "tos_transport_interface.h" -namespace wvoec { +namespace { void OpenOEMCryptoTASession() { - ODK_Message request; - ODK_Message response; - uint8_t response_buffer[0x1000]; uint8_t request_body[] = { - 0x06, // TAG_UINT32 - 0x09, 0x00, 0x00, 0x00, // API value (0x09) - 0x01, // TAG_BOOL - 0x00, // value (false) - 0x0a // TAG_EOM + 0x06, // TAG_UINT32 + 0x09, 0x00, 0x00, 0x00, // API value (0x09) + 0x07, // TAG_UINT64 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x01, // TAG_BOOL + 0x00, // value (false) + 0x0a // TAG_EOM }; - request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message_SetSize(&request, sizeof(request_body)); + ODK_Message response; OPK_DispatchMessage(&request, &response); } void InitializeOEMCryptoTA() { - ODK_Message init_request; - ODK_Message init_response; - uint8_t response_buffer[0x1000]; - uint8_t init_request_body[] = { - 0x06, // TAG_UINT32 - 0x01, 0x00, 0x00, 0x00, // API value(0x01) - 0x0a // TAG_EOM + uint8_t request_body[] = { + 0x06, // TAG_UINT32 + 0x01, 0x00, 0x00, 0x00, // API value (0x01) + 0x07, // TAG_UINT64 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x0a // TAG_EOM }; - - init_request = - ODK_Message_Create(init_request_body, sizeof(init_request_body)); - OPK_DispatchMessage(&init_request, &init_response); + ODK_Message request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message_SetSize(&request, sizeof(request_body)); + ODK_Message response; + OPK_DispatchMessage(&request, &response); } +} // namespace + extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { OPK_Initialize(); InitializeOEMCryptoTA(); @@ -45,18 +45,11 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - ODK_Message request; + std::vector request_body(data, data + size); + ODK_Message request = + ODK_Message_Create(request_body.data(), request_body.size()); + ODK_Message_SetSize(&request, request_body.size()); ODK_Message response; - unsigned char response_buffer[0x1000]; - - uint8_t* input = new uint8_t[size]; - memcpy(input, data, size); - - request = ODK_Message_Create(input, size); OPK_DispatchMessage(&request, &response); - - delete[] input; return 0; } - -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp index b5a73a1..58324f4 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp @@ -16,114 +16,30 @@ }, 'targets': [ { - 'target_name': 'oemcrypto_opk_load_license_fuzz', - 'sources': [ - 'oemcrypto_load_license_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_load_provisioning_fuzz', - 'sources': [ - 'oemcrypto_load_provisioning_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_load_renewal_fuzz', - 'sources': [ - 'oemcrypto_load_renewal_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_license_request_fuzz', - 'sources': [ - 'oemcrypto_license_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_provisioning_request_fuzz', - 'sources': [ - 'oemcrypto_provisioning_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_renewal_request_fuzz', - 'sources': [ - 'oemcrypto_renewal_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_decrypt_cenc_fuzz', - 'sources': [ - 'oemcrypto_decrypt_cenc_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_load_entitled_content_keys_fuzz', - 'sources': [ - 'oemcrypto_load_entitled_content_keys_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_generic_encrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_encrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_generic_decrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_decrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_generic_sign_fuzz', - 'sources': [ - 'oemcrypto_generic_sign_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_generic_verify_fuzz', - 'sources': [ - 'oemcrypto_generic_verify_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_generate_rsa_signature_fuzz', - 'sources': [ - 'oemcrypto_generate_rsa_signature_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_load_usage_table_header_fuzz', - 'sources': [ - 'oemcrypto_load_usage_table_header_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_load_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_load_usage_entry_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_deactivate_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_deactivate_usage_entry_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_opk_report_usage_fuzz', - 'sources': [ - 'oemcrypto_report_usage_fuzz.cc', - ], - }, - { 'target_name': 'oemcrypto_opk_copy_buffer_fuzz', 'sources': [ 'oemcrypto_copy_buffer_fuzz.cc', ], - }, - { + }, + { + 'target_name': 'oemcrypto_opk_deactivate_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_deactivate_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_decrypt_cenc_fuzz', + 'sources': [ + 'oemcrypto_decrypt_cenc_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_decrypt_hash_fuzz', + 'sources': [ + 'oemcrypto_decrypt_hash_fuzz.cc', + ], + }, + { 'target_name': 'oemcrypto_opk_dispatcher_fuzz', 'include_dirs': [ '<(oemcrypto_dir)/opk/serialization/common', @@ -144,5 +60,155 @@ '<(oemcrypto_dir)/opk/ports/trusty/serialization_adapter/shared_memory.c', ], }, + { + 'target_name': 'oemcrypto_opk_entitled_key_session_fuzz', + 'sources': [ + 'oemcrypto_entitled_key_session_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generate_certificate_key_pair_fuzz', + 'sources': [ + 'oemcrypto_generate_certificate_key_pair_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generate_rsa_signature_fuzz', + 'sources': [ + 'oemcrypto_generate_rsa_signature_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_decrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_decrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_encrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_encrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_sign_fuzz', + 'sources': [ + 'oemcrypto_generic_sign_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_verify_fuzz', + 'sources': [ + 'oemcrypto_generic_verify_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_get_boot_certificate_chain_fuzz', + 'sources': [ + 'oemcrypto_get_boot_certificate_chain_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_get_random_fuzz', + 'sources': [ + 'oemcrypto_get_random_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_install_oem_private_key_fuzz', + 'sources': [ + 'oemcrypto_install_oem_private_key_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_license_request_fuzz', + 'sources': [ + 'oemcrypto_license_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_entitled_content_keys_fuzz', + 'sources': [ + 'oemcrypto_load_entitled_content_keys_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_license_fuzz', + 'sources': [ + 'oemcrypto_load_license_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_provisioning_fuzz', + 'sources': [ + 'oemcrypto_load_provisioning_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_renewal_fuzz', + 'sources': [ + 'oemcrypto_load_renewal_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_load_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_usage_table_header_fuzz', + 'sources': [ + 'oemcrypto_load_usage_table_header_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_move_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_move_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_provisioning_request_fuzz', + 'sources': [ + 'oemcrypto_provisioning_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_query_key_control_fuzz', + 'sources': [ + 'oemcrypto_query_key_control_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_renewal_request_fuzz', + 'sources': [ + 'oemcrypto_renewal_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_report_usage_fuzz', + 'sources': [ + 'oemcrypto_report_usage_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_reuse_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_reuse_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_select_key_fuzz', + 'sources': [ + 'oemcrypto_select_key_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_shrink_usage_table_header_fuzz', + 'sources': [ + 'oemcrypto_shrink_usage_table_header_fuzz.cc', + ], + }, ], } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_provisioning_request_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_provisioning_request_fuzz.cc index b66aab6..7e709f6 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_provisioning_request_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_provisioning_request_fuzz.cc @@ -2,27 +2,26 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -namespace wvoec { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); + // If input size is less than fuzz data structure size, reject the input. - if (size < sizeof(OEMCrypto_Request_Fuzz)) { + if (size < sizeof(wvoec::OEMCrypto_Request_Fuzz)) { return 0; } // Input for provisioning request API will be modified by OEMCrypto, hence it // cannot be a const. Fuzzer complains if const identifier is removed of data, // hence copying data into a non const pointer. - uint8_t* input = new uint8_t[size]; - memcpy(input, data, size); - OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz; - provisioning_api_fuzz.provisioning_messages().InjectFuzzedRequestData(input, - size); - delete[] input; + std::vector input(data, data + size); + wvoec::OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz; + provisioning_api_fuzz.Initialize(); + provisioning_api_fuzz.provisioning_messages().InjectFuzzedRequestData( + input.data(), input.size()); + provisioning_api_fuzz.Terminate(); return 0; } -} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_renewal_request_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_renewal_request_fuzz.cc index 8b7fd79..658bdc1 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_renewal_request_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_renewal_request_fuzz.cc @@ -2,26 +2,26 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -namespace wvoec { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); + // If input size is less than fuzz data structure, reject the input. - if (size < sizeof(OEMCrypto_Request_Fuzz)) { + if (size < sizeof(wvoec::OEMCrypto_Request_Fuzz)) { return 0; } // Input for renewal request API will be modified by OEMCrypto, hence it // cannot be a const. Fuzzer complains if const identifier is removed of data, // hence copying data into a non const pointer. - uint8_t* input = new uint8_t[size]; - memcpy(input, data, size); - OEMCryptoRenewalAPIFuzz renewal_api_fuzz; - renewal_api_fuzz.renewal_messages().InjectFuzzedRequestData(input, size); - delete[] input; + std::vector input(data, data + size); + wvoec::OEMCryptoRenewalAPIFuzz renewal_api_fuzz; + renewal_api_fuzz.Initialize(); + renewal_api_fuzz.renewal_messages().InjectFuzzedRequestData(input.data(), + input.size()); + renewal_api_fuzz.Terminate(); return 0; } -} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc index 3b3813a..e943acd 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc @@ -2,45 +2,46 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include + +#include "FuzzedDataProvider.h" #include "oemcrypto_fuzz_helper.h" -namespace wvoec { -const size_t MAX_FUZZ_PST_REPORT_BUFFER_LENGTH = 5 * MB; +namespace { + +constexpr size_t MAX_FUZZ_PST_REPORT_BUFFER_LENGTH = 5 * wvoec::MB; + +} // namespace + extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); + wvoec::RedirectStdoutToFile(); - size_t pst_buffer_length = 0; - if (size <= sizeof(pst_buffer_length)) { - return 0; - } - - LicenseWithUsageEntryFuzz entry; + wvoec::LicenseWithUsageEntryFuzz entry; + entry.Initialize(); entry.CreateUsageTableHeader(); - // Open a session, create a usage entry. - Session* session = entry.license_messages().session(); - session->open(); - entry.InstallTestRSAKey(session); - session->GenerateNonce(); - session->CreateNewUsageEntry(); - vector encrypted_usage_header; - session->UpdateUsageEntry(&encrypted_usage_header); + entry.InstallTestRSAKey(); + entry.session().CreateNewUsageEntry(); + entry.session().GenerateNonce(); + std::vector encrypted_usage_header; + entry.session().UpdateUsageEntry(&encrypted_usage_header); // Sets pst for usage entry. entry.LoadLicense(); - memcpy(&pst_buffer_length, data, sizeof(pst_buffer_length)); - const uint8_t* extra_data = data + sizeof(pst_buffer_length); - size_t extra_data_size = size - sizeof(pst_buffer_length); - // We cannot allocate a huge buffer, hence limiting buffer size to - // MAX_FUZZ_PST_REPORT_BUFFER_LENGTH. - pst_buffer_length = - std::min(MAX_FUZZ_PST_REPORT_BUFFER_LENGTH, pst_buffer_length); - vector pst_report_buffer(pst_buffer_length); - // Call API with fuzzed pst_buffer_length, pst. - OEMCrypto_ReportUsage(session->session_id(), extra_data, extra_data_size, - pst_report_buffer.data(), &pst_buffer_length); - session->close(); + FuzzedDataProvider fuzzed_data(data, size); + + // pst_report_buffer and pst_report_buffer_length parameters + size_t pst_report_buffer_length_data = + fuzzed_data.ConsumeIntegralInRange( + 0, MAX_FUZZ_PST_REPORT_BUFFER_LENGTH); + std::vector pst_report_buffer(pst_report_buffer_length_data); + size_t* const pst_report_buffer_length = + fuzzed_data.ConsumeBool() ? &pst_report_buffer_length_data : nullptr; + + const std::vector pst = fuzzed_data.ConsumeRemainingBytes(); + + OEMCrypto_ReportUsage(entry.session().session_id(), pst.data(), pst.size(), + pst_report_buffer.data(), pst_report_buffer_length); + + entry.Terminate(); return 0; } -} // namespace wvoec diff --git a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gyp b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gyp index bd72a5c..63530b0 100644 --- a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gyp +++ b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gyp @@ -14,106 +14,178 @@ }, 'targets': [ { - 'target_name': 'oemcrypto_load_license_fuzz', + 'target_name': 'oemcrypto_copy_buffer_fuzz', 'sources': [ - 'oemcrypto_load_license_fuzz.cc', + 'oemcrypto_copy_buffer_fuzz.cc', ], - }, - { - 'target_name': 'oemcrypto_load_provisioning_fuzz', - 'sources': [ - 'oemcrypto_load_provisioning_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_renewal_fuzz', - 'sources': [ - 'oemcrypto_load_renewal_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_license_request_fuzz', - 'sources': [ - 'oemcrypto_license_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_provisioning_request_fuzz', - 'sources': [ - 'oemcrypto_provisioning_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_renewal_request_fuzz', - 'sources': [ - 'oemcrypto_renewal_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_decrypt_cenc_fuzz', - 'sources': [ - 'oemcrypto_decrypt_cenc_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_entitled_content_keys_fuzz', - 'sources': [ - 'oemcrypto_load_entitled_content_keys_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_encrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_encrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_decrypt_fuzz', - 'sources': [ - 'oemcrypto_generic_decrypt_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_sign_fuzz', - 'sources': [ - 'oemcrypto_generic_sign_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generic_verify_fuzz', - 'sources': [ - 'oemcrypto_generic_verify_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_generate_rsa_signature_fuzz', - 'sources': [ - 'oemcrypto_generate_rsa_signature_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_usage_table_header_fuzz', - 'sources': [ - 'oemcrypto_load_usage_table_header_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_load_usage_entry_fuzz', - 'sources': [ - 'oemcrypto_load_usage_entry_fuzz.cc', - ], - }, - { + }, + { 'target_name': 'oemcrypto_deactivate_usage_entry_fuzz', 'sources': [ 'oemcrypto_deactivate_usage_entry_fuzz.cc', ], - }, - { + }, + { + 'target_name': 'oemcrypto_decrypt_cenc_fuzz', + 'sources': [ + 'oemcrypto_decrypt_cenc_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_decrypt_hash_fuzz', + 'sources': [ + 'oemcrypto_decrypt_hash_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_entitled_key_session_fuzz', + 'sources': [ + 'oemcrypto_entitled_key_session_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_generate_certificate_key_pair_fuzz', + 'sources': [ + 'oemcrypto_generate_certificate_key_pair_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_generate_rsa_signature_fuzz', + 'sources': [ + 'oemcrypto_generate_rsa_signature_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_generic_decrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_decrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_generic_encrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_encrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_generic_sign_fuzz', + 'sources': [ + 'oemcrypto_generic_sign_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_generic_verify_fuzz', + 'sources': [ + 'oemcrypto_generic_verify_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_get_boot_certificate_chain_fuzz', + 'sources': [ + 'oemcrypto_get_boot_certificate_chain_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_get_random_fuzz', + 'sources': [ + 'oemcrypto_get_random_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_install_oem_private_key_fuzz', + 'sources': [ + 'oemcrypto_install_oem_private_key_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_license_request_fuzz', + 'sources': [ + 'oemcrypto_license_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_entitled_content_keys_fuzz', + 'sources': [ + 'oemcrypto_load_entitled_content_keys_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_license_fuzz', + 'sources': [ + 'oemcrypto_load_license_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_provisioning_fuzz', + 'sources': [ + 'oemcrypto_load_provisioning_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_renewal_fuzz', + 'sources': [ + 'oemcrypto_load_renewal_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_load_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_load_usage_table_header_fuzz', + 'sources': [ + 'oemcrypto_load_usage_table_header_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_move_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_move_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_provisioning_request_fuzz', + 'sources': [ + 'oemcrypto_provisioning_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_query_key_control_fuzz', + 'sources': [ + 'oemcrypto_query_key_control_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_renewal_request_fuzz', + 'sources': [ + 'oemcrypto_renewal_request_fuzz.cc', + ], + }, + { 'target_name': 'oemcrypto_report_usage_fuzz', 'sources': [ 'oemcrypto_report_usage_fuzz.cc', ], - }, + }, + { + 'target_name': 'oemcrypto_reuse_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_reuse_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_select_key_fuzz', + 'sources': [ + 'oemcrypto_select_key_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_shrink_usage_table_header_fuzz', + 'sources': [ + 'oemcrypto_shrink_usage_table_header_fuzz.cc', + ], + }, ], } diff --git a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi index 18eb2ad..ddf927d 100644 --- a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi @@ -27,6 +27,7 @@ '<(util_dir)/src/platform.cpp', '<(util_dir)/src/rw_lock.cpp', '<(util_dir)/src/string_conversions.cpp', + '<(util_dir)/src/string_format.cpp', '<(util_dir)/test/test_sleep.cpp', '<(util_dir)/test/test_clock.cpp', ], diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index 8eebf9b..cbf552b 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -198,26 +198,64 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsampleHalf( // Used for OEMCrypto Fuzzing: Corpus format is as below, let | be separator. // cipher_mode + pattern + sample_data for all samples | -// subsample_data for all samples +// input_data for all samples | subsample_data for all samples void WriteDecryptCencCorpus( OEMCryptoCipherMode cipher_mode, const OEMCrypto_SampleDescription* samples_description, const OEMCrypto_CENCEncryptPatternDesc* pattern, size_t samples_length) { const std::string file_name = GetFileName("oemcrypto_decrypt_cenc_fuzz_seed_corpus"); + + // Cipher mode and Pattern. OEMCrypto_Decrypt_Cenc_Fuzz decrypt_cenc_fuzz_struct; decrypt_cenc_fuzz_struct.cipher_mode = cipher_mode; decrypt_cenc_fuzz_struct.pattern = *pattern; - // Cipher mode and Pattern. AppendToFile(file_name, reinterpret_cast(&decrypt_cenc_fuzz_struct), sizeof(OEMCrypto_Decrypt_Cenc_Fuzz)); // Sample data for all samples. for (size_t i = 0; i < samples_length; i++) { + OEMCrypto_SampleDescription_Fuzz sample_description_data; + sample_description_data.buffers.input_data_length = + samples_description[i].buffers.input_data_length; + sample_description_data.buffers.output_descriptor.type = + samples_description[i].buffers.output_descriptor.type; + switch (sample_description_data.buffers.output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.clear.clear_buffer_length; + break; + + case OEMCrypto_BufferType_Secure: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.secure.secure_buffer_length; + break; + + case OEMCrypto_BufferType_Direct: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.direct.is_video; + break; + } + memcpy(sample_description_data.iv, samples_description[i].iv, + sizeof(sample_description_data.iv)); + sample_description_data.subsamples_length = + samples_description[i].subsamples_length; AppendToFile(file_name, - reinterpret_cast(&samples_description[i]), - sizeof(OEMCrypto_SampleDescription)); + reinterpret_cast(&sample_description_data), + sizeof(OEMCrypto_SampleDescription_Fuzz)); + } + AppendSeparator(file_name); + + // Input data for all samples. + for (size_t i = 0; i < samples_length; i++) { + AppendToFile(file_name, + reinterpret_cast( + samples_description[i].buffers.input_data), + samples_description[i].buffers.input_data_length); } AppendSeparator(file_name); diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 7977a7f..19bfc2c 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -58,29 +58,26 @@ using oemcrypto_core_message::features::CoreMessageFeatures; constexpr size_t kTestSubsampleSectionSize = 256; -// Encrypt a block of data using CTR mode. -void EncryptCTR(const vector& in_buffer, const uint8_t* key, - const uint8_t* starting_iv, vector* out_buffer) { - ASSERT_NE(nullptr, key); - ASSERT_NE(nullptr, starting_iv); - ASSERT_NE(nullptr, out_buffer); - AES_KEY aes_key; - AES_set_encrypt_key(key, AES_BLOCK_SIZE * 8, &aes_key); - out_buffer->resize(in_buffer.size()); +// Fill objects by consuming a source buffer of fuzzed data. +class FuzzedData { + public: + FuzzedData(const uint8_t* source, size_t source_size) + : source_(source), source_size_(source_size) {} - uint8_t iv[AES_BLOCK_SIZE]; // Current iv. - - memcpy(iv, &starting_iv[0], AES_BLOCK_SIZE); - size_t l = 0; // byte index into encrypted subsample. - while (l < in_buffer.size()) { - uint8_t aes_output[AES_BLOCK_SIZE]; - AES_encrypt(iv, aes_output, &aes_key); - for (size_t n = 0; n < AES_BLOCK_SIZE && l < in_buffer.size(); n++, l++) { - (*out_buffer)[l] = aes_output[n] ^ in_buffer[l]; + // Fill the destination buffer with fuzzed data. + void Fill(void* destination, size_t destination_size) { + if (source_ && destination) { + const size_t fill_size = std::min(source_size_, destination_size); + memcpy(destination, source_, fill_size); + source_ += fill_size; + source_size_ -= fill_size; } - ctr128_inc64(1, iv); } -} + + private: + const uint8_t* source_; + size_t source_size_; +}; // Uses OEMCrypto to decrypt some random data in 'cenc' mode. This function // assumes that the correct key is already selected in the session. It requires @@ -113,6 +110,31 @@ OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key, } // namespace + +// Encrypt a block of data using CTR mode. +void EncryptCTR(const vector& in_buffer, const uint8_t* key, + const uint8_t* starting_iv, vector* out_buffer) { + ASSERT_NE(nullptr, key); + ASSERT_NE(nullptr, starting_iv); + ASSERT_NE(nullptr, out_buffer); + AES_KEY aes_key; + AES_set_encrypt_key(key, AES_BLOCK_SIZE * 8, &aes_key); + out_buffer->resize(in_buffer.size()); + + uint8_t iv[AES_BLOCK_SIZE]; // Current iv. + + memcpy(iv, &starting_iv[0], AES_BLOCK_SIZE); + size_t l = 0; // byte index into encrypted subsample. + while (l < in_buffer.size()) { + uint8_t aes_output[AES_BLOCK_SIZE]; + AES_encrypt(iv, aes_output, &aes_key); + for (size_t n = 0; n < AES_BLOCK_SIZE && l < in_buffer.size(); n++, l++) { + (*out_buffer)[l] = aes_output[n] ^ in_buffer[l]; + } + ctr128_inc64(1, iv); + } +} + int GetRandBytes(unsigned char* buf, size_t num) { // returns 1 on success, -1 if not supported, or 0 if other failure. return RAND_bytes(buf, static_cast(num)); @@ -361,14 +383,6 @@ void ProvisioningRoundTrip::FillAndVerifyCoreRequest( EXPECT_EQ(global_features.api_version, core_request_.api_major_version); EXPECT_EQ(session()->nonce(), core_request_.nonce); EXPECT_EQ(session()->session_id(), core_request_.session_id); - size_t device_id_length = core_request_.device_id.size(); - std::vector device_id(device_id_length); - EXPECT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetDeviceID(device_id.data(), &device_id_length)); - EXPECT_EQ(core_request_.device_id.size(), device_id_length); - std::string device_id_string(reinterpret_cast(device_id.data()), - device_id_length); - EXPECT_EQ(device_id_string, core_request_.device_id); } void ProvisioningRoundTrip::CreateDefaultResponse() { @@ -459,14 +473,16 @@ void ProvisioningRoundTrip::SignResponse() { } void ProvisioningRoundTrip::InjectFuzzedResponseData(const uint8_t* data, - size_t size UNUSED) { + size_t size) { // Interpreting fuzz data as unencrypted core_response + message_data - const size_t core_response_size = sizeof(ODK_ParsedProvisioning); + FuzzedData fuzzed_data(data, size); + // Copy core_response from data and serialize. - memcpy(&core_response_, data, core_response_size); + fuzzed_data.Fill(&core_response_, sizeof(core_response_)); // Copy provisioning message data into response_data. - memcpy(&response_data_, data + core_response_size, sizeof(response_data_)); + fuzzed_data.Fill(&response_data_, sizeof(response_data_)); + // Set nonce to one from session to pass nonce checks. response_data_.nonce = session()->nonce(); } @@ -607,9 +623,6 @@ void LicenseRoundTrip::FillAndVerifyCoreRequest( // for L3 release only. EXPECT_LE(3, core_request_.api_minor_version); EXPECT_GE(5, core_request_.api_minor_version); - } else if (global_features.api_version == ODK_MAJOR_VERSION) { - // We do not expect older tests to work with a newer OEMCrypto. - EXPECT_GE(ODK_MINOR_VERSION, core_request_.api_minor_version); } if (expect_request_has_correct_nonce_) { EXPECT_EQ(session()->nonce(), core_request_.nonce); @@ -682,11 +695,13 @@ void LicenseRoundTrip::InjectFuzzedTimerLimits( } void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data, - size_t size UNUSED) { + size_t size) { // Interpreting fuzz data as unencrypted core_response + message_data - const size_t core_response_size = sizeof(ODK_ParsedLicense); + FuzzedData fuzzed_data(data, size); + // Copy core_response from data. - memcpy(&core_response_, data, core_response_size); + fuzzed_data.Fill(&core_response_, sizeof(core_response_)); + // Maximum number of keys could be kMaxNumKeys(30). key_array_length can be // any random value as it is read from fuzz data. // Key data array(MessageKeyData keys[kMaxNumKeys]) will be looped over @@ -697,10 +712,12 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data, if (core_response_.key_array_length > kMaxNumKeys) { core_response_.key_array_length = kMaxNumKeys; } + // For corpus data, this value gets set to 4, but we need to test other // scenarios too, hence reading key_array_length value. set_num_keys(core_response_.key_array_length); ConvertDataToValidBools(&core_response_); + // TODO(b/157520981): Once assertion bug is fixed, for loop can be removed. // Workaround for the above bug: key_data.length and key_id.length are being // used in AES decryption process and are expected to be a multiple of 16. An @@ -721,9 +738,9 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data, // Copy response_data from data and set nonce to match one in request to pass // nonce validations. - memcpy(&response_data_, data + core_response_size, sizeof(response_data_)); + fuzzed_data.Fill(&response_data_, sizeof(response_data_)); for (uint32_t i = 0; i < num_keys_; ++i) { - response_data_.keys[i].control.nonce = session()->nonce(); + response_data_.keys[i].control.nonce = htonl(session()->nonce()); } } @@ -1052,6 +1069,12 @@ void EntitledMessage::MakeOneKey(size_t entitlement_key_index) { sizeof(key_data->content_key_data_iv))); offsets->content_key_data_iv = FindSubstring( key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv)); + + EXPECT_EQ(1, GetRandBytes(key_data->content_iv, + sizeof(key_data->content_iv))); + key_data->content_iv_length = sizeof(key_data->content_iv); + offsets->content_iv = FindSubstring( + key_data->content_iv, key_data->content_iv_length); } OEMCrypto_EntitledContentKeyObject* EntitledMessage::entitled_key_array() { @@ -1185,8 +1208,8 @@ void EntitledMessage::LoadCasKeys(bool load_even, bool load_odd, // Convert the OEMCrypto_EntitledContentKeyObject to // OEMCrypto_EntitledCasKeyObject. Only the first two key object is used. - OEMCrypto_EntitledContentKeyObject even_key; - OEMCrypto_EntitledContentKeyObject odd_key; + OEMCrypto_EntitledContentKeyObject even_key = {}; + OEMCrypto_EntitledContentKeyObject odd_key = {}; bool has_even = load_even && num_keys_ >= 1; bool has_odd = load_odd && num_keys_ >= 2; if (has_even) { @@ -1194,14 +1217,14 @@ void EntitledMessage::LoadCasKeys(bool load_even, bool load_odd, even_key.content_key_id = entitled_key_array_[0].content_key_id; even_key.content_key_data_iv = entitled_key_array_[0].content_key_data_iv; even_key.content_key_data = entitled_key_array_[0].content_key_data; - even_key.content_iv.length = 0; + even_key.content_iv = entitled_key_array_[0].content_iv; } if (has_odd) { odd_key.entitlement_key_id = entitled_key_array_[1].entitlement_key_id; odd_key.content_key_id = entitled_key_array_[1].content_key_id; odd_key.content_key_data_iv = entitled_key_array_[1].content_key_data_iv; odd_key.content_key_data = entitled_key_array_[1].content_key_data; - odd_key.content_iv.length = 0; + even_key.content_iv = entitled_key_array_[1].content_iv; } OEMCryptoResult sts = OEMCrypto_LoadCasECMKeys( @@ -1592,6 +1615,42 @@ void Session::TestDecryptCTR(bool select_key_first, } } +void Session::TestDecryptEntitled(OEMCryptoResult expected_result, + OEMCrypto_SESSION session_id, + const uint8_t* content_key_id, + size_t content_key_id_length) { + OEMCryptoResult select_result = OEMCrypto_SUCCESS; + // Select the key (from FillSimpleMessage) + select_result = + OEMCrypto_SelectKey(session_id, content_key_id, content_key_id_length, + OEMCrypto_CipherMode_CENC); + + vector unencrypted_data; + vector output_buffer; + vector encrypted_data(kTestSubsampleSectionSize); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description)); + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + EncryptCTR(unencrypted_data, content_key_id, &sample_description.iv[0], + &encrypted_data); + // Try to decrypt the data with oemcrypto session id. + const OEMCryptoResult decrypt_result = + OEMCrypto_DecryptCENC(session_id, &sample_description, 1, &pattern); + + // We only have a few errors that we test are reported. + ASSERT_NO_FATAL_FAILURE( + TestDecryptResult(expected_result, select_result, decrypt_result)) + << "Either SelectKey or DecryptCENC should return " << expected_result + << ", but they returned " << select_result << " and " << decrypt_result + << ", respectively."; +} + void Session::TestDecryptResult(OEMCryptoResult expected_result, OEMCryptoResult actual_select_result, OEMCryptoResult actual_decrypt_result) { diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index bd67d58..c630eb2 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -110,6 +111,8 @@ struct EntitledContentKeyData { uint8_t content_key_data_iv[KEY_IV_SIZE]; uint8_t content_key_data[KEY_SIZE]; uint8_t encrypted_content_key_data[KEY_SIZE]; + uint8_t content_iv[KEY_IV_SIZE]; + size_t content_iv_length; size_t key_index; // Index into the license's key array. Only for testing. }; @@ -121,6 +124,10 @@ void GenerateSimpleSampleDescription(const std::vector& in, OEMCrypto_SampleDescription* sample, OEMCrypto_SubSampleDescription* subsample); +// Encrypt a block of data using CTR mode. +void EncryptCTR(const vector& in_buffer, const uint8_t* key, + const uint8_t* starting_iv, vector* out_buffer); + // Increment counter for AES-CTR. The CENC spec specifies we increment only // the low 64 bits of the IV counter, and leave the high 64 bits alone. This // is different from the OpenSSL implementation, so we implement the CTR loop @@ -493,7 +500,7 @@ class RenewalRoundTrip class EntitledMessage { public: EntitledMessage(LicenseRoundTrip* license_messages) - : license_messages_(license_messages), num_keys_() {} + : license_messages_(license_messages) {} void FillKeyArray(); void MakeOneKey(size_t entitlement_key_index); void SetEntitledKeySession(uint32_t key_session) { @@ -527,13 +534,13 @@ class EntitledMessage { void VerifyDecrypt(); LicenseRoundTrip* license_messages_; - uint32_t num_keys_; + uint32_t num_keys_ = 0; // Clear Entitlement key data. This is the backing data for // |entitled_key_array_|. - EntitledContentKeyData entitled_key_data_[kMaxNumKeys]; + EntitledContentKeyData entitled_key_data_[kMaxNumKeys] = {}; // Entitled key object. Pointers are backed by |entitled_key_data_|. - OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys]; - uint32_t entitled_key_session_; + OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys] = {}; + uint32_t entitled_key_session_ = 0; }; class Session { @@ -573,6 +580,12 @@ class Session { void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, size_t key_index = 0); + // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption + // for entitled sessions. + void TestDecryptEntitled(OEMCryptoResult expected_result = OEMCrypto_SUCCESS, + OEMCrypto_SESSION session = 0, + const uint8_t* content_key_id = nullptr, + size_t content_key_id_length = 0); // Verify that an attempt to select an expired key either succeeds, or gives // an actionable error code. void TestSelectExpired(size_t key_index); diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 2ae9f8c..f821559 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -228,11 +228,29 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { uint8_t subsample_flags) { if (ShouldGenerateCorpus() && input_buffer != nullptr && dest_buffer_descriptor != nullptr) { - OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; - fuzzed_structure.dest_buffer_desc = *dest_buffer_descriptor; - fuzzed_structure.subsample_flags = subsample_flags; const std::string file_name = GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus"); + + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + fuzzed_structure.dest_buffer_desc.type = dest_buffer_descriptor->type; + switch (fuzzed_structure.dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.clear.clear_buffer_length; + break; + + case OEMCrypto_BufferType_Secure: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.secure.secure_buffer_length; + break; + + case OEMCrypto_BufferType_Direct: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.direct.is_video; + break; + } + fuzzed_structure.subsample_flags = subsample_flags; + // Corpus for copy buffer fuzzer should be in the format: // (dest_buffer_descriptor | subsample_flags | input_buffer). AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), @@ -266,7 +284,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 17.1. Tests last updated 2022-06-17"; + "OEMCrypto unit tests for API 17.2. Tests last updated 2023-09-07"; cout << " " << log_message << "\n"; cout << " " << "These tests are part of Android T." @@ -275,7 +293,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { // If any of the following fail, then it is time to update the log message // above. EXPECT_EQ(ODK_MAJOR_VERSION, 17); - EXPECT_EQ(ODK_MINOR_VERSION, 1); + EXPECT_EQ(ODK_MINOR_VERSION, 2); EXPECT_EQ(kCurrentAPI, 17u); OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel(); EXPECT_GT(level, OEMCrypto_Level_Unknown); @@ -684,6 +702,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { ASSERT_NO_FATAL_FAILURE(s.open()); s.GenerateNonce(&error_counter); } + wvutil::TestSleep::SyncFakeClock(); const int64_t test_end = wvutil::Clock().GetCurrentTime(); int valid_counter = loop_count - error_counter; // Either oemcrypto should enforce a delay, or it should return an error from @@ -721,6 +740,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { s[j].GenerateNonce(&error_counter); } } + wvutil::TestSleep::SyncFakeClock(); const int64_t test_end = wvutil::Clock().GetCurrentTime(); int valid_counter = request_counter - error_counter; // Either oemcrypto should enforce a delay, or it should return an error from @@ -2070,13 +2090,13 @@ class OEMCryptoEntitlementLicenseTest : public OEMCryptoLicenseTest { } }; -// This verifies that entitlement keys and entitled content keys can be loaded. +/** This verifies that entitlement keys and entitled content keys can be loaded. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); entitled_message_1.SetEntitledKeySession(key_session_id); @@ -2092,7 +2112,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) { uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2113,19 +2132,19 @@ TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) { /*load_even=*/false, /*load_odd=*/false, OEMCrypto_SUCCESS)); } -// This verifies that entitled content keys cannot be loaded if we have not yet -// loaded the entitlement keys. +/** + * This verifies that entitled content keys cannot be loaded if we have not yet + * loaded the entitlement keys. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysNoEntitlementKeysAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2133,8 +2152,10 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false)); } -// This verifies that entitled content keys cannot be loaded if we have loaded -// the wrong entitlement keys. +/** + * This verifies that entitled content keys cannot be loaded if we have loaded + * the wrong entitlement keys. + */ TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysNoEntitlementKeysAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); @@ -2144,7 +2165,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2153,15 +2173,16 @@ TEST_P(OEMCryptoEntitlementLicenseTest, /*load_even=*/true, /*load_odd=*/true, OEMCrypto_ERROR_INVALID_CONTEXT)); } -// This verifies that entitled content keys cannot be loaded if we have loaded -// the wrong entitlement keys. +/** + * This verifies that entitled content keys cannot be loaded if we have loaded + * the wrong entitlement keys. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysWrongEntitlementKeysAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2177,7 +2198,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -2188,19 +2208,21 @@ TEST_P(OEMCryptoEntitlementLicenseTest, /*load_even=*/true, /*load_odd=*/true, OEMCrypto_KEY_NOT_ENTITLED)); } -// This verifies that entitled content keys cannot be loaded if we specify an -// entitled key session that has not been created. +/** + * This verifies that entitled content keys cannot be loaded if we specify an + * entitled key session that has not been created. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysWrongEntitledKeySessionAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); - entitled_message_1.SetEntitledKeySession(0); + const uint32_t wrong_key_session_id = key_session_id == 0 ? 1 : 0; + entitled_message_1.SetEntitledKeySession(wrong_key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false)); } @@ -2210,28 +2232,34 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); - entitled_message_1.SetEntitledKeySession(0); + const uint32_t wrong_key_session_id = key_session_id == 0 ? 1 : 0; + entitled_message_1.SetEntitledKeySession(wrong_key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( /*load_even=*/true, /*load_odd=*/true, OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION)); } -// This verifies that entitled content keys cannot be loaded if we specify an -// entitled key session that is actually an oemcrypto session. +/** + * This verifies that entitled content keys cannot be loaded if we specify an + * entitled key session that is actually an oemcrypto session. + */ TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysOemcryptoSessionAPI17) { LoadEntitlementLicense(); uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); + if (session_.session_id() == key_session_id) { + GTEST_SKIP() + << "Skipping test because entitled and entitlement sessions are both " + << key_session_id << "."; + } entitled_message_1.SetEntitledKeySession(session_.session_id()); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false)); } @@ -2242,7 +2270,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, uint32_t key_session_id = 0; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( session_.session_id(), &key_session_id)); - ASSERT_NE(key_session_id, 0u); EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); @@ -3069,15 +3096,16 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyNotThereAPI17) { ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); const char* content_key_id = "no_key"; - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id), - strlen(content_key_id), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_INVALID_CONTEXT, key_session_id, + reinterpret_cast(content_key_id), + strlen(content_key_id))); } -// Select key with entitlement license fails if the key id is entitlement key -// id. +/** + * Select key with entitlement license fails if the key id is entitlement key + * id. + */ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitlementKeyAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -3093,11 +3121,15 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyEntitlementKeyAPI17) { entitled_message_1.SetEntitledKeySession(key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); - OEMCryptoResult res = OEMCrypto_SelectKey( - session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); - EXPECT_TRUE(res == OEMCrypto_ERROR_INVALID_CONTEXT || - res == OEMCrypto_ERROR_NO_CONTENT_KEY); + if (session_.session_id() == key_session_id) { + GTEST_SKIP() + << "Skipping test because entitled and entitlement sessions are both " + << key_session_id << "."; + } + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_INVALID_CONTEXT, session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length)); } // This verifies that entitled key sessions can be created and removed. @@ -3126,6 +3158,28 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionsAPI17) { OEMCrypto_RemoveEntitledKeySession(key_session_id_2)); } +TEST_P(OEMCryptoLicenseTest, + EntitledKeySessionsCloseWithOEMCryptoSessionAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id_1; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_1)); + // Close the OEMCrypto session. + session_.close(); + // All entitled key sessions associated with the OEMCrypto session should + // already be been destroyed, + OEMCryptoResult sts = OEMCrypto_RemoveEntitledKeySession(key_session_id_1); + EXPECT_TRUE(sts == OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION || + sts == OEMCrypto_ERROR_INVALID_SESSION); + // Open a new session just for OEMCryptoLicenseTest TearDown. + session_.open(); +} + // This verifies that multiple entitled key sessions can be created. They can // load and select keys independently. TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { @@ -3145,15 +3199,24 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { entitled_message_1.SetContentKeyId(0, content_key_id_1); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); // We can select content key 1 in entitled key session 1. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id_1, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id_1, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); + // Create another entitled key session. uint32_t key_session_id_2; - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( - session_.session_id(), &key_session_id_2)); + OEMCryptoResult status = OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_2); + // For DRM, but not for CAS, we allow there to be only a single entitled + // session. + if (!global_features.supports_cas && + (key_session_id_2 == key_session_id_1 || + status == OEMCrypto_ERROR_TOO_MANY_SESSIONS)) { + GTEST_SKIP() + << "Skipping test because multiple entitled sessions not supported."; + } + ASSERT_EQ(OEMCrypto_SUCCESS, status); // Entitled key sessions should have unique ids. ASSERT_NE(key_session_id_1, key_session_id_2); @@ -3164,23 +3227,22 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { entitled_message_2.SetContentKeyId(0, content_key_id_2); ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadKeys(true)); // We can select content key 2 in entitled key session 2. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id_2, - reinterpret_cast(content_key_id_2), - strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id_2, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2))); + // Content key id 1 is not in entitled key session 2. - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id_2, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id_2, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); + // Content key id 2 is not in entitled key session 1. - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id_1, - reinterpret_cast(content_key_id_2), - strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id_1, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2))); } // This verifies that within an entitled key session, each entitlement key can @@ -3204,28 +3266,27 @@ TEST_P(OEMCryptoLicenseTest, entitled_message_1.SetContentKeyId(0, content_key_id_1); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); // We can select content key 1 in entitled key session. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); + // Load content key with new content id. const char* content_key_id_2 = "content_key_id_2"; entitled_message_1.SetContentKeyId(0, content_key_id_2); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true)); // We can select content key 2 in entitled key session. - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id_2), - strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2))); + // Content key one is no longer in the entitled key session as they use the // same entitlement key. - ASSERT_EQ( - OEMCrypto_ERROR_NO_CONTENT_KEY, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id_1), - strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1))); } // Decrypt should fail if the license is entitlement license, and the decrypt @@ -3249,11 +3310,10 @@ TEST_P(OEMCryptoLicenseTest, const char* content_key_id = "content_key_id"; entitled_message.SetContentKeyId(0, content_key_id); ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true)); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(key_session_id, - reinterpret_cast(content_key_id), - strlen(content_key_id), OEMCrypto_CipherMode_CENC)); + ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled( + OEMCrypto_SUCCESS, key_session_id, + reinterpret_cast(content_key_id), + strlen(content_key_id))); vector in_buffer(256); vector out_buffer(in_buffer.size()); @@ -3262,11 +3322,12 @@ TEST_P(OEMCryptoLicenseTest, ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( in_buffer, out_buffer, &sample_description, &subsample_description)); OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; - - // Try to decrypt the data with oemcrypto session id. - EXPECT_EQ(OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, - &pattern), - OEMCrypto_ERROR_INVALID_CONTEXT); + if (global_features.supports_cas || session_.session_id() != key_session_id) { + // Try to decrypt the data with oemcrypto session id. + EXPECT_EQ(OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, + 1, &pattern), + OEMCrypto_ERROR_INVALID_CONTEXT); + } // Decrypt the data with entitled key session id succeed. EXPECT_EQ( OEMCrypto_DecryptCENC(key_session_id, &sample_description, 1, &pattern), @@ -3297,8 +3358,14 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) { ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true)); // Now reassociate the entitled key session to the second OEMCrypto session. - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ReassociateEntitledKeySession( - key_session_id, session2.session_id())); + OEMCryptoResult status = OEMCrypto_ReassociateEntitledKeySession( + key_session_id, session2.session_id()); + if (status == OEMCrypto_ERROR_NOT_IMPLEMENTED && + !global_features.supports_cas) { + GTEST_SKIP() << "Skipping test because " + "OEMCrypto_ReassociateEntitledKeySession not implemented."; + } + ASSERT_EQ(OEMCrypto_SUCCESS, status); // session2 does not have entitlement keys. ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(false)); @@ -3467,7 +3534,7 @@ TEST_P(OEMCryptoLicenseTest, QueryKeyControl) { // clear key control block (KCB) in the license response. An OEMCrypto v17.1+ // implementation should be able to handle the clear KCB in the 16.4.x response // and load the license correctly. -TEST_F(OEMCryptoSessionTests, ClearKcbAPI16_4) { +TEST_F(OEMCryptoSessionTests, ClearKcbAPI17) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); @@ -3838,7 +3905,8 @@ TEST_P(OEMCryptoLicenseOverflowTest, TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { auto& pst = license_messages->core_response().pst; - pst.offset = response_message_length - pst.length + 1; + pst.offset = response_message_length; + if (pst.length == 0) pst.length = 1; }); } @@ -3881,8 +3949,8 @@ TEST_P( [](size_t response_message_length, LicenseRoundTrip* license_messages) { auto& srm_restriction_data = license_messages->core_response().srm_restriction_data; - srm_restriction_data.offset = - response_message_length - srm_restriction_data.length + 1; + srm_restriction_data.offset = response_message_length; + if (srm_restriction_data.length == 0) srm_restriction_data.length = 1; }); } @@ -5045,6 +5113,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, MakeBuffers(); EncryptData(); OEMCryptoResult result = DecryptCENC(); + FreeSecureBuffers(); // Closing the session and opening it for next iteration. // If it is last iteration, session will be closed in teardown method of // class. @@ -5054,6 +5123,9 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, return result; }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); + + // Avoid double free when test teardown calls FreeSecureBuffers() + MakeBuffers(); } TEST_P(OEMCryptoSessionTestsDecryptTests, @@ -5119,6 +5191,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, MakeBuffers(); EncryptData(); OEMCryptoResult result = DecryptCENC(); + FreeSecureBuffers(); // Closing the session and opening it for next iteration. // If it is last iteration, session will be closed in teardown method of // class. @@ -5128,6 +5201,9 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, return result; }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus); + + // Avoid double free when test teardown calls FreeSecureBuffers() + MakeBuffers(); } // Based on the resource rating, OEMCrypto should be able to handle the maximum @@ -5148,6 +5224,17 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) { ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); } +TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptZeroSizeSubSample) { + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {10, 10}, + {0, 0}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + // There are probably no frames this small, but we should handle them anyway. TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptSmallBuffer) { ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ @@ -5239,6 +5326,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, ContinueDecryptionAfterIdleAndWake) { ASSERT_NO_FATAL_FAILURE(MakeBuffers()); ASSERT_NO_FATAL_FAILURE(EncryptData()); ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); + FreeSecureBuffers(); // Set state to idle then wake again and try to reencrypt/decrypt ASSERT_NO_FATAL_FAILURE( OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); @@ -6363,7 +6451,9 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { OEMCryptoResult sts = provisioning_messages.LoadResponse(); key_loaded_ = (OEMCrypto_SUCCESS == sts); if (key_loaded_) { - encoded_rsa_key_ = provisioning_messages.encoded_rsa_key(); + uint8_t* ptr = provisioning_messages.response_data().rsa_key; + size_t len = provisioning_messages.response_data().rsa_key_length; + encoded_rsa_key_ = std::vector(ptr, ptr + len); wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key(); EXPECT_GT(wrapped_rsa_key_.size(), 0u); EXPECT_EQ(nullptr, find(wrapped_rsa_key_, encoded_rsa_key_)); @@ -7511,15 +7601,17 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { if (ShouldGenerateCorpus()) { const std::string file_name = GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus"); - OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; fuzzed_structure.algorithm = algorithm; - fuzzed_structure.signature_length = signature_length; // Cipher mode and algorithm. AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), sizeof(fuzzed_structure)); AppendToFile(file_name, reinterpret_cast(clear_buffer), clear_buffer_length); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(signature), + signature_length); } return OEMCrypto_Generic_Verify(session, clear_buffer, clear_buffer_length, algorithm, signature, signature_length); @@ -8487,6 +8579,9 @@ class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryUpdateUsageEntryForHugeHeaderBuffer) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { if (buffer_length < encrypted_usage_header_.size()) { return OEMCrypto_ERROR_SHORT_BUFFER; @@ -8514,6 +8609,9 @@ TEST_P(OEMCryptoUsageTableTest, TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryUpdateUsageEntryForHugeUsageEntryBuffer) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { LicenseWithUsageEntry entry; entry.license_messages().set_api_version(license_api_version_); @@ -8538,6 +8636,9 @@ TEST_P(OEMCryptoUsageTableTest, TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryDeactivateUsageEntryForHugePstBuffer) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { LicenseWithUsageEntry entry; std::string pst("pst"); @@ -8557,6 +8658,9 @@ TEST_P(OEMCryptoUsageTableTest, TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryLoadUsageTableHeaderForHugeHeader) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { if (buffer_length < encrypted_usage_header_.size()) { return OEMCrypto_ERROR_SHORT_BUFFER; @@ -8581,6 +8685,9 @@ TEST_P(OEMCryptoUsageTableTest, TEST_P( OEMCryptoUsageTableTest, OEMCryptoMemoryLoadUsageTableHeaderForHugeHeaderStartingHeaderLengthFrom1) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { LicenseWithUsageEntry entry; entry.license_messages().set_api_version(license_api_version_); @@ -8597,6 +8704,9 @@ TEST_P( TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryLoadUsageEntryForHugeUsageEntryBuffer) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { LicenseWithUsageEntry entry; entry.license_messages().set_api_version(license_api_version_); @@ -8639,6 +8749,9 @@ TEST_P(OEMCryptoUsageTableTest, } TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { LicenseWithUsageEntry entry; entry.license_messages().set_api_version(license_api_version_); @@ -8665,6 +8778,9 @@ TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { } TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugePstBuffer) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } auto oemcrypto_function = [&](size_t buffer_length) { LicenseWithUsageEntry entry; entry.license_messages().set_api_version(license_api_version_); @@ -8685,6 +8801,9 @@ TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugePstBuffer) { TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryShrinkUsageTableHeaderForHugeHeaderBufferLength) { + if (!wvoec::global_features.usage_table) { + GTEST_SKIP() << "Usage tables are not supported."; + } LicenseWithUsageEntry entry0; entry0.set_pst("pst 0"); entry0.MakeOfflineAndClose(this); @@ -10190,4 +10309,90 @@ INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, Values(kCurrentAPI)); /// @} + +#ifdef CAS_TEST + +# include "tuner_hal.h" + +class OEMCryptoCasDemoTest : public OEMCryptoEntitlementLicenseTest {}; + +TEST_P(OEMCryptoCasDemoTest, BasicFlow) { + // License contains entitlement keys, function reused from + // OEMCryptoEntitlementLicenseTest + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + + EntitledMessage entitled_message(&license_messages_); + + // Randomly generate entitled content keys + entitled_message.FillKeyArray(); + if (session_.session_id() == key_session_id) { + GTEST_SKIP() + << "Skipping test because entitled and entitlement sessions are both " + << key_session_id << "."; + } + entitled_message.SetEntitledKeySession(key_session_id); + + // Encrypt and load 0th key (even key) into OEMCrypto + ASSERT_NO_FATAL_FAILURE(entitled_message.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/false, OEMCrypto_SUCCESS)); + + // + // Perform DecryptCTR() but for CAS + // + vector unencrypted_data(256, 0); + vector encrypted_data(256, 0); + vector output_buffer(256, 0); + unencrypted_data.resize(encrypted_data.size()); + output_buffer.resize(encrypted_data.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(encrypted_data, output_buffer, + &sample_description, &subsample_description); + + // Use 0th entitled content key and IV to encrypt test data + EncryptCTR(unencrypted_data, + entitled_message.entitled_key_data()->content_key_data, + entitled_message.entitled_key_data()->content_iv, &encrypted_data); + + // Assume 0,0 pattern for CTR example + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Demo only -- copy IV into sample description so we can use + // WTPI_DecryptSample() in the Tuner decrypt impl. A real implementation would + // use the IV from the entitled content key, but the demo relies on the + // existing decrypt which uses SampleDescription IV. + memcpy(sample_description.iv, + entitled_message.entitled_key_data()->content_iv, 16); + + // Get key token to send to Tuner for decrypt + std::vector key_token; + size_t key_token_length = key_token.size(); + OEMCryptoResult res = OEMCrypto_GetOEMKeyToken( + key_session_id, key_token.data(), &key_token_length); + if (res == OEMCrypto_ERROR_SHORT_BUFFER) { + key_token.resize(key_token_length); + res = OEMCrypto_GetOEMKeyToken(key_session_id, key_token.data(), + &key_token_length); + } + ASSERT_EQ(OEMCrypto_SUCCESS, res); + + // Decrypt the data + ASSERT_EQ(TUNER_HAL_SUCCESS, + TunerHal_Decrypt(key_token.data(), key_token_length, + TunerHal_KeyParityType_EvenKey, + &sample_description, // an array of samples. + 1, // the number of samples. + &pattern)); + + ASSERT_EQ(unencrypted_data, output_buffer); +} + +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoCasDemoTest, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); + +#endif } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 3fbd0e4..c644a75 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -10,6 +10,7 @@ 'static_libcpp%' : 'false', }, 'sources': [ + 'GEN_api_lock_file.c', 'oec_device_features.cpp', 'oec_decrypt_fallback_chain.cpp', 'oec_key_deriver.cpp', diff --git a/oemcrypto/util/include/oemcrypto_key_deriver.h b/oemcrypto/util/include/oemcrypto_key_deriver.h index 4a52547..fdcf3ec 100644 --- a/oemcrypto/util/include/oemcrypto_key_deriver.h +++ b/oemcrypto/util/include/oemcrypto_key_deriver.h @@ -47,6 +47,11 @@ class KeyDeriver { bool DeriveEncryptionKey(const std::vector& enc_key_context, std::vector* enc_key); + // Derive renewed device key. Use on KeyDeriver initialized with old device + // key. |context| should be just the context field, eg A_priv+CA_token. + bool DeriveRenewedDeviceKey(const std::vector& context, + std::vector* renewed_device_key); + ~KeyDeriver() {} private: diff --git a/oemcrypto/util/include/oemcrypto_rsa_key.h b/oemcrypto/util/include/oemcrypto_rsa_key.h index d66f527..e1d6db1 100644 --- a/oemcrypto/util/include/oemcrypto_rsa_key.h +++ b/oemcrypto/util/include/oemcrypto_rsa_key.h @@ -268,6 +268,13 @@ class RsaPrivateKey { // Returns an empty vector on error. std::vector Serialize() const; + // Serializes the key's private exponent in network-byte-order + // using I2OSP primitive as defined by RFC3447 Section 4.1. The + // exact length of the exponent will depend on the exponents value, + // not the modulus size. + // Returns an empty vector on error. + std::vector GetPrivateExponent() const; + // Signs the provided |message| using the RSA signing algorithm // specified by |algorithm|. See RsaSignatureAlgorithm for // details on each algorithm. diff --git a/oemcrypto/util/src/oemcrypto_key_deriver.cpp b/oemcrypto/util/src/oemcrypto_key_deriver.cpp index 2d65a29..df8d8fb 100644 --- a/oemcrypto/util/src/oemcrypto_key_deriver.cpp +++ b/oemcrypto/util/src/oemcrypto_key_deriver.cpp @@ -40,6 +40,31 @@ bool Derive256Key(Cmac* cmac, uint8_t counter_base, const uint8_t* ctx, } return Derive128KeyAppend(cmac, counter_base + 1, ctx, ctx_size, derived_key); } + +bool NistKdf(Cmac* cmac, const std::vector& label, + const std::vector& context, size_t bits, + std::vector* renewed_device_key) { + const std::vector size_bits_big_endian = { + static_cast(bits >> 24), static_cast(bits >> 16), + static_cast(bits >> 8), static_cast(bits)}; + const size_t kAesBlockSizeBits = 16 * 8; + + if (bits % kAesBlockSizeBits != 0) return false; + if (renewed_device_key == nullptr) { + return false; + } + renewed_device_key->clear(); + bool res = false; + for (size_t counter = 0; counter < bits / kAesBlockSizeBits; counter++) { + cmac->Reset(); + res = cmac->Update(counter + 1) && cmac->Update(label) && + cmac->Update(0x00) && cmac->Update(context) && + cmac->Update(size_bits_big_endian) && + cmac->FinalizeAppend(renewed_device_key); + if (!res) break; + } + return res; +} } // namespace // static @@ -150,5 +175,20 @@ bool KeyDeriver::DeriveEncryptionKey( return DeriveEncryptionKey(enc_key_context.data(), enc_key_context.size(), enc_key); } + +bool KeyDeriver::DeriveRenewedDeviceKey( + const std::vector& context, + std::vector* renewed_device_key) { + if (renewed_device_key == nullptr) { + LOGE("Output key buffer is null"); + return false; + } + const std::string kKeyboxRenewalLabel = "Keyboxv4"; + const std::vector kKeyboxRenewalLabelVec(kKeyboxRenewalLabel.begin(), + kKeyboxRenewalLabel.end()); + + return NistKdf(cmac_.get(), kKeyboxRenewalLabelVec, context, 0x80, + renewed_device_key); +} } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/src/oemcrypto_rsa_key.cpp b/oemcrypto/util/src/oemcrypto_rsa_key.cpp index f77b2c1..ec4e6bb 100644 --- a/oemcrypto/util/src/oemcrypto_rsa_key.cpp +++ b/oemcrypto/util/src/oemcrypto_rsa_key.cpp @@ -326,6 +326,27 @@ bool RsaPublicKey::IsMatchingPrivateKey( return RsaKeysAreMatchingPair(GetRsaKey(), private_key.GetRsaKey()); } +std::vector RsaPrivateKey::GetPrivateExponent() const { + const BIGNUM* d = RSA_get0_d(key_); + if (d == nullptr) { + LOGE("Private exponent must not be null"); + return {}; + } + // Get the required length for the data. + const size_t length = BN_num_bytes(d); + if (length <= 0) { + LOGE("Private exponent length must be positive"); + return {}; + } + std::vector serialized_private_exponent(length, 0); + if (static_cast(BN_bn2bin(d, serialized_private_exponent.data())) != + length) { + LOGE("Failed to convert the private exponent"); + return {}; + } + return serialized_private_exponent; +} + OEMCryptoResult RsaPublicKey::Serialize(uint8_t* buffer, size_t* buffer_size) const { if (buffer_size == nullptr) { diff --git a/oemcrypto/util/test/oem_cert_test.cpp b/oemcrypto/util/test/oem_cert_test.cpp index 234d31c..e4dcd5d 100644 --- a/oemcrypto/util/test/oem_cert_test.cpp +++ b/oemcrypto/util/test/oem_cert_test.cpp @@ -2,9 +2,10 @@ // source code may only be used and distributed under the Widevine License // Agreement. -#include "oem_cert.h" +#include "oem_cert_test.h" -namespace wvoec_ref { +namespace wvoec { +namespace util { namespace { const uint32_t kTestOemSystemId = 7913; @@ -529,4 +530,5 @@ const uint8_t* kOEMPublicCert = kTestOemPublicCert; const size_t kOEMPrivateKeySize = kTestOemPrivateKeySize; const size_t kOEMPublicCertSize = kTestOemPublicCertSize; -} // namespace wvoec_ref +} // namespace util +} // namespace wvoec diff --git a/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp b/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp index 2f220e1..6239045 100644 --- a/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp +++ b/oemcrypto/util/test/oemcrypto_oem_cert_unittest.cpp @@ -7,16 +7,12 @@ #include #include "OEMCryptoCENCCommon.h" -#include "oem_cert.h" +#include "oem_cert_test.h" #include "oemcrypto_oem_cert.h" #include "oemcrypto_rsa_key.h" namespace wvoec { namespace util { -using wvoec_ref::kOEMPrivateKey; -using wvoec_ref::kOEMPrivateKeySize; -using wvoec_ref::kOEMPublicCert; -using wvoec_ref::kOEMPublicCertSize; namespace { const std::vector kOEMPrivateKeyVector(kOEMPrivateKey, kOEMPrivateKey + diff --git a/oemcrypto/util/test/oemcrypto_ref_test_utils.h b/oemcrypto/util/test/oemcrypto_ref_test_utils.h index fccc58f..3f62567 100644 --- a/oemcrypto/util/test/oemcrypto_ref_test_utils.h +++ b/oemcrypto/util/test/oemcrypto_ref_test_utils.h @@ -7,6 +7,7 @@ #ifndef WVOEC_UTIL_REF_TEST_UTILS_H_ #define WVOEC_UTIL_REF_TEST_UTILS_H_ +#include #include #include diff --git a/util/include/file_store.h b/util/include/file_store.h index 8594356..6bb1773 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -28,7 +28,7 @@ static const std::string kOemCertificateFileName = "oemcert.bin"; static const std::string kOemCertificateFileNamePrefix = "oemcert_"; // File class. The implementation is platform dependent. -class CORE_UTIL_EXPORT File { +class File { public: File() {} virtual ~File() {} @@ -39,7 +39,7 @@ class CORE_UTIL_EXPORT File { CORE_DISALLOW_COPY_AND_ASSIGN(File); }; -class CORE_UTIL_EXPORT FileSystem { +class FileSystem { public: FileSystem(); FileSystem(const std::string& origin, void* extra_data); diff --git a/util/include/log.h b/util/include/log.h index f4d5e72..2854956 100644 --- a/util/include/log.h +++ b/util/include/log.h @@ -77,31 +77,34 @@ struct LoggingUidSetter { // This function is supplied for cases where the system layer does not // initialize logging. This is also needed to initialize logging in // unit tests. -CORE_UTIL_EXPORT void InitLogging(); +void InitLogging(); #ifdef __GNUC__ -[[gnu::format(printf, 5, 6)]] CORE_UTIL_EXPORT void Log(const char* file, - const char* function, - int line, - LogPriority level, - const char* fmt, ...); -#else -CORE_UTIL_EXPORT void Log(const char* file, const char* function, int line, - LogPriority level, const char* fmt, ...); +[[gnu::format(printf, 5, 6)]] #endif +void Log(const char* file, const char* function, int line, + LogPriority level, const char* fmt, ...); // Log APIs -#ifndef LOGE -# define LOGE(...) \ +#ifdef CDM_DISABLE_LOGGING +# define LOGE(...) (void)0 +# define LOGW(...) (void)0 +# define LOGI(...) (void)0 +# define LOGD(...) (void)0 +# define LOGV(...) (void)0 +#else +# ifndef LOGE +# define LOGE(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_ERROR, __VA_ARGS__) -# define LOGW(...) \ +# define LOGW(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_WARN, __VA_ARGS__) -# define LOGI(...) \ +# define LOGI(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_INFO, __VA_ARGS__) -# define LOGD(...) \ +# define LOGD(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_DEBUG, __VA_ARGS__) -# define LOGV(...) \ +# define LOGV(...) \ Log(__FILE__, __func__, __LINE__, wvutil::CDM_LOG_VERBOSE, __VA_ARGS__) +# endif #endif } // namespace wvutil diff --git a/util/include/platform.h b/util/include/platform.h index effc514..d101dd6 100644 --- a/util/include/platform.h +++ b/util/include/platform.h @@ -21,7 +21,7 @@ using ssize_t = SSIZE_T; inline void sleep(int seconds) { Sleep(seconds * 1000); } -CORE_UTIL_EXPORT int setenv(const char* key, const char* value, int overwrite); +int setenv(const char* key, const char* value, int overwrite); #else # include # include diff --git a/util/include/rw_lock.h b/util/include/rw_lock.h index 5ea3a97..40d7902 100644 --- a/util/include/rw_lock.h +++ b/util/include/rw_lock.h @@ -16,7 +16,7 @@ namespace wvutil { // A simple reader-writer mutex implementation that mimics the one from C++17 -class CORE_UTIL_EXPORT shared_mutex { +class shared_mutex { public: shared_mutex() : reader_count_(0), has_writer_(false) {} ~shared_mutex(); diff --git a/util/include/string_conversions.h b/util/include/string_conversions.h index e5944bd..461ef41 100644 --- a/util/include/string_conversions.h +++ b/util/include/string_conversions.h @@ -15,53 +15,46 @@ namespace wvutil { // ASCII hex to Binary conversion. -CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& b); -CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& label, - const std::string& b); -CORE_UTIL_EXPORT std::string a2bs_hex(const std::string& b); +std::vector a2b_hex(const std::string& b); +std::vector a2b_hex(const std::string& label, + const std::string& b); +std::string a2bs_hex(const std::string& b); // Binary to ASCII hex conversion. The default versions limit output to 2k to // protect us from log spam. The unlimited version has no length limit. -CORE_UTIL_EXPORT std::string b2a_hex(const std::vector& b); -CORE_UTIL_EXPORT std::string unlimited_b2a_hex(const std::vector& b); -CORE_UTIL_EXPORT std::string b2a_hex(const std::string& b); -CORE_UTIL_EXPORT std::string unlimited_b2a_hex(const std::string& b); -CORE_UTIL_EXPORT std::string HexEncode(const uint8_t* bytes, size_t size); -CORE_UTIL_EXPORT std::string UnlimitedHexEncode(const uint8_t* bytes, - size_t size); +std::string b2a_hex(const std::vector& b); +std::string unlimited_b2a_hex(const std::vector& b); +std::string b2a_hex(const std::string& b); +std::string unlimited_b2a_hex(const std::string& b); +std::string HexEncode(const uint8_t* bytes, size_t size); +std::string UnlimitedHexEncode(const uint8_t* bytes, size_t size); // Base64 encoding/decoding. // Converts binary data into the ASCII Base64 character set and vice // versa using the encoding rules defined in RFC4648 section 4. -CORE_UTIL_EXPORT std::string Base64Encode( - const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64Encode(const std::string& bin_input); -CORE_UTIL_EXPORT std::vector Base64Decode( - const std::string& bin_input); +std::string Base64Encode(const std::vector& bin_input); +std::string Base64Encode(const std::string& bin_input); +std::vector Base64Decode(const std::string& bin_input); // URL-Safe Base64 encoding/decoding. // Converts binary data into the URL/Filename safe ASCII Base64 // character set and vice versa using the encoding rules defined in // RFC4648 section 5. -CORE_UTIL_EXPORT std::string Base64SafeEncode( - const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64SafeEncode(const std::string& bin_input); -CORE_UTIL_EXPORT std::vector Base64SafeDecode( - const std::string& bin_input); +std::string Base64SafeEncode(const std::vector& bin_input); +std::string Base64SafeEncode(const std::string& bin_input); +std::vector Base64SafeDecode(const std::string& bin_input); // URL-Safe Base64 encoding without padding. // Similar to Base64SafeEncode(), without any padding character '=' // at the end. -CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( - const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( - const std::string& bin_input); +std::string Base64SafeEncodeNoPad(const std::vector& bin_input); +std::string Base64SafeEncodeNoPad(const std::string& bin_input); // Host to Network/Network to Host conversion. -CORE_UTIL_EXPORT int64_t htonll64(int64_t x); -CORE_UTIL_EXPORT inline int64_t ntohll64(int64_t x) { return htonll64(x); } +int64_t htonll64(int64_t x); +inline int64_t ntohll64(int64_t x) { return htonll64(x); } // Encode unsigned integer into a big endian formatted string. -CORE_UTIL_EXPORT std::string EncodeUint32(uint32_t u); +std::string EncodeUint32(uint32_t u); } // namespace wvutil diff --git a/util/include/util_common.h b/util/include/util_common.h index 7b28c48..b1ddc16 100644 --- a/util/include/util_common.h +++ b/util/include/util_common.h @@ -9,23 +9,11 @@ #ifdef _WIN32 -# ifdef CORE_UTIL_IMPLEMENTATION -# define CORE_UTIL_EXPORT __declspec(dllexport) -# else -# define CORE_UTIL_EXPORT __declspec(dllimport) -# endif - # define CORE_UTIL_IGNORE_DEPRECATED # define CORE_UTIL_RESTORE_WARNINGS #else -# ifdef CORE_UTIL_IMPLEMENTATION -# define CORE_UTIL_EXPORT __attribute__((visibility("default"))) -# else -# define CORE_UTIL_EXPORT -# endif - # ifdef __GNUC__ # define CORE_UTIL_IGNORE_DEPRECATED \ _Pragma("GCC diagnostic push") \ diff --git a/util/libcrypto_dependency.gypi b/util/libcrypto_dependency.gypi index c456cec..8bf8ccf 100644 --- a/util/libcrypto_dependency.gypi +++ b/util/libcrypto_dependency.gypi @@ -3,17 +3,15 @@ # Agreement. { 'conditions': [ - [ - 'privacy_crypto_impl=="openssl"', { - 'libraries': [ - '-lcrypto', - ], - }, # privacy_crypto_impl=="openssl" - 'privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { - 'dependencies': [ - '<(boringssl_libcrypto_path)', - ], # dependencies - }, # privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple" - ], + ['privacy_crypto_impl=="openssl"', { + 'libraries': [ + '-lcrypto', + ], + }], + ['privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { + 'dependencies': [ + '<(boringssl_libcrypto_path)', + ], # dependencies + }], ], # conditions } diff --git a/util/libssl_dependency.gypi b/util/libssl_dependency.gypi index 837c4ce..1261570 100644 --- a/util/libssl_dependency.gypi +++ b/util/libssl_dependency.gypi @@ -3,18 +3,16 @@ # Agreement. { 'conditions': [ - [ - 'privacy_crypto_impl=="openssl"', { - 'libraries': [ - '-lcrypto', - '-lssl', - ], - }, # privacy_crypto_impl=="openssl" - 'privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { - 'dependencies': [ - '<(boringssl_libssl_path)', - ], # dependencies - }, # privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple" - ], + ['privacy_crypto_impl=="openssl"', { + 'libraries': [ + '-lcrypto', + '-lssl', + ], + }], + ['privacy_crypto_impl=="boringssl" or privacy_crypto_impl=="apple"', { + 'dependencies': [ + '<(boringssl_libssl_path)', + ], # dependencies + }], ], # conditions } diff --git a/util/test/test_clock.cpp b/util/test/test_clock.cpp index 18331bb..33edd9c 100644 --- a/util/test/test_clock.cpp +++ b/util/test/test_clock.cpp @@ -2,7 +2,9 @@ // source code may only be used and distributed under the Widevine License // Agreement. // -// Clock - A fake clock just for running tests. +// Clock - A fake clock just for running tests. This is used when running +// OEMCrypto unit tests. It is not used when tests include the CE CDM source +// code because that uses the clock in cdm/test_host.cpp instead. #include diff --git a/util/test/test_sleep.cpp b/util/test/test_sleep.cpp index 281e042..439a46d 100644 --- a/util/test/test_sleep.cpp +++ b/util/test/test_sleep.cpp @@ -14,6 +14,7 @@ #endif #include +#include #include #include @@ -53,6 +54,18 @@ void TestSleep::Sleep(unsigned int seconds) { if (callback_ != nullptr) callback_->ElapseTime(milliseconds); } +void TestSleep::SleepUntil(int64_t desired_time) { + SyncFakeClock(); + const int64_t now = Clock().GetCurrentTime(); + if (desired_time < now) { + LOGE("Test Clock skew sleeping from time %" PRId64 " to %" PRId64, now, + desired_time); + return; + } + const unsigned int sleep_time = static_cast(desired_time - now); + TestSleep::Sleep(sleep_time); +} + void TestSleep::SyncFakeClock() { // Syncing can be done by sleeping 0 seconds. Sleep(0); diff --git a/util/test/test_sleep.h b/util/test/test_sleep.h index 155b89d..f20e27a 100644 --- a/util/test/test_sleep.h +++ b/util/test/test_sleep.h @@ -13,7 +13,9 @@ namespace wvutil { class TestSleep { public: - // The callback is called when the clock should be advanced. + // The callback is called when the test clock should be advanced. If the + // system uses a real clock, it is used to sync the real and test + // clock. Otherwise it is used to simulate sleep in the test clock. class CallBack { public: virtual void ElapseTime(int64_t milliseconds) = 0; @@ -27,6 +29,9 @@ class TestSleep { // callback exists, this calls the callback. static void Sleep(unsigned int seconds); + // Like sleep, above, except it sleeps until the specified time. + static void SleepUntil(int64_t desired_time); + // If we are using a real clock and a fake clock, then the real clock advances // a little while we are doing work, but the fake one only advances when we // sleep. This function advances the fake clock to be in sync with the real