From b4e12724af47aaf990180758bac7fcfad4217c96 Mon Sep 17 00:00:00 2001 From: Vicky Min Date: Tue, 26 Nov 2024 20:50:11 +0000 Subject: [PATCH] OEMCrypto and OPK 19.4 --- CHANGELOG.md | 50 + oemcrypto/include/OEMCryptoCENC.h | 89 +- oemcrypto/include/level3.h | 4 + oemcrypto/odk/include/core_message_features.h | 4 +- oemcrypto/odk/include/odk_structs.h | 4 +- oemcrypto/odk/src/core_message_features.cpp | 2 +- oemcrypto/odk/src/odk_timer.c | 2 +- oemcrypto/odk/test/odk_test.cpp | 4 +- oemcrypto/opk/Android.bp | 32 + oemcrypto/opk/build/Makefile.rules | 5 + oemcrypto/opk/build/ree-sources.mk | 2 + oemcrypto/opk/oemcrypto_ta/oemcrypto.c | 120 +- .../opk/oemcrypto_ta/oemcrypto_api_macros.h | 4 +- .../wtpi/wtpi_provisioning_4_interface.h | 43 +- .../wtpi_reference/config/default.h | 9 +- .../oemcrypto_ta/wtpi_reference/cose_util.c | 41 +- .../wtpi_reference/wtpi_provisioning_4.c | 15 +- .../wtpi_reference/wtpi_reference.gyp | 2 +- .../wtpi_test/common/GEN_common_serializer.c | 11 - .../wtpi_test/common/GEN_common_serializer.h | 1 - .../wtpi_test/common/common_special_cases.c | 15 + .../wtpi_test/common/common_special_cases.h | 7 +- .../ree/GEN_oemcrypto_tee_test_api.c | 37 +- .../wtpi_test/ree/GEN_ree_serializer.c | 218 +-- .../wtpi_test/ree/GEN_ree_serializer.h | 8 +- .../wtpi_test/tee/GEN_dispatcher.c | 105 +- .../wtpi_test/tee/GEN_tee_serializer.c | 154 +- .../wtpi_test/tee/GEN_tee_serializer.h | 7 +- .../wtpi_test/tee/tee_special_cases.c | 6 + .../wtpi_test/tee/tee_special_cases.h | 1 + .../wtpi_useless/wtpi_bcc_signature_keybox.c | 13 +- .../ta/common/wtpi_impl/wtpi_test_impl.gyp | 2 +- .../ta/common/wtpi_impl/wtpi_provisioning_4.c | 13 +- oemcrypto/opk/ports/trusty/ta/README.md | 2 +- .../ta/reference/include/system_specific.h | 19 + .../trusty/ta/reference/include/tee_context.h | 2 +- .../ta/reference/interface_impls/opk_config.h | 56 + .../wtpi_persistent_storage_layer1.c | 6 +- .../interface_impls/wtpi_provisioning_4.c | 37 +- .../wtpi_root_of_trust_layer2.c | 264 ++-- .../ta/reference/liboemcrypto/Application.mk | 5 +- .../liboemcrypto/{Android.mk => OEMCrypto.mk} | 0 .../trusty/ta/reference/liboemcrypto/build.sh | 15 +- .../liboemcrypto/liboemcrypto-inc.mk | 12 +- .../reference/liboemcrypto/liboemcrypto.lds | 10 + .../opk/ports/trusty/ta/reference/rules.mk | 4 +- .../ports/trusty/ta/reference/secure_buffer.c | 2 +- .../ta/reference/shared/shared_memory.c | 4 +- .../ports/trusty/ta/reference/widevine_app.c | 15 +- .../wtpi_lib/impl/crypto/aidl/binding.rs | 61 + .../impl/crypto/aidl/bindings.h} | 22 +- .../wtpi_lib/impl/crypto/aidl/decrypt.rs | 460 ++++++ .../wtpi_lib/impl/crypto/aidl/error.rs | 52 + .../wtpi_lib/impl/crypto/aidl/lib.rs | 208 +++ .../wtpi_lib/impl/crypto/aidl/rules.mk | 71 + .../wtpi_lib/impl/device_key/aidl/bindings.h | 17 + .../wtpi_lib/impl/device_key/aidl/error.rs | 42 + .../wtpi_lib/impl/device_key/aidl/lib.rs | 132 ++ .../wtpi_lib/impl/device_key/aidl/rules.mk | 71 + .../wtpi_lib/impl/device_key/rules.mk | 66 + .../ta/reference/wtpi_lib/impl/other/rules.mk | 126 ++ .../ta/reference/wtpi_lib/impl/rules.mk | 78 + .../wtpi_lib/impl/storage/aidl/bindings.h | 19 + .../wtpi_lib/impl/storage/aidl/error.rs | 42 + .../wtpi_lib/impl/storage/aidl/lib.rs | 273 ++++ .../wtpi_lib/impl/storage/aidl/manifest.json | 6 + .../wtpi_lib/impl/storage/aidl/rules.mk | 66 + .../ta/reference/wtpi_lib/test/manifest.json | 6 + .../ta/reference/wtpi_lib/test/rules.mk | 53 + .../ta/reference/wtpi_lib/test/wtpi_test.cpp | 713 +++++++++ oemcrypto/opk/ports/trusty/ta/zuma/rules.mk | 22 + .../opk/ports/trusty/ta/zuma/wtpi_hdcp.c | 85 ++ .../common/GEN_common_serializer.c | 27 +- .../common/GEN_common_serializer.h | 3 +- .../common/common_special_cases.c | 4 +- .../opk/serialization/ree/GEN_oemcrypto_api.c | 38 +- .../serialization/ree/GEN_ree_serializer.c | 48 +- .../serialization/ree/GEN_ree_serializer.h | 7 +- .../opk/serialization/tee/GEN_dispatcher.c | 30 +- .../serialization/tee/GEN_tee_serializer.c | 34 +- .../serialization/tee/GEN_tee_serializer.h | 7 +- oemcrypto/test/GEN_api_lock_file.c | 3 + oemcrypto/test/common.mk | 2 + oemcrypto/test/oec_decrypt_fallback_chain.cpp | 16 +- oemcrypto/test/oec_session_util.h | 1 + oemcrypto/test/oemcrypto_basic_test.cpp | 139 +- oemcrypto/test/oemcrypto_basic_test.h | 1 + oemcrypto/test/oemcrypto_cast_test.cpp | 17 +- oemcrypto/test/oemcrypto_cast_test.h | 31 +- oemcrypto/test/oemcrypto_decrypt_test.cpp | 4 + oemcrypto/test/oemcrypto_license_test.cpp | 3 + .../test/oemcrypto_provisioning_test.cpp | 52 +- oemcrypto/test/oemcrypto_security_test.cpp | 1292 ++++++++++++++--- oemcrypto/test/oemcrypto_test.cpp | 1152 +-------------- oemcrypto/test/oemcrypto_test_android.cpp | 6 +- oemcrypto/test/oemcrypto_unittests.gypi | 1 + oemcrypto/test/oemcrypto_usage_table_test.cpp | 4 + oemcrypto/util/include/bcc_validator.h | 138 +- oemcrypto/util/include/cbor_validator.h | 17 +- .../util/include/device_info_validator.h | 51 +- .../util/include/prov4_validation_helper.h | 96 ++ .../include/signed_csr_payload_validator.h | 82 +- oemcrypto/util/oec_ref_util.gypi | 1 + oemcrypto/util/src/bcc_validator.cpp | 1082 ++++++++++---- oemcrypto/util/src/cbor_validator.cpp | 39 +- oemcrypto/util/src/device_info_validator.cpp | 601 ++++++-- .../util/src/prov4_validation_helper.cpp | 25 + .../util/src/signed_csr_payload_validator.cpp | 647 ++++++--- .../util/test/bcc_validator_unittest.cpp | 293 +++- .../test/device_info_validator_unittest.cpp | 165 ++- .../signed_csr_payload_validator_unittest.cpp | 54 +- util/include/file_store.h | 99 +- util/test/file_store_unittest.cpp | 592 +++++--- util/test/test_clock.cpp | 4 +- util/test/test_sleep.cpp | 13 +- util/test/test_sleep.h | 11 +- 116 files changed, 8156 insertions(+), 2950 deletions(-) create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/interface_impls/opk_config.h rename oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/{Android.mk => OEMCrypto.mk} (100%) create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto.lds create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/binding.rs rename oemcrypto/opk/ports/trusty/ta/reference/{interface_impls/wtpi_config.c => wtpi_lib/impl/crypto/aidl/bindings.h} (58%) create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/decrypt.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/error.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/lib.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/bindings.h create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/error.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/lib.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/other/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/bindings.h create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/error.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/lib.rs create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/manifest.json create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/manifest.json create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/wtpi_test.cpp create mode 100644 oemcrypto/opk/ports/trusty/ta/zuma/rules.mk create mode 100644 oemcrypto/opk/ports/trusty/ta/zuma/wtpi_hdcp.c create mode 100644 oemcrypto/util/include/prov4_validation_helper.h create mode 100644 oemcrypto/util/src/prov4_validation_helper.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index b21a118..63013b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,55 @@ [TOC] +## [Version 19.4][v19.4] + +This release includes some Provisioning 4.0 updates and better verification +and debugging for the BCC extraction tool. + +This release also adds and updates tests that provide stricter enforcement of +the existing OEMCrypto specification. + +### Tests + +- Update some CAST tests to enforce format of the message signed by + OEMCrypto_GenerateRSASignature() +- Fix key type used in InstallOemPrivateKeyCanBeUsed test +- Re-enable OEMCrypto security tests +- Skip usage table tests on devices that don't support usage tables + +### API + +- Add new OEMCrypto_GetBCCSignatureType() API. This API is optional and only + used on devices that support Provisioning 4 with a Phase 3 DICE chain. + - Add credential types to client identification protobuf + - Return BCC signature type into client identification protobuf + - Regenerate serialization and test files + - Update reference implementation of OEMCrypto_GetBootCertificateChain() to + ensure that the additional signature (UDS certificate) is populated with + the BCC signature when it is available on the device + +### OPK + +- Add new WTPI_GetMaxBCCSignatureSize() API +- Update Trusty OPK port sources to compile with latest OEMCrypto changes +- Fix compile error caused by undefined max_hdcp level in CloseSession() +- Add support for CAST key in handling Provisioning 3.0 response +- BCC extraction tool updates and refactoring + - Rewrite BCC, DeviceInfo and CSR Payload validators to cover info parsing, + validating and updating unit tests + - Update error codes returned by cbor/provisioning 4.0 validators to be less + severe when possible + - Add a few required fields for test-generated BCC +- Manually initialize OEMCrypto_SampleDescription in serialization +- Minor C style guide fixes + - OPK serialization to use assignment instead of memcpy + - Remove nonstandard malloc.h header include +- Minor Trusty code fixes/refactoring + - Merge unreferenced wtpi_persistent_storage.c into + wtpi_persistent_storage_layer1.c + - Check return value of munmap() to prevent potential memory leaks + - Add BCC signature functions to Trusty to prevent linker errors + ## [Version 19.3][v19.3] This release adds new tests that provide stricter enforcement of the existing @@ -683,3 +732,4 @@ Public release for OEMCrypto API and ODK library version 16.4. [v19.1]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v19.1 [v19.2]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v19.2 [v19.3]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v19.3 +[v19.4]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v19.4 diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index a234c35..559c42a 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -3,7 +3,7 @@ // License Agreement. /** - * @mainpage OEMCrypto API v19.3 + * @mainpage OEMCrypto API v19.4 * * 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 @@ -527,6 +527,7 @@ typedef enum OEMCrypto_ProvisioningMethod { /** Return value for OEMCrypto_GetBCCType(). + Provisioning 4.0 only. */ typedef enum OEMCrypto_BCCType { // Boot certificate chain in CBOR format. @@ -535,6 +536,21 @@ typedef enum OEMCrypto_BCCType { OEMCrypto_X509 = 1, } OEMCrypto_BCCType; +/** + Return value for OEMCrypto_GetBCCSignatureType(). + Provisioning 4.0 only. + */ +typedef enum OEMCrypto_BCCSignatureType { + // BCC signature is not supported. + OEMCrypto_BCCSigType_Unknown = 0, + // CBOR format used by the Provisioning 4.0 phase 3 uploading model. + OEMCrypto_BCCSigType_CBOR = 1, + // PKCS7 format, used by signing model. + OEMCrypto_BCCSigType_PKCS7 = 2, + // Signature generated by Keybox, reserved. + OEMCrypto_BCCSigType_Keybox = 3, +} OEMCrypto_BCCSignatureType; + /** Return value for OEMCrypto_GetWatermarkingSupport(). */ @@ -747,6 +763,7 @@ typedef enum OEMCrypto_SignatureHashAlgorithm { #define OEMCrypto_MarkOfflineSession _oecc153 #define OEMCrypto_WrapClearPrivateKey _oecc154 #define OEMCrypto_SetSessionUsage _oecc155 +#define OEMCrypto_GetBCCSignatureType _oecc156 // clang-format on /// @addtogroup initcontrol @@ -3256,9 +3273,77 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, * This method is new in API version 19.2. */ OEMCryptoResult OEMCrypto_WrapClearPrivateKey( - const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + const uint8_t* clear_private_key, size_t clear_private_key_length, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length); +/** + * This function is for OEMCrypto to tell the layer above what type of BCC + * signature it uses. This function is for Provisioning 4.0 signing model, or + * Provisioning 4.0 uploading model with Phase 3 enabled. + * + * The returned bcc_signature_type corresponds to the + * additional_signature parameter in the OEMCrypto_GetBootCertificateChain() + * function and specifies the type of signature returned by that function. + * + * Valid values for OEMCrypto_BCCSignatureType are: + * + * OEMCrypto_BCCSigType_CBOR, required by Android Remote Key Provisioning + * phase 3. The signature is CBOR encoded, which shall follow the IETF CBOR Web + * Token (CWT) specification. The format is described in Android + * generateCertificateRequestV2.cddl: + * UdsCerts = { + * * SignerName => UdsCertChain + * } + * + * SignerName = tstr + * + * UdsCertChain = [ + * + X509Certificate ; Root -> ... -> Leaf. + * ; "Root" is the vendor self-signed cert, + * ; "Leaf" contains Unique Device Secret public key. + * ; It's recommended to have at least 3 certificates + * ; in the chain. The Root certificate is recommended + * ; to be generated in an air-gapped, HSM-based secure + * ; environment. + * ] + * + * ; A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or + * ; EdDSA) + * X509Certificate = bstr + * + * OEMCrypto_BCCSigType_PKCS7, the signature is a PKCS#7 format containing a + * chain of X.509 certificates encoded with DER. The leaf certificate of the + * chain contains the Unique Device Secret public key (UDS_Pub). The signature + * shall be generated off-device for enhanced security. + * + * OEMCrypto_BCCSigType_Keybox, the signature is generated using Keybox on the + * device. Please work with your Widevine Partner Engineer to ensure the + * signature format meets the required specifications. + * + * OEMCrypto_BCCSigTypeUnknown, the signature is not supported. + * + * @param[out] bcc_signature_type: the type of the boot certificate chain. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if any pointer is NULL. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED: if the provisioning method is not + * Provisioning 4.0 or Provisioning 4.0 Phase 3 is not supported. The + * output bcc_signature_type may be set to OEMCrypto_BCCSigTypeUnknown + * in this case. + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failure. + * + * @threading + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * @version + * This method is new API version 19.4. + */ +OEMCryptoResult OEMCrypto_GetBCCSignatureType( + OEMCrypto_BCCSignatureType* bcc_signature_type); + /// @} /// @addtogroup keybox diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h index 8901539..d4ad527 100644 --- a/oemcrypto/include/level3.h +++ b/oemcrypto/include/level3.h @@ -129,6 +129,7 @@ #define Level3_UseSecondaryKey _lcc152 #define Level3_MarkOfflineSession _lcc153 #define Level3_SetSessionUsage _lcc155 +#define Level3_GetBCCSignatureType _lcc156 #else #define Level3_Initialize _oecc01 #define Level3_Terminate _oecc02 @@ -242,6 +243,7 @@ #define Level3_UseSecondaryKey _oecc152 #define Level3_MarkOfflineSession _oecc153 #define Level3_SetSessionUsage _oecc155 +#define Level3_GetBCCSignatureType _oecc156 #endif #define Level3_GetInitializationState _oecl3o01 @@ -543,6 +545,8 @@ OEMCryptoResult Level3_GetEmbeddedDrmCertificate(uint8_t* public_cert, OEMCryptoResult Level3_UseSecondaryKey(OEMCrypto_SESSION session_id, bool dual_key); OEMCryptoResult Level3_MarkOfflineSession(OEMCrypto_SESSION session_id); +OEMCryptoResult Level3_GetBCCSignatureType( + OEMCrypto_BCCSignatureType* bcc_signature_type); // The following are specific to Google's Level 3 implementation and are not // required. diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h index 93ee31f..1d87cd9 100644 --- a/oemcrypto/odk/include/core_message_features.h +++ b/oemcrypto/odk/include/core_message_features.h @@ -26,9 +26,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 19.3. + // number. The default is 19.4. uint32_t maximum_major_version = 19; - uint32_t maximum_minor_version = 3; + uint32_t maximum_minor_version = 4; bool operator==(const CoreMessageFeatures &other) const; bool operator!=(const CoreMessageFeatures &other) const { diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index 10efc8d..6e1edc5 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 19 -#define ODK_MINOR_VERSION 3 +#define ODK_MINOR_VERSION 4 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v19.3 2024-09-04" +#define ODK_RELEASE_DATE "ODK v19.4 2024-11-04" /* 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 d0e6b28..0b4cfb6 100644 --- a/oemcrypto/odk/src/core_message_features.cpp +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -33,7 +33,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures( features.maximum_minor_version = 4; // 18.4 break; case 19: - features.maximum_minor_version = 3; // 19.3 + features.maximum_minor_version = 4; // 19.4 break; default: features.maximum_minor_version = 0; diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index 822b266..ec9e25e 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -277,7 +277,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits, nonce_values->api_minor_version = 4; break; case 19: - nonce_values->api_minor_version = 3; + nonce_values->api_minor_version = 4; break; default: nonce_values->api_minor_version = 0; diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index b0cc632..7a0d645 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -1275,7 +1275,7 @@ std::vector TestCases() { {16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5}, {17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2}, {18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 4}, - {19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 3}, + {19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 4}, // Here are some known good versions. Make extra sure they work. {ODK_MAJOR_VERSION, 16, 3, 16, 3}, {ODK_MAJOR_VERSION, 16, 4, 16, 4}, @@ -1289,6 +1289,7 @@ std::vector TestCases() { {ODK_MAJOR_VERSION, 19, 1, 19, 1}, {ODK_MAJOR_VERSION, 19, 2, 19, 2}, {ODK_MAJOR_VERSION, 19, 3, 19, 3}, + {ODK_MAJOR_VERSION, 19, 4, 19, 4}, {0, 16, 3, 16, 3}, {0, 16, 4, 16, 4}, {0, 16, 5, 16, 5}, @@ -1300,6 +1301,7 @@ std::vector TestCases() { {0, 19, 1, 19, 1}, {0, 19, 2, 19, 2}, {0, 19, 3, 19, 3}, + {0, 19, 4, 19, 4}, }; return test_cases; } diff --git a/oemcrypto/opk/Android.bp b/oemcrypto/opk/Android.bp index 178d529..5b6d41b 100644 --- a/oemcrypto/opk/Android.bp +++ b/oemcrypto/opk/Android.bp @@ -2,11 +2,43 @@ // source code may only be used and distributed under the Widevine // License Agreement. +soong_config_module_type { + name: "widevine_disable_logging_type", + module_type: "cc_defaults", + config_namespace: "widevine", + variables: ["whitebox_os"], + properties: ["cflags"], +} + +soong_config_string_variable { + name: "whitebox_os", + values: ["dev_android", "android"], +} + +widevine_disable_logging_type { + name: "widevine_disable_logging_defaults", + soong_config_variables: { + whitebox_os: { + android: { + cflags: [ + "-DOPK_IS_DEBUG=0", + ], + }, + }, + }, + + proprietary: true, + owner: "widevine", +} + // ---------------------------------------------------------------- // The OPK code that is used by the Rikers L3 cc_library_static { name: "libwv_opk_rikers", min_sdk_version: "34", + defaults: [ + "widevine_disable_logging_defaults", + ], export_include_dirs: [ "oemcrypto_ta", "oemcrypto_ta/wtpi", diff --git a/oemcrypto/opk/build/Makefile.rules b/oemcrypto/opk/build/Makefile.rules index d0978f8..e1a69a1 100644 --- a/oemcrypto/opk/build/Makefile.rules +++ b/oemcrypto/opk/build/Makefile.rules @@ -326,6 +326,11 @@ ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ $(join ^,oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk)))),) include oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_renewal.target.mk)))),) + include oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_renewal.target.mk +endif ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ $(findstring $(join ^,$(prefix)),\ $(join ^,oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_root_of_trust.target.mk)))),) diff --git a/oemcrypto/opk/build/ree-sources.mk b/oemcrypto/opk/build/ree-sources.mk index 3a72ce5..234c4c1 100644 --- a/oemcrypto/opk/build/ree-sources.mk +++ b/oemcrypto/opk/build/ree-sources.mk @@ -224,6 +224,7 @@ oemcrypto_unittests_sources += \ $(oemcrypto_unittests_dir)/oemcrypto_generic_crypto_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_license_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_provisioning_test.cpp \ + $(oemcrypto_unittests_dir)/oemcrypto_security_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_usage_table_test.cpp \ $(oemcrypto_unittests_dir)/oemcrypto_test.cpp \ $(oemcrypto_dir)/util/src/bcc_validator.cpp \ @@ -235,6 +236,7 @@ oemcrypto_unittests_sources += \ $(oemcrypto_dir)/util/src/oemcrypto_key_deriver.cpp \ $(oemcrypto_dir)/util/src/oemcrypto_oem_cert.cpp \ $(oemcrypto_dir)/util/src/oemcrypto_rsa_key.cpp \ + $(oemcrypto_dir)/util/src/prov4_validation_helper.cpp \ $(oemcrypto_dir)/util/src/signed_csr_payload_validator.cpp \ $(oemcrypto_dir)/util/src/wvcrc.cpp \ $(json_dir)/jsmn.c \ diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c index b3291d3..0c308fa 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c @@ -5,7 +5,6 @@ #include "OEMCryptoCENC.h" #include -#include #include #include "odk.h" @@ -340,10 +339,24 @@ static OEMCryptoResult RewrapDeviceDRMKeyOEMCert( LOGE("Failed to AES CBC decrypt DRM private key with result: %u", result); goto cleanup; } + /* Adjust for RSA keys with specified schemes */ + uint32_t allowed_schemes = 0; + size_t key_offset = 0; + if (drm_key_type == DRM_RSA_PRIVATE_KEY) { + if (enc_drm_key_length >= 8 && + crypto_memcmp(clear_drm_key, "SIGN", 4) == 0) { + memcpy(&allowed_schemes, clear_drm_key + 4, 4); + allowed_schemes = oemcrypto_be32toh(allowed_schemes); + key_offset = 8; + } else { + allowed_schemes = kSign_RSASSA_PSS; + } + } /* Create asymmetric key handle for DRM private key in order to get the * signature size. */ WTPI_AsymmetricKey_Handle private_key_handle; - result = WTPI_CreateAsymmetricKeyHandle(clear_drm_key, enc_drm_key_length, + result = WTPI_CreateAsymmetricKeyHandle(clear_drm_key + key_offset, + enc_drm_key_length - key_offset, drm_key_type, &private_key_handle); if (result != OEMCrypto_SUCCESS) { LOGE( @@ -370,7 +383,7 @@ static OEMCryptoResult RewrapDeviceDRMKeyOEMCert( /* Check that it's a valid DRM key. */ result = OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key, - wrapped_drm_key_length, signature_size, kSign_RSASSA_PSS); + wrapped_drm_key_length, signature_size, allowed_schemes); if (result != OEMCrypto_SUCCESS) { LOGE("Failed to load DRM key with result: %u", result); } @@ -699,7 +712,7 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) { if (hdcp_result == OEMCrypto_ERROR_NOT_IMPLEMENTED) { LOGD("WTPI_SetHDCPLevel() not implemented."); } else if (hdcp_result != OEMCrypto_SUCCESS) { - LOGE("WTPI_SetHDCPLevel() failed for target level %d", max_hdcp_level); + LOGE("WTPI_SetHDCPLevel() failed for target level %d", HDCP_NONE); } } #endif // USE_OPK_FEATURE_SETHDCP @@ -2573,7 +2586,7 @@ OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, const OEMCrypto_ProvisioningMethod provisioning_method = WTPI_GetProvisioningMethod(); if (provisioning_method == OEMCrypto_Keybox) { - if (WTPI_GetBCCSignatureType() == BCC_SIG_KEYBOX) { + if (WTPI_GetBCCSignatureType() == OEMCrypto_BCCSigType_Keybox) { // Install keybox, which is needed to generate BCC sig OEMCryptoResult res = WTPI_UnwrapValidateAndInstallKeybox(rot, rot_length); @@ -2625,9 +2638,9 @@ OEMCryptoResult OEMCrypto_FactoryInstallBCCSignature(const uint8_t* signature, } RETURN_INVALID_CONTEXT_IF_NULL(signature); RETURN_INVALID_CONTEXT_IF_ZERO(signature_length); - const OPK_BCCSignatureType signature_type = WTPI_GetBCCSignatureType(); + const OEMCrypto_BCCSignatureType signature_type = WTPI_GetBCCSignatureType(); // Only signature by keybox is supported currently. - if (signature_type != BCC_SIG_KEYBOX) { + if (signature_type != OEMCrypto_BCCSigType_Keybox) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } // BCCSignatureByKeybox to be installed := @@ -3887,7 +3900,7 @@ OEMCryptoResult OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session UNUSED, } OEMCryptoResult OEMCrypto_GetBootCertificateChain( - uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature UNUSED, + uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature, size_t* additional_signature_size) { if (g_opk_system_state != SYSTEM_INITIALIZED) { LOGE("OEMCrypto is not yet initialized"); @@ -3895,33 +3908,64 @@ OEMCryptoResult OEMCrypto_GetBootCertificateChain( } RETURN_INVALID_CONTEXT_IF_NULL(bcc_size); RETURN_INVALID_CONTEXT_IF_NULL(additional_signature_size); - const OEMCryptoResult bcc_result = - WTPI_GetBootCertificateChain(bcc, bcc_size); - if (bcc_result != OEMCrypto_SUCCESS && - bcc_result != OEMCrypto_ERROR_SHORT_BUFFER) { + OEMCryptoResult result = OEMCrypto_SUCCESS; + size_t required_bcc_size = 0; + OEMCryptoResult bcc_result = + WTPI_GetMaxBootCertificateChainSize(&required_bcc_size); + if (bcc_result != OEMCrypto_SUCCESS) { return bcc_result; } -#ifdef FACTORY_BUILD_ONLY - const OPK_BCCSignatureType signature_type = WTPI_GetBCCSignatureType(); - if (signature_type == BCC_SIG_KEYBOX) { - const OEMCryptoResult sig_result = WTPI_GenerateBCCSignature( - additional_signature, additional_signature_size); - if (sig_result != OEMCrypto_SUCCESS && - sig_result != OEMCrypto_ERROR_SHORT_BUFFER) { - return sig_result; - } - if (bcc_result == OEMCrypto_ERROR_SHORT_BUFFER || - sig_result == OEMCrypto_ERROR_SHORT_BUFFER) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - return OEMCrypto_SUCCESS; - } else if (signature_type == BCC_SIG_X509) { - *additional_signature_size = 0; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + if (bcc == NULL || *bcc_size < required_bcc_size) { + *bcc_size = required_bcc_size; + bcc_result = OEMCrypto_ERROR_SHORT_BUFFER; } -#endif - *additional_signature_size = 0; - return bcc_result; + const OEMCrypto_BCCSignatureType signature_type = WTPI_GetBCCSignatureType(); + if (signature_type == OEMCrypto_BCCSigType_Unknown) { + if (bcc_result == OEMCrypto_ERROR_SHORT_BUFFER) return bcc_result; + *bcc_size = required_bcc_size; + return WTPI_GetBootCertificateChain(bcc, bcc_size); + } + size_t required_signature_size = 0; + OEMCryptoResult signature_result = + WTPI_GetMaxBCCSignatureSize(&required_signature_size); + if (signature_result != OEMCrypto_SUCCESS) return result; + if (additional_signature == NULL || + *additional_signature_size < required_signature_size) { + *additional_signature_size = required_signature_size; + signature_result = OEMCrypto_ERROR_SHORT_BUFFER; + } + if (bcc_result == OEMCrypto_ERROR_SHORT_BUFFER || + signature_result == OEMCrypto_ERROR_SHORT_BUFFER) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *bcc_size = required_bcc_size; + *additional_signature_size = required_signature_size; + + bcc_result = WTPI_GetBootCertificateChain(bcc, bcc_size); + if (bcc_result != OEMCrypto_SUCCESS) { + LOGE("Failed to get boot certificate chain with result: %u", bcc_result); + return bcc_result; + } + // Try to load the pre-generated BCC signature first, if available. + signature_result = + WTPI_LoadBCCSignature(additional_signature, additional_signature_size); + if (signature_result != OEMCrypto_SUCCESS) { + // If failing to load the pre-generated BCC signature, try to generate it on + // device. + if (signature_type == OEMCrypto_BCCSigType_Keybox) { + OEMCryptoResult gen_result = WTPI_GenerateBCCSignature( + additional_signature, additional_signature_size); + if (gen_result != OEMCrypto_SUCCESS && + gen_result != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + signature_result = gen_result; + LOGE("Failed to generate BCC signature with result: %u", gen_result); + } + } + } + if (signature_result != OEMCrypto_SUCCESS) { + *additional_signature_size = 0; + } + return signature_result; } OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( @@ -4778,3 +4822,15 @@ OEMCryptoResult OEMCrypto_WrapClearPrivateKey( return OEMCrypto_ERROR_NOT_IMPLEMENTED; #endif } + +OEMCryptoResult OEMCrypto_GetBCCSignatureType( + OEMCrypto_BCCSignatureType* bcc_signature_type) { + const OEMCrypto_ProvisioningMethod provisioning_method = + WTPI_GetProvisioningMethod(); + if (provisioning_method != OEMCrypto_BootCertificateChain) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + RETURN_INVALID_CONTEXT_IF_NULL(bcc_signature_type); + *bcc_signature_type = WTPI_GetBCCSignatureType(); + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h index 56e94e6..5d19f72 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_api_macros.h @@ -34,8 +34,8 @@ // version bumps to v17.1, the first released OPK implementation would be // v17.1.0 #define API_MAJOR_VERSION 19 -#define API_MINOR_VERSION 3 +#define API_MINOR_VERSION 4 #define OPK_PATCH_VERSION 0 -#define OPK_BUILD_ID "19.3.0" +#define OPK_BUILD_ID "19.4.0" #endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h index dbd63f1..496216c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_provisioning_4_interface.h @@ -7,8 +7,8 @@ #include "OEMCryptoCENC.h" -#include "wtpi_crypto_asymmetric_interface.h" #include "oemcrypto_key_types.h" +#include "wtpi_crypto_asymmetric_interface.h" #ifdef __cplusplus extern "C" { @@ -93,10 +93,9 @@ OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length); * modified based on used/required space of output. */ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( - CertSignatureType cert_type, - AsymmetricKeyType* key_type, uint8_t* wrapped_private_key, - size_t* wrapped_private_key_length, uint8_t* public_key, - size_t* public_key_length); + CertSignatureType cert_type, AsymmetricKeyType* key_type, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, + uint8_t* public_key, size_t* public_key_length); /** * Writes the serialized signed Certificate Signing Request (Csr) payload in @@ -224,23 +223,17 @@ OEMCryptoResult WTPI_GetMaxBccKeyCoseSign1Size(size_t* out_length); */ OEMCryptoResult WTPI_GetDeviceFusedStatus(bool* is_fused); -typedef enum OPK_BCCSignatureType { - BCC_SIG_NONE = 0x5a48f890, - BCC_SIG_KEYBOX = 0x692be012, - BCC_SIG_X509 = 0x23c9fa55, -} OPK_BCCSignatureType; - /** * Returns the BCC signature type configured for this TA. */ -OPK_BCCSignatureType WTPI_GetBCCSignatureType(void); +OEMCrypto_BCCSignatureType WTPI_GetBCCSignatureType(void); /** * Signs the device public key in the boot certificate chain (BCC) and writes * the signature to |out|, with number of bytes specified in |out_length|. The * signer can be either a keybox or an X509 certificate, depending on the return * type of WTPI_GetBCCSignatureType(). This function is used by Provisioning 4.0 - * signing model in the factory only. + * in the factory only. * * Caller retains ownership of all pointers. * @@ -252,7 +245,7 @@ OPK_BCCSignatureType WTPI_GetBCCSignatureType(void); * @retval OEMCrypto_ERROR_SHORT_BUFFER if |out_length| is too small, or * |out| is NULL, in which case it sets |out_length| to the * appropriate length - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if signing model is not used + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if BCC signature is not used * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures * @retval OEMCrypto_SUCCESS otherwise */ @@ -261,14 +254,14 @@ OEMCryptoResult WTPI_GenerateBCCSignature(uint8_t* out, size_t* out_length); /** * Saves the BCC signature to persistent storage. This is called once, after the * BCC signature is generated in the factory. This function is used by - * Provisioning 4.0 signing model in the factory only. + * Provisioning 4.0 in the factory only. * * @param[in] signature: BCC signature to save. * @param[in] signature_length: size of BCC signature. * * @retval OEMCrypto_ERROR_INVALID_CONTEXT if |signature| is NULL * @retval OEMCrypto_ERROR_OPEN_FAILURE if failing to create persistent file - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if signing model is not used + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if BCC signature is not used * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures * @retval OEMCrypto_SUCCESS data was stored */ @@ -276,8 +269,7 @@ OEMCryptoResult WTPI_StoreBCCSignature(const uint8_t* signature, size_t signature_length); /** - * Load the BCC signature from persistent storage. This function is used by - * Provisioning 4.0 signing model only. + * Load the BCC signature from persistent storage. * * @param[out] signature: BCC signature to be loaded to. * @param[in,out] signature_length: on input, the size of the signature buffer, @@ -287,7 +279,7 @@ OEMCryptoResult WTPI_StoreBCCSignature(const uint8_t* signature, * @retval OEMCrypto_ERROR_SHORT_BUFFER if |signature_length| is too small, or * |signature| is NULL, in which case it sets |signature_length| to the * appropriate length - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if signing model is not used + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if BCC signature is not used * @retval OPK_ERROR_NO_PERSISTENT_DATA No signature data available * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures * @retval OEMCrypto_SUCCESS data was loaded @@ -295,6 +287,19 @@ OEMCryptoResult WTPI_StoreBCCSignature(const uint8_t* signature, OEMCryptoResult WTPI_LoadBCCSignature(uint8_t* signature, size_t* signature_length); +/** + * Writes the maximum possible size of the BCC signature in to |out_length|. + * + * Caller retains ownership of all pointers. + * + * @param[out] out_length: max size of the BCC 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_GetMaxBCCSignatureSize(size_t* out_length); + /** * Retrieve the device unique secret and derive a device specific asymmetric key * pair (DK_priv/DK_pub) as the root of trust of BCC. The output key must be diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h index 64bb351..fd98cbf 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/config/default.h @@ -56,14 +56,13 @@ /** * BCC signature type used by the TA. - * If OPK_CONFIG_PROVISIONING_METHOD is not OEMCrypto_BootCertificateChain, or - * provisioning 4.0 signing model is not used, OPK_CONFIG_BCC_SIGNATURE_TYPE - * should be BCC_SIG_NONE. + * If OPK_CONFIG_PROVISIONING_METHOD is not OEMCrypto_BootCertificateChain, + * OPK_CONFIG_BCC_SIGNATURE_TYPE should be OEMCrypto_BCCSigType_Unknown. * - * Type is OPK_BCCSignatureType + * Type is OEMCrypto_BCCSignatureType */ #ifndef OPK_CONFIG_BCC_SIGNATURE_TYPE -# define OPK_CONFIG_BCC_SIGNATURE_TYPE BCC_SIG_NONE +# define OPK_CONFIG_BCC_SIGNATURE_TYPE OEMCrypto_BCCSigType_Unknown #endif /** diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c index 84da4d2..2260749 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/cose_util.c @@ -200,17 +200,29 @@ static DiceResult EncodeConfigurationDescriptor(size_t buffer_size, /* -4670548 : bstr .cbor { ; Configuration Descriptor ? -70002 : tstr, ; Component name - ? -70003 : int, ; Firmware version + ? -70003 : int, ; Component version ? -70004 : null, ; Resettable + ? -70005 : uint, ; Security version + ? -70006 : null, ; RKP VM marker } */ ABORT_IF_ZERO(buffer_size); ABORT_IF_NULL(buffer); ABORT_IF_NULL(encoded_size); + const int64_t kComponentNameLabel = -70002; + const int64_t kComponentVersionLabel = -70003; struct CborOut out; CborOutInit(buffer, buffer_size, &out); - // Leave optional fields blank. - CborWriteMap(/*num_pairs=*/0, &out); + CborWriteMap(/*num_pairs=*/2, &out); + + // Add component name. + CborWriteInt(kComponentNameLabel, &out); + CborWriteTstr("Widevine", &out); + + // Add component version. + CborWriteInt(kComponentVersionLabel, &out); + CborWriteTstr("19", &out); + if (CborOutOverflowed(&out)) { return kDiceResultBufferTooSmall; } @@ -363,10 +375,12 @@ static OEMCryptoResult GenerateEncodedBccPayload( const int64_t kIssuerLabel = 1; const int64_t kSubjectLabel = 2; + const int64_t kProfileNameLabel = -4670554; const int64_t kSubjectPublicKeyLabel = -4670552; const int64_t kKeyUsageLabel = -4670553; const uint8_t kKeyUsageCertSign = 32; const int64_t kCodeHashLabel = -4670545; + const int64_t kConfigurationHashLabel = -4670547; const int64_t kConfigurationDescriptorLabel = -4670548; const int64_t kAuthorityHashLabel = -4670549; const int64_t kModeLabel = -4670551; @@ -378,10 +392,9 @@ static OEMCryptoResult GenerateEncodedBccPayload( struct CborOut cbor_out; CborOutInit(out, *out_length, &cbor_out); // Make sure the number of items added below matches this num_pairs. - CborWriteMap(/*num_pairs=*/8, &cbor_out); + CborWriteMap(/*num_pairs=*/10, &cbor_out); - // Add mandatory field Issuer, which is ignored by provisioning server and can - // be empty. + // Add mandatory field Issuer. CborWriteInt(kIssuerLabel, &cbor_out); if (entry_index == 0) { snprintf(str_buf, sizeof(str_buf), "issuer 0"); @@ -392,14 +405,17 @@ static OEMCryptoResult GenerateEncodedBccPayload( CborWriteTstr(str_buf, &cbor_out); memset(str_buf, 0, sizeof(str_buf)); - // Add mandatory field Subject, which is ignored by provisioning server and - // can be empty. + // Add mandatory field Subject. CborWriteInt(kSubjectLabel, &cbor_out); // Subject text starts with "entry 1" snprintf(str_buf, sizeof(str_buf), "entry %u", entry_index + 1); CborWriteTstr(str_buf, &cbor_out); memset(str_buf, 0, sizeof(str_buf)); + // Add the profile name. + CborWriteInt(kProfileNameLabel, &cbor_out); + CborWriteTstr("android.15", &cbor_out); + // Add the subject public key. CborWriteInt(kSubjectPublicKeyLabel, &cbor_out); CborWriteBstr(encoded_public_key_size, encoded_public_key, &cbor_out); @@ -418,6 +434,15 @@ static OEMCryptoResult GenerateEncodedBccPayload( CborWriteBstr(sizeof(hash), hash, &cbor_out); memset(hash, 0, sizeof(hash)); + // Add the configuration hash. + CborWriteInt(kConfigurationHashLabel, &cbor_out); + snprintf(str_buf, sizeof(str_buf), "ConfigurationToHash %u", entry_index); + hash_res = WTPI_C1_SHA256((const uint8_t*)str_buf, sizeof(str_buf), hash); + memset(str_buf, 0, sizeof(str_buf)); + if (hash_res != OEMCrypto_SUCCESS) return hash_res; + CborWriteBstr(sizeof(hash), hash, &cbor_out); + memset(hash, 0, sizeof(hash)); + // Add the configuration descriptor. CborWriteInt(kConfigurationDescriptorLabel, &cbor_out); uint8_t configuration_descriptor[DICE_MAX_CONFIGURATION_DESCRIPTOR_SIZE]; diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c index d3d015f..deee175 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_provisioning_4.c @@ -18,6 +18,7 @@ #define MAX_BCC_PAYLOAD_SIZE 2048 #define MAX_COSE_SIGN1_SIZE 2048 +#define MAX_BCC_SIGNATURE_SIZE 4096 #define BCC_ENTRY_COUNT 2 #ifdef USE_DICE_BCC @@ -348,8 +349,8 @@ OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, signature_length); } -#if OPK_CONFIG_BCC_SIGNATURE_TYPE == BCC_SIG_NONE -OPK_BCCSignatureType WTPI_GetBCCSignatureType(void) { +#if OPK_CONFIG_BCC_SIGNATURE_TYPE == OEMCrypto_BCCSigType_Unknown +OEMCrypto_BCCSignatureType WTPI_GetBCCSignatureType(void) { return OPK_CONFIG_BCC_SIGNATURE_TYPE; } @@ -365,6 +366,7 @@ OEMCryptoResult WTPI_StoreBCCSignature(const uint8_t* signature, (void)signature_length; return OEMCrypto_ERROR_NOT_IMPLEMENTED; } +#endif OEMCryptoResult WTPI_LoadBCCSignature(uint8_t* signature, size_t* signature_length) { @@ -372,4 +374,11 @@ OEMCryptoResult WTPI_LoadBCCSignature(uint8_t* signature, (void)signature_length; return OEMCrypto_ERROR_NOT_IMPLEMENTED; } -#endif + +OEMCryptoResult WTPI_GetMaxBCCSignatureSize(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = MAX_BCC_SIGNATURE_SIZE; + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp index 58bd06b..b8e4df2 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp @@ -141,7 +141,7 @@ }], ['prov4_bcc_signature_type=="keybox"', { 'defines': [ - 'OPK_CONFIG_BCC_SIGNATURE_TYPE=BCC_SIG_KEYBOX', + 'OPK_CONFIG_BCC_SIGNATURE_TYPE=OEMCrypto_BCCSigType_Keybox', ], }], ['use_provisioning_30', { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.c index 976dc73..5ad9f67 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.c @@ -185,17 +185,6 @@ bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value) { } } -bool Is_Valid_OPK_BCCSignatureType(uint32_t value) { - switch (value) { - case 1514731664: /* BCC_SIG_NONE */ - case 1764483090: /* BCC_SIG_KEYBOX */ - case 600439381: /* BCC_SIG_X509 */ - return true; - default: - return false; - } -} - bool Is_Valid_OPK_FeatureStatus(uint32_t value) { switch (value) { case 1764049255: /* OPK_FEATURE_NOT_SUPPORTED */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.h index b833832..4369d57 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.h @@ -30,7 +30,6 @@ bool Is_Valid_OEMCrypto_LicenseType(uint32_t value); bool Is_Valid_OEMCrypto_PrivateKeyType(uint32_t value); bool Is_Valid_OEMCrypto_TimerDelayBase(uint32_t value); bool Is_Valid_OPK_OutputBuffer_Type(uint32_t value); -bool Is_Valid_OPK_BCCSignatureType(uint32_t value); bool Is_Valid_OPK_FeatureStatus(uint32_t value); void OPK_Pack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring const* obj); 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 5de2899..cd8c52a 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 @@ -212,6 +212,16 @@ void OPK_Pack_OEMCrypto_BCCType(ODK_Message* message, OPK_Pack_uint32_t(message, (const uint32_t*)value); } +void OPK_Pack_OEMCrypto_BCCSignatureType( + ODK_Message* message, const OEMCrypto_BCCSignatureType* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Pack_uint32_t(message, (const uint32_t*)value); +} + void OPK_Pack_OEMCrypto_WatermarkingSupport( ODK_Message* message, const OEMCrypto_WatermarkingSupport* value) { if (value == NULL) { @@ -257,6 +267,11 @@ void OPK_Unpack_OEMCrypto_BCCType(ODK_Message* message, OPK_Unpack_uint32_t(message, (uint32_t*)value); } +void OPK_Unpack_OEMCrypto_BCCSignatureType(ODK_Message* message, + OEMCrypto_BCCSignatureType* value) { + OPK_Unpack_uint32_t(message, (uint32_t*)value); +} + void OPK_Unpack_OEMCrypto_WatermarkingSupport( ODK_Message* message, OEMCrypto_WatermarkingSupport* value) { OPK_Unpack_uint32_t(message, (uint32_t*)value); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h index 123131e..99fa1eb 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h @@ -61,6 +61,8 @@ void OPK_Pack_OEMCrypto_ProvisioningMethod( ODK_Message* msg, const OEMCrypto_ProvisioningMethod* value); void OPK_Pack_OEMCrypto_BCCType(ODK_Message* msg, const OEMCrypto_BCCType* value); +void OPK_Pack_OEMCrypto_BCCSignatureType( + ODK_Message* msg, const OEMCrypto_BCCSignatureType* value); void OPK_Pack_OEMCrypto_WatermarkingSupport( ODK_Message* msg, const OEMCrypto_WatermarkingSupport* value); void OPK_Pack_OEMCrypto_HDCP_Capability(ODK_Message* msg, @@ -72,6 +74,8 @@ void OPK_Unpack_OEMCrypto_Security_Level(ODK_Message* msg, void OPK_Unpack_OEMCrypto_ProvisioningMethod( ODK_Message* msg, OEMCrypto_ProvisioningMethod* value); void OPK_Unpack_OEMCrypto_BCCType(ODK_Message* msg, OEMCrypto_BCCType* value); +void OPK_Unpack_OEMCrypto_BCCSignatureType(ODK_Message* msg, + OEMCrypto_BCCSignatureType* value); void OPK_Unpack_OEMCrypto_WatermarkingSupport( ODK_Message* msg, OEMCrypto_WatermarkingSupport* value); void OPK_Unpack_OEMCrypto_HDCP_Capability(ODK_Message* msg, @@ -83,6 +87,7 @@ void OPK_Unpack_OEMCrypto_SignatureHashAlgorithm( void OPK_Unpack_OEMCrypto_Usage_Entry_Status( ODK_Message* message, OEMCrypto_Usage_Entry_Status* status); void OPK_Pack_CertSignatureType(ODK_Message* message, CertSignatureType* value); -void OPK_Unpack_CertSignatureType(ODK_Message* message, CertSignatureType* value); +void OPK_Unpack_CertSignatureType(ODK_Message* message, + CertSignatureType* value); #endif 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 ba35a78..0e2f850 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 @@ -1656,9 +1656,9 @@ cleanup_and_return: return result; } -OPK_BCCSignatureType WTPI_GetBCCSignatureType(void) { +OEMCrypto_BCCSignatureType WTPI_GetBCCSignatureType(void) { pthread_mutex_lock(&api_lock); - OPK_BCCSignatureType result = BCC_SIG_NONE; + OEMCrypto_BCCSignatureType result = OEMCrypto_BCCSigType_Unknown; ODK_Message request = ODK_Message_Create(NULL, 0); ODK_Message response = ODK_Message_Create(NULL, 0); @@ -1791,6 +1791,39 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_GetMaxBCCSignatureSize(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_GetMaxBCCSignatureSize_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); + if (api_result != OEMCrypto_SUCCESS) goto cleanup_and_return; + OPK_Unpack_GetMaxBCCSignatureSize_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_CreateUDSDerivedAsymmetricKeyHandle( AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle* private_key_handle, uint8_t* public_key, size_t* public_key_length) { 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 52929dc..4b7c797 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 @@ -1694,16 +1694,13 @@ ODK_Message OPK_Pack_GetBCCSignatureType_Request(void) { return msg; } -void OPK_Unpack_GetBCCSignatureType_Response(ODK_Message* msg, - OPK_BCCSignatureType* result) { +void OPK_Unpack_GetBCCSignatureType_Response( + ODK_Message* msg, OEMCrypto_BCCSignatureType* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); if (api_value != 10045) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); - OPK_Unpack_uint32_t(msg, result); - if (!Is_Valid_OPK_BCCSignatureType(*result)) { - ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); - } + OPK_Unpack_OEMCrypto_BCCSignatureType(msg, result); OPK_UnpackEOM(msg); OPK_SharedBuffer_FinalizeUnpacking(); } @@ -1822,11 +1819,46 @@ void OPK_Unpack_LoadBCCSignature_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_GetMaxBCCSignatureSize_Request(const size_t* out_length) { + uint32_t api_value = 10049; /* from _tee10049 */ + 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_GetMaxBCCSignatureSize_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 != 10049) + 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); + } + if (SuccessResult(*result)) { + OPK_UnpackNullable_size_t(msg, out_length); + } else { + OPK_UnpackNullable_size_t(msg, NULL); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_CreateUDSDerivedAsymmetricKeyHandle_Request( const AsymmetricKeyType* key_type, const WTPI_AsymmetricKey_Handle* private_key_handle, const uint8_t* public_key, const size_t* public_key_length) { - uint32_t api_value = 10049; /* from _tee10049 */ + uint32_t api_value = 10050; /* from _tee10050 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1846,7 +1878,7 @@ void OPK_Unpack_CreateUDSDerivedAsymmetricKeyHandle_Response( size_t** public_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10049) + if (api_value != 10050) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, public_key_length); OPK_Unpack_uint32_t(msg, result); @@ -1878,7 +1910,7 @@ void OPK_Unpack_CreateUDSDerivedAsymmetricKeyHandle_Response( } ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash) { - uint32_t api_value = 10050; /* from _tee10050 */ + uint32_t api_value = 10051; /* from _tee10051 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1893,7 +1925,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 != 10050) + if (api_value != 10051) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1914,7 +1946,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 = 10051; /* from _tee10051 */ + uint32_t api_value = 10052; /* from _tee10052 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1932,7 +1964,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 != 10051) + if (api_value != 10052) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1955,7 +1987,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 = 10052; /* from _tee10052 */ + uint32_t api_value = 10053; /* from _tee10053 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1987,7 +2019,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 != 10052) + if (api_value != 10053) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -2006,7 +2038,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 = 10053; /* from _tee10053 */ + uint32_t api_value = 10054; /* from _tee10054 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2022,7 +2054,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 != 10053) + if (api_value != 10054) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -2041,7 +2073,7 @@ void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, } ODK_Message OPK_Pack_InitializeClock_Request(void) { - uint32_t api_value = 10054; /* from _tee10054 */ + uint32_t api_value = 10055; /* from _tee10055 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2055,34 +2087,6 @@ 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 != 10054) - 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_TerminateClock_Request(void) { - uint32_t api_value = 10055; /* from _tee10055 */ - 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_PackEOM(&msg); - OPK_SharedBuffer_FinalizePacking(); - return msg; -} - -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 != 10055) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); @@ -2096,7 +2100,7 @@ void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, } } -ODK_Message OPK_Pack_GetClockType_Request(void) { +ODK_Message OPK_Pack_TerminateClock_Request(void) { uint32_t api_value = 10056; /* from _tee10056 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); @@ -2107,11 +2111,39 @@ ODK_Message OPK_Pack_GetClockType_Request(void) { return msg; } +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 != 10056) + 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_GetClockType_Request(void) { + uint32_t api_value = 10057; /* from _tee10057 */ + 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_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + 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 != 10056) + if (api_value != 10057) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_OEMCrypto_Clock_Security_Level(msg, result); OPK_UnpackEOM(msg); @@ -2119,7 +2151,7 @@ void OPK_Unpack_GetClockType_Response(ODK_Message* msg, } ODK_Message OPK_Pack_GetSecurityLevel_Request(void) { - uint32_t api_value = 10057; /* from _tee10057 */ + uint32_t api_value = 10058; /* from _tee10058 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2133,7 +2165,7 @@ void OPK_Unpack_GetSecurityLevel_Response(ODK_Message* msg, OEMCrypto_Security_Level* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10057) + if (api_value != 10058) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_OEMCrypto_Security_Level(msg, result); OPK_UnpackEOM(msg); @@ -2141,7 +2173,7 @@ void OPK_Unpack_GetSecurityLevel_Response(ODK_Message* msg, } ODK_Message OPK_Pack_GetProvisioningMethod_Request(void) { - uint32_t api_value = 10058; /* from _tee10058 */ + uint32_t api_value = 10059; /* from _tee10059 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2155,7 +2187,7 @@ void OPK_Unpack_GetProvisioningMethod_Response( ODK_Message* msg, OEMCrypto_ProvisioningMethod* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10058) + if (api_value != 10059) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_OEMCrypto_ProvisioningMethod(msg, result); OPK_UnpackEOM(msg); @@ -2163,7 +2195,7 @@ void OPK_Unpack_GetProvisioningMethod_Response( } ODK_Message OPK_Pack_GetBCCType_Request(const OEMCrypto_BCCType* bcc_type) { - uint32_t api_value = 10059; /* from _tee10059 */ + uint32_t api_value = 10060; /* from _tee10060 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2178,7 +2210,7 @@ void OPK_Unpack_GetBCCType_Response(ODK_Message* msg, OEMCryptoResult* result, OEMCrypto_BCCType** bcc_type) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10059) + if (api_value != 10060) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -2197,7 +2229,7 @@ void OPK_Unpack_GetBCCType_Response(ODK_Message* msg, OEMCryptoResult* result, } ODK_Message OPK_Pack_GetResourceRatingTier_Request(void) { - uint32_t api_value = 10060; /* from _tee10060 */ + uint32_t api_value = 10061; /* from _tee10061 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2211,7 +2243,7 @@ void OPK_Unpack_GetResourceRatingTier_Response(ODK_Message* msg, uint32_t* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10060) + if (api_value != 10061) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); OPK_UnpackEOM(msg); @@ -2219,7 +2251,7 @@ void OPK_Unpack_GetResourceRatingTier_Response(ODK_Message* msg, } ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Request(void) { - uint32_t api_value = 10061; /* from _tee10061 */ + uint32_t api_value = 10062; /* from _tee10062 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2233,7 +2265,7 @@ void OPK_Unpack_IsTAAntiRollbackEnabled_Response(ODK_Message* msg, OPK_FeatureStatus* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10061) + if (api_value != 10062) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OPK_FeatureStatus(*result)) { @@ -2244,7 +2276,7 @@ void OPK_Unpack_IsTAAntiRollbackEnabled_Response(ODK_Message* msg, } ODK_Message OPK_Pack_IsProductionReady_Request(void) { - uint32_t api_value = 10062; /* from _tee10062 */ + uint32_t api_value = 10063; /* from _tee10063 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2257,7 +2289,7 @@ ODK_Message OPK_Pack_IsProductionReady_Request(void) { void OPK_Unpack_IsProductionReady_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10062) + if (api_value != 10063) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2265,7 +2297,7 @@ void OPK_Unpack_IsProductionReady_Response(ODK_Message* msg, bool* result) { } ODK_Message OPK_Pack_GetWatermarkingSupport_Request(void) { - uint32_t api_value = 10063; /* from _tee10063 */ + uint32_t api_value = 10064; /* from _tee10064 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2279,7 +2311,7 @@ void OPK_Unpack_GetWatermarkingSupport_Response( ODK_Message* msg, OEMCrypto_WatermarkingSupport* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10063) + if (api_value != 10064) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_OEMCrypto_WatermarkingSupport(msg, result); OPK_UnpackEOM(msg); @@ -2287,7 +2319,7 @@ void OPK_Unpack_GetWatermarkingSupport_Response( } ODK_Message OPK_Pack_IsAntiRollbackHWPresent_Request(void) { - uint32_t api_value = 10064; /* from _tee10064 */ + uint32_t api_value = 10065; /* from _tee10065 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2301,7 +2333,7 @@ void OPK_Unpack_IsAntiRollbackHWPresent_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10064) + if (api_value != 10065) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2309,7 +2341,7 @@ void OPK_Unpack_IsAntiRollbackHWPresent_Response(ODK_Message* msg, } ODK_Message OPK_Pack_IsCGMS_AActive_Request(void) { - uint32_t api_value = 10065; /* from _tee10065 */ + uint32_t api_value = 10066; /* from _tee10066 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2322,7 +2354,7 @@ ODK_Message OPK_Pack_IsCGMS_AActive_Request(void) { void OPK_Unpack_IsCGMS_AActive_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10065) + if (api_value != 10066) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2330,7 +2362,7 @@ void OPK_Unpack_IsCGMS_AActive_Response(ODK_Message* msg, bool* result) { } ODK_Message OPK_Pack_SupportsCGMS_A_Request(void) { - uint32_t api_value = 10066; /* from _tee10066 */ + uint32_t api_value = 10067; /* from _tee10067 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2343,7 +2375,7 @@ ODK_Message OPK_Pack_SupportsCGMS_A_Request(void) { void OPK_Unpack_SupportsCGMS_A_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10066) + if (api_value != 10067) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2351,7 +2383,7 @@ void OPK_Unpack_SupportsCGMS_A_Response(ODK_Message* msg, bool* result) { } ODK_Message OPK_Pack_HasAnalogDisplay_Request(void) { - uint32_t api_value = 10067; /* from _tee10067 */ + uint32_t api_value = 10068; /* from _tee10068 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2364,7 +2396,7 @@ ODK_Message OPK_Pack_HasAnalogDisplay_Request(void) { void OPK_Unpack_HasAnalogDisplay_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10067) + if (api_value != 10068) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2372,7 +2404,7 @@ void OPK_Unpack_HasAnalogDisplay_Response(ODK_Message* msg, bool* result) { } ODK_Message OPK_Pack_IsAnalogDisplayActive_Request(void) { - uint32_t api_value = 10068; /* from _tee10068 */ + uint32_t api_value = 10069; /* from _tee10069 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2385,7 +2417,7 @@ ODK_Message OPK_Pack_IsAnalogDisplayActive_Request(void) { void OPK_Unpack_IsAnalogDisplayActive_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10068) + if (api_value != 10069) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2393,7 +2425,7 @@ void OPK_Unpack_IsAnalogDisplayActive_Response(ODK_Message* msg, bool* result) { } ODK_Message OPK_Pack_CanDisableAnalogDisplay_Request(void) { - uint32_t api_value = 10069; /* from _tee10069 */ + uint32_t api_value = 10070; /* from _tee10070 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2407,7 +2439,7 @@ void OPK_Unpack_CanDisableAnalogDisplay_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10069) + if (api_value != 10070) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2415,7 +2447,7 @@ void OPK_Unpack_CanDisableAnalogDisplay_Response(ODK_Message* msg, } ODK_Message OPK_Pack_DisableAnalogDisplay_Request(void) { - uint32_t api_value = 10070; /* from _tee10070 */ + uint32_t api_value = 10071; /* from _tee10071 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2428,7 +2460,7 @@ ODK_Message OPK_Pack_DisableAnalogDisplay_Request(void) { void OPK_Unpack_DisableAnalogDisplay_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10070) + if (api_value != 10071) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2436,7 +2468,7 @@ void OPK_Unpack_DisableAnalogDisplay_Response(ODK_Message* msg, bool* result) { } ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Request(void) { - uint32_t api_value = 10071; /* from _tee10071 */ + uint32_t api_value = 10072; /* from _tee10072 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2450,7 +2482,7 @@ void OPK_Unpack_MaxOutputSizeForDecrypt_Response(ODK_Message* msg, size_t* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10071) + if (api_value != 10072) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_size_t(msg, result); OPK_UnpackEOM(msg); @@ -2458,7 +2490,7 @@ void OPK_Unpack_MaxOutputSizeForDecrypt_Response(ODK_Message* msg, } ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Request(void) { - uint32_t api_value = 10072; /* from _tee10072 */ + uint32_t api_value = 10073; /* from _tee10073 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2472,7 +2504,7 @@ void OPK_Unpack_MaxBufferSizeForGenericCrypto_Response(ODK_Message* msg, size_t* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10072) + if (api_value != 10073) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_size_t(msg, result); OPK_UnpackEOM(msg); @@ -2480,7 +2512,7 @@ void OPK_Unpack_MaxBufferSizeForGenericCrypto_Response(ODK_Message* msg, } ODK_Message OPK_Pack_MaxSampleSize_Request(void) { - uint32_t api_value = 10073; /* from _tee10073 */ + uint32_t api_value = 10074; /* from _tee10074 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2493,7 +2525,7 @@ ODK_Message OPK_Pack_MaxSampleSize_Request(void) { void OPK_Unpack_MaxSampleSize_Response(ODK_Message* msg, size_t* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10073) + if (api_value != 10074) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_size_t(msg, result); OPK_UnpackEOM(msg); @@ -2501,7 +2533,7 @@ void OPK_Unpack_MaxSampleSize_Response(ODK_Message* msg, size_t* result) { } ODK_Message OPK_Pack_SupportedCertificates_Request(void) { - uint32_t api_value = 10074; /* from _tee10074 */ + uint32_t api_value = 10075; /* from _tee10075 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2515,7 +2547,7 @@ void OPK_Unpack_SupportedCertificates_Response(ODK_Message* msg, uint32_t* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10074) + if (api_value != 10075) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); OPK_UnpackEOM(msg); @@ -2523,7 +2555,7 @@ void OPK_Unpack_SupportedCertificates_Response(ODK_Message* msg, } ODK_Message OPK_Pack_ContentDecryptBypassesTA_Request(void) { - uint32_t api_value = 10075; /* from _tee10075 */ + uint32_t api_value = 10076; /* from _tee10076 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2537,7 +2569,7 @@ void OPK_Unpack_ContentDecryptBypassesTA_Response(ODK_Message* msg, bool* result) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10075) + if (api_value != 10076) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_bool(msg, result); OPK_UnpackEOM(msg); @@ -2546,7 +2578,7 @@ void OPK_Unpack_ContentDecryptBypassesTA_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 = 10076; /* from _tee10076 */ + uint32_t api_value = 10077; /* from _tee10077 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2564,7 +2596,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 != 10076) + if (api_value != 10077) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -2587,7 +2619,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 = 10077; /* from _tee10077 */ + uint32_t api_value = 10078; /* from _tee10078 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2607,7 +2639,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 != 10077) + if (api_value != 10078) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -2633,7 +2665,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 = 10078; /* from _tee10078 */ + uint32_t api_value = 10079; /* from _tee10079 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2654,7 +2686,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 != 10078) + if (api_value != 10079) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -2678,7 +2710,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 = 10079; /* from _tee10079 */ + uint32_t api_value = 10080; /* from _tee10080 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -2698,7 +2730,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 != 10079) + if (api_value != 10080) 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 b0606f4..29dbb77 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 @@ -269,8 +269,8 @@ void OPK_Unpack_GetDeviceFusedStatus_Response(ODK_Message* msg, OEMCryptoResult* result, bool** is_fused); ODK_Message OPK_Pack_GetBCCSignatureType_Request(void); -void OPK_Unpack_GetBCCSignatureType_Response(ODK_Message* msg, - OPK_BCCSignatureType* result); +void OPK_Unpack_GetBCCSignatureType_Response( + ODK_Message* msg, OEMCrypto_BCCSignatureType* result); ODK_Message OPK_Pack_GenerateBCCSignature_Request(const uint8_t* out, const size_t* out_length); void OPK_Unpack_GenerateBCCSignature_Response(ODK_Message* msg, @@ -287,6 +287,10 @@ void OPK_Unpack_LoadBCCSignature_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** signature, size_t** signature_length); +ODK_Message OPK_Pack_GetMaxBCCSignatureSize_Request(const size_t* out_length); +void OPK_Unpack_GetMaxBCCSignatureSize_Response(ODK_Message* msg, + OEMCryptoResult* result, + size_t** out_length); ODK_Message OPK_Pack_CreateUDSDerivedAsymmetricKeyHandle_Request( const AsymmetricKeyType* key_type, const WTPI_AsymmetricKey_Handle* private_key_handle, 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 f51f566..9d9b22b 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c @@ -274,6 +274,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, uint8_t* input; OPK_InitPointer((uint8_t**)&input); uint8_t* signature = (uint8_t*)OPK_VarAlloc(sizeof(uint8_t)); + if (signature == NULL) goto handle_out_of_memory; OPK_Init_uint8_t((uint8_t*)signature); OPK_Unpack_C1_HMAC_SHA256_Verify_Request(request, &key_handle, &input, &input_length, &signature); @@ -311,6 +312,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_InitPointer((uint8_t**)&input); OPK_OutputBuffer* out = (OPK_OutputBuffer*)OPK_VarAlloc(sizeof(OPK_OutputBuffer)); + if (out == NULL) goto handle_out_of_memory; OPK_Init_OPK_OutputBuffer((OPK_OutputBuffer*)out); size_t output_offset; OPK_Init_size_t((size_t*)&output_offset); @@ -571,6 +573,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, case 10023: /* WTPI_K1_PrepareExternalKeyHandle */ { size_t* out_buffer_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_buffer_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_buffer_length); WTPI_K1_SymmetricKey_Handle key_handle; OPK_Init_WTPI_K1_SymmetricKey_Handle( @@ -704,6 +707,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t message_length; OPK_Init_size_t((size_t*)&message_length); size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (signature_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(signature_length); WTPI_AsymmetricKey_Handle key; OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); @@ -731,6 +735,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t input_length; OPK_Init_size_t((size_t*)&input_length); size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_length); WTPI_AsymmetricKey_Handle key; OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); @@ -753,6 +758,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t message_length; OPK_Init_size_t((size_t*)&message_length); size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (signature_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(signature_length); WTPI_AsymmetricKey_Handle key; OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); @@ -777,6 +783,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t key_source_length; OPK_Init_size_t((size_t*)&key_source_length); size_t* session_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (session_key_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(session_key_length); WTPI_AsymmetricKey_Handle key; OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); @@ -838,6 +845,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t context_length; OPK_Init_size_t((size_t*)&context_length); size_t* public_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (public_key_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(public_key_length); uint8_t* deriving_key; OPK_InitPointer((uint8_t**)&deriving_key); @@ -867,6 +875,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, case 10036: /* WTPI_GetBootCertificateChain */ { size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_length); uint8_t* out; OPK_InitPointer((uint8_t**)&out); @@ -898,8 +907,10 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, { size_t* wrapped_private_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (wrapped_private_key_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(wrapped_private_key_length); size_t* public_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (public_key_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(public_key_length); CertSignatureType cert_type; OPK_Init_CertSignatureType((CertSignatureType*)&cert_type); @@ -931,6 +942,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t encoded_device_info_length; OPK_Init_size_t((size_t*)&encoded_device_info_length); size_t* signed_csr_payload_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (signed_csr_payload_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(signed_csr_payload_length); uint8_t* challenge; OPK_InitPointer((uint8_t**)&challenge); @@ -968,6 +980,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, case 10041: /* WTPI_GetDeviceInformation */ { size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_length); uint8_t* out; OPK_InitPointer((uint8_t**)&out); @@ -986,6 +999,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, size_t message_length; OPK_Init_size_t((size_t*)&message_length); size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (signature_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(signature_length); uint8_t* message; OPK_InitPointer((uint8_t**)&message); @@ -1034,8 +1048,8 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, { OPK_Unpack_GetBCCSignatureType_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; - OPK_BCCSignatureType result; - OPK_Init_uint32_t((uint32_t*)&result); + OEMCrypto_BCCSignatureType result; + OPK_Init_OEMCrypto_BCCSignatureType((OEMCrypto_BCCSignatureType*)&result); LOGD("GetBCCSignatureType"); result = WTPI_GetBCCSignatureType(); *response = OPK_Pack_GetBCCSignatureType_Response(result); @@ -1044,6 +1058,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, case 10046: /* WTPI_GenerateBCCSignature */ { size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_length); uint8_t* out; OPK_InitPointer((uint8_t**)&out); @@ -1076,6 +1091,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, case 10048: /* WTPI_LoadBCCSignature */ { size_t* signature_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (signature_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(signature_length); uint8_t* signature; OPK_InitPointer((uint8_t**)&signature); @@ -1090,9 +1106,23 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, signature_length); break; } - case 10049: /* WTPI_CreateUDSDerivedAsymmetricKeyHandle */ + case 10049: /* WTPI_GetMaxBCCSignatureSize */ + { + size_t* out_length; + OPK_InitPointer((uint8_t**)&out_length); + OPK_Unpack_GetMaxBCCSignatureSize_Request(request, &out_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetMaxBCCSignatureSize"); + result = WTPI_GetMaxBCCSignatureSize(out_length); + *response = OPK_Pack_GetMaxBCCSignatureSize_Response(result, out_length); + break; + } + case 10050: /* WTPI_CreateUDSDerivedAsymmetricKeyHandle */ { size_t* public_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (public_key_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(public_key_length); AsymmetricKeyType* key_type; OPK_InitPointer((uint8_t**)&key_type); @@ -1113,7 +1143,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, result, key_type, private_key_handle, public_key, public_key_length); break; } - case 10050: /* WTPI_Crc32Init */ + case 10051: /* WTPI_Crc32Init */ { uint32_t* initial_hash; OPK_InitPointer((uint8_t**)&initial_hash); @@ -1126,7 +1156,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Init_Response(result, initial_hash); break; } - case 10051: /* WTPI_Crc32Cont */ + case 10052: /* WTPI_Crc32Cont */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -1146,7 +1176,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_Response(result, new_crc); break; } - case 10052: /* WTPI_Crc32Cont_OutputBuffer */ + case 10053: /* WTPI_Crc32Cont_OutputBuffer */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -1169,7 +1199,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_OutputBuffer_Response(result, new_crc); break; } - case 10053: /* WTPI_GetTrustedTime */ + case 10054: /* WTPI_GetTrustedTime */ { uint64_t* time_in_s; OPK_InitPointer((uint8_t**)&time_in_s); @@ -1182,7 +1212,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetTrustedTime_Response(result, time_in_s); break; } - case 10054: /* WTPI_InitializeClock */ + case 10055: /* WTPI_InitializeClock */ { OPK_Unpack_InitializeClock_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1193,7 +1223,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_InitializeClock_Response(result); break; } - case 10055: /* WTPI_TerminateClock */ + case 10056: /* WTPI_TerminateClock */ { OPK_Unpack_TerminateClock_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1204,7 +1234,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_TerminateClock_Response(result); break; } - case 10056: /* WTPI_GetClockType */ + case 10057: /* WTPI_GetClockType */ { OPK_Unpack_GetClockType_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1216,7 +1246,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetClockType_Response(result); break; } - case 10057: /* WTPI_GetSecurityLevel */ + case 10058: /* WTPI_GetSecurityLevel */ { OPK_Unpack_GetSecurityLevel_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1227,7 +1257,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetSecurityLevel_Response(result); break; } - case 10058: /* WTPI_GetProvisioningMethod */ + case 10059: /* WTPI_GetProvisioningMethod */ { OPK_Unpack_GetProvisioningMethod_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1239,7 +1269,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetProvisioningMethod_Response(result); break; } - case 10059: /* WTPI_GetBCCType */ + case 10060: /* WTPI_GetBCCType */ { OEMCrypto_BCCType* bcc_type; OPK_InitPointer((uint8_t**)&bcc_type); @@ -1252,7 +1282,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetBCCType_Response(result, bcc_type); break; } - case 10060: /* WTPI_GetResourceRatingTier */ + case 10061: /* WTPI_GetResourceRatingTier */ { OPK_Unpack_GetResourceRatingTier_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1263,7 +1293,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetResourceRatingTier_Response(result); break; } - case 10061: /* WTPI_IsTAAntiRollbackEnabled */ + case 10062: /* WTPI_IsTAAntiRollbackEnabled */ { OPK_Unpack_IsTAAntiRollbackEnabled_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1274,7 +1304,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_IsTAAntiRollbackEnabled_Response(result); break; } - case 10062: /* WTPI_IsProductionReady */ + case 10063: /* WTPI_IsProductionReady */ { OPK_Unpack_IsProductionReady_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1285,7 +1315,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_IsProductionReady_Response(result); break; } - case 10063: /* WTPI_GetWatermarkingSupport */ + case 10064: /* WTPI_GetWatermarkingSupport */ { OPK_Unpack_GetWatermarkingSupport_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1297,7 +1327,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetWatermarkingSupport_Response(result); break; } - case 10064: /* WTPI_IsAntiRollbackHWPresent */ + case 10065: /* WTPI_IsAntiRollbackHWPresent */ { OPK_Unpack_IsAntiRollbackHWPresent_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1308,7 +1338,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_IsAntiRollbackHWPresent_Response(result); break; } - case 10065: /* WTPI_IsCGMS_AActive */ + case 10066: /* WTPI_IsCGMS_AActive */ { OPK_Unpack_IsCGMS_AActive_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1319,7 +1349,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_IsCGMS_AActive_Response(result); break; } - case 10066: /* WTPI_SupportsCGMS_A */ + case 10067: /* WTPI_SupportsCGMS_A */ { OPK_Unpack_SupportsCGMS_A_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1330,7 +1360,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_SupportsCGMS_A_Response(result); break; } - case 10067: /* WTPI_HasAnalogDisplay */ + case 10068: /* WTPI_HasAnalogDisplay */ { OPK_Unpack_HasAnalogDisplay_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1341,7 +1371,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_HasAnalogDisplay_Response(result); break; } - case 10068: /* WTPI_IsAnalogDisplayActive */ + case 10069: /* WTPI_IsAnalogDisplayActive */ { OPK_Unpack_IsAnalogDisplayActive_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1352,7 +1382,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_IsAnalogDisplayActive_Response(result); break; } - case 10069: /* WTPI_CanDisableAnalogDisplay */ + case 10070: /* WTPI_CanDisableAnalogDisplay */ { OPK_Unpack_CanDisableAnalogDisplay_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1363,7 +1393,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_CanDisableAnalogDisplay_Response(result); break; } - case 10070: /* WTPI_DisableAnalogDisplay */ + case 10071: /* WTPI_DisableAnalogDisplay */ { OPK_Unpack_DisableAnalogDisplay_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1374,7 +1404,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_DisableAnalogDisplay_Response(result); break; } - case 10071: /* WTPI_MaxOutputSizeForDecrypt */ + case 10072: /* WTPI_MaxOutputSizeForDecrypt */ { OPK_Unpack_MaxOutputSizeForDecrypt_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1385,7 +1415,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_MaxOutputSizeForDecrypt_Response(result); break; } - case 10072: /* WTPI_MaxBufferSizeForGenericCrypto */ + case 10073: /* WTPI_MaxBufferSizeForGenericCrypto */ { OPK_Unpack_MaxBufferSizeForGenericCrypto_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1396,7 +1426,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_MaxBufferSizeForGenericCrypto_Response(result); break; } - case 10073: /* WTPI_MaxSampleSize */ + case 10074: /* WTPI_MaxSampleSize */ { OPK_Unpack_MaxSampleSize_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1407,7 +1437,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_MaxSampleSize_Response(result); break; } - case 10074: /* WTPI_SupportedCertificates */ + case 10075: /* WTPI_SupportedCertificates */ { OPK_Unpack_SupportedCertificates_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1418,7 +1448,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_SupportedCertificates_Response(result); break; } - case 10075: /* WTPI_ContentDecryptBypassesTA */ + case 10076: /* WTPI_ContentDecryptBypassesTA */ { OPK_Unpack_ContentDecryptBypassesTA_Request(request); if (!ODK_Message_IsValid(request)) goto handle_invalid_request; @@ -1429,7 +1459,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_ContentDecryptBypassesTA_Response(result); break; } - case 10076: /* WTPI_GetEncryptAndSignSize */ + case 10077: /* WTPI_GetEncryptAndSignSize */ { uint32_t context; OPK_Init_uint32_t((uint32_t*)&context); @@ -1448,11 +1478,12 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetEncryptAndSignSize_Response(result, wrapped_length); break; } - case 10077: /* WTPI_EncryptAndSign */ + case 10078: /* WTPI_EncryptAndSign */ { size_t data_length; OPK_Init_size_t((size_t*)&data_length); size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_length); uint32_t context; OPK_Init_uint32_t((uint32_t*)&context); @@ -1470,11 +1501,12 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_EncryptAndSign_Response(result, out, out_length); break; } - case 10078: /* WTPI_VerifyAndDecrypt */ + case 10079: /* WTPI_VerifyAndDecrypt */ { size_t wrapped_length; OPK_Init_size_t((size_t*)&wrapped_length); size_t* out_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); + if (out_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(out_length); uint32_t context; OPK_Init_uint32_t((uint32_t*)&context); @@ -1493,13 +1525,14 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_VerifyAndDecrypt_Response(result, out, out_length); break; } - case 10079: /* WTPI_VerifyAndDecryptUsageData_Legacy */ + case 10080: /* WTPI_VerifyAndDecryptUsageData_Legacy */ { size_t wrapped_length; OPK_Init_size_t((size_t*)&wrapped_length); uint8_t* wrapped; OPK_InitPointer((uint8_t**)&wrapped); uint8_t* signature = (uint8_t*)OPK_VarAlloc(sizeof(uint8_t)); + if (signature == NULL) goto handle_out_of_memory; OPK_Init_uint8_t((uint8_t*)signature); uint8_t* iv; OPK_InitPointer((uint8_t**)&iv); @@ -1526,4 +1559,10 @@ handle_invalid_request: LOGE("invalid request"); *response = CreateEmptyMessage(); return MESSAGE_STATUS_OK; + +handle_out_of_memory: + LOGE("out of memory"); + ODK_Message_SetStatus(request, MESSAGE_STATUS_OUT_OF_MEMORY); + *response = CreateEmptyMessage(); + return MESSAGE_STATUS_OK; } 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 233e677..c3045c2 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 @@ -1321,11 +1321,12 @@ void OPK_Unpack_GetBCCSignatureType_Request(ODK_Message* msg) { OPK_SharedBuffer_FinalizeUnpacking(); } -ODK_Message OPK_Pack_GetBCCSignatureType_Response(OPK_BCCSignatureType result) { +ODK_Message OPK_Pack_GetBCCSignatureType_Response( + OEMCrypto_BCCSignatureType result) { uint32_t api_value = 10045; /* from _tee10045 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); - OPK_Pack_uint32_t(&msg, &result); + OPK_Pack_OEMCrypto_BCCSignatureType(&msg, &result); OPK_PackEOM(&msg); OPK_SharedBuffer_FinalizePacking(); return msg; @@ -1419,13 +1420,38 @@ ODK_Message OPK_Pack_LoadBCCSignature_Response(OEMCryptoResult result, return msg; } +void OPK_Unpack_GetMaxBCCSignatureSize_Request(ODK_Message* msg, + size_t** out_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10049) + 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_GetMaxBCCSignatureSize_Response(OEMCryptoResult result, + const size_t* out_length) { + uint32_t api_value = 10049; /* from _tee10049 */ + 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_CreateUDSDerivedAsymmetricKeyHandle_Request( ODK_Message* msg, AsymmetricKeyType** key_type, WTPI_AsymmetricKey_Handle** private_key_handle, 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 != 10049) + if (api_value != 10050) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1444,7 +1470,7 @@ ODK_Message OPK_Pack_CreateUDSDerivedAsymmetricKeyHandle_Response( OEMCryptoResult result, const AsymmetricKeyType* key_type, const WTPI_AsymmetricKey_Handle* private_key_handle, const uint8_t* public_key, const size_t* public_key_length) { - uint32_t api_value = 10049; /* from _tee10049 */ + uint32_t api_value = 10050; /* from _tee10050 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, public_key_length); @@ -1463,7 +1489,7 @@ ODK_Message OPK_Pack_CreateUDSDerivedAsymmetricKeyHandle_Response( 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 != 10050) + if (api_value != 10051) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1474,7 +1500,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 = 10050; /* from _tee10050 */ + uint32_t api_value = 10051; /* from _tee10051 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1489,7 +1515,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 != 10051) + if (api_value != 10052) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1503,7 +1529,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 = 10051; /* from _tee10051 */ + uint32_t api_value = 10052; /* from _tee10052 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1518,7 +1544,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 != 10052) + if (api_value != 10053) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1559,7 +1585,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 = 10052; /* from _tee10052 */ + uint32_t api_value = 10053; /* from _tee10053 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1572,7 +1598,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 != 10053) + if (api_value != 10054) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1583,7 +1609,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 = 10053; /* from _tee10053 */ + uint32_t api_value = 10054; /* from _tee10054 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1596,7 +1622,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 != 10054) + if (api_value != 10055) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1605,7 +1631,7 @@ void OPK_Unpack_InitializeClock_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result) { - uint32_t api_value = 10054; /* from _tee10054 */ + uint32_t api_value = 10055; /* from _tee10055 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1617,7 +1643,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 != 10055) + if (api_value != 10056) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1626,7 +1652,7 @@ void OPK_Unpack_TerminateClock_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result) { - uint32_t api_value = 10055; /* from _tee10055 */ + uint32_t api_value = 10056; /* from _tee10056 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1638,7 +1664,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 != 10056) + if (api_value != 10057) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1648,7 +1674,7 @@ void OPK_Unpack_GetClockType_Request(ODK_Message* msg) { ODK_Message OPK_Pack_GetClockType_Response( OEMCrypto_Clock_Security_Level result) { - uint32_t api_value = 10056; /* from _tee10056 */ + uint32_t api_value = 10057; /* from _tee10057 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_OEMCrypto_Clock_Security_Level(&msg, &result); @@ -1660,7 +1686,7 @@ ODK_Message OPK_Pack_GetClockType_Response( void OPK_Unpack_GetSecurityLevel_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10057) + if (api_value != 10058) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1670,7 +1696,7 @@ void OPK_Unpack_GetSecurityLevel_Request(ODK_Message* msg) { ODK_Message OPK_Pack_GetSecurityLevel_Response( OEMCrypto_Security_Level result) { - uint32_t api_value = 10057; /* from _tee10057 */ + uint32_t api_value = 10058; /* from _tee10058 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_OEMCrypto_Security_Level(&msg, &result); @@ -1682,7 +1708,7 @@ ODK_Message OPK_Pack_GetSecurityLevel_Response( void OPK_Unpack_GetProvisioningMethod_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10058) + if (api_value != 10059) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1692,7 +1718,7 @@ void OPK_Unpack_GetProvisioningMethod_Request(ODK_Message* msg) { ODK_Message OPK_Pack_GetProvisioningMethod_Response( OEMCrypto_ProvisioningMethod result) { - uint32_t api_value = 10058; /* from _tee10058 */ + uint32_t api_value = 10059; /* from _tee10059 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_OEMCrypto_ProvisioningMethod(&msg, &result); @@ -1705,7 +1731,7 @@ void OPK_Unpack_GetBCCType_Request(ODK_Message* msg, OEMCrypto_BCCType** bcc_type) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10059) + if (api_value != 10060) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1717,7 +1743,7 @@ void OPK_Unpack_GetBCCType_Request(ODK_Message* msg, ODK_Message OPK_Pack_GetBCCType_Response(OEMCryptoResult result, const OEMCrypto_BCCType* bcc_type) { - uint32_t api_value = 10059; /* from _tee10059 */ + uint32_t api_value = 10060; /* from _tee10060 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1730,7 +1756,7 @@ ODK_Message OPK_Pack_GetBCCType_Response(OEMCryptoResult result, void OPK_Unpack_GetResourceRatingTier_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10060) + if (api_value != 10061) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1739,7 +1765,7 @@ void OPK_Unpack_GetResourceRatingTier_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_GetResourceRatingTier_Response(uint32_t result) { - uint32_t api_value = 10060; /* from _tee10060 */ + uint32_t api_value = 10061; /* from _tee10061 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1751,7 +1777,7 @@ ODK_Message OPK_Pack_GetResourceRatingTier_Response(uint32_t result) { void OPK_Unpack_IsTAAntiRollbackEnabled_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10061) + if (api_value != 10062) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1761,7 +1787,7 @@ void OPK_Unpack_IsTAAntiRollbackEnabled_Request(ODK_Message* msg) { ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Response( OPK_FeatureStatus result) { - uint32_t api_value = 10061; /* from _tee10061 */ + uint32_t api_value = 10062; /* from _tee10062 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -1773,7 +1799,7 @@ ODK_Message OPK_Pack_IsTAAntiRollbackEnabled_Response( void OPK_Unpack_IsProductionReady_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10062) + if (api_value != 10063) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1782,7 +1808,7 @@ void OPK_Unpack_IsProductionReady_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_IsProductionReady_Response(bool result) { - uint32_t api_value = 10062; /* from _tee10062 */ + uint32_t api_value = 10063; /* from _tee10063 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1794,7 +1820,7 @@ ODK_Message OPK_Pack_IsProductionReady_Response(bool result) { void OPK_Unpack_GetWatermarkingSupport_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10063) + if (api_value != 10064) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1804,7 +1830,7 @@ void OPK_Unpack_GetWatermarkingSupport_Request(ODK_Message* msg) { ODK_Message OPK_Pack_GetWatermarkingSupport_Response( OEMCrypto_WatermarkingSupport result) { - uint32_t api_value = 10063; /* from _tee10063 */ + uint32_t api_value = 10064; /* from _tee10064 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_OEMCrypto_WatermarkingSupport(&msg, &result); @@ -1816,7 +1842,7 @@ ODK_Message OPK_Pack_GetWatermarkingSupport_Response( void OPK_Unpack_IsAntiRollbackHWPresent_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10064) + if (api_value != 10065) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1825,7 +1851,7 @@ void OPK_Unpack_IsAntiRollbackHWPresent_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_IsAntiRollbackHWPresent_Response(bool result) { - uint32_t api_value = 10064; /* from _tee10064 */ + uint32_t api_value = 10065; /* from _tee10065 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1837,7 +1863,7 @@ ODK_Message OPK_Pack_IsAntiRollbackHWPresent_Response(bool result) { void OPK_Unpack_IsCGMS_AActive_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10065) + if (api_value != 10066) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1846,7 +1872,7 @@ void OPK_Unpack_IsCGMS_AActive_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_IsCGMS_AActive_Response(bool result) { - uint32_t api_value = 10065; /* from _tee10065 */ + uint32_t api_value = 10066; /* from _tee10066 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1858,7 +1884,7 @@ ODK_Message OPK_Pack_IsCGMS_AActive_Response(bool result) { void OPK_Unpack_SupportsCGMS_A_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10066) + if (api_value != 10067) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1867,7 +1893,7 @@ void OPK_Unpack_SupportsCGMS_A_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_SupportsCGMS_A_Response(bool result) { - uint32_t api_value = 10066; /* from _tee10066 */ + uint32_t api_value = 10067; /* from _tee10067 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1879,7 +1905,7 @@ ODK_Message OPK_Pack_SupportsCGMS_A_Response(bool result) { void OPK_Unpack_HasAnalogDisplay_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10067) + if (api_value != 10068) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1888,7 +1914,7 @@ void OPK_Unpack_HasAnalogDisplay_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_HasAnalogDisplay_Response(bool result) { - uint32_t api_value = 10067; /* from _tee10067 */ + uint32_t api_value = 10068; /* from _tee10068 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1900,7 +1926,7 @@ ODK_Message OPK_Pack_HasAnalogDisplay_Response(bool result) { void OPK_Unpack_IsAnalogDisplayActive_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10068) + if (api_value != 10069) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1909,7 +1935,7 @@ void OPK_Unpack_IsAnalogDisplayActive_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_IsAnalogDisplayActive_Response(bool result) { - uint32_t api_value = 10068; /* from _tee10068 */ + uint32_t api_value = 10069; /* from _tee10069 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1921,7 +1947,7 @@ ODK_Message OPK_Pack_IsAnalogDisplayActive_Response(bool result) { void OPK_Unpack_CanDisableAnalogDisplay_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10069) + if (api_value != 10070) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1930,7 +1956,7 @@ void OPK_Unpack_CanDisableAnalogDisplay_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_CanDisableAnalogDisplay_Response(bool result) { - uint32_t api_value = 10069; /* from _tee10069 */ + uint32_t api_value = 10070; /* from _tee10070 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1942,7 +1968,7 @@ ODK_Message OPK_Pack_CanDisableAnalogDisplay_Response(bool result) { void OPK_Unpack_DisableAnalogDisplay_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10070) + if (api_value != 10071) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1951,7 +1977,7 @@ void OPK_Unpack_DisableAnalogDisplay_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_DisableAnalogDisplay_Response(bool result) { - uint32_t api_value = 10070; /* from _tee10070 */ + uint32_t api_value = 10071; /* from _tee10071 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -1963,7 +1989,7 @@ ODK_Message OPK_Pack_DisableAnalogDisplay_Response(bool result) { void OPK_Unpack_MaxOutputSizeForDecrypt_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10071) + if (api_value != 10072) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1972,7 +1998,7 @@ void OPK_Unpack_MaxOutputSizeForDecrypt_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Response(size_t result) { - uint32_t api_value = 10071; /* from _tee10071 */ + uint32_t api_value = 10072; /* from _tee10072 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_size_t(&msg, &result); @@ -1984,7 +2010,7 @@ ODK_Message OPK_Pack_MaxOutputSizeForDecrypt_Response(size_t result) { void OPK_Unpack_MaxBufferSizeForGenericCrypto_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10072) + if (api_value != 10073) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -1993,7 +2019,7 @@ void OPK_Unpack_MaxBufferSizeForGenericCrypto_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Response(size_t result) { - uint32_t api_value = 10072; /* from _tee10072 */ + uint32_t api_value = 10073; /* from _tee10073 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_size_t(&msg, &result); @@ -2005,7 +2031,7 @@ ODK_Message OPK_Pack_MaxBufferSizeForGenericCrypto_Response(size_t result) { void OPK_Unpack_MaxSampleSize_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10073) + if (api_value != 10074) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2014,7 +2040,7 @@ void OPK_Unpack_MaxSampleSize_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_MaxSampleSize_Response(size_t result) { - uint32_t api_value = 10073; /* from _tee10073 */ + uint32_t api_value = 10074; /* from _tee10074 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_size_t(&msg, &result); @@ -2026,7 +2052,7 @@ ODK_Message OPK_Pack_MaxSampleSize_Response(size_t result) { void OPK_Unpack_SupportedCertificates_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10074) + if (api_value != 10075) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2035,7 +2061,7 @@ void OPK_Unpack_SupportedCertificates_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_SupportedCertificates_Response(uint32_t result) { - uint32_t api_value = 10074; /* from _tee10074 */ + uint32_t api_value = 10075; /* from _tee10075 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -2047,7 +2073,7 @@ ODK_Message OPK_Pack_SupportedCertificates_Response(uint32_t result) { void OPK_Unpack_ContentDecryptBypassesTA_Request(ODK_Message* msg) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10075) + if (api_value != 10076) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2056,7 +2082,7 @@ void OPK_Unpack_ContentDecryptBypassesTA_Request(ODK_Message* msg) { } ODK_Message OPK_Pack_ContentDecryptBypassesTA_Response(bool result) { - uint32_t api_value = 10075; /* from _tee10075 */ + uint32_t api_value = 10076; /* from _tee10076 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_bool(&msg, &result); @@ -2071,7 +2097,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 != 10076) + if (api_value != 10077) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2084,7 +2110,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 = 10076; /* from _tee10076 */ + uint32_t api_value = 10077; /* from _tee10077 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -2099,7 +2125,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 != 10077) + if (api_value != 10078) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2116,7 +2142,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 = 10077; /* from _tee10077 */ + uint32_t api_value = 10078; /* from _tee10078 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -2135,7 +2161,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 != 10078) + if (api_value != 10079) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2152,7 +2178,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 = 10078; /* from _tee10078 */ + uint32_t api_value = 10079; /* from _tee10079 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -2170,7 +2196,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 != 10079) + if (api_value != 10080) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -2185,7 +2211,7 @@ void OPK_Unpack_VerifyAndDecryptUsageData_Legacy_Request( ODK_Message OPK_Pack_VerifyAndDecryptUsageData_Legacy_Response( OEMCryptoResult result, const uint8_t* out) { - uint32_t api_value = 10079; /* from _tee10079 */ + uint32_t api_value = 10080; /* from _tee10080 */ 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 8df5622..089e4b9 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 @@ -249,7 +249,8 @@ void OPK_Unpack_GetDeviceFusedStatus_Request(ODK_Message* msg, bool** is_fused); ODK_Message OPK_Pack_GetDeviceFusedStatus_Response(OEMCryptoResult result, const bool* is_fused); void OPK_Unpack_GetBCCSignatureType_Request(ODK_Message* msg); -ODK_Message OPK_Pack_GetBCCSignatureType_Response(OPK_BCCSignatureType result); +ODK_Message OPK_Pack_GetBCCSignatureType_Response( + OEMCrypto_BCCSignatureType result); void OPK_Unpack_GenerateBCCSignature_Request(ODK_Message* msg, uint8_t** out, size_t** out_length); ODK_Message OPK_Pack_GenerateBCCSignature_Response(OEMCryptoResult result, @@ -263,6 +264,10 @@ void OPK_Unpack_LoadBCCSignature_Request(ODK_Message* msg, uint8_t** signature, ODK_Message OPK_Pack_LoadBCCSignature_Response(OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length); +void OPK_Unpack_GetMaxBCCSignatureSize_Request(ODK_Message* msg, + size_t** out_length); +ODK_Message OPK_Pack_GetMaxBCCSignatureSize_Response(OEMCryptoResult result, + const size_t* out_length); void OPK_Unpack_CreateUDSDerivedAsymmetricKeyHandle_Request( ODK_Message* msg, AsymmetricKeyType** key_type, WTPI_AsymmetricKey_Handle** private_key_handle, uint8_t** public_key, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c index 07ff32e..71fe99e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c @@ -107,6 +107,12 @@ void OPK_Init_CertSignatureType(CertSignatureType* obj) { } } +void OPK_Init_OEMCrypto_BCCSignatureType(OEMCrypto_BCCSignatureType* obj) { + if (obj) { + memset(obj, 0, sizeof(OEMCrypto_BCCSignatureType)); + } +} + void OPK_Unpack_WTPI_K1_SymmetricKey_Handle(ODK_Message* message, WTPI_K1_SymmetricKey_Handle* value); void OPK_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h index 587b81e..23435de 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h @@ -26,6 +26,7 @@ void OPK_Init_OEMCrypto_ProvisioningMethod(OEMCrypto_ProvisioningMethod* obj); void OPK_Init_OEMCrypto_WatermarkingSupport(OEMCrypto_WatermarkingSupport* obj); void OPK_Init_OEMCrypto_HDCP_Capability(OEMCrypto_HDCP_Capability* obj); void OPK_Init_CertSignatureType(CertSignatureType* obj); +void OPK_Init_OEMCrypto_BCCSignatureType(OEMCrypto_BCCSignatureType* obj); void OPK_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_bcc_signature_keybox.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_bcc_signature_keybox.c index da3f979..bd30d84 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_bcc_signature_keybox.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_bcc_signature_keybox.c @@ -17,17 +17,18 @@ #include "wtpi_root_of_trust_interface_layer1.h" #ifndef OPK_CONFIG_BCC_SIGNATURE_TYPE -# define OPK_CONFIG_BCC_SIGNATURE_TYPE BCC_SIG_KEYBOX +# define OPK_CONFIG_BCC_SIGNATURE_TYPE OEMCrypto_BCCSigType_Keybox #endif -OPK_BCCSignatureType WTPI_GetBCCSignatureType(void) { +OEMCrypto_BCCSignatureType WTPI_GetBCCSignatureType(void) { if (WTPI_GetProvisioningMethod() != OEMCrypto_BootCertificateChain) { - return BCC_SIG_NONE; + return OEMCrypto_BCCSigType_Unknown; } - if (OPK_CONFIG_BCC_SIGNATURE_TYPE != BCC_SIG_KEYBOX) { - return BCC_SIG_NONE; + if (OPK_CONFIG_BCC_SIGNATURE_TYPE != OEMCrypto_BCCSigType_Keybox) { + return OEMCrypto_BCCSigType_Unknown; } - if (WTPI_ValidateKeybox() != OEMCrypto_SUCCESS) return BCC_SIG_NONE; + if (WTPI_ValidateKeybox() != OEMCrypto_SUCCESS) + return OEMCrypto_BCCSigType_Unknown; return OPK_CONFIG_BCC_SIGNATURE_TYPE; } diff --git a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp index 2e83f4f..417d082 100644 --- a/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp +++ b/oemcrypto/opk/ports/linux/ta/common/wtpi_impl/wtpi_test_impl.gyp @@ -56,7 +56,7 @@ }], ['prov4_bcc_signature_type=="keybox"', { 'defines': [ - 'OPK_CONFIG_BCC_SIGNATURE_TYPE=BCC_SIG_KEYBOX', + 'OPK_CONFIG_BCC_SIGNATURE_TYPE=OEMCrypto_BCCSigType_Keybox', ], 'sources': [ '<(wtpi_stub_dir)/wtpi_bcc_signature_keybox.c', diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c index 14efa14..0798a65 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_provisioning_4.c @@ -15,6 +15,7 @@ #define BCC_PAYLOAD_MAX_SIZE 2048 #define COSE_SIGN1_MAX_SIZE 2048 +#define BCC_SIGNATURE_MAX_SIZE 4096 // Generate device-unique asymmetric key handle that is consistent across // reboots. ECDSA @@ -204,7 +205,7 @@ OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { OEMCryptoResult WTPI_GetMaxBootCertificateChainSize(size_t* out_length) { RETURN_INVALID_CONTEXT_IF_NULL(out_length); - *out_length = BCC_PAYLOAD_MAX_SIZE; + *out_length = BCC_SIGNATURE_MAX_SIZE; return OEMCrypto_SUCCESS; } @@ -218,7 +219,9 @@ OEMCryptoResult CoseSignOp(WTPI_AsymmetricKey_Handle key, false); } -OPK_BCCSignatureType WTPI_GetBCCSignatureType(void) { return BCC_SIG_NONE; } +OEMCrypto_BCCSignatureType WTPI_GetBCCSignatureType(void) { + return OEMCrypto_BCCSigType_Unknown; +} OEMCryptoResult WTPI_GenerateBCCSignature(uint8_t* out UNUSED, size_t* out_length UNUSED) { @@ -235,6 +238,12 @@ OEMCryptoResult WTPI_LoadBCCSignature(uint8_t* signature UNUSED, return OEMCrypto_ERROR_NOT_IMPLEMENTED; } +OEMCryptoResult WTPI_GetMaxBCCSignatureSize(size_t* out_length) { + RETURN_INVALID_CONTEXT_IF_NULL(out_length); + *out_length = BCC_PAYLOAD_MAX_SIZE; + return OEMCrypto_SUCCESS; +} + OEMCryptoResult WTPI_CreateUDSDerivedAsymmetricKeyHandle( AsymmetricKeyType* key_type, WTPI_AsymmetricKey_Handle* private_key_handle, uint8_t* public_key, size_t* public_key_length) { diff --git a/oemcrypto/opk/ports/trusty/ta/README.md b/oemcrypto/opk/ports/trusty/ta/README.md index 729ed76..68f6672 100644 --- a/oemcrypto/opk/ports/trusty/ta/README.md +++ b/oemcrypto/opk/ports/trusty/ta/README.md @@ -40,7 +40,7 @@ repo sync -c -j32 # Download an Android NDK prebuilt to compile liboemcrypto.so cd $TRUSTY_DIR/prebuilts mkdir ndk && cd ndk -git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r25 +git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r26 # Add the OEMCrypto TA path as a user module. The OEMCRYPTO_TA_DIR must expand # to a path that is relative to the Trusty directory diff --git a/oemcrypto/opk/ports/trusty/ta/reference/include/system_specific.h b/oemcrypto/opk/ports/trusty/ta/reference/include/system_specific.h index d45f235..cdd2c92 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/include/system_specific.h +++ b/oemcrypto/opk/ports/trusty/ta/reference/include/system_specific.h @@ -16,6 +16,8 @@ #pragma once +#include + /* * Does this IPC buffer have the security properties we expect? * The exact details are system-specific, but in general this function should @@ -37,3 +39,20 @@ int system_specific_validate_ipc_buffer(int handle); * Returns 0 on success, and a negative number on failiure. */ int system_specific_validate_secure_output_buffer(int handle); + +/* + * What is the current level of HDCP authentication? + * This exact details are system-specific, but in general this function should + * return the currently negotiated HDCP level by the output control. + */ +int system_specific_get_current_hdcp_level( + OEMCrypto_HDCP_Capability* cur_level); + +/* + * What is the max level of HDCP authentication? + * This exact details are system-specific, but in general this function should + * return the maximum HDCP level supported by the output control. + */ +int system_specific_get_max_hdcp_level(OEMCrypto_HDCP_Capability* max_level); + +int system_specific_set_hdcp_level(OEMCrypto_HDCP_Capability request_level); diff --git a/oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h b/oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h index 0ee246d..6dc4d34 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h +++ b/oemcrypto/opk/ports/trusty/ta/reference/include/tee_context.h @@ -24,4 +24,4 @@ typedef struct tee_context { storage_session_t new_provisioning_session; } tee_context; -tee_context* get_tee_context(); +tee_context* get_tee_context(void); diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/opk_config.h b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/opk_config.h new file mode 100644 index 0000000..5ea9181 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/opk_config.h @@ -0,0 +1,56 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _OPK_CONFIG_H_ +#define _OPK_CONFIG_H_ + +#ifndef OPK_CONFIG_SECURITY_LEVEL +#define OPK_CONFIG_SECURITY_LEVEL OEMCrypto_Level1 +#endif + +#ifndef OPK_CONFIG_RESOURCE_RATING_TIER +#define OPK_CONFIG_RESOURCE_RATING_TIER 3 +#endif + +#ifndef OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT +#define OPK_CONFIG_MAX_BUFFER_SIZE_FOR_DECRYPT 0 +#endif + +#ifndef OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO +/* 500 KiB according to resource rating tier. */ +#define OPK_CONFIG_MAX_BUFFER_SIZE_FOR_GENERIC_CRYPTO 500 * 1024 +#endif + +#ifndef OPK_CONFIG_MAX_SAMPLE_SIZE +/* 16 MiB according to resource rating tier. */ +#define OPK_CONFIG_MAX_SAMPLE_SIZE 16 * 1024 * 1024 +#endif + +#ifndef OPK_CONFIG_SUPPORTED_CERTIFICATES +#define OPK_CONFIG_SUPPORTED_CERTIFICATES \ + (OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit) +#endif + +#if WIDEVINE_PROVISION_METHOD == 2 +#define OPK_CONFIG_PROVISIONING_METHOD OEMCrypto_Keybox +#elif WIDEVINE_PROVISION_METHOD == 4 +#define OPK_CONFIG_PROVISIONING_METHOD OEMCrypto_BootCertificateChain +#endif + +// Use defaults from wtpi_reference for the rest +#include "config/default.h" + +#endif diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_persistent_storage_layer1.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_persistent_storage_layer1.c index f6af4dc..e079a78 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_persistent_storage_layer1.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_persistent_storage_layer1.c @@ -20,6 +20,7 @@ #include +#include #include #include "tee_context.h" @@ -47,6 +48,9 @@ OEMCryptoResult WTPI_LoadPersistentData(uint8_t* data, size_t* data_length) { int rc = storage_open_file(ctx->user_data_session, &handle, kPersistPath, 0, 0); if (rc < 0) { + if (rc == ERR_NOT_FOUND) { + return OPK_ERROR_NO_PERSISTENT_DATA; + } return OEMCrypto_ERROR_OPEN_FAILURE; } @@ -77,7 +81,7 @@ OEMCryptoResult WTPI_LoadPersistentData(uint8_t* data, size_t* data_length) { OEMCryptoResult WTPI_StorePersistentData(const uint8_t* data, size_t data_length) { - TLOGD("WTPI_SaveGenerationNumber\n"); + TLOGD("WTPI_StorePersistentData\n"); tee_context* ctx = get_tee_context(); assert(ctx->user_data_session != STORAGE_INVALID_SESSION); diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_provisioning_4.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_provisioning_4.c index 1bfa620..c98cec8 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_provisioning_4.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_provisioning_4.c @@ -32,12 +32,14 @@ #include "cose_util.h" #include "ecc_util.h" #include "oemcrypto_check_macros.h" +#include "oemcrypto_key_types.h" #include "wtpi_crypto_asymmetric_interface.h" #include "wtpi_device_key_interface.h" #include "wtpi_logging_interface.h" #include "wtpi_memory_interface.h" #define MAX_DEVICE_INFO_SIZE 768 +#define MAX_BCC_SIGNATURE_SIZE 4096 OEMCryptoResult WTPI_GetBootCertificateChain(uint8_t* out, size_t* out_length) { if (out_length == NULL) { @@ -128,7 +130,8 @@ OEMCryptoResult WTPI_GenerateRandomCertificateKeyPair( } else if (cert_type == CERT_SIGNATURE_OEM) { context = DEVICE_KEY_WRAP_OEM_CERT; } else { - return OEMCrypto_ERROR_INVALID_CONTEXT; + result = OEMCrypto_ERROR_INVALID_CONTEXT; + goto cleanup; } *wrapped_private_key_length = actual_wrapped_private_key_length; @@ -322,3 +325,35 @@ OEMCryptoResult WTPI_GetDeviceFusedStatus(bool* is_fused) { } return OEMCrypto_SUCCESS; } + +OEMCrypto_BCCSignatureType WTPI_GetBCCSignatureType(void) { + return OEMCrypto_BCCSigType_Unknown; +} + +OEMCryptoResult WTPI_GenerateBCCSignature(uint8_t* out, size_t* out_length) { + (void)out; + (void)out_length; + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult WTPI_StoreBCCSignature(const uint8_t* signature, + size_t signature_length) { + (void)signature; + (void)signature_length; + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult WTPI_LoadBCCSignature(uint8_t* signature, + size_t* signature_length) { + (void)signature; + (void)signature_length; + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCryptoResult WTPI_GetMaxBCCSignatureSize(size_t* out_length) { + if (out_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + *out_length = MAX_BCC_SIGNATURE_SIZE; + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c index 26cb2a4..fa13341 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_root_of_trust_layer2.c @@ -34,187 +34,135 @@ static const char* kKeyboxPath = "widevine_keybox"; OEMCryptoResult WTPI_UnwrapRootOfTrust(const uint8_t* input, - size_t input_length, uint8_t* output, + size_t input_length, + uint8_t* output, size_t* output_length) { - TLOGD("WTPI_UnwrapRootOfTrust\n"); + TLOGD("WTPI_UnwrapRootOfTrust\n"); - if (input == NULL || output == NULL || output_length == NULL) { - TLOGE("WTPI_UnwrapRootOfTrust: invalid parameters\n"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } + if (input == NULL || output == NULL || output_length == NULL) { + TLOGE("WTPI_UnwrapRootOfTrust: invalid parameters\n"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } - /* Try to unwrap the keybox. */ - int rc = - keybox_unwrap(input, input_length, output, *output_length, output_length); - if (rc == KEYBOX_STATUS_SUCCESS) { - return OEMCrypto_SUCCESS; - } + /* Try to unwrap the keybox. */ + int rc = keybox_unwrap(input, input_length, output, *output_length, + output_length); + if (rc == KEYBOX_STATUS_SUCCESS) { + return OEMCrypto_SUCCESS; + } - /* If unwrapping failed, assume the keybox is cleartext. */ - TLOGW("WTPI_UnwrapRootOfTrust: decryption failed (%d), assuming cleartext\n", - rc); + /* If unwrapping failed, assume the keybox is cleartext. */ + TLOGW("WTPI_UnwrapRootOfTrust: decryption failed (%d), assuming cleartext\n", + rc); + + /* The output buffer needs to be at least the size of the input buffer. */ + size_t min_output_length = input_length; + if (min_output_length > *output_length) { + *output_length = min_output_length; + TLOGE("WTPI_UnwrapRootOfTrust: output buffer too short, should be at least %zu bytes\n", + min_output_length); + return OEMCrypto_ERROR_SHORT_BUFFER; + } - /* The output buffer needs to be at least the size of the input buffer. */ - size_t min_output_length = input_length; - if (min_output_length > *output_length) { *output_length = min_output_length; - TLOGE( - "WTPI_UnwrapRootOfTrust: output buffer too short, should be at least " - "%zu bytes\n", - min_output_length); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - *output_length = min_output_length; - memcpy(output, input, *output_length); - return OEMCrypto_SUCCESS; + memcpy(output, input, *output_length); + return OEMCrypto_SUCCESS; } OEMCryptoResult WTPI_SaveRootOfTrust(const uint8_t* keybox, size_t length) { - TLOGD("WTPI_SaveRootOfTrust\n"); - tee_context* ctx = get_tee_context(); - assert(ctx->new_provisioning_session != STORAGE_INVALID_SESSION); + TLOGD("WTPI_SaveRootOfTrust\n"); + tee_context* ctx = get_tee_context(); + assert(ctx->new_provisioning_session != STORAGE_INVALID_SESSION); - if (!system_state_provisioning_allowed()) { - TLOGE("provisioning not allowed\n"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } + if (!system_state_provisioning_allowed()) { + TLOGE("provisioning not allowed\n"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } - if (keybox == NULL) { - TLOGE("WTPI_SaveRootOfTrust: no keybox provided\n"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } + if (keybox == NULL) { + TLOGE("WTPI_SaveRootOfTrust: no keybox provided\n"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } - file_handle_t handle; - int rc = storage_open_file( - ctx->new_provisioning_session, &handle, kKeyboxPath, - STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0); - if (rc < 0) { - TLOGE("WTPI_SaveRootOfTrust: failed to create keybox: %d\n", rc); - return OEMCrypto_ERROR_OPEN_FAILURE; - } - rc = storage_write(handle, 0, keybox, length, STORAGE_OP_COMPLETE); - storage_close_file(handle); - if (rc < 0) { - TLOGE("WTPI_SaveRootOfTrust: failed to write keybox: %d\n", rc); - return OEMCrypto_ERROR_CLOSE_FAILURE; - } + file_handle_t handle; + int rc = storage_open_file( + ctx->new_provisioning_session, &handle, kKeyboxPath, + STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0); + if (rc < 0) { + TLOGE("WTPI_SaveRootOfTrust: failed to create keybox: %d\n", rc); + return OEMCrypto_ERROR_OPEN_FAILURE; + } + rc = storage_write(handle, 0, keybox, length, STORAGE_OP_COMPLETE); + storage_close_file(handle); + if (rc < 0) { + TLOGE("WTPI_SaveRootOfTrust: failed to write keybox: %d\n", rc); + return OEMCrypto_ERROR_CLOSE_FAILURE; + } - return OEMCrypto_SUCCESS; + return OEMCrypto_SUCCESS; } OEMCryptoResult WTPI_LoadRootOfTrust(uint8_t* keybox, size_t* length) { - TLOGD("WTPI_LoadRootOfTrust\n"); - tee_context* ctx = get_tee_context(); - assert(ctx->new_provisioning_session != STORAGE_INVALID_SESSION); + TLOGD("WTPI_LoadRootOfTrust\n"); + tee_context* ctx = get_tee_context(); + assert(ctx->new_provisioning_session != STORAGE_INVALID_SESSION); - if (keybox == NULL || length == NULL) { - TLOGE("WTPI_LoadRootOfTrust: invalid parameters\n"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } + if (keybox == NULL || length == NULL) { + TLOGE("WTPI_LoadRootOfTrust: invalid parameters\n"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } - file_handle_t handle; - int rc = storage_open_file(ctx->new_provisioning_session, &handle, - kKeyboxPath, 0, 0); - bool loading_from_backup = false; - if (rc < 0) { - TLOGE( - "WTPI_LoadRootOfTrust: error opening keybox on TP. Attempting TDP.\n"); - assert(ctx->old_provisioning_session != STORAGE_INVALID_SESSION); - rc = storage_open_file(ctx->old_provisioning_session, &handle, kKeyboxPath, - 0, 0); + file_handle_t handle; + int rc = storage_open_file(ctx->new_provisioning_session, &handle, + kKeyboxPath, 0, 0); + bool loading_from_backup = false; if (rc < 0) { - TLOGE("WTPI_LoadRootOfTrust: error opening keybox: %d\n", rc); - return OEMCrypto_ERROR_OPEN_FAILURE; + TLOGE("WTPI_LoadRootOfTrust: error opening keybox on TP. Attempting TDP.\n"); + assert(ctx->old_provisioning_session != STORAGE_INVALID_SESSION); + rc = storage_open_file(ctx->old_provisioning_session, &handle, + kKeyboxPath, 0, 0); + if (rc < 0) { + TLOGE("WTPI_LoadRootOfTrust: error opening keybox: %d\n", rc); + return OEMCrypto_ERROR_OPEN_FAILURE; + } + + loading_from_backup = true; } - loading_from_backup = true; - } + storage_off_t keysize; + rc = storage_get_file_size(handle, &keysize); + if (rc < 0) { + TLOGE("WTPI_LoadRootOfTrust: couldn't get file size: %d\n", rc); + storage_close_file(handle); + return OEMCrypto_ERROR_OPEN_FAILURE; + } - storage_off_t keysize; - rc = storage_get_file_size(handle, &keysize); - if (rc < 0) { - TLOGE("WTPI_LoadRootOfTrust: couldn't get file size: %d\n", rc); - storage_close_file(handle); - return OEMCrypto_ERROR_OPEN_FAILURE; - } + if (*length < keysize) { + TLOGE("WTPI_LoadRootOfTrust: output buffer too small, should be at least %zu bytes\n", + (size_t)keysize); + storage_close_file(handle); + *length = keysize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } - if (*length < keysize) { - TLOGE( - "WTPI_LoadRootOfTrust: output buffer too small, should be at least %zu " - "bytes\n", - (size_t)keysize); + rc = storage_read(handle, 0, keybox, keysize); storage_close_file(handle); + if (rc < 0) { + TLOGE("WTPI_LoadRootOfTrust: error reading keybox: %d\n", rc); + return OEMCrypto_ERROR_KEYBOX_INVALID; + } + assert((size_t)rc == keysize); + + if (loading_from_backup) { + TLOGD("WTPI_LoadRootOfTrust: attempting to copy keybox from TDP to TP\n"); + rc = WTPI_SaveRootOfTrust(keybox, keysize); + if (rc != OEMCrypto_SUCCESS) { + TLOGE("WTPI_LoadRootOfTrust: failed to copy keybox from TDP to TP\n"); + } + } + + TLOGD("WTPI_LoadRootOfTrust: read %lu bytes for keybox\n", keysize); + *length = keysize; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - rc = storage_read(handle, 0, keybox, keysize); - storage_close_file(handle); - if (rc < 0) { - TLOGE("WTPI_LoadRootOfTrust: error reading keybox: %d\n", rc); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - assert((size_t)rc == keysize); - - if (loading_from_backup) { - TLOGD("WTPI_LoadRootOfTrust: attempting to copy keybox from TDP to TP\n"); - rc = WTPI_SaveRootOfTrust(keybox, keysize); - if (rc != OEMCrypto_SUCCESS) { - TLOGE("WTPI_LoadRootOfTrust: failed to copy keybox from TDP to TP\n"); - } - } - - TLOGD("WTPI_LoadRootOfTrust: read %lu bytes for keybox\n", keysize); - - *length = keysize; - return OEMCrypto_SUCCESS; + return OEMCrypto_SUCCESS; } - -OEMCryptoResult WTPI_WrapRootOfTrust30(const uint8_t* input, - size_t input_length, uint8_t* output, - size_t* output_length) { - (void)input; - (void)input_length; - (void)output; - (void)output_length; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult WTPI_UnwrapRootOfTrust30(const uint8_t* input, - size_t input_length, uint8_t* output, - size_t* output_length) { - (void)input; - (void)input_length; - (void)output; - (void)output_length; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult WTPI_SaveOEMPrivateKey30(const uint8_t* input, - size_t input_length) { - (void)input; - (void)input_length; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult WTPI_LoadOEMPrivateKey30(uint8_t* output, - size_t* output_length) { - (void)output; - (void)output_length; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult WTPI_SaveOEMPublicCertificate30(const uint8_t* input, - size_t input_length) { - (void)input; - (void)input_length; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCryptoResult WTPI_LoadOEMPublicCertificate30(uint8_t* output, - size_t* output_length) { - (void)output; - (void)output_length; - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} \ No newline at end of file diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Application.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Application.mk index 8b7f7d6..7c88697 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Application.mk +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Application.mk @@ -1,8 +1,7 @@ -APP_BUILD_SCRIPT := Android.mk -APP_PLATFORM := android-19 +APP_PLATFORM := android-34 APP_ABI := arm64-v8a APP_STL := c++_static APP_CFLAGS := -Werror -Wall -Wextra -Wno-unused-function -Wno-unused-label -Wvla APP_CONLYFLAGS += -std=c17 APP_CPPFLAGS += -std=c++17 -APP_CLANG_TIDY_FLAGS := --header-filter shared/include --quiet +APP_LDFLAGS += -Wl,-z,max-page-size=16384 -T liboemcrypto.lds diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Android.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/OEMCrypto.mk similarity index 100% rename from oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/Android.mk rename to oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/OEMCrypto.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh index fb9eca7..17f810e 100755 --- a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/build.sh @@ -3,18 +3,11 @@ set -e set -u -SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") - # Build liboemcrypto.so -if [ ! -v ANDROID_NDK_ROOT ]; then - ANDROID_NDK_ROOT=$(realpath "$SCRIPT_DIR/../../../../../prebuilts/ndk/r25") +if [ ! -v ANDROID_NDK_ROOT ]; +then + ANDROID_NDK_ROOT=$(realpath $(dirname "$0")/../../../../../prebuilts/ndk/r26) fi -"$ANDROID_NDK_ROOT/ndk-build" \ - -C "$SCRIPT_DIR" \ - NDK_PROJECT_PATH=out \ - NDK_APPLICATION_MK=Application.mk \ - NDK_DEBUG=1 \ - "-j$(nproc)" \ - "$@" +$ANDROID_NDK_ROOT/ndk-build -C $(dirname "${BASH_SOURCE[0]}") NDK_PROJECT_PATH=out APP_BUILD_SCRIPT=OEMCrypto.mk NDK_APPLICATION_MK=Application.mk NDK_DEBUG=1 -j`nproc` diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk index 0b1f6a3..599f6ef 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto-inc.mk @@ -24,18 +24,12 @@ endif LIBOEMCRYPTO_SO := $(LIBOEMCRYPTO_OUT_DIR)/lib/arm64-v8a/liboemcrypto.so -.PHONY: $(LIBOEMCRYPTO_SO) $(LIBOEMCRYPTO_SO): LOCAL_DIR := $(GET_LOCAL_DIR) $(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_BUILD_DIR := $(LIBOEMCRYPTO_BUILD_DIR) $(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_OUT_DIR := $(LIBOEMCRYPTO_OUT_DIR) -$(LIBOEMCRYPTO_SO): NDK_ROOT := $(TRUSTY_TOP)/prebuilts/ndk/r25 -$(LIBOEMCRYPTO_SO): - $(NOECHO)$(NDK_ROOT)/ndk-build \ - -C $(LOCAL_DIR) \ - NDK_PROJECT_PATH=$(LIBOEMCRYPTO_BUILD_DIR) \ - NDK_LIBS_OUT=$(LIBOEMCRYPTO_OUT_DIR)/lib \ - NDK_APPLICATION_MK=Application.mk \ - -j`nproc` +$(LIBOEMCRYPTO_SO): NDK_ROOT := $(TRUSTY_TOP)/prebuilts/ndk/r26 +$(LIBOEMCRYPTO_SO): .PHONY + $(NOECHO)(cd $(LOCAL_DIR) && $(NDK_ROOT)/ndk-build NDK_PROJECT_PATH=$(LIBOEMCRYPTO_BUILD_DIR) NDK_LIBS_OUT=$(LIBOEMCRYPTO_OUT_DIR)/lib APP_BUILD_SCRIPT=OEMCrypto.mk NDK_APPLICATION_MK=Application.mk -j`nproc`) # Ensure liboemcrypto.so is built EXTRA_BUILDDEPS += $(LIBOEMCRYPTO_SO) diff --git a/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto.lds b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto.lds new file mode 100644 index 0000000..fa25887 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/liboemcrypto/liboemcrypto.lds @@ -0,0 +1,10 @@ +SECTIONS +{ + .rodata.keep : + { + /* Prevent section-gc removing these symbols */ + KEEP(*(.rodata.kVersionInfo)) + KEEP(*(.rodata.kOdkReleaseDate)) + } +} +INSERT AFTER .rodata; diff --git a/oemcrypto/opk/ports/trusty/ta/reference/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/rules.mk index 35d8c68..7a4693c 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/rules.mk +++ b/oemcrypto/opk/ports/trusty/ta/reference/rules.mk @@ -45,6 +45,8 @@ MODULE_DEFINES += \ OPK_CONFIG_TEE_OS_VERSION=$(WIDEVINE_TEE_OS_VERSION) \ OPK_CONFIG_DEVICE_FORM_FACTOR=$(WIDEVINE_FORM_FACTOR) \ OPK_CONFIG_IMPLEMENTER_NAME=$(WIDEVINE_OEMCRYPTO_IMPLEMENTER) \ + OPK_CONFIG_IMPLEMENTER_NAME=$(WIDEVINE_OEMCRYPTO_IMPLEMENTER) \ + WIDEVINE_PROVISION_METHOD=4 \ # oemcrypto.h will declare constants as C++-style statics. # C sources do not like this, so change the behavior. @@ -94,10 +96,10 @@ MODULE_SRCS += \ $(APP_DIR)/wtpi_reference/wtpi_logging.c \ $(APP_DIR)/wtpi_reference/wtpi_memory.c \ $(APP_DIR)/wtpi_reference/wtpi_root_of_trust_layer1.c \ + $(APP_DIR)/wtpi_reference/device_info_util.c \ $(REF_IMPL_DIR)/wtpi_clock_layer2.c \ $(REF_IMPL_DIR)/wtpi_secure_buffer_access.c \ $(REF_IMPL_DIR)/wtpi_initialize_terminate.c \ - $(REF_IMPL_DIR)/wtpi_config.c \ $(REF_IMPL_DIR)/wtpi_persistent_storage_layer1.c \ $(REF_IMPL_DIR)/wtpi_provisioning_4.c \ $(REF_IMPL_DIR)/wtpi_root_of_trust_layer2.c \ diff --git a/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c b/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c index c8b805e..a22b231 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/secure_buffer.c @@ -124,7 +124,7 @@ void cleanup_secure_buffers(void) { /* Overly cautious clear */ secure_buffers[i] = (struct secure_buffer_info){ - .handle = INVALID_IPC_HANDLE, .size = 0, .addr = NULL}; + .handle = INVALID_IPC_HANDLE, .size = 0, .addr = NULL}; } num_secure_buffers = 0; } diff --git a/oemcrypto/opk/ports/trusty/ta/reference/shared/shared_memory.c b/oemcrypto/opk/ports/trusty/ta/reference/shared/shared_memory.c index dc42934..1011d44 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/shared/shared_memory.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/shared/shared_memory.c @@ -76,7 +76,7 @@ void TOS_SharedMemory_Release(void) { * Returns: * The address of the shared memory region refered by |handle| */ -uint8_t* TOS_SharedMemory_GetAddress() { +uint8_t* TOS_SharedMemory_GetAddress(void) { return pool; } @@ -86,7 +86,7 @@ uint8_t* TOS_SharedMemory_GetAddress() { * Returns: * the size of the shared memory region */ -size_t TOS_SharedMemory_GetSize() { +size_t TOS_SharedMemory_GetSize(void) { return pool_size; } diff --git a/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c b/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c index f388136..b44a9dc 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/widevine_app.c @@ -185,12 +185,18 @@ static bool is_bound(struct widevine_ctx* ctx) { static void close_shared_memory(struct widevine_ctx* ctx) { TEE_SharedMemory_Bind(NULL, 0); if (ctx->shared_buffer_addr != NULL) { - munmap(ctx->shared_buffer_addr, ctx->shared_buffer_size); + int rc = munmap(ctx->shared_buffer_addr, ctx->shared_buffer_size); + if (rc != NO_ERROR) { + TLOGW("munmap() failed: %d\n", rc); + } ctx->shared_buffer_addr = NULL; ctx->shared_buffer_size = 0; } if (ctx->shared_message_addr != NULL) { - munmap(ctx->shared_message_addr, ctx->shared_message_size); + int rc = munmap(ctx->shared_message_addr, ctx->shared_message_size); + if (rc != NO_ERROR) { + TLOGW("munmap() failed: %d\n", rc); + } ctx->shared_message_addr = NULL; ctx->shared_message_size = 0; } @@ -310,7 +316,10 @@ static int dispatch_bind_message(handle_t chan, PROT_READ | PROT_WRITE, 0, handles[1], 0); if (shared_buffer_addr == MAP_FAILED) { TLOGE("Could not map shared buffer.\n"); - munmap(shared_message_addr, shared_message_size); + int rc = munmap(shared_message_addr, shared_message_size); + if (rc != NO_ERROR) { + TLOGW("munmap() failed: %d\n", rc); + } return -1; } diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/binding.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/binding.rs new file mode 100644 index 0000000..be21759 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/binding.rs @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +pub mod opk { + include!(env!("BINDGEN_INC_FILE")); + + #[repr(C)] + #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] + pub struct wtpi_k1_symmetric_key_handle { + index: u32, + is_key_cached: bool, + cached_key: [u8; 32], + } + + pub type WTPI_K1_SymmetricKey_Handle = *mut wtpi_k1_symmetric_key_handle; + + #[allow(non_camel_case_types)] + #[allow(non_snake_case)] + #[no_mangle] + extern "C" { + // TODO(mattfedd): This is temporary while we are splitting C/Rust crypto. + // + // This function is one of several WTPI_ crypto functions that populates the + // `cached_key` field of the key handle with the raw key material. We are taking + // advantage of this implementation-specific detail to extract key material so that + // we can then pass it to HWCrypto. + // + // Eventually the rest of the crypto interface will be ported to use HWCrypto. + // Until then, we copy the wtpi_k1_symmetric_key_handle struct here in rust, and + // call this function to extract the key material. + pub fn WTPI_K1_WrapKey( + context: u32, + key_handle: WTPI_K1_SymmetricKey_Handle, + key_type: SymmetricKeyType, + wrapped_key: *mut u8, + wrapped_key_length: usize, + ) -> OEMCryptoResult; + + // Needed for WrapKey use + pub fn WTPI_K1_GetKeySize( + key_handle: WTPI_K1_SymmetricKey_Handle, + size: *mut KeySize, + ) -> OEMCryptoResult; + } +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_config.c b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/bindings.h similarity index 58% rename from oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_config.c rename to oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/bindings.h index dd0afc9..1fa04ab 100644 --- a/oemcrypto/opk/ports/trusty/ta/reference/interface_impls/wtpi_config.c +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/bindings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,9 @@ * limitations under the License. */ -#include - -uint32_t TEE_GetRSAPaddingSchemes(void) { - return kSign_RSASSA_PSS ^ kSign_PKCS1_Block1; -} - -OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) { - return HDCP_NO_DIGITAL_OUTPUT; -} - -bool WTPI_IsProductionReady(void) { - // TODO(b/224065807): revisit this for checking for production readiness - return true; -} +#include "wtpi_provisioning_4_interface.h" +#include "wtpi_device_renewal_interface_layer1.h" +#include "wtpi_crc32_interface.h" +#include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_crypto_asymmetric_interface.h" +#include "wtpi_decrypt_sample_interface.h" diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/decrypt.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/decrypt.rs new file mode 100644 index 0000000..b731c65 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/decrypt.rs @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#![deny(unsafe_op_in_unsafe_fn)] + +use crate::binding::opk as binding; +use crate::error::{OpkError, OpkSuccess}; + +use android_hardware_security_see::aidl::android::hardware::security::see::hwcrypto::{ + types::{ + AesCipherMode::AesCipherMode, AesKey::AesKey, CipherModeParameters::CipherModeParameters, + ExplicitKeyMaterial::ExplicitKeyMaterial, KeyLifetime::KeyLifetime, KeyType::KeyType, + KeyUse::KeyUse, MemoryBufferReference::MemoryBufferReference, OperationData::OperationData, + SymmetricCryptoParameters::SymmetricCryptoParameters, + SymmetricOperation::SymmetricOperation, + SymmetricOperationParameters::SymmetricOperationParameters, + }, + CryptoOperation::CryptoOperation, + CryptoOperationErrorAdditionalInfo::CryptoOperationErrorAdditionalInfo, + CryptoOperationSet::CryptoOperationSet, + ICryptoOperationContext::ICryptoOperationContext, + IHwCryptoKey::IHwCryptoKey, + IOpaqueKey::IOpaqueKey, + KeyPolicy::KeyPolicy, + MemoryBufferParameter::{ + MemoryBuffer::MemoryBuffer as MemoryBufferAidl, MemoryBufferParameter, + }, + OperationParameters::OperationParameters, + PatternParameters::PatternParameters, +}; +use binder::{ParcelFileDescriptor, StatusCode, Strong}; +use core::ffi::{c_void, CStr}; +use log::{debug, error}; +use rpcbinder::RpcSession; +use std::os::fd::{FromRawFd, OwnedFd}; + +fn connect() -> Result, StatusCode> { + const RUST_HWCRYPTO_SERVICE_PORT: &CStr = c"com.android.trusty.rust.hwcryptohal.V1"; + let session = RpcSession::new(); + // TODO(mattfedd): enable FD transport mode once supported in trusty + // session.set_file_descriptor_transport_mode(rpcbinder::FileDescriptorTransportMode::Trusty)?; + session.setup_trusty_client(RUST_HWCRYPTO_SERVICE_PORT) +} + +// The DecryptBuffer type is an attempt to abstract the two types of buffers +// that HWCrypto can use: file descriptors (MemoryBufferReference) and raw data +// (DataBuffer). When creating cmd lists, call input_data() or output_data() to +// get the appropriate command regardless of the underlying data type. +pub enum DecryptBuffer<'a> { + Fd(DecryptFd), + Raw(&'a mut [u8]), +} + +pub struct DecryptFd { + pfd: Option, + size: usize, +} + +impl DecryptFd { + /// Create a new object using raw pointer and size. + /// + /// 'ptr' must be page aligned, and 'size' must be a multiple of the page + /// size. Otherwise this function will return None. + /// + /// # Safety + /// + /// The memory pointed to by 'ptr' may not be modified externally during + /// the lifetime of the resulting DecryptFd object. + /// + /// Any ongoing operations on DecryptFd must be synchronized before `ptr` + /// can be read. + /// + /// There can only be one DecryptFd object created for a given `(ptr, size)` + /// region of memory. + pub unsafe fn new_from_ptr(ptr: *mut u8, size: usize) -> Option { + let prot_flags = trusty_sys::MMAP_FLAG_PROT_READ | trusty_sys::MMAP_FLAG_PROT_WRITE; + + let raw_trusty_fd = + unsafe { trusty_sys::memref_create(ptr as *mut c_void, size as u32, prot_flags) }; + if raw_trusty_fd < 0 { + error!( + "trusty_sys::memref_create() failed with result {}. Is the output buffer page aligned?", + raw_trusty_fd + ); + return None; + } + + // SAFETY: DecryptFd can only be created once from a given 'ptr', so + // this OwnedFd is exclusive. The raw_trusty_fd is open if memref_create + // succeeded. + let fd = unsafe { OwnedFd::from_raw_fd(raw_trusty_fd as i32) }; + let pfd = Some(ParcelFileDescriptor::new(fd)); + + Some(Self { pfd: pfd, size: size }) + } +} + +impl DecryptBuffer<'_> { + pub fn output_data(&self, offset: usize, size: usize) -> OperationData { + match self { + Self::Fd(_) => OperationData::MemoryBufferReference(MemoryBufferReference { + startOffset: offset as i32, + sizeBytes: size as i32, + }), + Self::Raw(_) => OperationData::DataBuffer(Vec::new()), + } + } + pub fn input_data(&self, offset: usize, size: usize) -> OperationData { + match self { + Self::Fd(_) => OperationData::MemoryBufferReference(MemoryBufferReference { + startOffset: offset as i32, + sizeBytes: size as i32, + }), + Self::Raw(data) => { + let mut v = Vec::new(); + v.extend_from_slice(&data[offset..offset + size]); + OperationData::DataBuffer(v) + } + } + } +} + +pub(crate) fn decrypt_sample( + key_handle: binding::WTPI_K1_SymmetricKey_Handle, + sample: &binding::OEMCrypto_SampleDescription, + pattern: &binding::OEMCrypto_CENCEncryptPatternDesc, + output_offset: usize, + cipher_mode: binding::OEMCryptoCipherMode, + subsamples: &[binding::OEMCrypto_SubSampleDescription], + input_buffer: &mut DecryptBuffer, + output_buffer: &mut DecryptBuffer, +) -> Result<(), OpkError> { + // Get initial IV + let mut subsample_iv = [0u8; 16]; + subsample_iv.copy_from_slice(&sample.iv[..]); + + // Get hwcrypto handles + let hw_crypto = connect().map_err(|_| OpkError::Unknown)?; + let hw_crypto_ops = hw_crypto.getHwCryptoOperations()?; + + // Register memref input/output buffers with hwcrypto, if applicable + let mut mem_setup_cmds = Vec::new(); + if let DecryptBuffer::Fd(val) = input_buffer { + let size = i32::try_from(val.size)?; + let pfd = val.pfd.take(); + mem_setup_cmds.push(CryptoOperation::SetMemoryBuffer(MemoryBufferParameter { + bufferHandle: MemoryBufferAidl::Input(pfd), + sizeBytes: size, + })); + } + if let DecryptBuffer::Fd(val) = output_buffer { + let size = i32::try_from(val.size)?; + let pfd = val.pfd.take(); + mem_setup_cmds.push(CryptoOperation::SetMemoryBuffer(MemoryBufferParameter { + bufferHandle: MemoryBufferAidl::Output(pfd), + sizeBytes: size, + })); + } + let mut context: Option> = None; + if !mem_setup_cmds.is_empty() { + let mem_setup = CryptoOperationSet { context: None, operations: mem_setup_cmds }; + let mut initial_cmds = Vec::new(); + initial_cmds.push(mem_setup); + let mut additional_error_info = + CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; + let Ok(mut op_result) = + hw_crypto_ops.processCommandList(&mut initial_cmds, &mut additional_error_info) + else { + error!("Could not process memory registration command list"); + return Err(OpkError::Unknown); + }; + context = op_result.remove(0).context; + debug!("Successfully set up buffers"); + } + + // Loop through subsamples and decrypt + let current_output_offset = output_offset; + let current_input_offset = 0usize; + let mut offset: usize = 0usize; + + // TODO(mattfedd): this key handle transformation will not be portable for TA bypass + let key = get_key_from_wtpi_c(&hw_crypto, key_handle, &cipher_mode)?; + + // set up cipher/key information up front + let mut cipher_cmds = Vec::new(); + let parameters = match cipher_mode { + binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CBCS => { + SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters { + nonce: subsample_iv.into(), + })) + } + binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CENC => { + SymmetricCryptoParameters::Aes(AesCipherMode::Ctr(CipherModeParameters { + nonce: subsample_iv.into(), + })) + } + _ => return Err(OpkError::UnsupportedCipher), + }; + + let direction = SymmetricOperation::DECRYPT; + let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters }; + let op_params = OperationParameters::SymmetricCrypto(sym_op_params); + cipher_cmds.push(CryptoOperation::SetOperationParameters(op_params)); + if cipher_mode == binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CBCS { + cipher_cmds.push(CryptoOperation::SetPattern(PatternParameters { + numberBlocksProcess: pattern.encrypt as i64, + numberBlocksCopy: pattern.skip as i64, + })); + } + let cipher_setup = CryptoOperationSet { context: None, operations: cipher_cmds }; + let mut initial_cmds = Vec::new(); + initial_cmds.push(cipher_setup); + let mut additional_error_info = CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; + let Ok(mut op_result) = + hw_crypto_ops.processCommandList(&mut initial_cmds, &mut additional_error_info) + else { + error!("Could not process cipher setup command list"); + return Err(OpkError::Unknown); + }; + debug!("Successfully set up cipher info"); + context = match context { + None => op_result.remove(0).context, + _ => context, + }; + + for index in 0..subsamples.len() { + let subsample = subsamples[index]; + if subsample.num_bytes_clear == 0 && subsample.num_bytes_encrypted == 0 { + continue; + } + + let (current_input_offset, current_output_offset) = { + let Some(offset1) = current_input_offset.checked_add(offset) else { + return Err(OpkError::InvalidContext); + }; + let Some(offset2) = current_output_offset.checked_add(offset) else { + return Err(OpkError::InvalidContext); + }; + + (offset1, offset2) + }; + + let decrypt_cmds = get_decrypt_subsample_commands( + &subsample, + current_input_offset, + current_output_offset, + &cipher_mode, + &input_buffer, + &output_buffer, + ); + let crypto_op_set = + CryptoOperationSet { context: context.clone(), operations: decrypt_cmds }; + let mut crypto_sets = Vec::new(); + crypto_sets.push(crypto_op_set); + + let mut additional_error_info = + CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; + + let Ok(mut op_result) = + hw_crypto_ops.processCommandList(&mut crypto_sets, &mut additional_error_info) + else { + error!("Could not process sample command list"); + return Err(OpkError::Unknown); + }; + + if context == None { + context = match &cipher_mode { + &binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CBCS => None, + &binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CENC => { + op_result.remove(0).context + } + _ => None, + }; + } + + // Copy data to output buffer if it is represented as a slice (this is the inefficient part) + if let DecryptBuffer::Raw(data) = output_buffer { + // copy into output buffer + let mut index = 0; + let mut data_written = 0; + let mut cmd_set = crypto_sets.remove(0); + if subsample.num_bytes_clear > 0 { + let CryptoOperation::DataOutput(OperationData::DataBuffer(copied_data)) = + cmd_set.operations.remove(index) + else { + error!("Unable to retrieve copied data from command list"); + return Err(OpkError::Unknown); + }; + + let starting_offset = current_output_offset + data_written; + let ending_offset = starting_offset + subsample.num_bytes_clear; + data[starting_offset..ending_offset].copy_from_slice(&copied_data[..]); + + index = index + 1; + data_written = data_written + subsample.num_bytes_clear; + } + + if subsample.num_bytes_encrypted > 0 { + let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) = + cmd_set.operations.remove(index) + else { + error!("Unable to retrieve decrypted data from command list"); + return Err(OpkError::Unknown); + }; + let starting_offset = current_output_offset + data_written; + let ending_offset = starting_offset + subsample.num_bytes_encrypted; + data[starting_offset..ending_offset].copy_from_slice(&decrypted_data[..]); + } + } + + offset = { + let Some(offset) = subsample + .num_bytes_encrypted + .checked_add(subsample.num_bytes_clear) + .and_then(|total_bytes| total_bytes.checked_add(offset)) + else { + return Err(OpkError::InvalidContext); + }; + + offset + }; + } + + return Ok(()); +} + +fn get_decrypt_subsample_commands( + subsample: &binding::OEMCrypto_SubSampleDescription, + input_offset: usize, + output_offset: usize, + cipher_mode: &binding::OEMCryptoCipherMode, + decrypt_input: &DecryptBuffer, + decrypt_output: &DecryptBuffer, +) -> Vec { + let mut cmd_list = Vec::::new(); + + let mut input_index = input_offset; + let mut output_index = output_offset; + let encrypted_length = subsample.num_bytes_encrypted; + let clear_length = subsample.num_bytes_clear; + let is_ctr = cipher_mode == &binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CENC; + + if clear_length > 0 { + cmd_list.push(CryptoOperation::DataOutput( + decrypt_output.output_data(output_index, clear_length), + )); + cmd_list + .push(CryptoOperation::CopyData(decrypt_input.input_data(input_index, clear_length))); + + output_index = output_index + clear_length; + input_index = input_index + clear_length; + } + + if encrypted_length > 0 { + cmd_list.push(CryptoOperation::DataOutput( + decrypt_output.output_data(output_index, encrypted_length), + )); + cmd_list.push(CryptoOperation::DataInput( + decrypt_input.input_data(input_index, encrypted_length), + )); + + if !is_ctr { + cmd_list.push(CryptoOperation::Finish(None)); + } + } + + cmd_list +} + +// TODO(mattfedd): This is temporary while we are splitting the crypto impl +// between existing C code and this new Rust hwcrypto code. Eventually we want +// either full C or full Rust for the crypto code. +fn get_key_from_wtpi_c( + hw_crypto: &Strong, + key_handle: binding::WTPI_K1_SymmetricKey_Handle, + cipher_mode: &binding::OEMCryptoCipherMode, +) -> Result, OpkError> { + // Get raw key material + let mut raw_key = [0u8; 32]; + let mut key_size = binding::KeySize_UNKNOWN_KEY_SIZE; + + // SAFETY: All C functions called in this block are called with unsafe{} + // because they take raw pointer arguments. + // We provide those arguments with Rust arrays and references, which are + // guaranteed to be non-null and properly aligned. The objects underlying + // these references are live throughout the entire unsafe block and are + // not accessed concurrently elsewhere. + unsafe { + let result = binding::WTPI_K1_GetKeySize(key_handle, &mut key_size); + if result != OpkSuccess.into() { + return Err(OpkError::Unknown); + } + // We are using the "wrapped key" returned here as the raw key + // material. This is specific to the wtpi_ref implementation of WrapKey, + // which does not in fact wrap the key. We could alternatively fetch the + // raw key from the `cached_key` field of the key handle after this op. + let result = binding::WTPI_K1_WrapKey( + 0u32, + key_handle, + binding::SymmetricKeyType_CONTENT_KEY, + raw_key.as_mut_ptr(), + raw_key.len(), + ); + if result != OpkSuccess.into() { + return Err(OpkError::Unknown); + }; + } + + let aes_key = match key_size { + binding::KeySize_KEY_SIZE_128 => ExplicitKeyMaterial::Aes(AesKey::Aes128( + raw_key[0..16].try_into().expect("size mismatch"), + )), + binding::KeySize_KEY_SIZE_256 => ExplicitKeyMaterial::Aes(AesKey::Aes256( + raw_key[0..32].try_into().expect("size mismatch"), + )), + _ => { + error!("key size didn't match"); + return Err(OpkError::InvalidContext); + } + }; + + let key_type = match key_size { + binding::KeySize_KEY_SIZE_128 => match cipher_mode { + &binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CBCS => { + KeyType::AES_128_CBC_NO_PADDING + } + _ => KeyType::AES_128_CTR, + }, + binding::KeySize_KEY_SIZE_256 => match cipher_mode { + &binding::OEMCryptoCipherMode_OEMCrypto_CipherMode_CBCS => { + KeyType::AES_256_CBC_NO_PADDING + } + _ => KeyType::AES_256_CTR, + }, + _ => return Err(OpkError::Unknown), + }; + let policy = KeyPolicy { + usage: KeyUse::ENCRYPT_DECRYPT, + keyLifetime: KeyLifetime::PORTABLE, + keyPermissions: Vec::new(), + keyType: key_type, + keyManagementKey: false, + }; + + let key = hw_crypto.importClearKey(&aes_key, &policy)?; + + Ok(key) +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/error.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/error.rs new file mode 100644 index 0000000..663e45d --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/error.rs @@ -0,0 +1,52 @@ +use crate::binding; +use core::num::TryFromIntError; + +#[derive(Debug)] +pub enum OpkError { + ShortBuffer { needed: usize }, + InvalidContext, + NotImplemented, + UnsupportedCipher, + Unknown, +} + +impl From for OpkError { + fn from(_e: binder::Status) -> Self { + OpkError::Unknown + } +} + +impl From for OpkError { + fn from(_e: TryFromIntError) -> Self { + OpkError::Unknown + } +} + +impl From for binding::opk::OEMCryptoResult { + fn from(e: OpkError) -> Self { + match e { + OpkError::ShortBuffer { .. } => { + binding::opk::OEMCryptoResult_OEMCrypto_ERROR_SHORT_BUFFER + } + OpkError::InvalidContext => { + binding::opk::OEMCryptoResult_OEMCrypto_ERROR_INVALID_CONTEXT + } + OpkError::NotImplemented => { + binding::opk::OEMCryptoResult_OEMCrypto_ERROR_NOT_IMPLEMENTED + } + OpkError::UnsupportedCipher => { + binding::opk::OEMCryptoResult_OEMCrypto_ERROR_UNSUPPORTED_CIPHER + } + OpkError::Unknown => binding::opk::OEMCryptoResult_OEMCrypto_ERROR_UNKNOWN_FAILURE, + } + } +} + +#[derive(Debug)] +pub struct OpkSuccess; + +impl From for binding::opk::OEMCryptoResult { + fn from(_: OpkSuccess) -> Self { + binding::opk::OEMCryptoResult_OEMCrypto_SUCCESS + } +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/lib.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/lib.rs new file mode 100644 index 0000000..e6de46a --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/lib.rs @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![deny(unsafe_op_in_unsafe_fn)] + +mod binding; +mod decrypt; +mod error; + +use error::{OpkError, OpkSuccess}; + +use crate::decrypt::*; +use log::error; +use std::sync::Once; +use trusty_std::slice; + +static LOG_INIT: Once = Once::new(); + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[no_mangle] +/// Rust implementation of WTPI lib function WTPI_DecryptSample. +/// +/// # Safety +/// +/// * The following values must each be [dereferenceable] +/// * `sample` +/// * `pattern` +/// * `output_buffer` +/// * The following values must each satisfy the same safety considerations as +/// slice [from_raw_parts]. +/// * `(sample.subsamples, sample.subsamples_length)` +/// * `(sample.buffers.input_data, sample.buffers.input_data_length)` +/// * `(output_buffer.buffer.clear_insecure, output_buffer.size)` +/// * The `output_buffer` union must be consistent between its `type` field and +/// underlying `buffer` data. +/// * The underlying memory of the following buffers must not be modified by +/// an external process while this function is executing +/// * `sample.buffers.input_data` +/// * `output_buffer.buffer.clear_insecure` +/// +/// [from_raw_parts]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety +/// [dereferenceable]: https://doc.rust-lang.org/std/ptr/index.html#safety +/// +pub unsafe extern "C" fn WTPI_DecryptSample( + key_handle: binding::opk::WTPI_K1_SymmetricKey_Handle, + sample: *const binding::opk::OEMCrypto_SampleDescription, + pattern: *const binding::opk::OEMCrypto_CENCEncryptPatternDesc, + output_buffer: *const binding::opk::OPK_OutputBuffer, + output_offset: usize, + cipher_mode: binding::opk::OEMCryptoCipherMode, +) -> binding::opk::OEMCryptoResult { + LOG_INIT.call_once(|| { + trusty_log::init(); + }); + + // SAFETY: + // WTPI_DecryptSample states that `sample` must satisfy `as_ref` safety + // requirements. + let Some(sample_ref) = (unsafe { sample.as_ref() }) else { + return OpkError::InvalidContext.into(); + }; + + // SAFETY: + // WTPI_DecryptSample states that `pattern` must satisfy `as_ref` safety + // requirements. + let Some(pattern_ref) = (unsafe { pattern.as_ref() }) else { + return OpkError::InvalidContext.into(); + }; + + // SAFETY: + // WTPI_DecryptSample states that `output_buffer` must satisfy `as_ref` + // safety requirements. + let Some(output_buffer_ref) = (unsafe { output_buffer.as_ref() }) else { + return OpkError::InvalidContext.into(); + }; + + // Get slice of subsamples + let subsamples = match sample_ref.subsamples.is_null() { + // SAFETY: + // WTPI_DecryptSample states that `sample.subsamples`, + // `sample.subsamples_length` must satisfy `from_raw_parts` safety + // requirements. + false => unsafe { + slice::from_raw_parts(sample_ref.subsamples, sample_ref.subsamples_length) + }, + true => return OpkError::InvalidContext.into(), + }; + + // Convert input and output buffers to types that HWCrypto cmd lists can accept. + // Try file descriptors first, fallback to slices otherwise. Slices are less efficient. + let (input_data_ptr, input_data_size) = + (sample_ref.buffers.input_data, sample_ref.buffers.input_data_length); + let (output_data_ptr, output_data_size) = match output_buffer_ref.type_ { + // SAFETY: + // WTPI_DecryptSample states that `output_buffer` must be consistent + // between its `type` field and underlying `buffer` data. + binding::opk::OPK_OutputBuffer_Type_OPK_CLEAR_INSECURE_OUTPUT_BUFFER => unsafe { + (output_buffer_ref.buffer.clear_insecure, output_buffer_ref.size) + }, + // TODO(mattfedd): secure buffer support + _ => { + error!("Secure buffers not supported yet"); + return OpkError::NotImplemented.into(); + } + }; + + let input_data_mut = input_data_ptr as *mut u8; + if input_data_mut.is_null() || input_data_mut.align_offset(core::mem::align_of::()) != 0 { + return OpkError::InvalidContext.into(); + } + + // SAFETY: + // new_from_ptr requires that + // 1. The memory pointed to by `input_data_mut` is not modified externally + // during the lifetime of the DecryptFd object. + // * WTPI_DecryptSample states that the underlying memory of + // `input_data_mut` cannot be modified externally during the lifetime of + // WTPI_DecryptSample so we assume that the C caller abides by this. + // * The data pointed to by `input_data_mut` is not accessed directly + // anywhere here in WTPI_DecryptSample. + // 2. `input_data_mut` buffer can only be read after synchronizing + // operations on DecryptFd. + // * `input_data_mut` is never read directly, no synchronization needed + // 3. A DecryptFd for `input_data_mut` does not already exist. + // * This is the first DecryptFd created in WTPI_DecryptSample, so it is + // the only instance of a DecryptFd using `input_data_mut` + let mut input_buf = unsafe { + match DecryptFd::new_from_ptr(input_data_mut, input_data_size) { + Some(decrypt_fd) => DecryptBuffer::Fd(decrypt_fd), + None => { + // null checked above + let data_slice = slice::from_raw_parts_mut(input_data_mut, input_data_size); + DecryptBuffer::Raw(data_slice) + } + } + }; + + let output_data_mut = output_data_ptr as *mut u8; + if output_data_mut.is_null() || output_data_mut.align_offset(core::mem::align_of::()) != 0 { + return OpkError::InvalidContext.into(); + } + + let input_is_fd = match input_buf { + DecryptBuffer::Fd(_) => true, + DecryptBuffer::Raw(_) => false, + }; + if input_is_fd && input_data_mut == output_data_mut { + return OpkError::InvalidContext.into(); + } + + // SAFETY: + // new_from_ptr requires that + // 1. The memory pointed to by `output_data_mut` is not modified externally + // during the lifetime of the DecryptFd object. + // * WTPI_DecryptSample states that the underlying memory of + // `output_data_mut` cannot be modified externally during the lifetime + // of WTPI_DecryptSample so we assume that the C caller abides by this. + // * The data pointed to by `output_data_mut` is not accessed directly + // anywhere here in WTPI_DecryptSample. + // 2. `output_data_mut` buffer can only be read after synchronizing + // operations on DecryptFd. + // * `output_data_mut` is never read directly, no synchronization needed + // 3. A DecryptFd for `output_data_mut` does not already exist. + // * We compare `input_data_mut` and `output_data_mut` above if the + // input buffer type is also DecryptFd. + let mut output_buf = unsafe { + match DecryptFd::new_from_ptr(output_data_mut, output_data_size) { + Some(decrypt_fd) => DecryptBuffer::Fd(decrypt_fd), + None => { + // null checked above + let data_slice = slice::from_raw_parts_mut(output_data_mut, output_data_size); + DecryptBuffer::Raw(data_slice) + } + } + }; + + match decrypt_sample( + key_handle, + sample_ref, + pattern_ref, + output_offset, + cipher_mode, + subsamples, + &mut input_buf, + &mut output_buf, + ) { + Ok(()) => OpkSuccess.into(), + Err(e) => { + error!("Decrypt sample returned an error {:?}", e); + e.into() + } + } +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/rules.mk new file mode 100644 index 0000000..51bf3ad --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/crypto/aidl/rules.mk @@ -0,0 +1,71 @@ +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LOCAL_DIR)/lib.rs + +MODULE_CRATE_NAME := wtpi_crypto_aidl + +MODULE_RUST_CRATE_TYPES := staticlib + +CDM_DIR := trusty/vendor/widevine/cdm +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk + +MODULE_INCLUDES += \ + $(CDM_DIR)/oemcrypto/include \ + $(ODK_DIR)/include \ + $(SERIALIZATION_DIR)/common \ + $(SERIALIZATION_DIR)/common/include \ + $(CDM_DIR)/oemcrypto/odk/src \ + $(SERIALIZATION_DIR)/os_interfaces \ + $(APP_DIR) \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libc-trusty \ + trusty/user/base/lib/trusty-std \ + trusty/user/base/lib/trusty-sys \ + trusty/user/app/sample/hwcryptohal/aidl/rust \ + frameworks/native/libs/binder/trusty/rust \ + frameworks/native/libs/binder/trusty/rust/rpcbinder \ + frameworks/native/libs/binder/trusty/rust/binder_rpc_server_bindgen \ + external/rust/crates/lazy_static \ + trusty/user/base/lib/trusty-log \ + $(call FIND_CRATE,log) \ + +MODULE_BINDGEN_ALLOW_TYPES := \ + KeySize \ + OEMCrypto.* \ + ODK.* \ + OPK.* \ + SymmetricKeyType \ + + +# MODULE_BINDGEN_ALLOW_VARS := \ + # .* \ + +# MODULE_BINDGEN_ALLOW_FUNCTIONS := \ + # WTPI.* \ + +MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/bindings.h + +include make/library.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/bindings.h b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/bindings.h new file mode 100644 index 0000000..dcb7f77 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/bindings.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wtpi_device_key_interface.h" diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/error.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/error.rs new file mode 100644 index 0000000..b8dd3eb --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/error.rs @@ -0,0 +1,42 @@ +use crate::binding; +use core::num::TryFromIntError; + +#[derive(Debug)] +pub enum OpkError { + ShortBuffer { needed: usize }, + InvalidContext, + NotImplemented, + Unknown, +} + +impl From for OpkError { + fn from(_e: binder::Status) -> Self { + OpkError::Unknown + } +} + +impl From for OpkError { + fn from(_e: TryFromIntError) -> Self { + OpkError::Unknown + } +} + +impl From for binding::OEMCryptoResult { + fn from(e: OpkError) -> Self { + match e { + OpkError::ShortBuffer { .. } => binding::OEMCryptoResult_OEMCrypto_ERROR_SHORT_BUFFER, + OpkError::InvalidContext => binding::OEMCryptoResult_OEMCrypto_ERROR_INVALID_CONTEXT, + OpkError::NotImplemented => binding::OEMCryptoResult_OEMCrypto_ERROR_NOT_IMPLEMENTED, + OpkError::Unknown => binding::OEMCryptoResult_OEMCrypto_ERROR_UNKNOWN_FAILURE, + } + } +} + +#[derive(Debug)] +pub struct OpkSuccess; + +impl From for binding::OEMCryptoResult { + fn from(_: OpkSuccess) -> Self { + binding::OEMCryptoResult_OEMCrypto_SUCCESS + } +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/lib.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/lib.rs new file mode 100644 index 0000000..2186d43 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/lib.rs @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![deny(unsafe_op_in_unsafe_fn)] + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +mod binding { + include!(env!("BINDGEN_INC_FILE")); +} + +mod error; +use error::OpkError; + +use trusty_sys; +use android_hardware_security_see::aidl::android::hardware::security::see::hwcrypto::{ + IHwCryptoKey::{ + DerivedKey::DerivedKey, DerivedKeyParameters::DerivedKeyParameters, + DerivedKeyPolicy::DerivedKeyPolicy, DeviceKeyId::DeviceKeyId, + DiceBoundDerivationKey::DiceBoundDerivationKey, + DiceCurrentBoundKeyResult::DiceCurrentBoundKeyResult, IHwCryptoKey, + ClearKeyPolicy::ClearKeyPolicy, + }, +}; + +use binder::{StatusCode, Strong}; +use core::ffi::CStr; +use rpcbinder::RpcSession; +use trusty_std::slice; + +const DERIVATION_DATA: &str = "..........TrustyWvDerivationData"; + +fn connect() -> Result, StatusCode> { + const RUST_DEVICE_KEY_SERVICE_PORT: &CStr = c"com.android.trusty.rust.hwcryptohal.V1"; + RpcSession::new().setup_trusty_client(RUST_DEVICE_KEY_SERVICE_PORT) +} + +fn get_current_device_key() -> Result { + let hw_device_key = connect().map_err(|_| OpkError::Unknown)?; + + let device_bound_key = DiceBoundDerivationKey::KeyId(DeviceKeyId::DEVICE_BOUND_KEY); + let key_and_policy = hw_device_key.deriveCurrentDicePolicyBoundKey(&device_bound_key)?; + + let DiceCurrentBoundKeyResult { + diceBoundKey: derivation_key, + dicePolicyForKeyVersion: _dice_policy, + } = key_and_policy; + + // Derive a clear key from returned current policy and derivation key + let params = DerivedKeyParameters { + derivationKey: derivation_key, + keyPolicy: DerivedKeyPolicy::ClearKey(ClearKeyPolicy { keySizeBytes: 256 }), + context: DERIVATION_DATA.as_bytes().to_vec(), + }; + + let derived_key = hw_device_key.deriveKey(¶ms)?; + + Ok(derived_key) +} + +const TRUSTY_FAILURE: trusty_sys::c_long = -1; +#[no_mangle] +/// Rust implementation of wv_derive_device_key. +/// +/// This function is called by C code that is only used in the Widevine TA on +/// Trusty. This is not part of the core OPK or the WTPI interfaces. The C +/// implementation of this function calls hwkey_derive_versioned(). +/// +/// # Safety +/// +/// * `key` and `size` must satisfy the same safety considerations as slice +/// [from_raw_parts_mut]. +/// +/// [from_raw_parts_mut]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety +/// [dereferenceable]: https://doc.rust-lang.org/std/ptr/index.html#safety +/// +pub unsafe extern "C" fn wv_derive_device_key( + _derivation_data: *const u8, + key: *mut u8, + size: usize, +) -> trusty_sys::c_long { + if key.is_null() { + return TRUSTY_FAILURE; + } + + // SAFETY: This is not safe. Therefore the entire function is not safe. + // + // We can guarantee that `key` is not null and is properly aligned. + // + // But we cannot guarantee that the underlying memory is valid or that it + // will not be modified for the lifetime of this pointer. + let buf = unsafe { slice::from_raw_parts_mut(key, size) }; + + let derived_key = match get_current_device_key() { + Ok(key) => match key { + DerivedKey::Opaque(_) => { + return TRUSTY_FAILURE; + } + DerivedKey::ExplicitKey(k) => k, + }, + Err(_) => return TRUSTY_FAILURE, + }; + + if derived_key.len() < size { + return TRUSTY_FAILURE; + } + + buf.copy_from_slice(&derived_key[..size]); + + 0 +} + +// TODO(mattfedd): Implement WTPI_EncryptAndSign() and WTPI_DecryptAndVerify(), +// which wraps and unwraps blobs such as offline licenses. Without these, the +// derived key is always the latest DICE based policy, and will fail to unwrap +// blobs that were wrapped with an older DICE policy. New wrapping code here +// would embed the dice policy so we know how to derive the appropriate wrapping +// keys correctly. diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/rules.mk new file mode 100644 index 0000000..01627f0 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/aidl/rules.mk @@ -0,0 +1,71 @@ +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LOCAL_DIR)/lib.rs + +MODULE_CRATE_NAME := wtpi_devicekey_aidl + +MODULE_RUST_CRATE_TYPES := staticlib + +CDM_DIR := trusty/vendor/widevine/cdm +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk +IMPL_DIR := $(LOCAL_DIR)/../../../..//interface_impls + +MODULE_INCLUDES += \ + $(CDM_DIR)/oemcrypto/include \ + $(ODK_DIR)/include \ + $(SERIALIZATION_DIR)/common \ + $(SERIALIZATION_DIR)/common/include \ + $(CDM_DIR)/oemcrypto/odk/src \ + $(SERIALIZATION_DIR)/os_interfaces \ + $(APP_DIR) \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + $(IMPL_DIR) \ + + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libc-trusty \ + trusty/user/base/lib/trusty-std \ + trusty/user/base/lib/trusty-sys \ + trusty/user/app/sample/hwcryptohal/aidl/rust \ + frameworks/native/libs/binder/trusty/rust \ + frameworks/native/libs/binder/trusty/rust/rpcbinder \ + frameworks/native/libs/binder/trusty/rust/binder_rpc_server_bindgen \ + +MODULE_BINDGEN_ALLOW_TYPES := \ + OEMCrypto.* \ + OPK.* \ + ODK.* \ + SymmetricKeyType.* \ + KeySize.* \ + .* \ + + +MODULE_BINDGEN_ALLOW_VARS := \ + .* \ + +MODULE_BINDGEN_ALLOW_FUNCTIONS := \ + WTPI.* \ + +MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/bindings.h + +include make/library.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/rules.mk new file mode 100644 index 0000000..f1457c5 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/device_key/rules.mk @@ -0,0 +1,66 @@ +# Copyright (C) 2020 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +TOP_LEVEL := $(LOCAL_DIR)/../../../../ +SHARED_DIR := $(TOP_LEVEL)/shared +IMPL_DIR := $(TOP_LEVEL)/interface_impls + +CDM_DIR := trusty/vendor/widevine/cdm +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk + +ifndef WIDEVINE_PROVISION_METHOD +$(error WIDEVINE_PROVISION_METHOD is not set. \ + Please set it in the [target_name]-inc.mk file of your project) +endif + +MODULE_DEFINES += \ + WIDEVINE_PROVISION_METHOD=$(WIDEVINE_PROVISION_METHOD) \ + +MODULE_DEFINES += \ + OPK_CONFIG_SOC_VENDOR_NAME=Google \ + OPK_CONFIG_SOC_MODEL_NAME=$(PLATFORM) \ + OPK_CONFIG_TEE_OS_NAME=Trusty \ + OPK_CONFIG_TEE_OS_VERSION=0.0 \ + OPK_CONFIG_DEVICE_FORM_FACTOR=phone+tablet \ + OPK_CONFIG_IMPLEMENTER_NAME=Widevine \ + WTPI_BUILD_INFO=TRUSTY \ + +MODULE_SRCS += \ + $(IMPL_DIR)/derive_key.c \ + +MODULE_INCLUDES += \ + $(LOCAL_DIR)/include \ + $(SHARED_DIR)/include \ + +MODULE_INCLUDES += \ + $(CDM_DIR)/oemcrypto/include \ + $(ODK_DIR)/include \ + $(CDM_DIR)/oemcrypto/odk/src \ + $(IMPL_DIR) \ + $(APP_DIR) \ + $(TOP_LEVEL)/include \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/hwkey \ + +include make/library.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/other/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/other/rules.mk new file mode 100644 index 0000000..67fa54d --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/other/rules.mk @@ -0,0 +1,126 @@ +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +WV_TA_TOP_LEVEL := $(LOCAL_DIR)/../../../ +SHARED_DIR := $(WV_TA_TOP_LEVEL)/shared +IMPL_DIR := $(WV_TA_TOP_LEVEL)/interface_impls + +CDM_DIR := trusty/vendor/widevine/cdm +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk + +ifndef WIDEVINE_PROVISION_METHOD +$(error WIDEVINE_PROVISION_METHOD is not set. \ + Please set it in the [target_name]-inc.mk file of your project) +endif + +MODULE_DEFINES += \ + WIDEVINE_PROVISION_METHOD=$(WIDEVINE_PROVISION_METHOD) \ + +MODULE_DEFINES += \ + OPK_CONFIG_SOC_VENDOR_NAME=Google \ + OPK_CONFIG_SOC_MODEL_NAME=$(PLATFORM) \ + OPK_CONFIG_TEE_OS_NAME=Trusty \ + OPK_CONFIG_TEE_OS_VERSION=0.0 \ + OPK_CONFIG_DEVICE_FORM_FACTOR=phone+tablet \ + OPK_CONFIG_IMPLEMENTER_NAME=Widevine \ + WTPI_BUILD_INFO=TRUSTY \ + +# Widevine vendor code assumes trusty defines __linux__. We need to get this +# fixed upstream. TODO(b/232255239) +MODULE_CFLAGS += -D__linux__ + +# The base Trusty app. +MODULE_SRCS += \ + $(IMPL_DIR)/wtpi_clock_layer2.c \ + $(IMPL_DIR)/wtpi_secure_buffer_access.c \ + $(IMPL_DIR)/wtpi_config.c \ + $(IMPL_DIR)/transport_interface.c \ + $(SHARED_DIR)/shared_memory.c \ + $(SHARED_DIR)/widevine_ipc_protocol.c \ + $(APP_DIR)/wtpi_reference/wtpi_abort.c \ + $(APP_DIR)/wtpi_reference/wtpi_clock_and_gn_layer1.c \ + $(APP_DIR)/wtpi_reference/wtpi_idle.c \ + $(APP_DIR)/wtpi_reference/wtpi_logging.c \ + $(APP_DIR)/wtpi_reference/wtpi_memory.c \ + $(APP_DIR)/wtpi_reference/wtpi_root_of_trust_layer1.c \ + $(APP_DIR)/wtpi_reference/wtpi_device_renewal_layer1.c \ + $(APP_DIR)/oemcrypto_output.c \ + $(IMPL_DIR)/device_key_util.c \ + $(IMPL_DIR)/wtpi_device_renewal_layer2.c \ + $(IMPL_DIR)/wtpi_provisioning_4.c \ + $(APP_DIR)/wtpi_reference/cose_util.c \ + $(APP_DIR)/wtpi_reference/crypto_util.c \ + $(APP_DIR)/wtpi_reference/device_info_util.c \ + $(APP_DIR)/wtpi_reference/ecc_util.c \ + $(APP_DIR)/wtpi_reference/device_info_util.c \ + $(APP_DIR)/wtpi_reference/renewal_util.c \ + $(APP_DIR)/wtpi_reference/rsa_util.c \ + $(APP_DIR)/wtpi_reference/wtpi_crc32.c \ + $(APP_DIR)/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c \ + $(APP_DIR)/wtpi_reference/wtpi_crypto_asymmetric.c \ + $(APP_DIR)/wtpi_reference/wtpi_crypto_wrap_asymmetric.c \ + $(APP_DIR)/oemcrypto_object_table.c \ + $(IMPL_DIR)/device_key_v0.c \ + $(IMPL_DIR)/wtpi_device_key.c \ + $(ODK_DIR)/src/odk_util.c \ + +# define USE_OPK_FEATURE_SETHDCP to use experimental HDCP auth +# - turns on HDCP to max during OEMCrypto_Initialize() +# - turns off HDCP during OEMCrypto_Terminate() +# - plan is to improve granularity in the future +MODULE_SRCS += \ + $(IMPL_DIR)/wtpi_hdcp.c \ + +MODULE_INCLUDES += \ + +MODULE_INCLUDES += \ + $(WV_TA_TOP_LEVEL)/include \ + $(SHARED_DIR)/include \ + $(CDM_DIR)/oemcrypto/include \ + $(ODK_DIR)/include \ + $(SERIALIZATION_DIR)/common \ + $(SERIALIZATION_DIR)/common/include \ + $(CDM_DIR)/oemcrypto/odk/src \ + $(SERIALIZATION_DIR)/os_interfaces \ + $(IMPL_DIR) \ + +MODULE_INCLUDES += \ + $(APP_DIR) \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libc-trusty \ + trusty/user/base/interface/hwbcc \ + trusty/user/base/interface/keybox \ + trusty/user/base/lib/hwbcc/client \ + trusty/user/base/lib/hwkey \ + trusty/user/base/lib/keybox/client \ + trusty/user/base/lib/keymaster \ + trusty/user/base/lib/system_state \ + external/boringssl \ + external/open-dice \ + +MODULE_LIBRARY_DEPS += \ + trusty/user/whitechapel/tz/base/lib/hwhdcp \ + + +include make/library.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/rules.mk new file mode 100644 index 0000000..2b1f09f --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/rules.mk @@ -0,0 +1,78 @@ +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +WTPI_STORAGE_USE_AIDL := 0 +WTPI_CRYPTO_USE_AIDL := 0 +WTPI_DEVICEKEY_USE_AIDL := 0 + +ifeq ($(WTPI_STORAGE_USE_AIDL),1) +INCLUDE_BINDER=yes +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/storage/aidl \ + +else +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/storage/ref \ + +endif + + +ifeq ($(WTPI_CRYPTO_USE_AIDL),1) +INCLUDE_BINDER=yes +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/crypto/aidl \ + +else +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/crypto/ref \ + +endif + + +ifeq ($(WTPI_DEVICEKEY_USE_AIDL),1) +INCLUDE_BINDER=yes +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/device_key/aidl \ + +else +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/device_key/ref \ + +endif + + +ifdef INCLUDE_BINDER +# the /aidl/ implementations are Rust static libs and can't link the Rust +# versions of the below dependencies since those are rlibs. Something to do with +# proc macros. So I'll manually link what I assume are the cpp versions here. +MODULE_LIBRARY_DEPS += \ + frameworks/native/libs/binder/trusty/binder_rpc_unstable \ + + # frameworks/native/libs/binder/trusty \ + # frameworks/native/libs/binder/trusty/ndk \ + # frameworks/native/libs/binder/trusty/rust/binder_rpc_server_bindgen \ + +endif + + +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl/other \ + +include make/library.mk + diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/bindings.h b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/bindings.h new file mode 100644 index 0000000..420a00a --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/bindings.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wtpi_initialize_terminate_interface.h" +#include "wtpi_persistent_storage_interface_layer1.h" +#include "wtpi_root_of_trust_interface_layer2.h" diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/error.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/error.rs new file mode 100644 index 0000000..b8dd3eb --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/error.rs @@ -0,0 +1,42 @@ +use crate::binding; +use core::num::TryFromIntError; + +#[derive(Debug)] +pub enum OpkError { + ShortBuffer { needed: usize }, + InvalidContext, + NotImplemented, + Unknown, +} + +impl From for OpkError { + fn from(_e: binder::Status) -> Self { + OpkError::Unknown + } +} + +impl From for OpkError { + fn from(_e: TryFromIntError) -> Self { + OpkError::Unknown + } +} + +impl From for binding::OEMCryptoResult { + fn from(e: OpkError) -> Self { + match e { + OpkError::ShortBuffer { .. } => binding::OEMCryptoResult_OEMCrypto_ERROR_SHORT_BUFFER, + OpkError::InvalidContext => binding::OEMCryptoResult_OEMCrypto_ERROR_INVALID_CONTEXT, + OpkError::NotImplemented => binding::OEMCryptoResult_OEMCrypto_ERROR_NOT_IMPLEMENTED, + OpkError::Unknown => binding::OEMCryptoResult_OEMCrypto_ERROR_UNKNOWN_FAILURE, + } + } +} + +#[derive(Debug)] +pub struct OpkSuccess; + +impl From for binding::OEMCryptoResult { + fn from(_: OpkSuccess) -> Self { + binding::OEMCryptoResult_OEMCrypto_SUCCESS + } +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/lib.rs b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/lib.rs new file mode 100644 index 0000000..aadd8c5 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/lib.rs @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![deny(unsafe_op_in_unsafe_fn)] + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +mod binding { + include!(env!("BINDGEN_INC_FILE")); +} + +mod error; +use error::{OpkError, OpkSuccess}; + +use android_hardware_security_see_storage::aidl::android::hardware::security::see::storage::{ + Availability::Availability, CreationMode::CreationMode, FileMode::FileMode, + Filesystem::Filesystem, IFile::IFile, ISecureStorage::ISecureStorage, + IStorageSession::IStorageSession, Integrity::Integrity, OpenOptions::OpenOptions, +}; + +use binder::{Status, StatusCode, Strong}; +use core::ffi::CStr; +use rpcbinder::RpcSession; +use trusty_std::slice; + +const FILENAME: &str = "wtpi_persistent_data"; + +fn connect() -> Result, StatusCode> { + const STORAGE_AIDL_PORT_NAME: &CStr = c"com.android.hardware.security.see.storage"; + RpcSession::new().setup_trusty_client(STORAGE_AIDL_PORT_NAME) +} + +fn start_session(properties: &Filesystem) -> Result, Status> { + connect()?.startSession(properties) +} + +// TP is accessible from emulator +static TP: Filesystem = Filesystem { + integrity: Integrity::TAMPER_PROOF_AT_REST, + availability: Availability::BEFORE_USERDATA, + persistent: true, +}; + +// TD is what we want to use on device +#[allow(unused)] +static TD: Filesystem = Filesystem { + integrity: Integrity::TAMPER_DETECT, + availability: Availability::BEFORE_USERDATA, + persistent: true, +}; + +static CREATE: OpenOptions = OpenOptions { + createMode: CreationMode::CREATE, + accessMode: FileMode::READ_WRITE, + truncateOnOpen: false, +}; + +fn open_file( + ss: &(impl IStorageSession + ?Sized), + filename: &str, +) -> Result, Status> { + ss.openFile(filename, &CREATE) +} + +// In the C implementation, WTPI_Initialize() and WTPI_Terminate() are used +// to set up secure storage. And thankfully nothing else. +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn WTPI_Initialize() -> binding::OEMCryptoResult { + OpkSuccess.into() +} + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn WTPI_Terminate() -> binding::OEMCryptoResult { + OpkSuccess.into() +} + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn WTPI_PrepareStoredPersistentData() -> binding::OEMCryptoResult { + OpkSuccess.into() +} + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +/// Rust implementation of WTPI lib function WTPI_LoadPersistentData. +/// +/// # Safety +/// +/// * `data` and `*data_length` must satisfy the same safety considerations as +/// slice [from_raw_parts_mut]. +/// * 'data_length' must be [dereferenceable]. +/// +/// [from_raw_parts_mut]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety +/// [dereferenceable]: https://doc.rust-lang.org/std/ptr/index.html#safety +/// +pub unsafe extern "C" fn WTPI_LoadPersistentData( + data: *mut u8, + data_length: *mut usize, +) -> binding::OEMCryptoResult { + if data_length.is_null() || data_length.align_offset(core::mem::align_of::()) != 0 { + return OpkError::InvalidContext.into(); + } + if data.is_null() || data.align_offset(core::mem::align_of::()) != 0 { + return OpkError::InvalidContext.into(); + } + + // SAFETY: This is not safe. Therefore the entire function is not safe. + // + // We can guarantee that `data_length` is not null and is properly aligned. + // + // But we cannot guarantee that the underlying memory is valid or that it + // will not be modified for the lifetime of this pointer. + let Some(mut data_len_ref) = (unsafe { data_length.as_mut() }) else { + return OpkError::InvalidContext.into(); + }; + + // SAFETY: This is not safe. Therefore the entire function is not safe. + // + // We can guarantee that `data` is not null and is properly aligned. + // + // But we cannot guarantee that the underlying memory is valid or that it + // will not be modified for the lifetime of this pointer. + let buf = unsafe { slice::from_raw_parts_mut(data, *data_len_ref) }; + + match load_data(buf) { + Ok(()) => OpkSuccess.into(), + Err(e) => { + if let OpkError::ShortBuffer { needed } = e { + *data_len_ref = needed; + } + e.into() + } + } +} + +fn load_data(buf: &mut [u8]) -> Result<(), OpkError> { + let session = start_session(&TP)?; + let file = open_file(&*session, FILENAME)?; + let file_len = file.getSize()?; + let file_len_usize = usize::try_from(file_len)?; + + if file_len_usize > buf.len() { + return Err(OpkError::ShortBuffer { needed: file_len_usize }); + } + + let read_buf = file.read(file_len, 0)?; + if read_buf.len() != buf.len() { + return Err(OpkError::Unknown); + } + + buf.copy_from_slice(&read_buf); + + Ok(()) +} + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +/// Rust implementation of WTPI lib function WTPI_StorePersistentData. +/// +/// # Safety +/// +/// * `data` must satisfy the same safety considerations as slice +/// [from_raw_parts]. +/// +/// [from_raw_parts]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety +/// +pub unsafe extern "C" fn WTPI_StorePersistentData( + data: *const u8, + data_length: usize, +) -> binding::OEMCryptoResult { + if data.is_null() || data.align_offset(core::mem::align_of::()) != 0 { + return OpkError::InvalidContext.into(); + } + + // SAFETY: This is not safe. Therefore the entire function is not safe. + // + // We can guarantee that `data` is not null and is properly aligned. + // + // But we cannot guarantee that the underlying memory is valid or that it + // will not be modified for the lifetime of this pointer. + let buf = unsafe { slice::from_raw_parts(data, data_length) }; + + match store_data(buf) { + Ok(()) => OpkSuccess.into(), + Err(e) => e.into(), + } +} + +fn store_data(buf: &[u8]) -> Result<(), OpkError> { + let session = start_session(&TP)?; + let file = open_file(&*session, FILENAME)?; + let data_length_i64 = i64::try_from(buf.len())?; + file.setSize(data_length_i64)?; + let written = file.write(0, &buf)?; + let data_length_i64 = i64::try_from(buf.len())?; + + if written != data_length_i64 { + return Err(OpkError::Unknown); + } + + Ok(session.commitChanges()?) +} + +// Below are keybox-specific acess functions. We assume Prov 4 only for the time +// being, so these are not needed. +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn WTPI_UnwrapRootOfTrust( + input: *const u8, + input_length: usize, + output: *mut u8, + output_length: *mut usize, +) -> binding::OEMCryptoResult { + OpkError::NotImplemented.into() +} + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn WTPI_SaveRootOfTrust( + keybox: *const u8, + length: usize, +) -> binding::OEMCryptoResult { + OpkError::NotImplemented.into() +} + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(unused)] +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn WTPI_LoadRootOfTrust( + keybox: *mut u8, + length: *mut usize, +) -> binding::OEMCryptoResult { + OpkError::NotImplemented.into() +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/manifest.json b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/manifest.json new file mode 100644 index 0000000..b32cfdd --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/manifest.json @@ -0,0 +1,6 @@ +{ + "app_name": "wtpi_storage_aidl", + "uuid": "4e93db02-19f2-4227-9dda-171a91e0d6d5", + "min_heap": 118784, + "min_stack": 32768 +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/rules.mk new file mode 100644 index 0000000..c9d1406 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/impl/storage/aidl/rules.mk @@ -0,0 +1,66 @@ +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LOCAL_DIR)/lib.rs + +MODULE_CRATE_NAME := wtpi_storage_aidl + +MODULE_RUST_CRATE_TYPES := staticlib + +CDM_DIR := trusty/vendor/widevine/cdm +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk + +MODULE_INCLUDES += \ + $(CDM_DIR)/oemcrypto/include \ + $(ODK_DIR)/include \ + $(SERIALIZATION_DIR)/common \ + $(SERIALIZATION_DIR)/common/include \ + $(CDM_DIR)/oemcrypto/odk/src \ + $(SERIALIZATION_DIR)/os_interfaces \ + $(APP_DIR) \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libc-trusty \ + trusty/user/base/lib/trusty-std \ + trusty/user/base/lib/trusty-sys \ + trusty/user/base/interface/secure_storage/rust \ + frameworks/native/libs/binder/trusty/rust \ + frameworks/native/libs/binder/trusty/rust/rpcbinder \ + frameworks/native/libs/binder/trusty/rust/binder_rpc_server_bindgen \ + $(call FIND_CRATE,log) \ + +MODULE_BINDGEN_ALLOW_TYPES := \ + OEMCrypto.* \ + OPK.* \ + ODK.* \ + +MODULE_BINDGEN_ALLOW_VARS := \ + .* \ + +MODULE_BINDGEN_ALLOW_FUNCTIONS := \ + WTPI.* \ + +MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/bindings.h + +include make/library.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/manifest.json b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/manifest.json new file mode 100644 index 0000000..1dac023 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/manifest.json @@ -0,0 +1,6 @@ +{ + "app_name": "wtpi_interface_test", + "uuid": "bb974dbb-0fa1-4a17-8e02-76c3ed6017c9", + "min_heap": 16384, + "min_stack": 16384 +} diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/rules.mk b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/rules.mk new file mode 100644 index 0000000..aa124b6 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/rules.mk @@ -0,0 +1,53 @@ +# Copyright (C) 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MANIFEST := $(LOCAL_DIR)/manifest.json + +MODULE_SRCS += \ + $(LOCAL_DIR)/wtpi_test.cpp + +CDM_DIR := trusty/vendor/widevine/cdm +APP_DIR := $(CDM_DIR)/oemcrypto/opk/oemcrypto_ta +SERIALIZATION_DIR := $(CDM_DIR)/oemcrypto/opk/serialization +ODK_DIR := $(CDM_DIR)/oemcrypto/odk + +MODULE_INCLUDES += \ + $(CDM_DIR)/oemcrypto/include \ + $(ODK_DIR)/include \ + $(SERIALIZATION_DIR)/common \ + $(SERIALIZATION_DIR)/common/include \ + $(CDM_DIR)/oemcrypto/odk/src \ + $(CDM_DIR)/cdm/test \ + $(SERIALIZATION_DIR)/os_interfaces \ + $(APP_DIR) \ + $(APP_DIR)/wtpi \ + $(APP_DIR)/wtpi_reference \ + $(LOCAL_DIR)/../rust \ + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libc-trusty \ + trusty/user/base/lib/unittest \ + trusty/user/base/lib/libstdc++-trusty \ + + +WIDEVINE_PROVISION_METHOD := 4 +MODULE_LIBRARY_DEPS += \ + trusty/user/app/widevine/wtpi_lib/impl \ + +include make/trusted_app.mk diff --git a/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/wtpi_test.cpp b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/wtpi_test.cpp new file mode 100644 index 0000000..596f28b --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/reference/wtpi_lib/test/wtpi_test.cpp @@ -0,0 +1,713 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_decrypt_sample_interface.h" +#include "wtpi_device_key_interface.h" +#include "wtpi_initialize_terminate_interface.h" +#include "wtpi_persistent_storage_interface_layer1.h" + +#define TLOG_TAG "wtpi-test" + +// template +/* +TEST(wtpi, name) { + +test_abort:; +} +*/ + +TEST(wtpi_tests, simple_decrypt_ctr_1) { + std::vector key = { + 0x1B, 0x0C, 0x04, 0x47, 0x78, 0x46, 0xB4, 0xC4, + 0xDC, 0xA3, 0x80, 0x87, 0x55, 0x94, 0x8C, 0x2B, + }; + std::vector iv = {0x42, 0xcd, 0x8d, 0x2b, 0x5e, 0x8b, 0x95, 0xe1, + 0x39, 0xf0, 0x66, 0x3c, 0xf8, 0x9b, 0xbe, 0xc8}; + std::vector clear = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f}; + std::vector encrypted = {0x4f, 0xf1, 0x9a, 0x72, 0x01, 0x19, + 0xda, 0x61, 0xe4, 0xfe, 0xfc, 0x11, + 0x69, 0xef, 0x2f, 0xf7}; + + uint8_t output[32] = {0}; + + // set up sample description + OEMCrypto_SampleDescription sample = {}; + OEMCrypto_SubSampleDescription subsample = {}; + subsample.num_bytes_clear = 0; + subsample.num_bytes_encrypted = 16; + subsample.subsample_flags = 3; + subsample.block_offset = 0; + sample.subsamples_length = 1; + sample.subsamples = &subsample; + OEMCrypto_InputOutputPair* iop = &sample.buffers; + iop->input_data = encrypted.data(); + iop->input_data_length = encrypted.size(); + iop->output_descriptor.type = OEMCrypto_BufferType_Clear; + iop->output_descriptor.buffer.clear.clear_buffer = output; + iop->output_descriptor.buffer.clear.clear_buffer_length = clear.size(); + + memcpy(sample.iv, iv.data(), iv.size()); + + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + OPK_OutputBuffer output_buffer = {}; + output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER; + output_buffer.buffer.clear_insecure = output; + output_buffer.size = clear.size(); + size_t output_offset = 0; + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CENC; + WTPI_K1_SymmetricKey_Handle key_handle = NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + result = WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, + &key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + result = WTPI_DecryptSample(key_handle, &sample, &pattern, &output_buffer, + output_offset, cipher_mode); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + for (size_t i = 0; i < clear.size(); i++) { + ASSERT_EQ(clear[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + +TEST(wtpi_tests, simple_decrypt_ctr_2) { + std::vector key = {0xac, 0x72, 0x37, 0x3e, 0x03, 0x21, 0x3c, 0x25, + 0xf2, 0x61, 0x2e, 0x85, 0x7b, 0xaf, 0xdb, 0x5e}; + std::vector iv = {0x0c, 0x0b, 0x1a, 0x92, 0x9f, 0x55, 0xbc, 0x48, + 0x1f, 0x02, 0xda, 0x78, 0x02, 0x3d, 0x13, 0x11}; + std::vector clear = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, + 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf}; + std::vector encrypted = { + 0x5d, 0xd9, 0xfb, 0x2b, 0xa8, 0xf2, 0xa9, 0xec, 0x34, 0xb9, 0x83, + 0x74, 0x24, 0x6b, 0x9f, 0x75, 0xae, 0xbd, 0xe5, 0x7c, 0x81, 0x48, + 0xac, 0x05, 0x94, 0xec, 0xed, 0x85, 0x05, 0x60, 0xa6, 0x56, 0x71, + 0x22, 0x79, 0xf0, 0xf0, 0xab, 0x3f, 0x98, 0x5a, 0x8e, 0xe9, 0x5a, + 0xbd, 0xb1, 0xf0, 0x39, 0x7a, 0xf0, 0x97, 0x4e, 0x55, 0xd0, 0xaa, + 0xa0, 0x53, 0x70, 0xe1, 0x34, 0x67, 0x3f, 0x22, 0x54, 0x90, 0xe1, + 0xde, 0xf4, 0x2b, 0x31, 0xb4, 0x99, 0xc7, 0x20, 0x18, 0x30, 0x19, + 0xf8, 0xb9, 0xa0, 0x25, 0xd6, 0x4b, 0xea, 0xf5, 0x26, 0x30, 0x1e, + 0xcd, 0xa7, 0xf6, 0xb3, 0x0c, 0x55, 0xa8, 0x0b, 0xfe, 0x1a, 0xf9, + 0x85, 0x94, 0xfc, 0x4f, 0xfa, 0x68, 0xf9, 0x28, 0xe8, 0xf8, 0x0e, + 0x1f, 0x5a, 0xa5, 0x0a, 0xb4, 0xe3, 0x91, 0x5c, 0xb0, 0xf7, 0xb5, + 0x5d, 0x1b, 0x95, 0xa5, 0x00, 0xa5, 0x60, 0x2c, 0x93, 0xf9, 0xa5, + 0xde, 0x32, 0x94, 0x72, 0xa3, 0xf9, 0xda, 0x87, 0x29, 0x7b, 0x91, + 0xf0, 0x17, 0x0a, 0xae, 0x82, 0xbc, 0xc3, 0x34, 0xc8, 0x4c, 0x82, + 0x9d, 0x7b, 0xe3, 0xce, 0x7f, 0x94, 0x41, 0x5f, 0x50, 0x57, 0xaa, + 0x5e, 0x17, 0xd1, 0x0b, 0xee, 0x98, 0x69, 0xd3, 0x1c, 0x84, 0x2f, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; + uint8_t output[176] = {0}; + + // set up sample description + OEMCrypto_SampleDescription sample = {}; + OEMCrypto_SubSampleDescription subsample = {}; + subsample.num_bytes_clear = 0; + subsample.num_bytes_encrypted = 176; + subsample.subsample_flags = 3; + subsample.block_offset = 0; + sample.subsamples_length = 1; + sample.subsamples = &subsample; + OEMCrypto_InputOutputPair* iop = &sample.buffers; + iop->input_data = encrypted.data(); + iop->input_data_length = encrypted.size(); + iop->output_descriptor.type = OEMCrypto_BufferType_Clear; + iop->output_descriptor.buffer.clear.clear_buffer = output; + iop->output_descriptor.buffer.clear.clear_buffer_length = clear.size(); + + memcpy(sample.iv, iv.data(), iv.size()); + + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + OPK_OutputBuffer output_buffer = {}; + output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER; + output_buffer.buffer.clear_insecure = output; + output_buffer.size = clear.size(); + size_t output_offset = 0; + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CENC; + WTPI_K1_SymmetricKey_Handle key_handle = NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + result = WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, + &key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + result = WTPI_DecryptSample(key_handle, &sample, &pattern, &output_buffer, + output_offset, cipher_mode); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + for (size_t i = 0; i < clear.size(); i++) { + ASSERT_EQ(clear[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + +TEST(wtpi_tests, simple_decrypt_ctr_3) { + std::vector key = {0x02, 0xaa, 0xd5, 0xa4, 0x34, 0x11, 0x3b, 0xab, + 0xb0, 0xdf, 0xbe, 0x46, 0xc3, 0x33, 0x76, 0x6f}; + std::vector iv = {0x89, 0xa9, 0xf0, 0x0c, 0xdc, 0xa1, 0x50, 0x9d, + 0x58, 0x8f, 0x7f, 0x46, 0x8f, 0x8c, 0xd4, 0x42}; + std::vector clear = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, + 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, + 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, + 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, + 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, + 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, + 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, + 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, + 0x9f, 0xa0, 0xa1, 0xa2, 0xa3}; + std::vector encrypted = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0xa2, 0x10, 0xff, 0xf5, 0xc3, 0x78, 0xce, 0x45, + 0x6a, 0xe9, 0xd6, 0xb7, 0xb5, 0x66, 0x85, 0xde, 0xf0, 0x5f, 0x5f, + 0x29, 0x36, 0x65, 0x6a, 0xb3, 0x2d, 0x29, 0xef, 0x00, 0x3e, 0xfb, + 0x7a, 0x10, 0xe0, 0x2a, 0xac, 0xae, 0xcb, 0xc7, 0x25, 0xc9, 0xcc, + 0xc2, 0x13, 0xbf, 0x8f, 0x3f, 0x5a, 0xa6, 0xf4, 0xb2, 0x10, 0x85, + 0xcb, 0x9b, 0xe5, 0x39, 0x7d, 0xa1, 0x2b, 0xd9, 0x6a, 0x89, 0x58, + 0x2c, 0xb5, 0x56, 0xf5, 0x09, 0x2f, 0xaf, 0x09, 0xc6, 0x87, 0xbf, + 0xa5, 0xce, 0xfe, 0x0b, 0x98, 0x35, 0xa1, 0xd3, 0xce, 0x24, 0xa3, + 0xa8, 0x52, 0x5a, 0x70, 0x0f, 0x6b, 0x79, 0xc6, 0x41, 0x30, 0x4d, + 0x0b, 0x43, 0x2f, 0x39, 0xd1, 0x01, 0x35, 0x3f, 0xe7, 0xf7, 0x2b, + 0xc3, 0x61, 0xdb, 0x07, 0x24, 0xb7, 0x2b, 0x0a, 0x1e, 0x91, 0x0a, + 0x8f, 0x2e, 0x84, 0x38, 0x25, 0xef, 0x46, 0xc4, 0x1f, 0xb3, 0x4d, + 0x92, 0x94, 0xe0, 0xef, 0x09, 0xee, 0xa6, 0x6e, 0x84, 0xc0, 0xab, + 0xaa, 0x51, 0x3f, 0xf0, 0x8b, 0x74, 0x9a, 0x26, 0x44, 0xd5, 0x05, + 0x19, 0xbc, 0x2c, 0xd0, 0x34, 0xd3, 0x63, 0xb6, 0x65, 0xb9, 0xba, + 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xc0, 0xdb, 0xec, 0x85, 0x93, 0xb6, 0x13, + 0x06, 0xa1, 0x66, 0x12, 0x2c, 0x7b, 0x8f, 0x60, 0x49, 0x2f, 0x30, + 0x0d, 0xae, 0xd9, 0x32, 0xf9, 0x73, 0x06, 0xd4, 0x3e, 0xd2, 0x8e, + 0xbf, 0xa5, 0xbb, 0xab, 0x14, 0x84, 0x92, 0x27, 0xa1, 0x28, 0x73, + 0x0b, 0x73, 0x86, 0x0e, 0xb3, 0xe7, 0x85, 0xdb, 0xc0, 0xcf, 0x28, + 0xde, 0x05, 0x81, 0x38, 0x35, 0x90, 0xc2, 0xfd, 0x57, 0x16, 0x39, + 0x04, 0x9e, 0x92, 0xb7, 0x27, 0x23, 0x8c, 0xf3, 0x82, 0x0a, 0x7b, + 0xf3, 0xcb, 0xbc, 0xf4, 0xba, 0x3d, 0xc6, 0x50, 0xec, 0x1a, 0x13, + 0x9d, 0x5a, 0x00, 0x6d, 0x8f, 0x61, 0xdb, 0xce, 0x8e, 0xee, 0x32, + 0x2b, 0x39, 0xf4, 0xa8, 0xe7, 0xe7, 0xc9, 0xe8, 0x13, 0xeb, 0xed, + 0xb1, 0x6c, 0x24, 0xa8, 0xd1, 0xcb, 0xb9, 0x76, 0xed, 0x50, 0xf7, + 0x28, 0xe9, 0x65, 0x32, 0x10, 0x0a, 0x1c, 0x2c, 0x0b, 0xf9, 0x18, + 0x11, 0xde, 0x87, 0xb3, 0x71, 0x7f, 0xa9, 0x30, 0x3c, 0xd3, 0x45, + 0x29, 0x64, 0x39, 0x56, 0x02, 0xa1, 0x25, 0xa1, 0xeb, 0x21, 0xfe, + 0x61, 0x41, 0xe3, 0x82, 0x96, 0x50, 0x9b, 0x8f, 0xaf, 0xce, 0xe5, + 0x76, 0xee, 0x92, 0x22, 0x17, 0x2c, 0x91, 0xce, 0x59, 0x32, 0xc3, + 0x97, 0x46, 0xa7, 0x63, 0x8f, 0x06, 0x97, 0xc9, 0x5c, 0xef, 0xf6, + 0x6a, 0x1d, 0xd3, 0xec, 0xb1, 0xa7, 0x9b, 0x82, 0xbf, 0x5f, 0xf9, + 0x1c, 0xee, 0x25, 0x17, 0xa9, 0x90, 0x50, 0x93, 0xc6, 0xc2, 0x10, + 0x70, 0xd4, 0x97, 0x58, 0xa6, 0x6c, 0x08, 0xc7, 0xcf, 0x52, 0x3d, + 0x3f, 0xf4, 0x40, 0xd0, 0x49, 0xa5, 0x9b, 0x02, 0x3d, 0xa7, 0x56, + 0xe8, 0xba, 0x17, 0xcf, 0xe8, 0xf2, 0x8e, 0x28, 0xe2, 0xa7, 0x36, + 0x72, 0x9e, 0xa5, 0x22, 0x86, 0x02, 0xab, 0x2a, 0xbc, 0x42, 0xd8, + 0x38, 0xbf, 0x06, 0xa7, 0xd9, 0x45, 0x97, 0xeb, 0xec, 0xed, 0xee, + 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0xe1, + 0xc1, 0x79, 0xaa, 0x81, 0x94, 0x15, 0xad, 0xa5, 0x13, 0xfe, 0xe1, + 0xc1, 0x6f, 0xd3, 0x87, 0xda, 0x02, 0x84, 0xb0, 0xbe, 0xa1, 0x8a, + 0x4c, 0xe1, 0x70, 0x0e, 0xe5, 0x0c, 0xcf, 0xe4, 0x0e, 0x20, 0x2e, + 0xdc, 0xe7, 0xc5, 0x48, 0x23, 0x03, 0xb6, 0x92, 0x32, 0xdf, 0xb3, + 0x64, 0xdd, 0x57, 0x5d, 0xfc, 0x51, 0xfc, 0x47, 0x11, 0x84, 0x73, + 0xf1, 0x13, 0xe4, 0xdf, 0x05, 0x74, 0x35, 0xa0, 0x9d, 0xfd, 0x4d, + 0x77, 0xb9, 0x5b, 0xf7, 0x2a, 0xe3, 0x7d, 0xd4, 0x13, 0xb5, 0xdc, + 0xa4, 0x24, 0xad, 0xae, 0x4f, 0x8f, 0x97, 0xb6, 0x1d, 0x8f, 0xe3, + 0x39, 0xc7, 0x92, 0xe6, 0xa9, 0xa1, 0xe4, 0xee, 0x6a, 0xb4, 0x3f, + 0x90, 0xfd, 0xfc, 0x24, 0xfc, 0xfd, 0x5d, 0xe9, 0x32, 0xfb, 0xe2, + 0x8c, 0x41, 0xd4, 0x96, 0x4f, 0x59, 0x96, 0xbd, 0x4f, 0x76, 0x58, + 0xbc, 0x65, 0xbe, 0x2a, 0x63, 0xe4, 0xcf, 0x24, 0x8d, 0xa5, 0x63, + 0x75, 0x59, 0x1f, 0x19, 0xd4, 0x70, 0x52, 0xe8, 0xd4, 0x4d, 0x36, + 0x1c, 0xec, 0x23, 0x6b, 0xbe, 0x77, 0xcd, 0x41, 0xc9, 0xa4, 0x52, + 0xaf, 0x23, 0x55, 0xa2, 0xa1}; + uint8_t output[676] = {0}; + + // set up sample description + OEMCrypto_SampleDescription sample = {}; + OEMCrypto_SubSampleDescription subsamples[3]; + subsamples[0].num_bytes_clear = 25; + subsamples[0].num_bytes_encrypted = 160; + subsamples[0].subsample_flags = 1; + subsamples[0].block_offset = 0; + subsamples[1].num_bytes_clear = 50; + subsamples[1].num_bytes_encrypted = 256; + subsamples[1].subsample_flags = 0; + subsamples[1].block_offset = 0; + subsamples[2].num_bytes_clear = 25; + subsamples[2].num_bytes_encrypted = 160; + subsamples[2].subsample_flags = 2; + subsamples[2].block_offset = 0; + sample.subsamples_length = 3; + sample.subsamples = &subsamples[0]; + OEMCrypto_InputOutputPair* iop = &sample.buffers; + iop->input_data = encrypted.data(); + iop->input_data_length = encrypted.size(); + iop->output_descriptor.type = OEMCrypto_BufferType_Clear; + iop->output_descriptor.buffer.clear.clear_buffer = output; + iop->output_descriptor.buffer.clear.clear_buffer_length = clear.size(); + + memcpy(sample.iv, iv.data(), iv.size()); + + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + OPK_OutputBuffer output_buffer = {}; + output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER; + output_buffer.buffer.clear_insecure = output; + output_buffer.size = clear.size(); + size_t output_offset = 0; + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CENC; + WTPI_K1_SymmetricKey_Handle key_handle = NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + result = WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, + &key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + result = WTPI_DecryptSample(key_handle, &sample, &pattern, &output_buffer, + output_offset, cipher_mode); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + for (size_t i = 0; i < clear.size(); i++) { + ASSERT_EQ(clear[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + +TEST(wtpi_tests, simple_decrypt_ctr_4) { + std::vector key = {0x7d, 0x54, 0x07, 0x87, 0x02, 0x4e, 0x0f, 0x87, + 0x9f, 0xe4, 0x29, 0xc2, 0xb4, 0xc9, 0x83, 0x1a}; + std::vector iv = {0x1c, 0x26, 0x2b, 0xbd, 0xb6, 0xdc, 0xb1, 0x14, + 0xb8, 0x20, 0x93, 0x23, 0x87, 0xfa, 0xe3, 0xa9}; + std::vector clear = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, + 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5}; + std::vector encrypted = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x58, + 0xd8, 0xae, 0xaf, 0x34, 0x08, 0x0a, 0xc5, 0x2e, 0xa2, 0x96, 0xd1, + 0x23, 0x38, 0x29, 0x49, 0x6e, 0x13, 0x3a, 0xe0, 0x94, 0x7e, 0xc1, + 0x1f, 0xb4, 0x48, 0xac, 0x59, 0x86, 0x4e, 0x9d, 0xc7, 0x2a, 0x92, + 0x4a, 0x19, 0xfe, 0xb8, 0x1b, 0x84, 0x66, 0x4f, 0xd4, 0x4b, 0xaa, + 0x94, 0x7f, 0xd1, 0x96, 0x57, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x82, 0x0b, 0xb3, 0x11, 0x1b, 0x4b, 0x86, + 0x5e, 0x19, 0xdb, 0x49, 0xd8, 0x6f, 0xe0, 0x25, 0x6d, 0x33, 0xa3, + 0x42, 0x28, 0x8a, 0x46, 0xe1, 0x36, 0xbb, 0x1a, 0x1c, 0x0b, 0x8b, + 0xa7, 0x25, 0x87, 0xa1, 0x9a, 0x2d, 0xf0, 0xa7, 0x40, 0xb3, 0x0d, + 0x05, 0xfc, 0xe4, 0x33, 0x68, 0xb1, 0xb4, 0x18, 0x3c, 0x29, 0x2b, + 0xb1, 0xd2, 0x3e, 0x2e, 0x4d, 0x1e, 0x74, 0xff, 0x31, 0x34, 0x4c, + 0xd1, 0xee, 0x9d, 0x1e, 0xd7, 0x07, 0x4a, 0x05, 0x4e, 0x4d, 0xb8, + 0x97, 0xe2, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x16, 0xe8, 0xee, 0x35, 0x1a, 0x45, 0x34, 0xd9, 0xd5, 0x33, + 0xb6, 0xb9, 0x33, 0x67, 0x1c, 0x71, 0xe3, 0x37, 0x94, 0xde, 0x8c, + 0x48, 0x40, 0xe3, 0xf3, 0x05, 0xc3, 0xcc, 0x42, 0x8e, 0x04, 0x23, + 0xa9, 0xd7, 0x03, 0x43, 0x8e, 0x92, 0x3b, 0x1f, 0x40, 0xf5, 0xb3, + 0xc3, 0x3a, 0x1a, 0x12, 0x30, 0x0e, 0x78, 0x83, 0xa6, 0xc6, 0x9c, + 0x79, 0xf6, 0x31, 0xba, 0x24, 0x38, 0x27, 0x08, 0x7a, 0x0c, 0xe9, + 0xc2, 0x4e, 0xa7, 0xf6, 0xb5, 0x7a, 0x45, 0x0b, 0xe3, 0xfb}; + uint8_t output[230] = {0}; + + // set up sample description + OEMCrypto_SampleDescription sample = {}; + OEMCrypto_SubSampleDescription subsamples[3]; + subsamples[0].num_bytes_clear = 10; + subsamples[0].num_bytes_encrypted = 50; + subsamples[0].subsample_flags = 1; + subsamples[0].block_offset = 0; + subsamples[1].num_bytes_clear = 10; + subsamples[1].num_bytes_encrypted = 75; + subsamples[1].subsample_flags = 0; + subsamples[1].block_offset = 2; + subsamples[2].num_bytes_clear = 10; + subsamples[2].num_bytes_encrypted = 75; + subsamples[2].subsample_flags = 2; + subsamples[2].block_offset = 13; + sample.subsamples_length = 3; + sample.subsamples = &subsamples[0]; + OEMCrypto_InputOutputPair* iop = &sample.buffers; + iop->input_data = encrypted.data(); + iop->input_data_length = encrypted.size(); + iop->output_descriptor.type = OEMCrypto_BufferType_Clear; + iop->output_descriptor.buffer.clear.clear_buffer = output; + iop->output_descriptor.buffer.clear.clear_buffer_length = clear.size(); + + memcpy(sample.iv, iv.data(), iv.size()); + + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + OPK_OutputBuffer output_buffer = {}; + output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER; + output_buffer.buffer.clear_insecure = output; + output_buffer.size = clear.size(); + size_t output_offset = 0; + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CENC; + WTPI_K1_SymmetricKey_Handle key_handle = NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + result = WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, + &key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + result = WTPI_DecryptSample(key_handle, &sample, &pattern, &output_buffer, + output_offset, cipher_mode); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + for (size_t i = 0; i < clear.size(); i++) { + ASSERT_EQ(clear[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + +TEST(wtpi_tests, simple_decrypt_cbc_1) { + std::vector key = {0x7a, 0x3b, 0xc9, 0xb7, 0xce, 0xb6, 0x96, 0xf5, + 0xb1, 0x50, 0x29, 0xdc, 0x2a, 0x26, 0xd4, 0xbe}; + std::vector iv = {0x1b, 0x2e, 0x62, 0x62, 0x7b, 0x19, 0xc5, 0xba, + 0x68, 0x00, 0x58, 0x9f, 0xca, 0x70, 0xc8, 0x8b}; + std::vector clear = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f}; + std::vector encrypted = {0x1d, 0x4a, 0x20, 0xf4, 0x49, 0x02, + 0x13, 0xad, 0x1e, 0x47, 0xee, 0x44, + 0x36, 0x29, 0x4c, 0xae}; + uint8_t output[32] = {0}; + + // set up sample description + OEMCrypto_SampleDescription sample = {}; + OEMCrypto_SubSampleDescription subsample = {}; + subsample.num_bytes_clear = 0; + subsample.num_bytes_encrypted = 16; + subsample.subsample_flags = 3; + subsample.block_offset = 0; + sample.subsamples_length = 1; + sample.subsamples = &subsample; + OEMCrypto_InputOutputPair* iop = &sample.buffers; + iop->input_data = encrypted.data(); + iop->input_data_length = encrypted.size(); + iop->output_descriptor.type = OEMCrypto_BufferType_Clear; + iop->output_descriptor.buffer.clear.clear_buffer = output; + iop->output_descriptor.buffer.clear.clear_buffer_length = clear.size(); + + memcpy(sample.iv, iv.data(), iv.size()); + + OEMCrypto_CENCEncryptPatternDesc pattern = {3, 7}; + OPK_OutputBuffer output_buffer = {}; + output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER; + output_buffer.buffer.clear_insecure = output; + output_buffer.size = clear.size(); + size_t output_offset = 0; + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CBCS; + WTPI_K1_SymmetricKey_Handle key_handle = NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + + // SetPattern not yet supported + GTEST_SKIP(); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + result = WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, + &key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + result = WTPI_DecryptSample(key_handle, &sample, &pattern, &output_buffer, + output_offset, cipher_mode); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + for (size_t i = 0; i < clear.size(); i++) { + ASSERT_EQ(clear[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + +TEST(wtpi_tests, simple_decrypt_cbc_2) { + std::vector key = {0x0e, 0xe1, 0x08, 0x9c, 0x61, 0x05, 0xf5, 0xb1, + 0x86, 0x9d, 0x46, 0x3e, 0xde, 0x4b, 0xf2, 0xe3}; + std::vector iv = {0x1a, 0x08, 0x96, 0x4c, 0x09, 0x03, 0x3d, 0xad, + 0x6a, 0xf8, 0x72, 0x4d, 0x99, 0x77, 0xcb, 0x93}; + std::vector clear = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, + 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5}; + std::vector encrypted = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x55, + 0x85, 0xde, 0x61, 0xea, 0x4a, 0x03, 0x88, 0xce, 0x04, 0x93, 0xf8, + 0x92, 0x94, 0x77, 0x22, 0x57, 0x38, 0x12, 0x61, 0xb2, 0x04, 0x76, + 0x9e, 0x55, 0x82, 0x81, 0xc5, 0x8d, 0x14, 0xb6, 0x94, 0x01, 0x72, + 0x41, 0xcd, 0xd7, 0xf3, 0x82, 0x47, 0x7d, 0x1c, 0x28, 0x69, 0x14, + 0xb8, 0x17, 0x49, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, + 0x42, 0x43, 0x44, 0x45, 0xed, 0xa2, 0xbf, 0x5b, 0xfc, 0xf3, 0x27, + 0x79, 0x3b, 0xf4, 0x59, 0x76, 0x28, 0x20, 0x2a, 0xf8, 0xdd, 0x82, + 0x9a, 0xa0, 0x55, 0x57, 0x11, 0x9a, 0x1a, 0x41, 0x18, 0x0d, 0xd0, + 0x9f, 0x54, 0x9e, 0xf5, 0x20, 0x52, 0xa1, 0xc6, 0x1b, 0xd6, 0xee, + 0x06, 0xcc, 0x1e, 0x33, 0xa9, 0x2e, 0x1f, 0xc2, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, + 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0xf5, 0xa5, 0xca, 0xf9, 0x0e, 0x46, 0x31, 0x2f, 0xd1, 0x48, + 0xac, 0x9b, 0xae, 0xc5, 0x8b, 0x16, 0x6e, 0x95, 0xdb, 0x66, 0x72, + 0x0c, 0xaa, 0x56, 0x37, 0x55, 0x87, 0x56, 0x51, 0xe2, 0x11, 0x87, + 0xb2, 0x69, 0xa2, 0x3b, 0x44, 0xf9, 0x85, 0x9c, 0x70, 0xfd, 0xb2, + 0xef, 0x7e, 0x56, 0xd9, 0x6c, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5}; + uint8_t output[230] = {0}; + + // set up sample description + OEMCrypto_SampleDescription sample = {}; + OEMCrypto_SubSampleDescription subsamples[3]; + subsamples[0].num_bytes_clear = 10; + subsamples[0].num_bytes_encrypted = 50; + subsamples[0].subsample_flags = 1; + subsamples[0].block_offset = 0; + subsamples[1].num_bytes_clear = 10; + subsamples[1].num_bytes_encrypted = 75; + subsamples[1].subsample_flags = 0; + subsamples[1].block_offset = 0; + subsamples[2].num_bytes_clear = 10; + subsamples[2].num_bytes_encrypted = 75; + subsamples[2].subsample_flags = 2; + subsamples[2].block_offset = 0; + sample.subsamples_length = 3; + sample.subsamples = &subsamples[0]; + OEMCrypto_InputOutputPair* iop = &sample.buffers; + iop->input_data = encrypted.data(); + iop->input_data_length = encrypted.size(); + iop->output_descriptor.type = OEMCrypto_BufferType_Clear; + iop->output_descriptor.buffer.clear.clear_buffer = output; + iop->output_descriptor.buffer.clear.clear_buffer_length = clear.size(); + + memcpy(sample.iv, iv.data(), iv.size()); + + OEMCrypto_CENCEncryptPatternDesc pattern = {3, 7}; + OPK_OutputBuffer output_buffer = {}; + output_buffer.type = OPK_CLEAR_INSECURE_OUTPUT_BUFFER; + output_buffer.buffer.clear_insecure = output; + output_buffer.size = clear.size(); + size_t output_offset = 0; + OEMCryptoCipherMode cipher_mode = OEMCrypto_CipherMode_CBCS; + WTPI_K1_SymmetricKey_Handle key_handle = NULL; + OEMCryptoResult result = OEMCrypto_SUCCESS; + + // SetPattern not yet supported + GTEST_SKIP(); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + result = WTPI_K1_CreateKeyHandle(key.data(), key.size(), CONTENT_KEY, + &key_handle); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + result = WTPI_DecryptSample(key_handle, &sample, &pattern, &output_buffer, + output_offset, cipher_mode); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + + for (size_t i = 0; i < clear.size(); i++) { + ASSERT_EQ(clear[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + + +TEST(wtpi, storage_save_and_load) { + std::vector d1 = {'w', 't', 'p', 'i', 0xF}; + uint8_t* data_in = d1.data(); + size_t in_size = 3; + std::vector data_out(0); + size_t out_size = data_out.size(); + + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_Initialize()); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_PrepareStoredPersistentData()); + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_StorePersistentData(data_in, in_size)); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + WTPI_LoadPersistentData(data_out.data(), &out_size)); + data_out.resize(out_size); + ASSERT_EQ(in_size, out_size); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_LoadPersistentData(data_out.data(), &out_size)); + ASSERT_EQ(memcmp(data_out.data(), data_in, data_out.size()), 0); + + // Do it again + data_out.clear(); + out_size = data_out.size(); + in_size = 5; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_PrepareStoredPersistentData()); + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_StorePersistentData(data_in, in_size)); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + WTPI_LoadPersistentData(data_out.data(), &out_size)); + data_out.resize(out_size); + ASSERT_EQ(in_size, out_size); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_LoadPersistentData(data_out.data(), &out_size)); + ASSERT_EQ(memcmp(data_out.data(), data_in, data_out.size()), 0); + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_Terminate()); +} + +TEST(wtpi, encrypt_and_sign) { + uint32_t context = 0x1234; + std::vector input(32, 0); + for (int i = 0; i < 32; i++) { + input[i] = i; + } + std::vector intermediate(1024, 0); + size_t intermediate_size = intermediate.size(); + std::vector output(32, 0); + size_t output_size = output.size(); + + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_EncryptAndSign(context, input.data(), input.size(), + intermediate.data(), &intermediate_size)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_VerifyAndDecrypt(context, intermediate.data(), + intermediate_size, output.data(), + &output_size)); + + for (size_t i = 0; i < input.size(); i++) { + ASSERT_EQ(input[i], output[i]); + } + +test_abort:; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); +} + + +PORT_TEST(wtpi_tests, "com.android.trusty.widevine.test") diff --git a/oemcrypto/opk/ports/trusty/ta/zuma/rules.mk b/oemcrypto/opk/ports/trusty/ta/zuma/rules.mk new file mode 100644 index 0000000..f47b20a --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/zuma/rules.mk @@ -0,0 +1,22 @@ + +# Copyright (C) 2020 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Same as GS201 build +# TODO: refactor build files to add hdcp +WIDEVINE_SOC_MODEL_NAME ?= ZUMA + +THIS_DIR := $(GET_LOCAL_DIR) +include $(THIS_DIR)/../gs201/rules.mk diff --git a/oemcrypto/opk/ports/trusty/ta/zuma/wtpi_hdcp.c b/oemcrypto/opk/ports/trusty/ta/zuma/wtpi_hdcp.c new file mode 100644 index 0000000..990d779 --- /dev/null +++ b/oemcrypto/opk/ports/trusty/ta/zuma/wtpi_hdcp.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "wtpi_hdcp_interface.h" + +#define TLOG_TAG "widevine" + +hwhdcp_session_t hwhdcp_session = INVALID_IPC_HANDLE; + +int system_specific_get_max_hdcp_level(OEMCrypto_HDCP_Capability* max_level) { + if (hwhdcp_session == INVALID_IPC_HANDLE) { + int rc = hwhdcp_open(&hwhdcp_session); + if (rc) { + TLOGE("Open hwhdcp session failed. (%d)\n", rc); + return rc; + } + } + + *max_level = hwhdcp_get_max_cap(hwhdcp_session); + return 0; +} + +int system_specific_get_current_hdcp_level( + OEMCrypto_HDCP_Capability* cur_level) { + if (hwhdcp_session == INVALID_IPC_HANDLE) { + int rc = hwhdcp_open(&hwhdcp_session); + if (rc) { + TLOGE("Open hwhdcp session failed. (%d)\n", rc); + return rc; + } + } + + *cur_level = hwhdcp_get_current_cap(hwhdcp_session); + return 0; +} + +int system_specific_set_hdcp_level(OEMCrypto_HDCP_Capability request_level) { + if (hwhdcp_session == INVALID_IPC_HANDLE) { + int rc = hwhdcp_open(&hwhdcp_session); + if (rc) { + TLOGE("Open hwhdcp session failed. (%d)\n", rc); + return rc; + } + } + + return hwhdcp_set_cp_level(hwhdcp_session, request_level); +} + +OEMCryptoResult WTPI_SetHDCPLevel(OEMCrypto_HDCP_Capability level) { + if (0 != system_specific_set_hdcp_level(level)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + return OEMCrypto_SUCCESS; +} + +OEMCrypto_HDCP_Capability WTPI_CurrentHDCPCapability(void) { + OEMCrypto_HDCP_Capability current_level; + return system_specific_get_current_hdcp_level(¤t_level) + ? HDCP_NO_DIGITAL_OUTPUT + : current_level; +} + +OEMCrypto_HDCP_Capability WTPI_MaxHDCPCapability(void) { + OEMCrypto_HDCP_Capability max_level; + return system_specific_get_max_hdcp_level(&max_level) + ? HDCP_NO_DIGITAL_OUTPUT + : max_level; +} diff --git a/oemcrypto/opk/serialization/common/GEN_common_serializer.c b/oemcrypto/opk/serialization/common/GEN_common_serializer.c index 4cbac92..fed33e1 100644 --- a/oemcrypto/opk/serialization/common/GEN_common_serializer.c +++ b/oemcrypto/opk/serialization/common/GEN_common_serializer.c @@ -274,6 +274,18 @@ bool Is_Valid_OEMCrypto_BCCType(uint32_t value) { } } +bool Is_Valid_OEMCrypto_BCCSignatureType(uint32_t value) { + switch (value) { + case 0: /* OEMCrypto_BCCSigType_Unknown */ + case 1: /* OEMCrypto_BCCSigType_CBOR */ + case 2: /* OEMCrypto_BCCSigType_PKCS7 */ + case 3: /* OEMCrypto_BCCSigType_Keybox */ + return true; + default: + return false; + } +} + bool Is_Valid_OEMCrypto_WatermarkingSupport(uint32_t value) { switch (value) { case 0: /* OEMCrypto_WatermarkingError */ @@ -664,21 +676,6 @@ void OPK_UnpackNullable_OEMCrypto_DestBufferDesc( OPK_Unpack_OEMCrypto_DestBufferDesc(msg, NULL); } } -void OPK_PackNullable_uint8_t(ODK_Message* msg, const uint8_t* value) { - OPK_PackBoolValue(msg, value == NULL); - if (value) { - OPK_Pack_uint8_t(msg, value); - } -} -void OPK_UnpackNullable_uint8_t(ODK_Message* msg, uint8_t** value) { - if (OPK_UnpackIsNull(msg)) { - if (value) *value = NULL; - } else if (value) { - OPK_Unpack_uint8_t(msg, *value); - } else { - OPK_Unpack_uint8_t(msg, NULL); - } -} void OPK_PackNullable_uint16_t(ODK_Message* msg, const uint16_t* value) { OPK_PackBoolValue(msg, value == NULL); if (value) { diff --git a/oemcrypto/opk/serialization/common/GEN_common_serializer.h b/oemcrypto/opk/serialization/common/GEN_common_serializer.h index 4242946..62bbd10 100644 --- a/oemcrypto/opk/serialization/common/GEN_common_serializer.h +++ b/oemcrypto/opk/serialization/common/GEN_common_serializer.h @@ -32,6 +32,7 @@ bool Is_Valid_OEMCrypto_HDCP_Capability(uint32_t value); bool Is_Valid_OEMCrypto_DTCP2_Capability(uint32_t value); bool Is_Valid_OEMCrypto_ProvisioningMethod(uint32_t value); bool Is_Valid_OEMCrypto_BCCType(uint32_t value); +bool Is_Valid_OEMCrypto_BCCSignatureType(uint32_t value); bool Is_Valid_OEMCrypto_WatermarkingSupport(uint32_t value); bool Is_Valid_OEMCrypto_SignatureHashAlgorithm(uint32_t value); bool Is_Valid_OEMCrypto_IdleState(uint32_t value); @@ -100,8 +101,6 @@ void OPK_PackNullable_OEMCrypto_DestBufferDesc( ODK_Message* msg, const OEMCrypto_DestBufferDesc* value); void OPK_UnpackNullable_OEMCrypto_DestBufferDesc( ODK_Message* msg, OEMCrypto_DestBufferDesc** value); -void OPK_PackNullable_uint8_t(ODK_Message* msg, const uint8_t* value); -void OPK_UnpackNullable_uint8_t(ODK_Message* msg, uint8_t** value); void OPK_PackNullable_uint16_t(ODK_Message* msg, const uint16_t* value); void OPK_UnpackNullable_uint16_t(ODK_Message* msg, uint16_t** value); void OPK_UnpackAlloc_uint16_t(ODK_Message* msg, uint16_t** value); diff --git a/oemcrypto/opk/serialization/common/common_special_cases.c b/oemcrypto/opk/serialization/common/common_special_cases.c index 9748104..96c0cbe 100644 --- a/oemcrypto/opk/serialization/common/common_special_cases.c +++ b/oemcrypto/opk/serialization/common/common_special_cases.c @@ -119,7 +119,7 @@ void OPK_Unpack_OEMCrypto_InputOutputPair(ODK_Message* msg, OPK_ToLengthType(obj->input_data_length), /* map */ true, /* is_output */ false); OPK_Unpack_OEMCrypto_DestBufferDesc(msg, &obj->output_descriptor); - memcpy(&obj->input_data, &input_data, sizeof(input_data)); + obj->input_data = input_data; } void OPK_Pack_OEMCrypto_SampleDescription( @@ -186,5 +186,5 @@ void OPK_Unpack_OEMCrypto_SampleDescription(ODK_Message* msg, } } - memcpy(&obj->subsamples, &subsamples, sizeof(subsamples)); + obj->subsamples = subsamples; } diff --git a/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c b/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c index 0d401c2..f3f99f3 100644 --- a/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c +++ b/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.c @@ -1390,7 +1390,7 @@ cleanup_and_return: } OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapClearPrivateKey( - const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + const uint8_t* clear_private_key, size_t clear_private_key_length, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length) { pthread_mutex_lock(&api_lock); OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1399,7 +1399,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapClearPrivateKey( API_Initialize(); request = OPK_Pack_WrapClearPrivateKey_Request( - clear_private_key_bytes, clear_private_key_length, wrapped_private_key, + clear_private_key, clear_private_key_length, 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) { @@ -1426,6 +1426,40 @@ cleanup_and_return: return result; } +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GetBCCSignatureType(OEMCrypto_BCCSignatureType* bcc_signature_type) { + 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_GetBCCSignatureType_Request(bcc_signature_type); + 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); + if (api_result != OEMCrypto_SUCCESS) goto cleanup_and_return; + OPK_Unpack_GetBCCSignatureType_Response(&response, &result, + &bcc_signature_type); + + 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_GetKeyData(uint8_t* key_data, size_t* key_data_length) { pthread_mutex_lock(&api_lock); diff --git a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c index 942d19e..b217ae7 100644 --- a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c +++ b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.c @@ -1448,7 +1448,7 @@ void OPK_Unpack_GetDeviceID_Response(ODK_Message* msg, OEMCryptoResult* result, } ODK_Message OPK_Pack_WrapClearPrivateKey_Request( - const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + const uint8_t* clear_private_key, size_t clear_private_key_length, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length) { uint32_t api_value = 154; /* from _oecc154 */ @@ -1456,9 +1456,10 @@ ODK_Message OPK_Pack_WrapClearPrivateKey_Request( OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); OPK_Pack_uint64_t(&msg, ×tamp); - OPK_PackNullable_size_t(&msg, wrapped_private_key_length); - OPK_PackNullable_uint8_t(&msg, clear_private_key_bytes); OPK_Pack_size_t(&msg, &clear_private_key_length); + OPK_PackNullable_size_t(&msg, wrapped_private_key_length); + OPK_PackMemory(&msg, (const uint8_t*)clear_private_key, + OPK_ToLengthType(clear_private_key_length)); OPK_PackAlloc(&msg, wrapped_private_key); OPK_PackEOM(&msg); OPK_SharedBuffer_FinalizePacking(); @@ -1492,6 +1493,47 @@ void OPK_Unpack_WrapClearPrivateKey_Response( } } +ODK_Message OPK_Pack_GetBCCSignatureType_Request( + const OEMCrypto_BCCSignatureType* bcc_signature_type) { + uint32_t api_value = 156; /* from _oecc156 */ + 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, bcc_signature_type); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetBCCSignatureType_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_BCCSignatureType** bcc_signature_type) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 156) + 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); + } + if (SuccessResult(*result)) { + OPK_UnpackNullable_uint32_t(msg, bcc_signature_type); + if (*bcc_signature_type) { + if (!Is_Valid_OEMCrypto_BCCSignatureType(**bcc_signature_type)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + } + } else { + OPK_UnpackNullable_uint32_t(msg, NULL); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_GetKeyData_Request(const uint8_t* key_data, const size_t* key_data_length) { uint32_t api_value = 4; /* from _oecc4 */ diff --git a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h index 702cdf7..2ef8a55 100644 --- a/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h +++ b/oemcrypto/opk/serialization/ree/GEN_ree_serializer.h @@ -208,12 +208,17 @@ void OPK_Unpack_GetDeviceID_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** device_id, size_t** device_id_length); ODK_Message OPK_Pack_WrapClearPrivateKey_Request( - const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + const uint8_t* clear_private_key, size_t clear_private_key_length, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length); void OPK_Unpack_WrapClearPrivateKey_Response( ODK_Message* msg, OEMCryptoResult* result, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length); +ODK_Message OPK_Pack_GetBCCSignatureType_Request( + const OEMCrypto_BCCSignatureType* bcc_signature_type); +void OPK_Unpack_GetBCCSignatureType_Response( + ODK_Message* msg, OEMCryptoResult* result, + OEMCrypto_BCCSignatureType** bcc_signature_type); ODK_Message OPK_Pack_GetKeyData_Request(const uint8_t* key_data, const size_t* key_data_length); void OPK_Unpack_GetKeyData_Response(ODK_Message* msg, OEMCryptoResult* result, diff --git a/oemcrypto/opk/serialization/tee/GEN_dispatcher.c b/oemcrypto/opk/serialization/tee/GEN_dispatcher.c index 31ac2f8..38237f0 100644 --- a/oemcrypto/opk/serialization/tee/GEN_dispatcher.c +++ b/oemcrypto/opk/serialization/tee/GEN_dispatcher.c @@ -911,32 +911,44 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, } case 154: /* OEMCrypto_WrapClearPrivateKey */ { + size_t clear_private_key_length; + OPK_Init_size_t((size_t*)&clear_private_key_length); size_t* wrapped_private_key_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); if (wrapped_private_key_length == NULL) goto handle_out_of_memory; OPK_Init_size_t(wrapped_private_key_length); - uint8_t* clear_private_key_bytes = - (uint8_t*)OPK_VarAlloc(sizeof(uint8_t)); - if (clear_private_key_bytes == NULL) goto handle_out_of_memory; - OPK_Init_uint8_t((uint8_t*)clear_private_key_bytes); - size_t clear_private_key_length; - OPK_Init_size_t((size_t*)&clear_private_key_length); + uint8_t* clear_private_key; + OPK_InitPointer((uint8_t**)&clear_private_key); uint8_t* wrapped_private_key; OPK_InitPointer((uint8_t**)&wrapped_private_key); OPK_Unpack_WrapClearPrivateKey_Request( - request, &clear_private_key_bytes, &clear_private_key_length, + request, &clear_private_key, &clear_private_key_length, &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("WrapClearPrivateKey"); result = OEMCrypto_WrapClearPrivateKey( - clear_private_key_bytes, clear_private_key_length, - wrapped_private_key, wrapped_private_key_length); + clear_private_key, clear_private_key_length, wrapped_private_key, + wrapped_private_key_length); *response = OPK_Pack_WrapClearPrivateKey_Response( result, wrapped_private_key, wrapped_private_key_length); break; } + case 156: /* OEMCrypto_GetBCCSignatureType */ + { + OEMCrypto_BCCSignatureType* bcc_signature_type; + OPK_InitPointer((uint8_t**)&bcc_signature_type); + OPK_Unpack_GetBCCSignatureType_Request(request, &bcc_signature_type); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetBCCSignatureType"); + result = OEMCrypto_GetBCCSignatureType(bcc_signature_type); + *response = + OPK_Pack_GetBCCSignatureType_Response(result, bcc_signature_type); + break; + } case 4: /* OEMCrypto_GetKeyData */ { size_t* key_data_length = (size_t*)OPK_VarAlloc(sizeof(size_t)); diff --git a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c index 9e13e2a..7614f33 100644 --- a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c +++ b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.c @@ -1216,7 +1216,7 @@ ODK_Message OPK_Pack_GetDeviceID_Response(OEMCryptoResult result, } void OPK_Unpack_WrapClearPrivateKey_Request( - ODK_Message* msg, uint8_t** clear_private_key_bytes, + ODK_Message* msg, uint8_t** clear_private_key, size_t* clear_private_key_length, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length) { uint32_t api_value = UINT32_MAX; @@ -1225,9 +1225,10 @@ void OPK_Unpack_WrapClearPrivateKey_Request( ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); - OPK_UnpackNullable_size_t(msg, wrapped_private_key_length); - OPK_UnpackNullable_uint8_t(msg, clear_private_key_bytes); OPK_Unpack_size_t(msg, clear_private_key_length); + OPK_UnpackNullable_size_t(msg, wrapped_private_key_length); + OPK_UnpackInPlace(msg, (uint8_t**)clear_private_key, + OPK_FromSizeTPtr(clear_private_key_length)); *wrapped_private_key = (uint8_t*)OPK_UnpackAllocBuffer( msg, OPK_FromSizeTPtrPtr(wrapped_private_key_length), sizeof(uint8_t)); OPK_UnpackEOM(msg); @@ -1251,6 +1252,33 @@ ODK_Message OPK_Pack_WrapClearPrivateKey_Response( return msg; } +void OPK_Unpack_GetBCCSignatureType_Request( + ODK_Message* msg, OEMCrypto_BCCSignatureType** bcc_signature_type) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 156) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *bcc_signature_type = + (uint32_t*)OPK_UnpackAlloc(msg, sizeof(OEMCrypto_BCCSignatureType)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetBCCSignatureType_Response( + OEMCryptoResult result, + const OEMCrypto_BCCSignatureType* bcc_signature_type) { + uint32_t api_value = 156; /* from _oecc156 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_uint32_t(&msg, bcc_signature_type); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_GetKeyData_Request(ODK_Message* msg, uint8_t** key_data, size_t** key_data_length) { uint32_t api_value = UINT32_MAX; diff --git a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h index abdf124..11629f1 100644 --- a/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h +++ b/oemcrypto/opk/serialization/tee/GEN_tee_serializer.h @@ -211,12 +211,17 @@ ODK_Message OPK_Pack_GetDeviceID_Response(OEMCryptoResult result, const uint8_t* device_id, const size_t* device_id_length); void OPK_Unpack_WrapClearPrivateKey_Request( - ODK_Message* msg, uint8_t** clear_private_key_bytes, + ODK_Message* msg, uint8_t** clear_private_key, size_t* clear_private_key_length, uint8_t** wrapped_private_key, size_t** wrapped_private_key_length); ODK_Message OPK_Pack_WrapClearPrivateKey_Response( OEMCryptoResult result, const uint8_t* wrapped_private_key, const size_t* wrapped_private_key_length); +void OPK_Unpack_GetBCCSignatureType_Request( + ODK_Message* msg, OEMCrypto_BCCSignatureType** bcc_signature_type); +ODK_Message OPK_Pack_GetBCCSignatureType_Response( + OEMCryptoResult result, + const OEMCrypto_BCCSignatureType* bcc_signature_type); void OPK_Unpack_GetKeyData_Request(ODK_Message* msg, uint8_t** key_data, size_t** key_data_length); ODK_Message OPK_Pack_GetKeyData_Response(OEMCryptoResult result, diff --git a/oemcrypto/test/GEN_api_lock_file.c b/oemcrypto/test/GEN_api_lock_file.c index 63165bd..5985206 100644 --- a/oemcrypto/test/GEN_api_lock_file.c +++ b/oemcrypto/test/GEN_api_lock_file.c @@ -438,3 +438,6 @@ OEMCryptoResult _oecc153(OEMCrypto_SESSION session); // OEMCrypto_SetSessionUsage defined in v18.7 OEMCryptoResult _oecc155(OEMCrypto_SESSION session, uint32_t intent, uint32_t mode); + +// OEMCrypto_GetBCCSignatureType defined in v19.4 +OEMCryptoResult _oecc156(OEMCrypto_BCCSignatureType* bcc_signature_type); diff --git a/oemcrypto/test/common.mk b/oemcrypto/test/common.mk index 8f8b7d7..2e9cb1b 100644 --- a/oemcrypto/test/common.mk +++ b/oemcrypto/test/common.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES:= \ oemcrypto_generic_crypto_test.cpp \ oemcrypto_license_test.cpp \ oemcrypto_provisioning_test.cpp \ + oemcrypto_security_test.cpp \ oemcrypto_usage_table_test.cpp \ oemcrypto_test.cpp \ oemcrypto_test_android.cpp \ @@ -33,6 +34,7 @@ LOCAL_SRC_FILES:= \ ../util/src/device_info_validator.cpp \ ../util/src/oemcrypto_ecc_key.cpp \ ../util/src/oemcrypto_rsa_key.cpp \ + ../util/src/prov4_validation_helper.cpp \ ../util/src/signed_csr_payload_validator.cpp \ ../util/src/wvcrc.cpp \ diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index fe303fc..6cb7aac 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -17,6 +17,7 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { switch (dest_buffer->type) { case OEMCrypto_BufferType_Clear: dest_buffer->buffer.clear.clear_buffer += bytes; + dest_buffer->buffer.clear.clear_buffer_length -= bytes; break; case OEMCrypto_BufferType_Secure: @@ -98,11 +99,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( const size_t length = subsample.num_bytes_clear + subsample.num_bytes_encrypted; fake_sample.buffers.input_data_length = length; - if (fake_sample.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = - length; - } fake_sample.subsamples = &subsample; fake_sample.subsamples_length = 1; @@ -148,11 +144,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.num_bytes_clear > 0) { fake_sample.buffers.input_data_length = subsample.num_bytes_clear; - if (fake_sample.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = - subsample.num_bytes_clear; - } fake_subsample.num_bytes_clear = subsample.num_bytes_clear; fake_subsample.num_bytes_encrypted = 0; fake_subsample.block_offset = 0; @@ -176,11 +167,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample( if (subsample.num_bytes_encrypted > 0) { fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted; - if (fake_sample.buffers.output_descriptor.type == - OEMCrypto_BufferType_Clear) { - fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length = - subsample.num_bytes_encrypted; - } fake_subsample.num_bytes_clear = 0; fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted; fake_subsample.block_offset = subsample.block_offset; diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index 4141942..3f2ee9a 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -287,6 +287,7 @@ class ProvisioningRoundTrip OEMCryptoResult LoadResponse() override { return LoadResponse(session_); } OEMCryptoResult LoadResponse(Session* session) override; void VerifyLoadFailed(); + const std::vector& request() { return request_; } const std::vector& encoded_rsa_key() { return encoded_rsa_key_; } const std::vector& wrapped_rsa_key() { return wrapped_rsa_key_; } void set_allowed_schemes(uint32_t allowed_schemes) { diff --git a/oemcrypto/test/oemcrypto_basic_test.cpp b/oemcrypto/test/oemcrypto_basic_test.cpp index 36dccb9..879aab8 100644 --- a/oemcrypto/test/oemcrypto_basic_test.cpp +++ b/oemcrypto/test/oemcrypto_basic_test.cpp @@ -73,6 +73,76 @@ int32_t JsmnAncestorCount(const std::vector& tokens, } return count; } + +const char* BoolName(bool value) { return value ? "true" : "false"; } +const char* SecurityLevelName(OEMCrypto_Security_Level value) { + switch (value) { + case OEMCrypto_Level_Unknown: + return "OEMCrypto_Level_Unknown"; + case OEMCrypto_Level1: + return "OEMCrypto_Level1"; + case OEMCrypto_Level2: + return "OEMCrypto_Level2"; + case OEMCrypto_Level3: + return "OEMCrypto_Level3"; + } + // Not reachable unless the enum value is invalid + return ""; +} +const char* HDCPCapabilityName(OEMCrypto_HDCP_Capability value) { + switch (value) { + case HDCP_NONE: + return "HDCP_NONE"; + case HDCP_V1: + return "HDCP_V1"; + case HDCP_V1_0: + return "HDCP_V1_0"; + case HDCP_V1_1: + return "HDCP_V1_1"; + case HDCP_V1_2: + return "HDCP_V1_2"; + case HDCP_V1_3: + return "HDCP_V1_3"; + case HDCP_V1_4: + return "HDCP_V1_4"; + case HDCP_V2: + return "HDCP_V2"; + case HDCP_V2_1: + return "HDCP_V2_1"; + case HDCP_V2_2: + return "HDCP_V2_2"; + case HDCP_V2_3: + return "HDCP_V2_3"; + case HDCP_NO_DIGITAL_OUTPUT: + return "HDCP_NO_DIGITAL_OUTPUT"; + } + // Not reachable unless the enum value is invalid + return ""; +} +const char* WatermarkingSupportName(OEMCrypto_WatermarkingSupport value) { + switch (value) { + case OEMCrypto_WatermarkingError: + return "OEMCrypto_WatermarkingError"; + case OEMCrypto_WatermarkingNotSupported: + return "OEMCrypto_WatermarkingNotSupported"; + case OEMCrypto_WatermarkingConfigurable: + return "OEMCrypto_WatermarkingConfigurable"; + case OEMCrypto_WatermarkingAlwaysOn: + return "OEMCrypto_WatermarkingAlwaysOn"; + } + // Not reachable unless the enum value is invalid + return ""; +} +const char* DTCP2CapabiityName(OEMCrypto_DTCP2_Capability value) { + switch (value) { + case OEMCrypto_NO_DTCP2: + return "OEMCrypto_NO_DTCP2"; + case OEMCrypto_DTCP2_V1: + return "OEMCrypto_DTCP2_V1"; + } + // Not reachable unless the enum value is invalid + return ""; +} } // namespace void OEMCryptoClientTest::SetUp() { @@ -148,6 +218,11 @@ OEMCryptoResult OEMCryptoClientTest::CopyBuffer( dest_buffer_descriptor, subsample_flags); } +void OEMCryptoClientTest::RecordWvProperty(const std::string& key, + const std::string& value) { + RecordProperty("widevine_metadata_oec_" + key, value); +} + const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { switch (value) { case HDCP_NONE: @@ -174,9 +249,9 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { return "HDCP version 2.3"; case HDCP_NO_DIGITAL_OUTPUT: return "No HDCP device attached/using local display with secure path"; - default: - return ""; } + // Not reachable unless the enum value is invalid + return ""; } // Return a printable string from data. If all the characters are printable, @@ -242,40 +317,55 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 19.3. Tests last updated 2024-09-04"; + "OEMCrypto unit tests for API 19.4. Tests last updated 2024-11-04"; cout << " " << log_message << "\n"; cout << " " << "These tests are part of Android V." << "\n"; LOGI("%s", log_message.c_str()); // If any of the following fail, then it is time to update the log message // above. EXPECT_EQ(ODK_MAJOR_VERSION, 19); - EXPECT_EQ(ODK_MINOR_VERSION, 3); + EXPECT_EQ(ODK_MINOR_VERSION, 4); EXPECT_EQ(kCurrentAPI, static_cast(ODK_MAJOR_VERSION)); + RecordWvProperty("test_major_version", std::to_string(ODK_MAJOR_VERSION)); + RecordWvProperty("test_minor_version", std::to_string(ODK_MINOR_VERSION)); + OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel(); EXPECT_GT(level, OEMCrypto_Level_Unknown); EXPECT_LE(level, OEMCrypto_Level3); cout << " OEMCrypto Security Level is L" << level << endl; + RecordWvProperty("security_level", SecurityLevelName(level)); + uint32_t version = OEMCrypto_APIVersion(); uint32_t minor_version = OEMCrypto_MinorAPIVersion(); cout << " OEMCrypto API version is " << version << "." << minor_version << endl; + RecordWvProperty("major_version", std::to_string(version)); + RecordWvProperty("minor_version", std::to_string(minor_version)); + cout << " OEMCrypto Device ID is '" << GetDeviceId() << "'" << endl; - if (OEMCrypto_SupportsUsageTable()) { + const bool supports_usage_tables = OEMCrypto_SupportsUsageTable(); + if (supports_usage_tables) { cout << " OEMCrypto supports usage tables" << endl; } else { cout << " OEMCrypto does not support usage tables" << endl; } + RecordWvProperty("supports_usage_tables", BoolName(supports_usage_tables)); + if (version >= 15) { const uint32_t tier = OEMCrypto_ResourceRatingTier(); cout << " Resource Rating Tier: " << tier << endl; + RecordWvProperty("resource_rating_tier", std::to_string(tier)); } + if (version >= 17) { OEMCryptoResult sts = OEMCrypto_ProductionReady(); if (sts != OEMCrypto_SUCCESS) { LOGW("Device is not production ready, returns %d", sts); } + RecordWvProperty("is_production_ready", BoolName(sts == OEMCrypto_SUCCESS)); + std::string build_info; size_t buf_length = 0; sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); @@ -287,6 +377,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { if (build_info.size() != buf_length) { build_info.resize(buf_length); } + RecordWvProperty("build_info", build_info); const std::string comma = ","; const std::string pretty_comma = ",\n "; std::string::size_type pos = 0; @@ -295,9 +386,12 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { pos += pretty_comma.size(); } cout << " BuildInformation: " << build_info << endl; + OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport(); cout << " WatermarkingSupport: " << support << endl; + RecordWvProperty("watermarking_support", WatermarkingSupportName(support)); } + ASSERT_GE(version, 8u); ASSERT_LE(version, kCurrentAPI); } @@ -317,8 +411,9 @@ TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) { TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) { OEMCrypto_ProvisioningMethod provisioning_method = OEMCrypto_GetProvisioningMethod(); - cout << " Provisioning method = " - << ProvisioningMethodName(provisioning_method) << endl; + const char* const name = ProvisioningMethodName(provisioning_method); + cout << " Provisioning method = " << name << endl; + RecordWvProperty("provisioning_method", name); ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method); } @@ -331,6 +426,8 @@ TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) { static_cast(current), HDCPCapabilityAsString(current)); printf(" Maximum HDCP Capability: 0x%02x = %s.\n", static_cast(maximum), HDCPCapabilityAsString(maximum)); + RecordWvProperty("hdcp_current", HDCPCapabilityName(current)); + RecordWvProperty("hdcp_max", HDCPCapabilityName(maximum)); } TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { @@ -339,11 +436,15 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version); if (current_result == OEMCrypto_SUCCESS) { printf(" Current SRM Version: %d.\n", version); + RecordWvProperty("srm_supported", BoolName(true)); + RecordWvProperty("srm_version", std::to_string(version)); EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr)); } else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) { printf(" Current SRM Status: Local Display Only.\n"); + RecordWvProperty("srm_supported", BoolName(false)); } else { EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result); + RecordWvProperty("srm_supported", BoolName(false)); } } @@ -586,6 +687,9 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { {"is_debug", JSMN_PRIMITIVE}, }; + // The prefix of every field name when logged to RecordWvProperty. + const std::string kBuildInfoRecordPrefix = "build_info_"; + // A set of the required fields found when examining the // build information, use to verify all fields are present. std::set found_required_fields; @@ -612,11 +716,17 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { << "Unexpected required field type: field = " << key << ", build_info = " << build_info; found_required_fields.insert(key); + RecordWvProperty(kBuildInfoRecordPrefix + key, + build_info.substr(value_token.start, + value_token.end - value_token.start)); } else if (kOptionalFields.find(key) != kOptionalFields.end()) { ASSERT_EQ(value_token.type, kOptionalFields.at(key)) << "Unexpected optional field type: field = " << key << ", build_info = " << build_info; - } // Do not validate vendor fields. + RecordWvProperty(kBuildInfoRecordPrefix + key, + build_info.substr(value_token.start, + value_token.end - value_token.start)); + } // Do not validate or record vendor fields. if (key == kSpecialCaseReeKey) { // Store the tokens of the "ree" field for additional validation. @@ -657,6 +767,11 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { // If no "ree" field tokens, then end here. if (!has_ree_info) return; // Step 4a: Verify "ree" object scheme. + + // The prefix of every REE field name when logged to RecordWvProperty. + const std::string kReeBuildInfoRecordPrefix = + kBuildInfoRecordPrefix + kSpecialCaseReeKey + "_"; + ASSERT_FALSE(ree_tokens.empty()) << "REE field was specified, but contents were empty: build_info = " << build_info; @@ -686,7 +801,10 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) { << "Unexpected optional REE field type: ree_field = " << key << ", build_info = " << build_info; found_required_fields.insert(key); - } // Do not validate vendor fields. + RecordWvProperty(kReeBuildInfoRecordPrefix + key, + build_info.substr(value_token.start, + value_token.end - value_token.start)); + } // Do not validate or record vendor fields. // Skip potential nested tokens. i += JsmnAncestorCount(ree_tokens, i + 1); @@ -722,6 +840,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum); ASSERT_EQ(OEMCrypto_SUCCESS, sts); printf(" Max Number of Sessions: %zu.\n", maximum); + RecordWvProperty("max_number_of_sessions", std::to_string(maximum)); size_t required_max = GetResourceValue(kMaxConcurrentSession); ASSERT_GE(maximum, required_max); } @@ -729,6 +848,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) { const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize(); printf(" Max Usage Table Size: %zu.\n", maximum); + RecordWvProperty("max_usage_table_size", std::to_string(maximum)); // A maximum of 0 means the table is constrained by dynamic memory allocation. if (maximum > 0) { ASSERT_GE(maximum, RequiredUsageSize()); @@ -765,6 +885,7 @@ TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) { "DTCP2 is supported.\n"); break; } + RecordWvProperty("dtcp2_capability", DTCP2CapabiityName(capability)); } // diff --git a/oemcrypto/test/oemcrypto_basic_test.h b/oemcrypto/test/oemcrypto_basic_test.h index 2cbe235..303ee4a 100644 --- a/oemcrypto/test/oemcrypto_basic_test.h +++ b/oemcrypto/test/oemcrypto_basic_test.h @@ -35,6 +35,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { size_t input_buffer_size, const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, uint8_t subsample_flags); + void RecordWvProperty(const std::string& key, const std::string& value); }; } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_cast_test.cpp b/oemcrypto/test/oemcrypto_cast_test.cpp index 2a6e019..6cf2be3 100644 --- a/oemcrypto/test/oemcrypto_cast_test.cpp +++ b/oemcrypto/test/oemcrypto_cast_test.cpp @@ -5,8 +5,6 @@ #include "oemcrypto_cast_test.h" -#include "oemcrypto_usage_table_test.h" - using ::testing::Range; namespace wvoec { @@ -260,18 +258,8 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); - // The application will compute the SHA-1 Hash of the message, so this - // test must do that also. - uint8_t hash[SHA_DIGEST_LENGTH]; - if (!SHA1(message.data(), message.size(), hash)) { - dump_boringssl_error(); - FAIL() << "boringssl error creating SHA1 hash."; - } - - // The application will prepend the digest info to the hash. - // SHA-1 digest info prefix = 0x30 0x21 0x30 ... - vector digest = wvutil::a2b_hex("3021300906052b0e03021a05000414"); - digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH); + vector digest; + ASSERT_NO_FATAL_FAILURE(PrepareCastDigestedMessage(message, digest)); // OEMCrypto will apply the padding, and encrypt to generate the // signature. @@ -1019,5 +1007,6 @@ TEST_P(OEMCryptoSessionTestLoadCasKeysWithHDCP, CasOnlyLoadCasKeysAPI17) { } INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP, Range(1, 6)); + /// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_cast_test.h b/oemcrypto/test/oemcrypto_cast_test.h index 3317fb7..0aa0491 100644 --- a/oemcrypto/test/oemcrypto_cast_test.h +++ b/oemcrypto/test/oemcrypto_cast_test.h @@ -14,6 +14,7 @@ #include "OEMCryptoCENC.h" #include "oemcrypto_provisioning_test.h" #include "oemcrypto_session_tests_helper.h" +#include "oemcrypto_usage_table_test.h" namespace wvoec { @@ -22,6 +23,25 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value); // This test attempts to use alternate algorithms for loaded device certs. class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { protected: + // The message to be signed by OEMCrypto_GenerateRSASignature() starts with a + // constant digest info prefix followed by a SHA-1 hash of the message. + void PrepareCastDigestedMessage(const std::vector& message, + std::vector& digest) { + // The application will compute the SHA-1 Hash of the message, so this + // test must do that also. + uint8_t hash[SHA_DIGEST_LENGTH]; + if (!SHA1(message.data(), message.size(), hash)) { + dump_boringssl_error(); + FAIL() << "boringssl error creating SHA1 hash."; + } + // The application will prepend the digest info to the hash. + // SHA-1 digest info prefix = 0x30 0x21 0x30 ... + static const std::vector prefix = + wvutil::a2b_hex("3021300906052b0e03021a05000414"); + digest.insert(digest.end(), prefix.begin(), prefix.end()); + digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH); + } + void TestSignature(RSA_Padding_Scheme scheme, size_t size) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); @@ -29,16 +49,19 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { vector licenseRequest(size); GetRandBytes(licenseRequest.data(), licenseRequest.size()); + vector digested_message; + ASSERT_NO_FATAL_FAILURE( + PrepareCastDigestedMessage(licenseRequest, digested_message)); size_t signature_length = 0; OEMCryptoResult sts = OEMCrypto_GenerateRSASignature( - s.session_id(), licenseRequest.data(), licenseRequest.size(), nullptr, - &signature_length, scheme); + s.session_id(), digested_message.data(), digested_message.size(), + nullptr, &signature_length, scheme); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); std::vector signature(signature_length, 0); sts = OEMCrypto_GenerateRSASignature( - s.session_id(), licenseRequest.data(), licenseRequest.size(), + s.session_id(), digested_message.data(), digested_message.size(), signature.data(), &signature_length, scheme); ASSERT_EQ(OEMCrypto_SUCCESS, sts) @@ -48,7 +71,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo( encoded_rsa_key_.data(), encoded_rsa_key_.size())); ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature( - licenseRequest, signature.data(), signature_length, scheme)); + digested_message, signature.data(), signature_length, scheme)); } // If force is true, we assert that the key loads successfully. diff --git a/oemcrypto/test/oemcrypto_decrypt_test.cpp b/oemcrypto/test/oemcrypto_decrypt_test.cpp index 6dcf901..34a2647 100644 --- a/oemcrypto/test/oemcrypto_decrypt_test.cpp +++ b/oemcrypto/test/oemcrypto_decrypt_test.cpp @@ -13,6 +13,9 @@ using ::testing::Values; namespace wvoec { +/// @addtogroup decrypt +/// @{ + // Cannot decrypt without first getting a key handle. TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutGettingAHandle) { ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -658,4 +661,5 @@ TEST_P(OEMCryptoLicenseTest, KeyDuration) { INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest, Range(kCurrentAPI - 2, kCurrentAPI + 1)); +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_license_test.cpp b/oemcrypto/test/oemcrypto_license_test.cpp index 18031c4..9ad5542 100644 --- a/oemcrypto/test/oemcrypto_license_test.cpp +++ b/oemcrypto/test/oemcrypto_license_test.cpp @@ -5,6 +5,8 @@ #include "oemcrypto_license_test.h" +#include + #include "platform.h" #include "test_sleep.h" @@ -769,6 +771,7 @@ TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) { TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { uint8_t patch_level = OEMCrypto_Security_Patch_Level(); printf(" Current Patch Level: %u.\n", patch_level); + RecordWvProperty("security_patch_level", std::to_string(patch_level)); { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); diff --git a/oemcrypto/test/oemcrypto_provisioning_test.cpp b/oemcrypto/test/oemcrypto_provisioning_test.cpp index 37b2777..a34a534 100644 --- a/oemcrypto/test/oemcrypto_provisioning_test.cpp +++ b/oemcrypto/test/oemcrypto_provisioning_test.cpp @@ -5,6 +5,10 @@ #include "oemcrypto_provisioning_test.h" +#include + +#include + #include "bcc_validator.h" #include "device_info_validator.h" #include "log.h" @@ -15,6 +19,9 @@ namespace wvoec { +/// @addtogroup provision +/// @{ + // This test is used to print the device ID to stdout. TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { OEMCryptoResult sts; @@ -24,6 +31,7 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl; + RecordWvProperty("device_id", wvutil::HexEncode(dev_id, dev_id_len)); } TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) { @@ -53,8 +61,12 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { sts = OEMCrypto_GetKeyData(key_data, &key_data_len); uint32_t* data = reinterpret_cast(key_data); + const uint32_t system_id = htonl(data[1]); + const uint32_t version = htonl(data[0]); printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n", - htonl(data[1]), htonl(data[1]), htonl(data[0])); + system_id, system_id, version); + RecordWvProperty("system_id", std::to_string(system_id)); + RecordWvProperty("key_data_version", std::to_string(version)); ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -91,6 +103,8 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) { dev_id.resize(dev_id_len); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) << " len = " << dev_id_len << endl; + RecordWvProperty("device_id", + wvutil::HexEncode(dev_id.data(), dev_id.size())); } // The OEM certificate must be valid. @@ -241,6 +255,35 @@ TEST_F(OEMCryptoProv40Test, GetBootCertificateChainSuccess) { EXPECT_EQ(util::CborMessageStatus::kCborValidateOk, validator.Validate()); } +// Verifies BCC signature and its type if they are available. +TEST_F(OEMCryptoProv40Test, AdditionalBccSignature) { + std::vector bcc; + size_t bcc_size = 0; + std::vector additional_signature; + size_t additional_signature_size = 0; + ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size, + additional_signature.data(), + &additional_signature_size), + OEMCrypto_ERROR_SHORT_BUFFER); + + bcc.resize(bcc_size); + additional_signature.resize(additional_signature_size); + ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size, + additional_signature.data(), + &additional_signature_size), + OEMCrypto_SUCCESS); + OEMCrypto_BCCSignatureType bcc_signature_type; + const OEMCryptoResult result = + OEMCrypto_GetBCCSignatureType(&bcc_signature_type); + if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) return; + ASSERT_EQ(result, OEMCrypto_SUCCESS); + if (!additional_signature.empty()) { + ASSERT_NE(bcc_signature_type, OEMCrypto_BCCSigType_Unknown); + } else { + ASSERT_EQ(bcc_signature_type, OEMCrypto_BCCSigType_Unknown); + } +} + // Verifies that short buffer error returns when the buffer is short. TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairShortBuffer) { Session s; @@ -546,13 +589,13 @@ TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) { wrapped_private_key2.resize(wrapped_private_key_size2); // Verify public_key_signature2 with public_key1. - if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) { + if (key_type1 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) { ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromSubjectPublicKey( public_key1.data(), public_key1.size())); ASSERT_NO_FATAL_FAILURE( s.VerifyRsaSignature(public_key2, public_key_signature2.data(), public_key_signature2.size(), kSign_RSASSA_PSS)); - } else if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) { + } else if (key_type1 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) { ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey( public_key1.data(), public_key1.size())); ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2, @@ -620,6 +663,8 @@ TEST_F(OEMCryptoProv40Test, GetDeviceId) { dev_id.resize(dev_id_len); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) << " len = " << dev_id_len << endl; + RecordWvProperty("device_id", + wvutil::HexEncode(dev_id.data(), dev_id.size())); // Device id should be stable. Query again. std::vector dev_id2(dev_id_len); sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len); @@ -1282,4 +1327,5 @@ TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) { << "Supported certificates is only " << OEMCrypto_SupportedCertificates(); } +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_security_test.cpp b/oemcrypto/test/oemcrypto_security_test.cpp index ca853d4..5f08000 100644 --- a/oemcrypto/test/oemcrypto_security_test.cpp +++ b/oemcrypto/test/oemcrypto_security_test.cpp @@ -23,14 +23,14 @@ #include #include -// TODO(b/253779846) Change it to include a header instead -#include "oemcrypto_test.cpp" +#include "oemcrypto_basic_test.h" +#include "oemcrypto_cast_test.h" +#include "oemcrypto_decrypt_test.h" +#include "oemcrypto_license_test.h" +#include "oemcrypto_provisioning_test.h" +#include "oemcrypto_usage_table_test.h" -using ::testing::Bool; -using ::testing::Combine; using ::testing::Range; -using ::testing::tuple; -using ::testing::Values; using ::testing::WithParamInterface; using namespace std; @@ -39,6 +39,136 @@ namespace wvoec { /// @addtogroup security /// @{ +class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests, + public WithParamInterface { + public: + OEMCryptoLicenseOverflowTest() : license_api_version_(kCurrentAPI) {} + + void SetUp() override { + OEMCryptoSessionTests::SetUp(); + license_api_version_ = GetParam(); + } + + void TearDown() override { OEMCryptoSessionTests::TearDown(); } + + void TestLoadLicenseForHugeBufferLengths( + const std::function f, bool check_status, + bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + s.open(); + InstallTestDrmKey(&s); + bool verify_keys_loaded = true; + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make the license message big enough so that updated core message + // substring offset and length values from tests are still able to read + // data from license_message buffer rather than reading some garbage + // data. + license_messages.set_message_size( + sizeof(license_messages.response_data()) + message_length); + } + f(message_length, &license_messages); + if (update_core_message_substring_values) { + // We will be updating offset for these tests, which will cause verify + // keys to fail with an assertion. Hence skipping verification. + verify_keys_loaded = false; + } + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = + license_messages.LoadResponse(&s, verify_keys_loaded); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + const std::function f) { + Session s; + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + s.open(); + InstallTestDrmKey(&s); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + size_t message_length = sizeof(license_messages.response_data()); + f(message_length, &license_messages); + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = license_messages.LoadResponse(); + s.close(); + // Verifying error is not due to signature failure which can be caused due + // to test code. + ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); + ASSERT_NE(OEMCrypto_SUCCESS, result); + } + + protected: + uint32_t license_api_version_; +}; + +// This class is for testing a single license with the default API version +// of 16. Used for buffer overflow tests. +class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { + public: + OEMCryptoMemoryLicenseTest() : entitled_message_(&license_messages_) {} + + void SetUp() override { + OEMCryptoLicenseTestAPI16::SetUp(); + SetUpEntitledMessage(); + entitlement_response_length_ = entitled_message_.entitled_key_data_size(); + } + + void LoadLicense() { + 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()); + } + + void SetUpEntitledMessage() { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + LoadLicense(); + entitled_message_.FillKeyArray(); + entitled_message_.EncryptContentKey(); + uint32_t key_session_id = 0; + OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + return; + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + entitled_message_.SetEntitledKeySession(key_session_id); + } + + void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } + + protected: + EntitledMessage entitled_message_; + size_t entitlement_response_length_; + + void TestLoadEntitledKeysForHugeBufferLengths( + const std::function f, + bool check_status) { + size_t entitled_key_data_size = entitled_message_.entitled_key_data_size(); + vector message(entitled_key_data_size); + memcpy(message.data(), entitled_message_.entitled_key_data(), + entitled_key_data_size); + auto oemcrypto_function = [&](size_t length) { + // Make entitled message big enough so that updated substring offset and + // length fields by core message substring tests can still be able to read + // valid data from entitled message buffer rather than some garbage data. + message.resize(entitled_key_data_size + length); + f(length, &entitled_message_); + return entitled_message_.LoadKeys(message); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } +}; + /** Test that OEMCrypto_FreeSecureBuffer fails gracefully on a huge buffer. */ TEST_F(OEMCryptoClientTest, @@ -102,7 +232,7 @@ TEST_F(OEMCryptoClientTest, TEST_F(OEMCryptoClientTest, OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeTransportKey) { auto oemcrypto_function = [](size_t transport_key_length) { - size_t wrapped_keybox_length = sizeof(&kTestKeybox) + 50; + size_t wrapped_keybox_length = sizeof(kTestKeybox) + 50; vector wrapped_keybox_buffer(wrapped_keybox_length); vector transport_key_buffer(transport_key_length); return OEMCrypto_WrapKeyboxOrOEMCert( @@ -315,51 +445,11 @@ TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForHugeIdLength) { TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } -/** Test that OEMCrypto_GenerateDerivedKeys fails gracefully on a huge buffer. - */ -TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryGenerateDerivedKeysForHugeMacContextLength) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - vector mac_context; - vector enc_context; - s.FillDefaultContext(&mac_context, &enc_context); - - auto oemcrypto_function = [&s, &mac_context, - &enc_context](size_t buffer_length) { - mac_context.resize(buffer_length); - return OEMCrypto_GenerateDerivedKeys(s.session_id(), mac_context.data(), - mac_context.size(), enc_context.data(), - enc_context.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - -/** Test that OEMCrypto_GenerateDerivedKeys fails gracefully on a huge buffer. - */ -TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryGenerateDerivedKeysForHugeEncContextLength) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - vector mac_context; - vector enc_context; - s.FillDefaultContext(&mac_context, &enc_context); - - auto oemcrypto_function = [&s, &mac_context, - &enc_context](size_t buffer_length) { - enc_context.resize(buffer_length); - return OEMCrypto_GenerateDerivedKeys(s.session_id(), mac_context.data(), - mac_context.size(), enc_context.data(), - enc_context.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); -} - /** Test that OEMCrypto_GetOEMPublicCertificate fails gracefully on a huge * buffer. */ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { - if (wrapped_rsa_key_.size() == 0) { + if (wrapped_drm_key_.size() == 0) { // If we don't have a wrapped key yet, create one. // This wrapped key will be shared by all sessions in the test. ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); @@ -367,7 +457,7 @@ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); // Install the DRM Cert's RSA key. - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); ASSERT_NO_FATAL_FAILURE(s.SetTestRsaPublicKey()); auto oemcrypto_function = [](size_t input_length) { @@ -463,9 +553,12 @@ TEST_F(OEMCryptoSessionTests, license_messages.SignAndVerifyRequest(); license_messages.CreateDefaultResponse(); license_messages.EncryptAndSignResponse(); + const std::vector context = s.GetDefaultContext(); vector signature(signature_size); OEMCryptoResult result = OEMCrypto_LoadLicense( - s.session_id(), license_messages.encrypted_response_buffer().data(), + s.session_id(), context.data(), context.size(), + s.enc_session_key().data(), s.enc_session_key().size(), + license_messages.encrypted_response_buffer().data(), license_messages.encrypted_response_buffer().size(), license_messages.serialized_core_message().size(), signature.data(), signature_size); @@ -593,29 +686,12 @@ TEST_F(OEMCryptoSessionTests, TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } -/** This test verifies that OEMCrypto_SetDecryptHash doesn't crash for a very - large hash buffer. -*/ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryDecryptHashForHugeHashBuffer) { - uint32_t session_id = session_.session_id(); - auto f = [session_id]() { - const uint32_t frame_number = 1; - const uint32_t crc32 = 0; - return OEMCrypto_SetDecryptHash(session_id, frame_number, crc32); - }; - TestHugeLengthDoesNotCrashAPI(f, kCheckStatus); -} - /** Test Decrypt fails gracefully for huge input. */ TEST_P(OEMCryptoSessionTestsDecryptTests, OEMCryptoMemoryDecryptCENCForHugeNumberOfSubSamples) { auto oemcrypto_function = [&](size_t number_of_subsamples) { - std::vector subsample_sizes; - while (number_of_subsamples-- > 0) { - subsample_sizes.push_back({1, 1}); - } - SetSubsampleSizes(subsample_sizes); + std::vector subsample_sizes(number_of_subsamples, {1, 1}); + SetSubsampleSizes(std::move(subsample_sizes)); LoadLicense(); MakeBuffers(); EncryptData(); @@ -639,13 +715,10 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, TEST_P(OEMCryptoSessionTestsDecryptTests, OEMCryptoMemoryDecryptCENCForHugeNumberOfSamples) { auto oemcrypto_function = [&](size_t number_of_samples) { - std::vector> samples; - std::vector subsample_sizes; - subsample_sizes.push_back({1, 1}); - while (number_of_samples-- > 0) { - samples.push_back(subsample_sizes); - } - SetSampleSizes(samples); + std::vector subsample_sizes(1, {1, 1}); + std::vector> sample_sizes(number_of_samples, + subsample_sizes); + SetSampleSizes(std::move(sample_sizes)); LoadLicense(); MakeBuffers(); EncryptData(); @@ -686,18 +759,20 @@ TEST_F(OEMCryptoLoadsCertificate, size_t wrapped_private_key_length = 0; // Find wrapped_private_key_length. OEMCrypto_LoadProvisioning( - s.session_id(), + s.session_id(), provisioning_messages.request().data(), + provisioning_messages.request().size(), provisioning_messages.encrypted_response_buffer().data(), provisioning_messages.encrypted_response_buffer().size(), provisioning_messages.serialized_core_message().size(), signature.data(), signature_size, nullptr, &wrapped_private_key_length); - std::vector wrapped_rsa_key(wrapped_private_key_length); + std::vector wrapped_private_key(wrapped_private_key_length); OEMCryptoResult result = OEMCrypto_LoadProvisioning( - s.session_id(), + s.session_id(), provisioning_messages.request().data(), + provisioning_messages.request().size(), provisioning_messages.encrypted_response_buffer().data(), provisioning_messages.encrypted_response_buffer().size(), provisioning_messages.serialized_core_message().size(), - signature.data(), signature_size, wrapped_rsa_key.data(), + signature.data(), signature_size, wrapped_private_key.data(), &wrapped_private_key_length); s.close(); return result; @@ -725,7 +800,8 @@ TEST_F(OEMCryptoLoadsCertificate, size_t wrapped_private_key_length = buffer_length; vector wrapped_private_key(wrapped_private_key_length); OEMCryptoResult result = OEMCrypto_LoadProvisioning( - s.session_id(), + s.session_id(), provisioning_messages.request().data(), + provisioning_messages.request().size(), provisioning_messages.encrypted_response_buffer().data(), provisioning_messages.encrypted_response_buffer().size(), provisioning_messages.serialized_core_message().size(), @@ -749,21 +825,21 @@ TEST_F(OEMCryptoLoadsCertificate, GTEST_SKIP() << "Test for non Prov 4.0 devices only."; } ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); - auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + auto oemcrypto_function = [&](size_t wrapped_drm_key_length) { Session s; s.open(); - vector wrapped_rsa_key_buffer = wrapped_rsa_key_; - wrapped_rsa_key_buffer.resize(wrapped_rsa_key_length); + vector wrapped_drm_key_buffer = wrapped_drm_key_; + wrapped_drm_key_buffer.resize(wrapped_drm_key_length); OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( s.session_id(), OEMCrypto_RSA_Private_Key, - wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + wrapped_drm_key_buffer.data(), wrapped_drm_key_buffer.size()); s.close(); return result; }; // It is hard to generate varying length valid wrapped rsa key with valid // signature. Hence we just call function with random data and do not check // status to test API with varying length wrapped rsa key. - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, wrapped_rsa_key_.size(), + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, wrapped_drm_key_.size(), kHugeInputBufferLength, !kCheckStatus); } @@ -779,13 +855,13 @@ TEST_F( GTEST_SKIP() << "Test for non Prov 4.0 devices only."; } ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey()); - auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + auto oemcrypto_function = [&](size_t wrapped_drm_key_length) { Session s; s.open(); - vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + vector wrapped_drm_key_buffer(wrapped_drm_key_length); OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( s.session_id(), OEMCrypto_RSA_Private_Key, - wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + wrapped_drm_key_buffer.data(), wrapped_drm_key_buffer.size()); s.close(); return result; }; @@ -795,71 +871,316 @@ TEST_F( TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } -/** Test that OEMCrypto_LoadDRMPrivateKey fails gracefully on a huge buffer. +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on huge buffer. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key = + provisioning_messages->core_response().enc_private_key; + enc_private_key.length = + response_message_length - enc_private_key.offset + 1; + }); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key = + provisioning_messages->core_response().enc_private_key; + enc_private_key.offset = + response_message_length - enc_private_key.length + 1; + }); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLengthAPI16) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key_iv = + provisioning_messages->core_response().enc_private_key_iv; + enc_private_key_iv.length = + response_message_length - enc_private_key_iv.offset + 1; + }); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key_iv = + provisioning_messages->core_response().enc_private_key_iv; + enc_private_key_iv.offset = + response_message_length - enc_private_key_iv.length + 1; + }); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLengthProv30) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { + GTEST_SKIP() << "Test for Prov 3.0 devices only."; + } + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& encrypted_message_key = + provisioning_messages->core_response().encrypted_message_key; + encrypted_message_key.length = + response_message_length - encrypted_message_key.offset + 1; + }); +} + +/** Test that LoadProvisioning fails gracefully on out of range substring. */ +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffsetProv30) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { + GTEST_SKIP() << "Test for Prov 3.0 devices only."; + } + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& encrypted_message_key = + provisioning_messages->core_response().encrypted_message_key; + encrypted_message_key.offset = + response_message_length - encrypted_message_key.length + 1; + }); +} + +/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a + * huge buffer. */ -TEST_F(OEMCryptoUsesCertificate, - OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeMacContext) { - vector session_key; - vector enc_session_key; - ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key)); - vector mac_context; - vector enc_context; - session_.FillDefaultContext(&mac_context, &enc_context); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [&session_id, &enc_context, &mac_context, - &enc_session_key](size_t buffer_length) { - mac_context.resize(buffer_length); - return OEMCrypto_DeriveKeysFromSessionKey( - session_id, enc_session_key.data(), enc_session_key.size(), - mac_context.data(), mac_context.size(), enc_context.data(), - enc_context.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + kCheckStatus); } -/** Test that OEMCrypto_DeriveKeysFromSessionKey fails gracefully on a huge - * buffer. */ -TEST_F(OEMCryptoUsesCertificate, - OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncContext) { - vector session_key; - vector enc_session_key; - ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key)); - vector mac_context; - vector enc_context; - session_.FillDefaultContext(&mac_context, &enc_context); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [&session_id, &enc_context, &mac_context, - &enc_session_key](size_t buffer_length) { - enc_context.resize(buffer_length); - return OEMCrypto_DeriveKeysFromSessionKey( - session_id, enc_session_key.data(), enc_session_key.size(), - mac_context.data(), mac_context.size(), enc_context.data(), - enc_context.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a + * huge buffer. + */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_request_signature_size(message_size); + }, + !kCheckStatus); } -/** Test that OEMCrypto_DeriveKeysFromSessionKey fails gracefully on a huge - * buffer. */ -TEST_F(OEMCryptoUsesCertificate, - OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncSessionKey) { - vector session_key; - vector enc_session_key; - ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key)); - vector mac_context; - vector enc_context; - session_.FillDefaultContext(&mac_context, &enc_context); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [&session_id, &session_key, &enc_context, - &mac_context, - &enc_session_key](size_t buffer_length) { - session_key.resize(buffer_length); - return OEMCrypto_DeriveKeysFromSessionKey( - session_id, enc_session_key.data(), enc_session_key.size(), - mac_context.data(), mac_context.size(), enc_context.data(), - enc_context.size()); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a + * huge buffer. + */ +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) { + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!global_features.loads_certificate || + global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + } + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + kCheckStatus); } /** Test that OEMCrypto_GenerateRSASignature fails gracefully on a huge @@ -882,7 +1203,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, // If the key did load, then it should be processed correctly. Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); vector message_buffer(10); size_t signature_length = 0; @@ -924,7 +1245,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, // If the key did load, then it should be processed correctly. Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); vector message_buffer(50); vector signature; @@ -965,9 +1286,7 @@ TEST_P(OEMCryptoGenericCryptoTest, session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC, key_handle)); - OEMCrypto_SESSION session_id = session_.session_id(); - auto& iv = iv_; - auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { + auto oemcrypto_function = [&key_handle, &iv = iv_](size_t buffer_length) { vector buffer(buffer_length); return OEMCrypto_Generic_Encrypt( key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv, @@ -987,9 +1306,7 @@ TEST_P(OEMCryptoGenericCryptoTest, session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC, key_handle); - OEMCrypto_SESSION session_id = session_.session_id(); - auto iv = iv_; - auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { + auto oemcrypto_function = [&key_handle, &iv = iv_](size_t buffer_length) { vector encrypted(buffer_length); vector resultant(encrypted.size()); @@ -1013,12 +1330,10 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { GetKeyHandleIntoVector(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC), - key_handle); + OEMCrypto_CipherMode_CENC, key_handle)); vector signature(SHA256_DIGEST_LENGTH); size_t signature_length = signature.size(); - OEMCrypto_SESSION session_id = session_.session_id(); - auto oemcrypto_function = [&session_id, &signature, + auto oemcrypto_function = [&key_handle, &signature, &signature_length](size_t buffer_length) { vector buffer(buffer_length); return OEMCrypto_Generic_Sign( @@ -1039,19 +1354,16 @@ TEST_P(OEMCryptoGenericCryptoTest, GetKeyHandleIntoVector(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CENC), - key_handle); - OEMCrypto_SESSION session_id = session_.session_id(); - auto clear_buffer = clear_buffer_; - auto oemcrypto_function = [&session_id, - &clear_buffer](size_t signature_length) { - vector signature(signature_length); - size_t gen_signature_length = signature_length; - return OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), - clear_buffer.data(), clear_buffer.size(), - OEMCrypto_HMAC_SHA256, signature.data(), - &gen_signature_length); - }; + OEMCrypto_CipherMode_CENC, key_handle)); + auto oemcrypto_function = + [&key_handle, &clear_buffer = clear_buffer_](size_t signature_length) { + vector signature(signature_length); + size_t gen_signature_length = signature_length; + return OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(), + clear_buffer.data(), clear_buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + &gen_signature_length); + }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } @@ -1093,9 +1405,7 @@ TEST_P(OEMCryptoGenericCryptoTest, session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC, key_handle)); - OEMCrypto_SESSION session_id = session_.session_id(); - auto clear_buffer = clear_buffer_; - auto oemcrypto_function = [&session_id, &clear_buffer, + auto oemcrypto_function = [&key_handle, &clear_buffer = clear_buffer_, &signature](size_t signature_length) { return OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(), clear_buffer.data(), clear_buffer.size(), @@ -1340,6 +1650,632 @@ TEST_P(OEMCryptoUsageTableTest, }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } -/// @} +/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) { + auto& content_key_id = + entitled_message_.entitled_key_array()[0].content_key_id; + content_key_id.length = + entitlement_response_length_ - content_key_id.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) { + auto& content_key_id = + entitled_message_.entitled_key_array()[0].content_key_id; + content_key_id.offset = + entitlement_response_length_ - content_key_id.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test that LoadEntitledContentKeys fails gracefully on huge substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) { + auto& entitlement_key_id = + entitled_message_.entitled_key_array()[0].entitlement_key_id; + entitlement_key_id.length = + entitlement_response_length_ - entitlement_key_id.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { + auto& entitlement_key_id = + entitled_message_.entitled_key_array()[0].entitlement_key_id; + entitlement_key_id.offset = + entitlement_response_length_ - entitlement_key_id.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t content_key_data_iv_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data_iv.length = + content_key_data_iv_length; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data_iv.offset = + content_key_data_iv_offset; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) { + auto& content_key_data_iv = + entitled_message_.entitled_key_array()[0].content_key_data_iv; + content_key_data_iv.length = + entitlement_response_length_ - content_key_data_iv.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) { + auto& content_key_data_iv = + entitled_message_.entitled_key_array()[0].content_key_data_iv; + content_key_data_iv.offset = + entitlement_response_length_ - content_key_data_iv.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t content_key_data_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data.length = + content_key_data_length; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t content_key_data_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data.offset = + content_key_data_offset; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) { + auto& content_key_data = + entitled_message_.entitled_key_array()[0].content_key_data; + content_key_data.length = + entitlement_response_length_ - content_key_data.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) { + auto& content_key_data = + entitled_message_.entitled_key_array()[0].content_key_data; + content_key_data.offset = + entitlement_response_length_ - content_key_data.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->entitlement_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test LoadEntitledContentKeys rejects out of range substring. */ +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->content_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +/** Test that LoadLicense fails gracefully on huge buffer. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.length = length; + license_messages->response_data().keys[0].key_id_length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_id = license_messages->core_response().key_array[0].key_id; + key_id.length = response_message_length - key_id.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_id = license_messages->core_response().key_array[0].key_id; + key_id.offset = response_message_length - key_id.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data_iv = + license_messages->core_response().key_array[0].key_data_iv; + key_data_iv.length = response_message_length - key_data_iv.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data_iv = + license_messages->core_response().key_array[0].key_data_iv; + key_data_iv.offset = response_message_length - key_data_iv.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.length = length; + license_messages->response_data().keys[0].key_data_length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data = + license_messages->core_response().key_array[0].key_data; + key_data.length = response_message_length - key_data.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data = + license_messages->core_response().key_array[0].key_data; + key_data.offset = response_message_length - key_data.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLengthAPI16) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control_iv = + license_messages->core_response().key_array[0].key_control_iv; + key_control_iv.length = + response_message_length - key_control_iv.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control_iv = + license_messages->core_response().key_array[0].key_control_iv; + key_control_iv.offset = + response_message_length - key_control_iv.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLengthAPI16) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control = + license_messages->core_response().key_array[0].key_control; + key_control.length = response_message_length - key_control.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control = + license_messages->core_response().key_array[0].key_control; + key_control.offset = response_message_length - key_control.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys_iv = + license_messages->core_response().enc_mac_keys_iv; + enc_mac_keys_iv.length = + response_message_length - enc_mac_keys_iv.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys_iv = + license_messages->core_response().enc_mac_keys_iv; + enc_mac_keys_iv.offset = + response_message_length - enc_mac_keys_iv.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; + enc_mac_keys.length = response_message_length - enc_mac_keys.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; + enc_mac_keys.offset = response_message_length - enc_mac_keys.length + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.length = response_message_length - pst.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.offset = response_message_length; + if (pst.length == 0) pst.length = 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& srm_restriction_data = + license_messages->core_response().srm_restriction_data; + srm_restriction_data.length = + response_message_length - srm_restriction_data.offset + 1; + }); +} + +/** Test that LoadLicense fails gracefully on out of range substring. */ +TEST_P( + OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](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; + if (srm_restriction_data.length == 0) srm_restriction_data.length = 1; + }); +} + +/** Test that LoadLicense fails gracefully on huge buffer. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeResponseLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +/** Test that LoadLicense fails gracefully on huge buffer. */ +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); + +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index ab245ce..cba7379 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -18,36 +18,39 @@ * be skipped. * * @defgroup license License Request Tests - * Test for requesting and loading licenses. + * Test for requesting and loading licenses. * - * @defgroup renewal License Renewal Tests - * Tests for renewing licenses. + * @defgroup renewal License Renewal Tests + * Tests for renewing licenses. * - * @defgroup decrypt Decrypt Tests - * Tests for decrypting content. + * @defgroup decrypt Decrypt Tests + * Tests for decrypting content. * - * @defgroup usage_table Usage Table Tests - * Tests that use the usage table. + * @defgroup usage_table Usage Table Tests + * Tests that use the usage table. * - * @defgroup entitle Entitlement License tests - * Tests for entitlement licenses. + * @defgroup entitle Entitlement License tests + * Tests for entitlement licenses. * - * @defgroup cas Conditional Access System Tests - * Tests for OEMCrypto implementations that support MediaCAS. + * @defgroup cas Conditional Access System Tests + * Tests for OEMCrypto implementations that support MediaCAS. * - * @defgroup cast Cast Test - * Tests for OEMCrypto implementations that support being a Cast receiver. + * @defgroup cast Cast Test + * Tests for OEMCrypto implementations that support being a Cast receiver. * - * @defgroup generic Generic Crypto Tests - * Tests for the Generic Crypto functionality. + * @defgroup android Android Tests + * Tests that enforce requirements that are specific to Android. * - * @defgroup security Security Tests - * Buffer overflow tests, off-by-one tests, and other security tests. + * @defgroup generic Generic Crypto Tests + * Tests for the Generic Crypto functionality. * - * The way the huge buffer tests work is to create a large buffer and then call - * the API. The test then loops and doubles the buffer until the API returns an - * error. An error is considered a passing test. We expect OEMCrypto to fail - * gracefully on a huge buffer rather than crashing. + * @defgroup security Security Tests + * Buffer overflow tests, off-by-one tests, and other security tests. + * + * The way the huge buffer tests work is to create a large buffer and then call + * the API. The test then loops and doubles the buffer until the API returns an + * error. An error is considered a passing test. We expect OEMCrypto to fail + * gracefully on a huge buffer rather than crashing. */ #include @@ -94,7 +97,6 @@ using ::testing::Range; using ::testing::tuple; -using ::testing::WithParamInterface; using namespace std; namespace std { // GTest wants PrintTo to be in the std namespace. @@ -129,141 +131,6 @@ void PrintTo(const tuple { - public: - OEMCryptoLicenseOverflowTest() : license_api_version_(kCurrentAPI) {} - - void SetUp() override { - OEMCryptoSessionTests::SetUp(); - license_api_version_ = GetParam(); - } - - void TearDown() override { OEMCryptoSessionTests::TearDown(); } - - void TestLoadLicenseForHugeBufferLengths( - const std::function f, bool check_status, - bool update_core_message_substring_values) { - auto oemcrypto_function = [&](size_t message_length) { - Session s; - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - s.open(); - InstallTestDrmKey(&s); - bool verify_keys_loaded = true; - license_messages.SignAndVerifyRequest(); - license_messages.CreateDefaultResponse(); - if (update_core_message_substring_values) { - // Make the license message big enough so that updated core message - // substring offset and length values from tests are still able to read - // data from license_message buffer rather than reading some garbage - // data. - license_messages.set_message_size( - sizeof(license_messages.response_data()) + message_length); - } - f(message_length, &license_messages); - if (update_core_message_substring_values) { - // We will be updating offset for these tests, which will cause verify - // keys to fail with an assertion. Hence skipping verification. - verify_keys_loaded = false; - } - license_messages.EncryptAndSignResponse(); - OEMCryptoResult result = - license_messages.LoadResponse(&s, verify_keys_loaded); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } - - void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - const std::function f) { - Session s; - LicenseRoundTrip license_messages(&s); - license_messages.set_api_version(license_api_version_); - s.open(); - InstallTestDrmKey(&s); - license_messages.SignAndVerifyRequest(); - license_messages.CreateDefaultResponse(); - size_t message_length = sizeof(license_messages.response_data()); - f(message_length, &license_messages); - license_messages.EncryptAndSignResponse(); - OEMCryptoResult result = license_messages.LoadResponse(); - s.close(); - // Verifying error is not due to signature failure which can be caused due - // to test code. - ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); - ASSERT_NE(OEMCrypto_SUCCESS, result); - } - - protected: - uint32_t license_api_version_; -}; - -// This class is for testing a single license with the default API version -// of 16. Used for buffer overflow tests. -class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { - public: - OEMCryptoMemoryLicenseTest() : entitled_message_(&license_messages_) {} - - void SetUp() override { - OEMCryptoLicenseTestAPI16::SetUp(); - SetUpEntitledMessage(); - entitlement_response_length_ = entitled_message_.entitled_key_data_size(); - } - - void LoadLicense() { - 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()); - } - - void SetUpEntitledMessage() { - license_messages_.set_license_type(OEMCrypto_EntitlementLicense); - LoadLicense(); - entitled_message_.FillKeyArray(); - entitled_message_.EncryptContentKey(); - uint32_t key_session_id = 0; - OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession( - session_.session_id(), &key_session_id); - if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { - return; - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - entitled_message_.SetEntitledKeySession(key_session_id); - } - - void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } - - protected: - EntitledMessage entitled_message_; - size_t entitlement_response_length_; - - void TestLoadEntitledKeysForHugeBufferLengths( - const std::function f, - bool check_status) { - size_t entitled_key_data_size = entitled_message_.entitled_key_data_size(); - vector message(entitled_key_data_size); - memcpy(message.data(), entitled_message_.entitled_key_data(), - entitled_key_data_size); - auto oemcrypto_function = [&](size_t length) { - // Make entitled message big enough so that updated substring offset and - // length fields by core message substring tests can still be able to read - // valid data from entitled message buffer rather than some garbage data. - message.resize(entitled_key_data_size + length); - f(length, &entitled_message_); - return entitled_message_.LoadKeys(message); - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } -}; - -/// @} - /// @addtogroup entitle /// @{ @@ -367,214 +234,6 @@ TEST_P(OEMCryptoEntitlementLicenseTest, INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoEntitlementLicenseTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); -/// @} - -/// @addtogroup security -/// @{ - -/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_id.length = - key_id_length; - }, - !kCheckStatus); -} - -/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_offset, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_id.offset = - key_id_offset; - }, - !kCheckStatus); -} - -/** Test that LoadEntitledContentKeys fails gracefully on huge buffer. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) { - auto& content_key_id = - entitled_message_.entitled_key_array()[0].content_key_id; - content_key_id.length = - entitlement_response_length_ - content_key_id.offset + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) { - auto& content_key_id = - entitled_message_.entitled_key_array()[0].content_key_id; - content_key_id.offset = - entitlement_response_length_ - content_key_id.length + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test that LoadEntitledContentKeys fails gracefully on huge substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].entitlement_key_id.length = - key_id_length; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_offset, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].entitlement_key_id.offset = - key_id_offset; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) { - auto& entitlement_key_id = - entitled_message_.entitled_key_array()[0].entitlement_key_id; - entitlement_key_id.length = - entitlement_response_length_ - entitlement_key_id.offset + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { - auto& entitlement_key_id = - entitled_message_.entitled_key_array()[0].entitlement_key_id; - entitlement_key_id.offset = - entitlement_response_length_ - entitlement_key_id.length + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t content_key_data_iv_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_data_iv.length = - content_key_data_iv_length; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_data_iv.offset = - content_key_data_iv_offset; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) { - auto& content_key_data_iv = - entitled_message_.entitled_key_array()[0].content_key_data_iv; - content_key_data_iv.length = - entitlement_response_length_ - content_key_data_iv.offset + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) { - auto& content_key_data_iv = - entitled_message_.entitled_key_array()[0].content_key_data_iv; - content_key_data_iv.offset = - entitlement_response_length_ - content_key_data_iv.length + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t content_key_data_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_data.length = - content_key_data_length; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t content_key_data_offset, EntitledMessage* entitled_message) { - entitled_message->entitled_key_array()[0].content_key_data.offset = - content_key_data_offset; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) { - auto& content_key_data = - entitled_message_.entitled_key_array()[0].content_key_data; - content_key_data.length = - entitlement_response_length_ - content_key_data.offset + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) { - auto& content_key_data = - entitled_message_.entitled_key_array()[0].content_key_data; - content_key_data.offset = - entitlement_response_length_ - content_key_data.length + 1; - ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_data()->entitlement_key_id_length = - key_id_length; - }, - !kCheckStatus); -} - -/** Test LoadEntitledContentKeys rejects out of range substring. */ -TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) { - TestLoadEntitledKeysForHugeBufferLengths( - [](size_t key_id_length, EntitledMessage* entitled_message) { - entitled_message->entitled_key_data()->content_key_id_length = - key_id_length; - }, - !kCheckStatus); -} - -/// @} - -/// @addtogroup entitle -/// @{ - TEST_P(OEMCryptoLicenseTest, GetKeyHandleEntitledKeyAPI17) { if (wvoec::global_features.api_version < 17) { GTEST_SKIP() << "Test for versions 17 and up only."; @@ -849,441 +508,9 @@ TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) { /// @} -/// @addtogroup security -/// @{ - -/** Test that LoadLicense fails gracefully on huge buffer. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_id.length = length; - license_messages->response_data().keys[0].key_id_length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_id.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_id = license_messages->core_response().key_array[0].key_id; - key_id.length = response_message_length - key_id.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_id = license_messages->core_response().key_array[0].key_id; - key_id.offset = response_message_length - key_id.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data_iv.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data_iv.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_data_iv = - license_messages->core_response().key_array[0].key_data_iv; - key_data_iv.length = response_message_length - key_data_iv.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_data_iv = - license_messages->core_response().key_array[0].key_data_iv; - key_data_iv.offset = response_message_length - key_data_iv.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data.length = length; - license_messages->response_data().keys[0].key_data_length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_data.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_data = - license_messages->core_response().key_array[0].key_data; - key_data.length = response_message_length - key_data.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_data = - license_messages->core_response().key_array[0].key_data; - key_data.offset = response_message_length - key_data.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control_iv.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control_iv.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLengthAPI16) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_control_iv = - license_messages->core_response().key_array[0].key_control_iv; - key_control_iv.length = - response_message_length - key_control_iv.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_control_iv = - license_messages->core_response().key_array[0].key_control_iv; - key_control_iv.offset = - response_message_length - key_control_iv.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().key_array[0].key_control.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLengthAPI16) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_control = - license_messages->core_response().key_array[0].key_control; - key_control.length = response_message_length - key_control.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& key_control = - license_messages->core_response().key_array[0].key_control; - key_control.offset = response_message_length - key_control.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys_iv.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys_iv.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& enc_mac_keys_iv = - license_messages->core_response().enc_mac_keys_iv; - enc_mac_keys_iv.length = - response_message_length - enc_mac_keys_iv.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& enc_mac_keys_iv = - license_messages->core_response().enc_mac_keys_iv; - enc_mac_keys_iv.offset = - response_message_length - enc_mac_keys_iv.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().enc_mac_keys.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; - enc_mac_keys.length = response_message_length - enc_mac_keys.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; - enc_mac_keys.offset = response_message_length - enc_mac_keys.length + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().pst.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().pst.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& pst = license_messages->core_response().pst; - pst.length = response_message_length - pst.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& pst = license_messages->core_response().pst; - pst.offset = response_message_length; - if (pst.length == 0) pst.length = 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t length, LicenseRoundTrip* license_messages) { - license_messages->core_response().srm_restriction_data.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { - TestLoadLicenseForHugeBufferLengths( - [](size_t offset, LicenseRoundTrip* license_messages) { - license_messages->core_response().srm_restriction_data.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataLength) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](size_t response_message_length, LicenseRoundTrip* license_messages) { - auto& srm_restriction_data = - license_messages->core_response().srm_restriction_data; - srm_restriction_data.length = - response_message_length - srm_restriction_data.offset + 1; - }); -} - -/** Test that LoadLicense fails gracefully on out of range substring. */ -TEST_P( - OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataOffset) { - TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - [](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; - if (srm_restriction_data.length == 0) srm_restriction_data.length = 1; - }); -} - -/** Test that LoadLicense fails gracefully on huge buffer. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeResponseLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t message_size, LicenseRoundTrip* license_messages) { - license_messages->set_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadLicense fails gracefully on huge buffer. */ -TEST_P(OEMCryptoLicenseOverflowTest, - OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { - TestLoadLicenseForHugeBufferLengths( - [](size_t message_size, LicenseRoundTrip* license_messages) { - license_messages->set_core_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); - -/// @} - /// @addtogroup cas /// @{ + TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) { if (wvoec::global_features.api_version < 17) { GTEST_SKIP() << "Test for versions 17 and up only."; @@ -1538,335 +765,12 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { reinterpret_cast(content_key_id_2), strlen(content_key_id_2))); } + /// @} -/// @addtogroup security +/// @addtogroup cas /// @{ -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_core_message_size(message_size); - }, - !kCheckStatus, !kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t length, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key.length = length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on huge buffer. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key.offset = offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - [](size_t response_message_length, - ProvisioningRoundTrip* provisioning_messages) { - auto& enc_private_key = - provisioning_messages->core_response().enc_private_key; - enc_private_key.length = - response_message_length - enc_private_key.offset + 1; - }); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - [](size_t response_message_length, - ProvisioningRoundTrip* provisioning_messages) { - auto& enc_private_key = - provisioning_messages->core_response().enc_private_key; - enc_private_key.offset = - response_message_length - enc_private_key.length + 1; - }); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t length, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key_iv.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().enc_private_key_iv.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLengthAPI16) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - [](size_t response_message_length, - ProvisioningRoundTrip* provisioning_messages) { - auto& enc_private_key_iv = - provisioning_messages->core_response().enc_private_key_iv; - enc_private_key_iv.length = - response_message_length - enc_private_key_iv.offset + 1; - }); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - [](size_t response_message_length, - ProvisioningRoundTrip* provisioning_messages) { - auto& enc_private_key_iv = - provisioning_messages->core_response().enc_private_key_iv; - enc_private_key_iv.offset = - response_message_length - enc_private_key_iv.length + 1; - }); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t length, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().encrypted_message_key.length = - length; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestLoadProvisioningForHugeBufferLengths( - [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->core_response().encrypted_message_key.offset = - offset; - }, - !kCheckStatus, kUpdateCoreMessageSubstringValues); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLengthProv30) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { - GTEST_SKIP() << "Test for Prov 3.0 devices only."; - } - TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - [](size_t response_message_length, - ProvisioningRoundTrip* provisioning_messages) { - auto& encrypted_message_key = - provisioning_messages->core_response().encrypted_message_key; - encrypted_message_key.length = - response_message_length - encrypted_message_key.offset + 1; - }); -} - -/** Test that LoadProvisioning fails gracefully on out of range substring. */ -TEST_F( - OEMCryptoLoadsCertificate, - OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffsetProv30) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - if (global_features.provisioning_method != OEMCrypto_OEMCertificate) { - GTEST_SKIP() << "Test for Prov 3.0 devices only."; - } - TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( - [](size_t response_message_length, - ProvisioningRoundTrip* provisioning_messages) { - auto& encrypted_message_key = - provisioning_messages->core_response().encrypted_message_key; - encrypted_message_key.offset = - response_message_length - encrypted_message_key.length + 1; - }); -} - -/// @} - -/// @addtogroup security -/// @{ - -/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a - * huge buffer. - */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestPrepareProvisioningRequestForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_message_size(message_size); - }, - kCheckStatus); -} - -/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a - * huge buffer. - */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestPrepareProvisioningRequestForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_request_signature_size(message_size); - }, - !kCheckStatus); -} - -/** Test that OEMCrypto_PrepAndSignProvisioningRequest fails gracefully on a - * huge buffer. - */ -TEST_F(OEMCryptoLoadsCertificate, - OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; - } - TestPrepareProvisioningRequestForHugeBufferLengths( - [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { - provisioning_messages->set_core_message_size(message_size); - }, - kCheckStatus); -} - -/// @} - -/// @addtogroup cast -/// @{ - -/// @} - #ifdef CAS_TEST # include "tuner_hal.h" @@ -1952,4 +856,6 @@ INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoCasDemoTest, Range(kCoreMessagesAPI, kCurrentAPI + 1)); #endif + +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test_android.cpp b/oemcrypto/test/oemcrypto_test_android.cpp index 9f1e891..b23a841 100644 --- a/oemcrypto/test/oemcrypto_test_android.cpp +++ b/oemcrypto/test/oemcrypto_test_android.cpp @@ -21,6 +21,9 @@ namespace wvoec { +/// @addtogroup android +/// @{ + /** These tests are required for LollyPop Android devices.*/ class OEMCryptoAndroidLMPTest : public ::testing::Test { protected: @@ -102,7 +105,7 @@ TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) { } /** Android requires implementation of functions that report how many open - * sesions are available. */ + * sessions are available. */ TEST_F(OEMCryptoAndroidMNCTest, NumberOfSessionsImplemented) { ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, OEMCrypto_GetNumberOfOpenSessions(nullptr)); @@ -126,4 +129,5 @@ TEST_F(OEMCryptoAndroidRVCTest, MinVersionNumber16) { ASSERT_GE(version, 16u); } +/// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 3ccd422..7b2c8ba 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -23,6 +23,7 @@ 'oemcrypto_generic_crypto_test.cpp', 'oemcrypto_license_test.cpp', 'oemcrypto_provisioning_test.cpp', + 'oemcrypto_security_test.cpp', 'oemcrypto_usage_table_test.cpp', 'oemcrypto_test.cpp', '<(jsmn_dir)/jsmn.c', diff --git a/oemcrypto/test/oemcrypto_usage_table_test.cpp b/oemcrypto/test/oemcrypto_usage_table_test.cpp index d9ae34f..bae0c9c 100644 --- a/oemcrypto/test/oemcrypto_usage_table_test.cpp +++ b/oemcrypto/test/oemcrypto_usage_table_test.cpp @@ -10,6 +10,9 @@ using ::testing::Values; namespace wvoec { +/// @addtogroup usage_table +/// @{ + // Test that successive calls to PrepAndSignProvisioningRequest only increase // the provisioning count in the ODK message TEST_F(OEMCryptoSessionTests, Provisioning_IncrementCounterAPI18) { @@ -1810,4 +1813,5 @@ INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest, INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, Values(kCurrentAPI)); +/// @} } // namespace wvoec diff --git a/oemcrypto/util/include/bcc_validator.h b/oemcrypto/util/include/bcc_validator.h index 77c753c..adc84a6 100644 --- a/oemcrypto/util/include/bcc_validator.h +++ b/oemcrypto/util/include/bcc_validator.h @@ -7,15 +7,10 @@ #ifndef WVOEC_UTIL_BCC_VALIDATOR_H_ #define WVOEC_UTIL_BCC_VALIDATOR_H_ -#include - #include -#include -#include #include "cbor_validator.h" -#include "cppbor.h" -#include "wv_class_utils.h" +#include "prov4_validation_helper.h" namespace wvoec { namespace util { @@ -34,11 +29,99 @@ enum BccCurve { kBccP384 = 3 }; +// Android/Widevine Dice Attestation allows two signing models. This is +// identified using MAP_KEY_DEVICE_KEY_ALGORITHM. +enum { + DEVICE_KEY_ALGORITHM_ES256 = -7, // EC key with SHA-256 + DEVICE_KEY_ALGORITHM_EDDSA = -8, // Pure ED25519. + DEVICE_KEY_ALGORITHM_ES384 = -35, // EC key with SHA-384 +}; + +// BCC definition: +// https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl + +// See PubKeyEd25519/PubKeyECDSA256/PubKeyECDSA384 in BCC definition. struct BccPublicKeyInfo { - BccSignatureAlgorithm signature_algorithm; - BccCurve curve; + std::pair key_type; + std::pair signature_algorithm; + std::pair curve; // Raw EC key bytes extracted from BCC - std::vector key_bytes; + std::pair> key_bytes; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + +// protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 +// } +struct BccEntryProtected { + std::pair algorithm; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + +// See ConfigurationDescriptor in BCC definition. +struct ConfigurationDescriptor { + std::pair component_name; + std::pair component_version; + std::pair resettable; // null string + std::pair security_version; + std::pair vm_marker; // null string + std::string ToString() const; + // Validate ConfigurationDescriptor and set |is_widevine_entry| to true if the + // component_name is "widevine". Caller ensures that |is_widevine_entry| is + // not null. + CborMessageStatus Validate( + std::vector>& msgs, + bool* is_widevine_entry) const; +}; + +// See DiceChainEntryPayload in BCC definition. +struct BccEntryPayload { + std::pair issuer; + std::pair subject; + std::pair profile_name; + std::pair subject_public_key; + std::pair> key_usage; + std::pair> code_hash; + std::pair> code_descriptor; + std::pair> config_hash; + std::pair config_descriptor; + std::pair> authority_hash; + std::pair> authority_descriptor; + std::pair> mode; + std::string ToString() const; + // Validate BccEntryPayload and set |is_widevine_entry| to true if the payload + // contains a Widevine certificate. Caller ensures that |is_widevine_entry| is + // not null. + CborMessageStatus Validate( + std::vector>& msgs, + bool is_degenerated, bool* is_widevine_entry) const; +}; + +// See DiceChainEntry in BCC definition. +struct BccEntry { + std::pair protected_data; + std::pair unprotected; + std::pair payload; + std::pair> signature; + std::string ToString() const; + // Validate BccEntryPayload and set |is_widevine_entry| to true if the BCC + // entry contains a Widevine certificate. Caller ensures that + // |is_widevine_entry| is not null. + CborMessageStatus Validate( + std::vector>& msgs, + bool is_degenerated, bool* is_widevine_entry) const; +}; + +struct Bcc { + BccPublicKeyInfo dk_pub; + std::vector entries; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs, + bool is_degenerated) const; }; // BccValidator processes a Provisioning 4.0 device root of trust. It extracts @@ -52,25 +135,34 @@ class BccValidator : public CborValidator { virtual ~BccValidator() override = default; WVCDM_DISALLOW_COPY_AND_MOVE(BccValidator); - // Verifies the Cbor struct of a client generated root of trust. This message - // is part of an attestation model conforming to the Google Open Dice Profile. - // This message is received from a client device to attest it is a valid - // Widevine device. + // Verifies the Cbor struct of a client generated root of trust. virtual CborMessageStatus Validate() override; - // Outputs BCC in YAML. + // Outputs formatted BCC. virtual std::string GetFormattedMessage() const override; private: - // Processes CoseKey PubKeyEd25519 / PubKeyECDSA256, prints into |fmt_msgs|, - // and extracts the PubKey to *|public_key_info|. + // Processes CoseKey PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, which + // contains subject public key, and extracts the PubKey to *|public_key_info|. + // Caller ensures that all pointers are not null. CborMessageStatus ProcessSubjectPublicKeyInfo( - const cppbor::Map& public_key_info_map, - std::vector& fmt_msgs, BccPublicKeyInfo* public_key_info); - // Processes DiceChainEntryPayload, which contains subject public key, prints - // into |fmt_msgs|, and extracts the PubKey to *|public_key_info|. - CborMessageStatus ProcessDiceChainEntryPayload( - const std::vector& payload, std::vector& fmt_msgs, - BccPublicKeyInfo* public_key_info); + const cppbor::Map* public_key_map, BccPublicKeyInfo* public_key_info); + + // Processes protected field in Bcc entry and extracts it *|protected_data|. + // Caller ensures that all pointers are not null. + CborMessageStatus ProcessBccEntryProtected(const cppbor::Map* protected_map, + BccEntryProtected* protected_data); + + // Processes DiceChainEntryPayload and extracts the payload to *|payload|. + // Caller ensures that all pointers are not null. + CborMessageStatus ProcessDiceChainEntryPayload(const cppbor::Map* payload_map, + BccEntryPayload* payload); + + // Processes ConfigurationDescriptor in DiceChainEntryPayload and extracts the + // ConfigurationDescriptor to *|cd|. Caller ensures that all pointers are not + // null. + CborMessageStatus ProcessConfigurationDescriptor( + const cppbor::Map* config_descriptor_map, ConfigurationDescriptor* cd); + // Verifies the raw EC signature |signature| with the public key // |signing_key|. |signature| extracted from BCC is not ASN.1 DER encoded. bool VerifySignature(const BccPublicKeyInfo& signing_key, diff --git a/oemcrypto/util/include/cbor_validator.h b/oemcrypto/util/include/cbor_validator.h index 9c67bbf..ddc9dce 100644 --- a/oemcrypto/util/include/cbor_validator.h +++ b/oemcrypto/util/include/cbor_validator.h @@ -7,12 +7,6 @@ #ifndef WVOEC_UTIL_CBOR_VALIDATOR_H_ #define WVOEC_UTIL_CBOR_VALIDATOR_H_ -#include - -#include -#include -#include - #include "cppbor.h" #include "cppbor_parse.h" #include "wv_class_utils.h" @@ -28,8 +22,9 @@ enum CborMessageStatus { kCborParseError = 2, kCborValidateOk = 3, kCborValidateWarning = 4, - kCborValidateError = 5, - kCborValidateFatal = 6 + kCborValidateError = 5, // e.g. unexpected value, signature error, etc. + kCborValidateFatal = + 6, // e.g. unexpected data type, key size, or missing required field }; std::string CppborMajorTypeToString(cppbor::MajorType type); @@ -61,10 +56,6 @@ class CborValidator { // first and |parse_result_| contains a valid CBOR message. virtual std::string GetFormattedMessage() const; const cppbor::ParseResult& parse_result() const { return parse_result_; } - const std::vector>& - validate_messages() { - return validate_messages_; - } protected: void Reset(); @@ -77,6 +68,8 @@ class CborValidator { static std::string CheckMapEntry(const cppbor::Map& map, cppbor::MajorType major_type, const std::string& entry_name); + // Formats the parsed CBOR |input| and adds identation for readability. + static std::string FormatString(const std::string& input); CborMessageStatus message_status_ = kCborUninitialized; private: diff --git a/oemcrypto/util/include/device_info_validator.h b/oemcrypto/util/include/device_info_validator.h index bb3373a..618c7b9 100644 --- a/oemcrypto/util/include/device_info_validator.h +++ b/oemcrypto/util/include/device_info_validator.h @@ -15,10 +15,47 @@ #include "cbor_validator.h" #include "cppbor.h" +#include "prov4_validation_helper.h" #include "wv_class_utils.h" namespace wvoec { namespace util { +struct DeviceInfo { + // Version 2 and 3 fields + std::pair brand; + std::pair manufacturer; + std::pair product; + std::pair model; + std::pair device; + std::pair + vb_state; // "green" / "yellow" / "orange" + std::pair + bootloader_state; // "locked" / "unlocked" + std::pair> vbmeta_digest; + std::pair os_version; + std::pair system_patch_level; // YYYYMM + std::pair boot_patch_level; // YYYYMMDD + std::pair vendor_patch_level; // YYYYMMDD + std::pair security_level; // "tee" / "strongbox" + std::pair fused; // 1 / 0 + // Version 1 fields + std::pair board; + std::pair version; + std::pair att_id_state; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs, bool is_gms, + int version_number) const; + CborMessageStatus ValidateV3Fields( + bool is_tee_device_info, + std::vector>& msgs) const; + CborMessageStatus ValidateV2Fields( + bool is_tee_device_info, + std::vector>& msgs) const; + CborMessageStatus ValidateV1Fields( + std::vector>& msgs) const; +}; + // DeviceInfoValidator parses and validates a Cbor struct of DeviceInfo used by // Provisioning 4.0. DeviceInfo definition: // https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV3.cddl @@ -27,8 +64,8 @@ class DeviceInfoValidator : public CborValidator { DeviceInfoValidator() = delete; WVCDM_DISALLOW_COPY_AND_MOVE(DeviceInfoValidator); - explicit DeviceInfoValidator(int version_number) - : version_number_(version_number) {} + explicit DeviceInfoValidator(int version_number = 3, bool is_gms = false) + : version_number_(version_number), is_gms_(is_gms) {} virtual ~DeviceInfoValidator() override = default; @@ -41,15 +78,15 @@ class DeviceInfoValidator : public CborValidator { virtual std::string GetFormattedMessage() const override; private: - // Checks whether a device info entry with |entry_name| and |major_type| - // exists in |device_info| map. - void CheckDeviceInfoMapEntry(const cppbor::Map& device_info, - cppbor::MajorType major_type, - const std::string& entry_name); + // Builds a struct of DeviceInfo from input CBOR map |device_info_map|. + CborMessageStatus BuildDeviceInfo(DeviceInfo& device_info, + const cppbor::Map* device_info_map); // Used to generate formatted message. std::stringstream msg_ss_; // Device info version. Validations are done based on the version number. int version_number_; + // Whether the device is a GMS device. + bool is_gms_; // Saved Cbor-encoded device info. std::vector device_info_bytes_; }; // class DeviceInfoValidator diff --git a/oemcrypto/util/include/prov4_validation_helper.h b/oemcrypto/util/include/prov4_validation_helper.h new file mode 100644 index 0000000..0667f90 --- /dev/null +++ b/oemcrypto/util/include/prov4_validation_helper.h @@ -0,0 +1,96 @@ +// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +#ifndef WVOEC_UTIL_PROV4_VALIDATION_HELPER_H_ +#define WVOEC_UTIL_PROV4_VALIDATION_HELPER_H_ + +#include + +#include "cbor_validator.h" +#include "string_conversions.h" + +namespace wvoec { +namespace util { + +enum FieldStatus { + kAbsent = 0, // field key doesn't exist + kEmpty = 1, // field value is empty, e.g. empty string, map, array, etc. + kPresent = 2 // present and non-empty +}; + +std::string StatusToString(FieldStatus status); +// Apply a new status to current status if it is more severe. +void ApplyStatus(CborMessageStatus& status, CborMessageStatus new_status); + +// Validates that the given field name is present, and prints error messages +// if not. +template +CborMessageStatus ValidateRequiredField( + const std::string& name, const std::string& component, + const std::pair& p, + std::vector>& msgs) { + if (p.first != kPresent) { + msgs.push_back(std::make_pair( + kCborValidateError, component + ": missing required field " + name)); + return kCborValidateError; + } + return kCborValidateOk; +} + +// Validates that the given field name is present, and prints warning messages +// if not. +template +CborMessageStatus ValidateImportantField( + const std::string& name, const std::string& component, + const std::pair& p, + std::vector>& msgs) { + if (p.first != kPresent) { + msgs.push_back(std::make_pair( + kCborValidateWarning, component + ": missing important field " + name)); + return kCborValidateWarning; + } + return kCborValidateOk; +} + +// Print a field value with a built-in type in component with |name| to +// stringstream. +template +void PrintField(std::stringstream& ss, const std::string& name, + const std::pair& p) { + ss << " " << name << ":"; + if (p.first != kPresent) { + ss << StatusToString(p.first) << ","; + } else { + ss << p.second << ","; + } +} + +// Print a field encoded as a CBOR bstr in component with |name| to +// stringstream. +template +void PrintBstrField(std::stringstream& ss, const std::string& name, + const std::pair& p) { + ss << " " << name << ":"; + if (p.first != kPresent) { + ss << StatusToString(p.first) << ","; + } else { + ss << wvutil::b2a_hex(p.second) << ","; + } +} + +// Print a field encoded as CBOR structure in component with |name| to +// stringstream. +template +void PrintCborField(std::stringstream& ss, const std::string& name, + const std::pair& p) { + ss << " " << name << ":"; + if (p.first != kPresent) { + ss << StatusToString(p.first) << ","; + } else { + ss << p.second.ToString() << ","; + } +} +} // namespace util +} // namespace wvoec +#endif // WVOEC_UTIL_PROV4_VALIDATION_HELPER_H_ diff --git a/oemcrypto/util/include/signed_csr_payload_validator.h b/oemcrypto/util/include/signed_csr_payload_validator.h index 911943b..f43f298 100644 --- a/oemcrypto/util/include/signed_csr_payload_validator.h +++ b/oemcrypto/util/include/signed_csr_payload_validator.h @@ -8,10 +8,12 @@ #define WVOEC_UTIL_SIGNED_CSR_PAYLOAD_VALIDATOR_H_ #include -#include +#include "bcc_validator.h" #include "cbor_validator.h" #include "cppbor.h" +#include "device_info_validator.h" +#include "prov4_validation_helper.h" #include "wv_class_utils.h" namespace wvoec { @@ -20,6 +22,67 @@ namespace util { // SignedData. The definition of SignedData and CsrPayload can be // found at: // https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl +struct CertificateType { + std::pair type; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + +// CsrPayload = [ ; CBOR Array defining the payload for Csr +// version: 3, ; The CsrPayload CDDL Schema version. +// CertificateType, ; The type of certificate being requested. +// DeviceInfo, ; Defined in the relevant DeviceInfoV*.cddl file. +// KeysToSign, ; Provided by the method parameters +// ] +struct CsrPayload { + std::pair version; + std::pair certificate_type; + std::pair device_info; + std::vector keys_to_sign; // always empty + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + +struct SignedDataProtected { + std::pair algorithm; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + +// SignedData<[ +// challenge: bstr .size (0..64), ; Provided by the method parameters +// bstr .cbor T, +// ]>, +struct DataToBeSigned { + std::pair> challenge; + std::pair csr_payload; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + +// clang-format off +// SignedData = [ +// protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 }, +// unprotected: {}, +// payload: bstr .cbor Data / nil, +// signature: bstr ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct) / +// ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct) +// ] +// clang-format on +struct SignedCsrPayload { + std::pair protected_data; + std::pair unprotected; + std::pair payload; + std::pair> signature; + std::string ToString() const; + CborMessageStatus Validate( + std::vector>& msgs) const; +}; + class SignedCsrPayloadValidator : public CborValidator { public: explicit SignedCsrPayloadValidator() {} @@ -32,9 +95,20 @@ class SignedCsrPayloadValidator : public CborValidator { virtual std::string GetFormattedMessage() const override; private: - CborMessageStatus ValidateProtectedParams( - const cppbor::Bstr* protected_params); - CborMessageStatus ValidateDataToBeSigned(const cppbor::Bstr* data); + // Processes protected field in signed csr payload and extracts it to + // *|protected_data|. + // Caller ensures that all pointers are not null. + CborMessageStatus ProcessSignedDataProtected( + const cppbor::Map* protected_map, SignedDataProtected* protected_data); + // Processes the data to be signed and extracts it to *|payload_to_be_signed|. + // Caller ensures that all pointers are not null. + CborMessageStatus ProcessDataToBeSigned( + const cppbor::Array* payload_to_be_signed_array, + DataToBeSigned* payload_to_be_signed); + // Processes csr payload field and extracts it to *|csr_payload|. + // Caller ensures that all pointers are not null. + CborMessageStatus ProcessCsrPayload(const cppbor::Array* csr_payload_array, + CsrPayload* csr_payload); // Used to generate formatted message. std::stringstream msg_ss_; }; // class SignedCsrPayloadValidator diff --git a/oemcrypto/util/oec_ref_util.gypi b/oemcrypto/util/oec_ref_util.gypi index 1196f5a..1a098f9 100644 --- a/oemcrypto/util/oec_ref_util.gypi +++ b/oemcrypto/util/oec_ref_util.gypi @@ -29,6 +29,7 @@ '<(oemcrypto_dir)/util/src/oemcrypto_key_deriver.cpp', '<(oemcrypto_dir)/util/src/oemcrypto_oem_cert.cpp', '<(oemcrypto_dir)/util/src/oemcrypto_rsa_key.cpp', + '<(oemcrypto_dir)/util/src/prov4_validation_helper.cpp', '<(oemcrypto_dir)/util/src/signed_csr_payload_validator.cpp', '<(oemcrypto_dir)/util/src/wvcrc.cpp', ], diff --git a/oemcrypto/util/src/bcc_validator.cpp b/oemcrypto/util/src/bcc_validator.cpp index a09f1a8..74a538a 100644 --- a/oemcrypto/util/src/bcc_validator.cpp +++ b/oemcrypto/util/src/bcc_validator.cpp @@ -6,14 +6,8 @@ // #include "bcc_validator.h" -#include - -#include -#include -#include -#include - #include +#include #include "oemcrypto_ecc_key.h" #include "string_conversions.h" @@ -47,14 +41,6 @@ enum { DEVICE_KEY_OCTET_PAIR = 2, }; -// Android/Widevine Dice Attestation allows two signing models. This is -// identified using MAP_KEY_DEVICE_KEY_ALGORITHM. -enum { - DEVICE_KEY_ALGORITHM_ES256 = -7, // EC key with SHA-256 - DEVICE_KEY_ALGORITHM_EDDSA = -8, // Pure ED25519. - DEVICE_KEY_ALGORITHM_ES384 = -35, // EC key with SHA-384 -}; - // The curve used to generate the device public key is identified using the // MAP_KEY_DEVICE_KEY_CURVE. enum { @@ -76,73 +62,348 @@ constexpr int kMarshaledP384KeySize = kP384KeyComponentSize * 2 + 1; constexpr char kMarshaledECKeyZValue = 0x04; constexpr int kED25519KeyDataItemSize = 32; // The Issuer field key in BccEntryPayload. -constexpr int64_t kIssuer = 1; +constexpr int64_t kIssuerLabel = 1; // The Subject field key in BccEntryPayload. -constexpr int64_t kSubject = 2; +constexpr int64_t kSubjectLabel = 2; +// The Profile Name field key in BccEntryPayload. +constexpr int64_t kProfileNameLabel = -4670554; // The SubjectPublicKey field key in BccEntryPayload. -constexpr int64_t kSubjectPublicKey = -4670552; +constexpr int64_t kSubjectPublicKeyLabel = -4670552; +// The KeyUsage field key in BccEntryPayload. +constexpr int64_t kKeyUsageLabel = -4670553; +// The CodeHash field key in BccEntryPayload. +constexpr int64_t kCodeHashLabel = -4670545; +// The CodeDescriptorLabel field key in BccEntryPayload. +constexpr int64_t kCodeDescriptorLabel = -4670546; +// The ConfigurationHashLabel field key in BccEntryPayload. +constexpr int64_t kConfigurationHashLabel = -4670547; +// The ConfigurationDescriptor field key in BccEntryPayload. +constexpr int64_t kConfigurationDescriptorLabel = -4670548; +constexpr int64_t kComponentNameLabel = -70002; +constexpr int64_t kComponentVersionLabel = -70003; +constexpr int64_t kResettableLabel = -70004; +constexpr int64_t kSecurityVersionLabel = -70005; +constexpr int64_t kVmMarkerLabel = -70006; +// The AuthorityHash field key in BccEntryPayload. +constexpr int64_t kAuthorityHashLabel = -4670549; +// The AuthorityDescriptor field key in BccEntryPayload. +constexpr int64_t kAuthorityDescriptorLabel = -4670550; +// The Mode field key in BccEntryPayload. +constexpr int64_t kModeLabel = -4670551; // This signature context is defined by COSE SIGN1. constexpr char kSignatureContextString[] = "Signature1"; - -struct IssuerSubject { - std::string issuer; - std::string subject; - bool IsValid() const { return !issuer.empty() && !subject.empty(); } - void PrintTo(std::vector& fmt_msgs) const { - fmt_msgs.push_back("Issuer: "); - fmt_msgs.back().append(issuer.empty() ? "" : issuer); - fmt_msgs.push_back("Subject: "); - fmt_msgs.back().append(subject.empty() ? "" : subject); - } -}; - -IssuerSubject GetIssuerSubjectFromBccEntryPayload( - const cppbor::Map* bcc_entry_payload) { - IssuerSubject ret; - for (size_t i = 0; i < bcc_entry_payload->size(); ++i) { - const auto& entry = (*bcc_entry_payload)[i]; - if (entry.first == nullptr || entry.first->asInt() == nullptr || - entry.second == nullptr || entry.second->asTstr() == nullptr) { - continue; - } - const auto& value = entry.second->asTstr()->value(); - if (entry.first->asInt()->value() == kIssuer) { - ret.issuer = value.empty() ? "" : value; - } else if (entry.first->asInt()->value() == kSubject) { - ret.subject = value.empty() ? "" : value; - } - } - return ret; -} - -const cppbor::Bstr* GetSubjectPublicKeyFromBccEntryPayload( - const cppbor::Map* bcc_entry_payload) { - for (size_t i = 0; i < bcc_entry_payload->size(); ++i) { - const auto& entry = (*bcc_entry_payload)[i]; - if (entry.first == nullptr || entry.first->asInt() == nullptr || - entry.second == nullptr) { - continue; - } - if (entry.first->asInt()->value() == kSubjectPublicKey) { - return entry.second->asBstr(); - } - } - return nullptr; -} - -void AddMessages(std::stringstream& ss, - const std::vector& fmt_msgs, int indent) { - const std::string spaces = std::string(indent * 2, ' '); - for (auto& msg : fmt_msgs) { - ss << spaces << msg << "\n"; - } -} } // namespace +std::string BccPublicKeyInfo::ToString() const { + std::stringstream ss; + ss << "{"; + ss << " key_type:"; + if (key_type.first != kPresent) { + ss << StatusToString(key_type.first) << ","; + } else { + if (key_type.second == DEVICE_KEY_BYTE_STRING) { + ss << "byte_string" << ","; + } else if (key_type.second == DEVICE_KEY_OCTET_PAIR) { + ss << "octet_pair" << ","; + } else { + ss << "unknown(" << key_type.second << ")" << ","; + } + } + ss << " signature_algorithm:"; + if (signature_algorithm.first != kPresent) { + ss << StatusToString(signature_algorithm.first) << ","; + } else { + if (signature_algorithm.second == kBccEdDsa) { + ss << "EdDSA" << ","; + } else if (signature_algorithm.second == kBccEcdsaSha256) { + ss << "ES256" << ","; + } else if (signature_algorithm.second == kBccEcdsaSha384) { + ss << "ES384" << ","; + } else { + ss << "unknown" << ","; + } + } + ss << " curve:"; + if (curve.first != kPresent) { + ss << StatusToString(curve.first) << ","; + } else { + if (curve.second == kBccEd25519) { + ss << "Ed25519" << ","; + } else if (curve.second == kBccP256) { + ss << "P256" << ","; + } else if (curve.second == kBccP384) { + ss << "P384" << ","; + } else { + ss << "unknown(" << curve.second << ")" << ","; + } + } + PrintBstrField(ss, "key_bytes", key_bytes); + ss << " }"; + return ss.str(); +} + +CborMessageStatus BccPublicKeyInfo::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "BccPublicKey"; + CborMessageStatus cur_status = + ValidateRequiredField("key_type", component, key_type, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + if (key_type.second != DEVICE_KEY_OCTET_PAIR && + key_type.second != DEVICE_KEY_BYTE_STRING) { + msgs.push_back(std::make_pair( + kCborValidateError, + component + ": Invalid key type " + std::to_string(key_type.second))); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("signature_algorithm", component, + signature_algorithm, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + if (signature_algorithm.second != kBccEdDsa && + signature_algorithm.second != kBccEcdsaSha256 && + signature_algorithm.second != kBccEcdsaSha384) { + msgs.push_back(std::make_pair( + kCborValidateError, component + ": Invalid signature algorithm " + + std::to_string(signature_algorithm.second))); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("curve", component, curve, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + if (curve.second != kBccEd25519 && curve.second != kBccP256 && + curve.second != kBccP384) { + msgs.push_back(std::make_pair( + kCborValidateError, + component + ": Invalid curve " + std::to_string(curve.second))); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("key_bytes", component, curve, msgs); + ApplyStatus(status, cur_status); + return status; +} + +std::string BccEntryProtected::ToString() const { + std::stringstream ss; + ss << "{"; + ss << " algorithm:"; + if (algorithm.first != kPresent) { + ss << StatusToString(algorithm.first) << ","; + } else { + if (algorithm.second == DEVICE_KEY_ALGORITHM_EDDSA) { + ss << "EdDSA" << ","; + } else if (algorithm.second == DEVICE_KEY_ALGORITHM_ES256) { + ss << "ECDSA_SHA256" << ","; + } else if (algorithm.second == DEVICE_KEY_ALGORITHM_ES384) { + ss << "ECDSA_SHA384" << ","; + } else { + ss << "unknown(" << algorithm.second << ")" << ","; + } + } + ss << " }"; + return ss.str(); +} + +CborMessageStatus BccEntryProtected::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "BccEntryProtected"; + CborMessageStatus cur_status = + ValidateRequiredField("algorithm", component, algorithm, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + if (algorithm.second != DEVICE_KEY_ALGORITHM_EDDSA && + algorithm.second != DEVICE_KEY_ALGORITHM_ES256 && + algorithm.second != DEVICE_KEY_ALGORITHM_ES384) { + msgs.push_back(std::make_pair(kCborValidateError, + component + ": Invalid algorithm " + + std::to_string(algorithm.second))); + ApplyStatus(status, kCborValidateError); + } + } + return status; +} + +std::string ConfigurationDescriptor::ToString() const { + std::stringstream ss; + ss << "{"; + PrintField(ss, "component_name", component_name); + PrintField(ss, "component_version", component_version); + PrintField(ss, "resettable", resettable); + PrintField(ss, "security_version", security_version); + PrintField(ss, "vm_marker", vm_marker); + ss << " }"; + return ss.str(); +} + +CborMessageStatus ConfigurationDescriptor::Validate( + std::vector>& msgs, + bool* is_widevine_entry) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "ConfigurationDescriptor"; + CborMessageStatus cur_status = + ValidateRequiredField("component_name", component, component_name, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + std::string name = component_name.second; + std::transform(name.begin(), name.end(), name.begin(), + [](unsigned char c) { return std::tolower(c); }); + *is_widevine_entry = (name == "widevine"); + } + return status; +} + +std::string BccEntryPayload::ToString() const { + std::stringstream ss; + ss << "{"; + PrintField(ss, "issuer", issuer); + PrintField(ss, "subject", subject); + PrintField(ss, "profile_name", profile_name); + PrintCborField(ss, "subject_public_key", subject_public_key); + PrintBstrField(ss, "key_usage(hex)", key_usage); + PrintBstrField(ss, "code_hash", code_hash); + PrintBstrField(ss, "code_descriptor", code_descriptor); + PrintBstrField(ss, "config_hash", config_hash); + PrintCborField(ss, "config_descriptor", config_descriptor); + PrintBstrField(ss, "authority_hash", authority_hash); + PrintBstrField(ss, "authority_descriptor", authority_descriptor); + PrintBstrField(ss, "mode(hex)", mode); + ss << " }"; + return ss.str(); +} + +CborMessageStatus BccEntryPayload::Validate( + std::vector>& msgs, + bool is_degenerated, bool* is_widevine_entry) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "BccEntryPayload"; + CborMessageStatus cur_status = + ValidateRequiredField("issuer", component, issuer, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateRequiredField("subject", component, subject, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateRequiredField("subject_public_key", component, + subject_public_key, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + cur_status = subject_public_key.second.Validate(msgs); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("key_usage", component, key_usage, msgs); + ApplyStatus(status, cur_status); + // Validates more fields for non-degenerated BCC payload. + if (!is_degenerated) { + cur_status = ValidateRequiredField("code_hash", component, code_hash, msgs); + ApplyStatus(status, cur_status); + cur_status = + ValidateRequiredField("config_hash", component, config_hash, msgs); + ApplyStatus(status, cur_status); + if (config_descriptor.first == kAbsent) { + msgs.push_back(std::make_pair( + kCborValidateError, + component + ": missing required field config_descriptor")); + ApplyStatus(status, kCborValidateError); + } else { + cur_status = config_descriptor.second.Validate(msgs, is_widevine_entry); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("authority_hash", component, + authority_hash, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateRequiredField("mode", component, mode, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk && *is_widevine_entry) { + uint32_t mode_value = 0; + for (uint8_t byte : mode.second) { + mode_value <<= 8; + mode_value |= byte; + } + if (mode_value == 0x0) { + msgs.push_back(std::make_pair(kCborValidateError, + component + ": mode can not be 0")); + ApplyStatus(status, kCborValidateError); + } + } + } + return status; +} + +std::string BccEntry::ToString() const { + std::stringstream ss; + ss << "["; + PrintCborField(ss, "protected", protected_data); + PrintField(ss, "unprotected", unprotected); + PrintCborField(ss, "payload", payload); + PrintBstrField(ss, "signature", signature); + ss << " ]"; + return ss.str(); +} + +CborMessageStatus BccEntry::Validate( + std::vector>& msgs, + bool is_degenerated, bool* is_widevine_entry) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "BccEntry"; + CborMessageStatus cur_status = + ValidateRequiredField("protected", component, protected_data, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + cur_status = protected_data.second.Validate(msgs); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("payload", component, payload, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + cur_status = + payload.second.Validate(msgs, is_degenerated, is_widevine_entry); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("signature", component, signature, msgs); + ApplyStatus(status, cur_status); + return status; +} + +std::string Bcc::ToString() const { + std::stringstream ss; + ss << "BCC = ["; + ss << "dk_pub:" << dk_pub.ToString() << ","; + for (size_t i = 0; i < entries.size(); ++i) { + ss << "entry:" << entries[i].ToString() << ","; + } + ss << "]"; + return ss.str(); +} + +CborMessageStatus Bcc::Validate( + std::vector>& msgs, + bool is_degenerated) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "Bcc"; + CborMessageStatus cur_status = dk_pub.Validate(msgs); + ApplyStatus(status, cur_status); + bool found_widevine_entry = false; + for (size_t i = 0; i < entries.size(); ++i) { + bool is_widevine_entry = false; + cur_status = entries[i].Validate(msgs, is_degenerated, &is_widevine_entry); + ApplyStatus(status, cur_status); + if (is_widevine_entry) found_widevine_entry = true; + } + if (!is_degenerated && !found_widevine_entry) { + msgs.push_back(std::make_pair(kCborValidateError, + component + ": Widevine cert not found.")); + ApplyStatus(status, kCborValidateError); + } + return status; +} + bool BccValidator::VerifySignature(const BccPublicKeyInfo& signing_key, const std::vector& message, const std::vector& signature) { - if (signing_key.signature_algorithm == kBccEdDsa) { + if (signing_key.signature_algorithm.second == kBccEdDsa) { constexpr size_t kEd25519SignatureLength = 64; // ED25519 incorporates SHA512 into the signing algorithm. if (signature.size() != kEd25519SignatureLength) { @@ -154,8 +415,9 @@ bool BccValidator::VerifySignature(const BccPublicKeyInfo& signing_key, EVP_PKEY* pkey = nullptr; if ((pkey = EVP_PKEY_new_raw_public_key( EVP_PKEY_ED25519, nullptr, - reinterpret_cast(signing_key.key_bytes.data()), - signing_key.key_bytes.size())) == nullptr) { + reinterpret_cast( + signing_key.key_bytes.second.data()), + signing_key.key_bytes.second.size())) == nullptr) { AddValidationMessage( kCborValidateError, "Can not create EVP_PKEY_ED25519 from the public key info."); @@ -170,14 +432,16 @@ bool BccValidator::VerifySignature(const BccPublicKeyInfo& signing_key, EVP_PKEY_free(pkey); return res; } - if (signing_key.signature_algorithm == kBccEcdsaSha256 || - signing_key.signature_algorithm == kBccEcdsaSha384) { - const EccCurve curve = (signing_key.signature_algorithm == kBccEcdsaSha256) - ? EccCurve::kEccSecp256r1 - : EccCurve::kEccSecp384r1; + if (signing_key.signature_algorithm.second == kBccEcdsaSha256 || + signing_key.signature_algorithm.second == kBccEcdsaSha384) { + const EccCurve curve = + (signing_key.signature_algorithm.second == kBccEcdsaSha256) + ? EccCurve::kEccSecp256r1 + : EccCurve::kEccSecp384r1; std::unique_ptr key = EccPublicKey::LoadKeyPoint( - curve, reinterpret_cast(signing_key.key_bytes.data()), - signing_key.key_bytes.size()); + curve, + reinterpret_cast(signing_key.key_bytes.second.data()), + signing_key.key_bytes.second.size()); if (!key) { AddValidationMessage(kCborValidateError, "Can not create ECPublicKey from raw EC KeyPoint."); @@ -187,9 +451,10 @@ bool BccValidator::VerifySignature(const BccPublicKeyInfo& signing_key, message.data(), message.size(), signature.data(), signature.size()); return (res == OEMCrypto_SUCCESS); } - AddValidationMessage(kCborValidateError, - "Unknown signature algorithm: " + - std::to_string(signing_key.signature_algorithm)); + AddValidationMessage( + kCborValidateError, + "Unknown signature algorithm: " + + std::to_string(signing_key.signature_algorithm.second)); return false; } @@ -207,6 +472,12 @@ CborMessageStatus BccValidator::Validate() { return message_status_; } const cppbor::Array* bcc_array = parsed_bcc->asArray(); + /* + * Bcc = [ + * PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384, ; DK_pub + * + BccEntry, ; Root -> leaf (KM_pub) + * ] + */ if (bcc_array->size() < 2) { AddValidationMessage(kCborValidateFatal, "BCC should contain at least two elements. Actual: " + @@ -214,14 +485,9 @@ CborMessageStatus BccValidator::Validate() { return message_status_; } - // Writes YAML-formatted output to |msg_ss_| during validation. - msg_ss_.str(std::string()); - msg_ss_ << "---" - << "\n"; - msg_ss_ << "DEVICE PUBLIC KEY:\n"; - // The first element in the array contains the root device public key - // definition. + // definition: + // PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384; DK_pub, cbor map const cppbor::Map* device_public_key_map = (*bcc_array)[0]->asMap(); if (device_public_key_map == nullptr) { AddValidationMessage( @@ -231,161 +497,348 @@ CborMessageStatus BccValidator::Validate() { return message_status_; } BccPublicKeyInfo root_pub_key; - std::vector key_value_texts; // for pretty print - CborMessageStatus status = ProcessSubjectPublicKeyInfo( - *device_public_key_map, key_value_texts, &root_pub_key); - AddMessages(msg_ss_, key_value_texts, 1); + CborMessageStatus status = + ProcessSubjectPublicKeyInfo(device_public_key_map, &root_pub_key); if (status == kCborValidateFatal) return status; + Bcc bcc; + bcc.dk_pub = root_pub_key; BccPublicKeyInfo leaf_pub_key = root_pub_key; - msg_ss_ << "BCC ENTRY:\n"; - // Parse and verify each certificate in the chain. The structure of thr - // entries are COSE_Sign1 (untagged). leaf_pub_key is being updated while we - // process the chain. - for (size_t i = 1; i < bcc_array->size(); ++i) { - msg_ss_ << "- CDI PUBLIC KEY INDEX: " << i << "\n"; - const cppbor::Array* bcc_entry = (*bcc_array)[i]->asArray(); - if (bcc_entry == nullptr) { - AddValidationMessage(kCborValidateFatal, - "BCC entry is empty at index " + std::to_string(i)); - return message_status_; - } - if (bcc_entry->size() != 4) { - AddValidationMessage(kCborValidateFatal, - "BCC entry should contain 4 items. Actual: " + - std::to_string(bcc_entry->size())); - return message_status_; - } - // Skip CoseSign1 signature verification here, only extract pub keys - if ((*bcc_entry)[0]->type() != cppbor::BSTR || - (*bcc_entry)[1]->type() != cppbor::MAP || - (*bcc_entry)[2]->type() != cppbor::BSTR || - (*bcc_entry)[3]->type() != cppbor::BSTR) { - AddValidationMessage(kCborValidateFatal, "Invalid BCC entry type."); - return message_status_; - } - // Signature verification Step 1: construct and encode signature input - const std::vector& protected_bytes = - (*bcc_entry)[0]->asBstr()->value(); - // Index 1 is unprotected parameters, which is ignored. - const std::vector& payload = (*bcc_entry)[2]->asBstr()->value(); - const std::vector& actual_signature = - (*bcc_entry)[3]->asBstr()->value(); - - const std::vector signature_input = - cppbor::Array() - .add(kSignatureContextString) - .add(protected_bytes) - .add(/* AAD */ std::vector()) - .add(payload) - .encode(); - - // Signature verification Step 2: verify - if (!VerifySignature(leaf_pub_key, signature_input, actual_signature)) { - AddValidationMessage( - kCborValidateError, - "Failed to verify the signature for BCC entry index: " + - std::to_string(i)); - } - - key_value_texts.clear(); - BccPublicKeyInfo entry_pub_key; - status = - ProcessDiceChainEntryPayload(payload, key_value_texts, &entry_pub_key); - AddMessages(msg_ss_, key_value_texts, 1); - if (status == kCborValidateFatal) return status; - leaf_pub_key = std::move(entry_pub_key); - } // If the size of the BCC array (including device pub key) is 2, then it // must be a de-generated BCC, which means the second element in the array // is a self-signed entry. The entry's public key should be identical to the // device's public key. + bool is_degenerated = false; if (bcc_array->size() == 2) { // self-signed BCC entry - if (leaf_pub_key.key_bytes != root_pub_key.key_bytes) { + if (leaf_pub_key.key_bytes.second != root_pub_key.key_bytes.second) { AddValidationMessage(kCborValidateError, "The public key of a self-signed entry should be " "identical to its device public key."); } + is_degenerated = true; } - msg_ss_ << "...\n"; + + // Parse and verify each entry in the chain. The structure of the + // signature in the entry is COSE_Sign1 (untagged). leaf_pub_key is being + // updated while we process the chain. + /* + * BccEntry = [ ; COSE_Sign1 (untagged) + * protected : bstr .cbor { + * 1 : AlgorithmEdDSA / AlgorithmES256, ; Algorithm + * }, + * unprotected: {}, + * payload: bstr .cbor BccPayload, + * signature: bstr ; PureEd25519(SigningKey, bstr .cbor BccEntryInput) + * / ; ECDSA(SigningKey, bstr .cbor BccEntryInput) ; See RFC 8032 for details + * of how to encode the signature value for Ed25519. + * ] + */ + for (size_t i = 1; i < bcc_array->size(); ++i) { + const cppbor::Array* bcc_entry = (*bcc_array)[i]->asArray(); + if (bcc_entry == nullptr) { + AddValidationMessage(kCborValidateError, + "BCC entry is empty at index " + std::to_string(i)); + continue; + } + if (bcc_entry->size() != 4) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " should contain 4 items. Actual: " + + std::to_string(bcc_entry->size())); + continue; + } + if ((*bcc_entry)[0]->type() != cppbor::BSTR) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " protected field is not a CBOR bstr."); + continue; + } + if ((*bcc_entry)[1]->type() != cppbor::MAP) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " unprotected field is not a CBOR map."); + continue; + } + if ((*bcc_entry)[2]->type() != cppbor::BSTR) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " payload field is not a CBOR bstr."); + continue; + } + if ((*bcc_entry)[3]->type() != cppbor::BSTR) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " signature field is not a CBOR bstr."); + continue; + } + + // Parse and verify the protected data + const std::vector& encoded_protected_data = + (*bcc_entry)[0]->asBstr()->value(); + if (encoded_protected_data.empty()) { + AddValidationMessage( + kCborValidateError, + "BCC entry index " + std::to_string(i) + " empty protected data."); + continue; + } + auto parse_result = cppbor::parse(encoded_protected_data); + std::unique_ptr sub_item = + std::move(std::get<0>(parse_result)); + std::string error_message = std::move(std::get<2>(parse_result)); + if (sub_item == nullptr || !error_message.empty()) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " unable to parse protected: " + error_message); + continue; + } + if (sub_item->type() != cppbor::MAP) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " unexpected protected type: " + + CppborMajorTypeToString(sub_item->type())); + continue; + } + const cppbor::Map* protected_map = sub_item->asMap(); + if (protected_map == nullptr) { + AddValidationMessage( + kCborValidateError, + "BCC entry index " + std::to_string(i) + " protected map is null."); + continue; + } + BccEntry entry; + if (protected_map->size() == 0) { + entry.protected_data.first = kEmpty; + } else { + status = + ProcessBccEntryProtected(protected_map, &entry.protected_data.second); + if (status == kCborValidateFatal) return status; + if (status != kCborValidateError) { + entry.protected_data.first = kPresent; + } + } + // Unprotected data in BCC entry is always empty, which is ignored. + entry.unprotected.first = kEmpty; + entry.unprotected.second = "{}"; + + // Signature verification + const std::vector& encoded_payload = + (*bcc_entry)[2]->asBstr()->value(); + const std::vector& actual_signature = + (*bcc_entry)[3]->asBstr()->value(); + entry.signature.second = actual_signature; + entry.signature.first = entry.signature.second.empty() ? kEmpty : kPresent; + + const std::vector signature_input = + cppbor::Array() + .add(kSignatureContextString) + .add(encoded_protected_data) + .add(/* AAD */ std::vector()) + .add(encoded_payload) + .encode(); + if (!VerifySignature(leaf_pub_key, signature_input, actual_signature)) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " failed to verify the signature."); + } + + // Parse and verify the payload + if (encoded_payload.empty()) { + AddValidationMessage( + kCborValidateError, + "BCC entry index " + std::to_string(i) + " empty payload."); + continue; + } + parse_result = cppbor::parse(encoded_payload); + std::unique_ptr sub_item_payload = + std::move(std::get<0>(parse_result)); + error_message = std::move(std::get<2>(parse_result)); + if (sub_item_payload == nullptr || !error_message.empty()) { + AddValidationMessage(kCborValidateError, + "BCC entry index " + std::to_string(i) + + " unable to parse payload: " + error_message); + continue; + } + if (sub_item_payload->type() != cppbor::MAP) { + AddValidationMessage( + kCborValidateError, + "BCC entry index " + std::to_string(i) + + " unexpected payload type: " + + CppborMajorTypeToString(sub_item_payload->type())); + continue; + } + const cppbor::Map* payload_map = sub_item_payload->asMap(); + if (payload_map == nullptr) { + AddValidationMessage( + kCborValidateError, + "BCC entry index " + std::to_string(i) + " payload is empty."); + continue; + } + if (payload_map->size() == 0) { + entry.payload.first = kEmpty; + } else { + status = ProcessDiceChainEntryPayload(payload_map, &entry.payload.second); + if (status == kCborValidateFatal) return status; + if (status != kCborValidateError) { + entry.payload.first = kPresent; + leaf_pub_key = entry.payload.second.subject_public_key.second; + } + } + bcc.entries.push_back(std::move(entry)); + } + + msg_ss_ << bcc.ToString() << "\n"; + + // More validations on the BCC + std::vector> msgs; + CborMessageStatus validate_status = bcc.Validate(msgs, is_degenerated); + ApplyStatus(message_status_, validate_status); + for (const auto& msg : msgs) { + AddValidationMessage(msg.first, msg.second); + } + if (message_status_ == kCborParseOk) message_status_ = kCborValidateOk; return message_status_; } -CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( - const cppbor::Map& public_key_info_map, std::vector& fmt_msgs, - BccPublicKeyInfo* public_key_info) { - int key_encoding_format = DEVICE_KEY_ENCODING_UNKNOWN; - std::vector device_key_bytes_0; - std::vector device_key_bytes_1; - std::unordered_set key_set; - for (size_t index = 0; index < public_key_info_map.size(); ++index) { +CborMessageStatus BccValidator::ProcessConfigurationDescriptor( + const cppbor::Map* config_descriptor_map, ConfigurationDescriptor* cd) { + for (size_t index = 0; index < config_descriptor_map->size(); ++index) { std::pair&, const std::unique_ptr&> - entry = public_key_info_map[index]; + entry = (*config_descriptor_map)[index]; if (entry.first->type() != cppbor::NINT && entry.first->type() != cppbor::UINT) { - AddValidationMessage(kCborValidateFatal, + AddValidationMessage( + kCborValidateError, + "Invalid key type in configuration descriptor map: " + + CppborMajorTypeToString(entry.first->type())); + continue; + } + const int64_t map_key = entry.first->asInt()->value(); + switch (map_key) { + case kComponentNameLabel: { + if (entry.second->type() != cppbor::TSTR) { + AddValidationMessage( + kCborValidateError, + "Invalid value type in configuration descriptor map for " + "key component name: " + + CppborMajorTypeToString(entry.second->type())); + continue; + } + cd->component_name.second = entry.second->asTstr()->value(); + cd->component_name.first = + cd->component_name.second.empty() ? kEmpty : kPresent; + } break; + case kComponentVersionLabel: { + if (entry.second->type() == cppbor::NINT || + entry.second->type() == cppbor::UINT) { + cd->component_version.second = + std::to_string(entry.second->asInt()->value()); + cd->component_version.first = kPresent; + } else if (entry.second->type() == cppbor::TSTR) { + cd->component_version.second = entry.second->asTstr()->value(); + cd->component_version.first = kPresent; + } else { + AddValidationMessage( + kCborValidateError, + "Invalid value type in configuration descriptor map for " + "component version: " + + CppborMajorTypeToString(entry.second->type())); + continue; + } + } break; + case kResettableLabel: { + // null string, do nothing + break; + } + case kSecurityVersionLabel: { + if (entry.second->type() != cppbor::UINT) { + AddValidationMessage( + kCborValidateError, + "Invalid value type in configuration descriptor map for " + "security version: " + + CppborMajorTypeToString(entry.second->type())); + continue; + } else { + cd->security_version.second = entry.second->asUint()->value(); + cd->security_version.first = kPresent; + } + } break; + case kVmMarkerLabel: { + // null string, do nothing + break; + } + } + } + return message_status_; +} + +CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( + const cppbor::Map* public_key_map, BccPublicKeyInfo* public_key) { + std::vector device_key_bytes_0; + std::vector device_key_bytes_1; + for (size_t index = 0; index < public_key_map->size(); ++index) { + std::pair&, + const std::unique_ptr&> + entry = (*public_key_map)[index]; + if (entry.first->type() != cppbor::NINT && + entry.first->type() != cppbor::UINT) { + AddValidationMessage(kCborValidateError, "Invalid key type in public key info map: " + CppborMajorTypeToString(entry.first->type())); - return kCborValidateFatal; + continue; } const int64_t map_key = entry.first->asInt()->value(); switch (map_key) { case MAP_KEY_DEVICE_KEY_TYPE: { if (entry.second->type() != cppbor::UINT) { AddValidationMessage( - kCborValidateFatal, + kCborValidateError, "Invalid value type in public key info map for " "key MAP_KEY_DEVICE_KEY_TYPE: " + CppborMajorTypeToString(entry.second->type())); - return kCborValidateFatal; + continue; } - std::string kv = "key encoding format: "; + public_key->key_type.first = kPresent; const int64_t value = entry.second->asUint()->value(); if (value == DEVICE_KEY_OCTET_PAIR) { - key_encoding_format = DEVICE_KEY_OCTET_PAIR; - kv += "DEVICE_KEY_OCTET_PAIR"; + public_key->key_type.second = DEVICE_KEY_OCTET_PAIR; } else if (value == DEVICE_KEY_BYTE_STRING) { - key_encoding_format = DEVICE_KEY_BYTE_STRING; - kv += "DEVICE_KEY_BYTE_STRING"; + public_key->key_type.second = DEVICE_KEY_BYTE_STRING; } else { + public_key->key_type.second = DEVICE_KEY_ENCODING_UNKNOWN; AddValidationMessage(kCborValidateError, "Invalid value in public key info map for key " "MAP_KEY_DEVICE_KEY_TYPE: " + std::to_string(value)); } - fmt_msgs.push_back(std::move(kv)); } break; case MAP_KEY_DEVICE_KEY_ALGORITHM: { if (entry.second->type() != cppbor::NINT) { AddValidationMessage( - kCborValidateFatal, + kCborValidateError, "Invalid value type in public key info map for " "key MAP_KEY_DEVICE_KEY_ALGORITHM: " + CppborMajorTypeToString(entry.second->type())); - return kCborValidateFatal; + continue; } - std::string kv = "key algorithm type: "; + public_key->signature_algorithm.first = kPresent; const int64_t value = entry.second->asNint()->value(); if (value == DEVICE_KEY_ALGORITHM_ES256) { - kv += "ECDSA_SHA256"; - public_key_info->signature_algorithm = kBccEcdsaSha256; + public_key->signature_algorithm.second = kBccEcdsaSha256; } else if (value == DEVICE_KEY_ALGORITHM_ES384) { - kv += "ECDSA_SHA384"; - public_key_info->signature_algorithm = kBccEcdsaSha384; + public_key->signature_algorithm.second = kBccEcdsaSha384; } else if (value == DEVICE_KEY_ALGORITHM_EDDSA) { - kv += "EDDSA"; - public_key_info->signature_algorithm = kBccEdDsa; + public_key->signature_algorithm.second = kBccEdDsa; } else { + public_key->signature_algorithm.second = kBccDefaultSignature; AddValidationMessage(kCborValidateError, "Invalid value in public key info map for key " "MAP_KEY_DEVICE_KEY_ALGORITHM: " + std::to_string(value)); } - fmt_msgs.push_back(std::move(kv)); } break; case MAP_KEY_DEVICE_KEY_OPS: // The OPS is an array. Ignored for now. @@ -393,30 +846,27 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( case MAP_KEY_DEVICE_KEY_CURVE: { if (entry.second->type() != cppbor::UINT) { AddValidationMessage( - kCborValidateFatal, + kCborValidateError, "Invalid value type in public key info map for " "key MAP_KEY_DEVICE_KEY_CURVE: " + CppborMajorTypeToString(entry.second->type())); - return kCborValidateFatal; + continue; } - std::string kv = "curve: "; + public_key->curve.first = kPresent; const int64_t value = entry.second->asUint()->value(); if (value == DEVICE_KEY_CURVE_P256) { - public_key_info->curve = kBccP256; - kv += "P256"; + public_key->curve.second = kBccP256; } else if (value == DEVICE_KEY_CURVE_P384) { - public_key_info->curve = kBccP384; - kv += "P384"; + public_key->curve.second = kBccP384; } else if (value == DEVICE_KEY_CURVE_ED25519) { - public_key_info->curve = kBccEd25519; - kv += "ED25519"; + public_key->curve.second = kBccEd25519; } else { + public_key->curve.second = kBccDefaultCurve; AddValidationMessage(kCborValidateError, "Invalid value in public key info map for key " "MAP_KEY_DEVICE_KEY_CURVE: " + std::to_string(value)); } - fmt_msgs.push_back(std::move(kv)); } break; case MAP_KEY_DEVICE_KEY_BYTES_0: case MAP_KEY_DEVICE_KEY_BYTES_1: @@ -424,52 +874,40 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( // octet string. The format used depends on the key type. if (entry.second->type() != cppbor::BSTR) { AddValidationMessage( - kCborValidateFatal, + kCborValidateError, "Invalid value type in public key info map for " "key MAP_KEY_DEVICE_KEY_BYTES_0/1: " + CppborMajorTypeToString(entry.second->type())); - return kCborValidateFatal; + continue; } const std::vector& key_bytes = entry.second->asBstr()->value(); // Key byte length depends upon the key type. if (key_bytes.size() != kED25519KeyDataItemSize && key_bytes.size() != kP256KeyComponentSize && key_bytes.size() != kP384KeyComponentSize) { - AddValidationMessage(kCborValidateFatal, + AddValidationMessage(kCborValidateError, "Malformed public key data size of: " + std::to_string(key_bytes.size())); - return kCborValidateFatal; + continue; } + public_key->key_bytes.first = kPresent; if (map_key == MAP_KEY_DEVICE_KEY_BYTES_0) { device_key_bytes_0 = key_bytes; } else { device_key_bytes_1 = key_bytes; } } - key_set.insert(map_key); - } - if (key_set.find(MAP_KEY_DEVICE_KEY_TYPE) == key_set.end()) { - AddValidationMessage(kCborValidateError, - "Missing MAP_KEY_DEVICE_KEY_TYPE."); - } - if (key_set.find(MAP_KEY_DEVICE_KEY_ALGORITHM) == key_set.end()) { - AddValidationMessage(kCborValidateError, - "Missing MAP_KEY_DEVICE_KEY_ALGORITHM."); - } - if (key_set.find(MAP_KEY_DEVICE_KEY_CURVE) == key_set.end()) { - AddValidationMessage(kCborValidateError, - "Missing MAP_KEY_DEVICE_KEY_CURVE."); } if (device_key_bytes_0.empty() || - (key_encoding_format == DEVICE_KEY_OCTET_PAIR && + (public_key->key_type.second == DEVICE_KEY_OCTET_PAIR && device_key_bytes_1.empty())) { AddValidationMessage( - kCborValidateFatal, + kCborValidateError, "Malformed public key definition. Missing device public key bytes."); - return kCborValidateFatal; + return message_status_; } std::vector device_key_bytes; - if (key_encoding_format == DEVICE_KEY_OCTET_PAIR) { + if (public_key->key_type.second == DEVICE_KEY_OCTET_PAIR) { // Key is an ECDSA elliptic key. We need to return the ANSI X9.62 // marshaled public key. Generate the marshaled key if needed. The // marshaled key is needed to create an ECPublicKey object. @@ -480,72 +918,172 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( device_key_bytes_1.end()); if (device_key_bytes.size() != kMarshaledP384KeySize && device_key_bytes.size() != kMarshaledP256KeySize) { - AddValidationMessage(kCborValidateFatal, + AddValidationMessage(kCborValidateError, "Invalid ECDSA public key size: " + std::to_string(device_key_bytes.size())); - return kCborValidateFatal; + return message_status_; } } else { device_key_bytes = std::move(device_key_bytes_0); } - fmt_msgs.push_back("public key bytes: " + wvutil::b2a_hex(device_key_bytes)); - public_key_info->key_bytes = std::move(device_key_bytes); + public_key->key_bytes.second = std::move(device_key_bytes); + if (public_key->key_bytes.second.empty()) { + public_key->key_bytes.first = kEmpty; + } + return message_status_; +} + +CborMessageStatus BccValidator::ProcessBccEntryProtected( + const cppbor::Map* protected_map, BccEntryProtected* protected_data) { + for (size_t index = 0; index < protected_map->size(); ++index) { + std::pair&, + const std::unique_ptr&> + entry = (*protected_map)[index]; + if (entry.first->type() != cppbor::NINT && + entry.first->type() != cppbor::UINT) { + AddValidationMessage( + kCborValidateError, + "Invalid key type in protected data map in bcc entry: " + + CppborMajorTypeToString(entry.first->type())); + continue; + } + const int64_t map_key = entry.first->asInt()->value(); + switch (map_key) { + case 1: { + if (entry.second->type() != cppbor::NINT && + entry.second->type() != cppbor::UINT) { + AddValidationMessage( + kCborValidateError, + "Invalid value type in protected data map for " + "key 1: " + + CppborMajorTypeToString(entry.second->type())); + continue; + } + protected_data->algorithm.first = kPresent; + protected_data->algorithm.second = entry.second->asInt()->value(); + } break; + } + } return message_status_; } CborMessageStatus BccValidator::ProcessDiceChainEntryPayload( - const std::vector& payload, std::vector& fmt_msgs, - BccPublicKeyInfo* entry_public_key_info) { - if (payload.empty()) { - AddValidationMessage(kCborValidateFatal, "Empty bcc entry payload."); - return kCborValidateFatal; + const cppbor::Map* payload_map, BccEntryPayload* payload) { + for (size_t i = 0; i < payload_map->size(); ++i) { + const auto& entry = (*payload_map)[i]; + if (entry.first == nullptr || entry.first->asInt() == nullptr || + entry.second == nullptr) { + continue; + } + int64_t key = entry.first->asInt()->value(); + if (key == kIssuerLabel) { + const auto& value = entry.second->asTstr()->value(); + payload->issuer.second = value; + payload->issuer.first = value.empty() ? kEmpty : kPresent; + } else if (key == kSubjectLabel) { + const auto& value = entry.second->asTstr()->value(); + payload->subject.second = value; + payload->subject.first = value.empty() ? kEmpty : kPresent; + } else if (key == kProfileNameLabel) { + const auto& value = entry.second->asTstr()->value(); + payload->profile_name.second = value; + payload->profile_name.first = value.empty() ? kEmpty : kPresent; + } else if (key == kSubjectPublicKeyLabel) { + const auto& value = entry.second->asBstr()->value(); + if (value.empty()) { + AddValidationMessage(kCborValidateError, "Empty public key."); + continue; + } + auto parse_result = cppbor::parse(value); + std::unique_ptr sub_item = + std::move(std::get<0>(parse_result)); + std::string error_message = std::move(std::get<2>(parse_result)); + if (sub_item == nullptr || !error_message.empty()) { + AddValidationMessage(kCborValidateError, + "Unable to parse public key: " + error_message); + continue; + } + if (sub_item->type() != cppbor::MAP || sub_item->asMap() == nullptr) { + AddValidationMessage(kCborValidateError, + "Unexpected public key type: " + + CppborMajorTypeToString(sub_item->type())); + continue; + } + const cppbor::Map* public_key_map = sub_item->asMap(); + if (public_key_map->size() == 0) { + payload->subject_public_key.first = kEmpty; + } else { + payload->subject_public_key.first = kPresent; + CborMessageStatus status = ProcessSubjectPublicKeyInfo( + public_key_map, &(payload->subject_public_key.second)); + if (status == kCborValidateFatal) return status; + } + } else if (key == kKeyUsageLabel) { + payload->key_usage.second = entry.second->asBstr()->value(); + payload->key_usage.first = + payload->key_usage.second.empty() ? kEmpty : kPresent; + } else if (key == kCodeHashLabel) { + payload->code_hash.second = entry.second->asBstr()->value(); + payload->code_hash.first = + payload->code_hash.second.empty() ? kEmpty : kPresent; + } else if (key == kCodeDescriptorLabel) { + payload->code_descriptor.second = entry.second->asBstr()->value(); + payload->code_descriptor.first = + payload->code_descriptor.second.empty() ? kEmpty : kPresent; + } else if (key == kConfigurationHashLabel) { + payload->config_hash.second = entry.second->asBstr()->value(); + payload->config_hash.first = + payload->config_hash.second.empty() ? kEmpty : kPresent; + } else if (key == kConfigurationDescriptorLabel) { + const auto& encoded_cd = entry.second->asBstr()->value(); + if (encoded_cd.empty()) { + AddValidationMessage(kCborValidateError, + "Empty configuration descriptor."); + continue; + } + auto parse_result = cppbor::parse(encoded_cd); + std::unique_ptr sub_item = + std::move(std::get<0>(parse_result)); + std::string error_message = std::move(std::get<2>(parse_result)); + if (sub_item == nullptr || !error_message.empty()) { + AddValidationMessage( + kCborValidateError, + "Unable to parse configuration descriptor: " + error_message); + continue; + } + if (sub_item->type() != cppbor::MAP) { + AddValidationMessage(kCborValidateError, + "Unexpected configuration descriptor type: " + + CppborMajorTypeToString(sub_item->type())); + continue; + } + const cppbor::Map* config_descriptor_map = sub_item->asMap(); + if (config_descriptor_map == nullptr || + config_descriptor_map->size() == 0) { + // OK, configuration descriptor is optional. + payload->config_descriptor.first = kEmpty; + } else { + CborMessageStatus status = ProcessConfigurationDescriptor( + config_descriptor_map, &(payload->config_descriptor.second)); + if (status == kCborValidateFatal) return status; + if (status != kCborValidateError) { + payload->config_descriptor.first = kPresent; + } + } + } else if (key == kAuthorityHashLabel) { + payload->authority_hash.second = entry.second->asBstr()->value(); + payload->authority_hash.first = + payload->authority_hash.second.empty() ? kEmpty : kPresent; + } else if (key == kAuthorityDescriptorLabel) { + payload->authority_descriptor.second = entry.second->asBstr()->value(); + payload->authority_descriptor.first = + payload->authority_descriptor.second.empty() ? kEmpty : kPresent; + } else if (key == kModeLabel) { + payload->mode.second = entry.second->asBstr()->value(); + payload->mode.first = payload->mode.second.empty() ? kEmpty : kPresent; + } } - auto parse_result = cppbor::parse(payload); - std::unique_ptr item = std::move(std::get<0>(parse_result)); - std::string error_message = std::move(std::get<2>(parse_result)); - if (item == nullptr || !error_message.empty()) { - AddValidationMessage(kCborValidateFatal, - "Unable to parse bcc entry payload: " + error_message); - return kCborValidateFatal; - } - if (item->type() != cppbor::MAP) { - AddValidationMessage(kCborValidateFatal, - "Unexpected bcc entry payload type: " + - CppborMajorTypeToString(item->type())); - return kCborValidateFatal; - } - const IssuerSubject issuer_subject = - GetIssuerSubjectFromBccEntryPayload(item->asMap()); - if (!issuer_subject.IsValid()) { - AddValidationMessage(kCborValidateError, "Missing Issuer or Subject."); - } - issuer_subject.PrintTo(fmt_msgs); - const cppbor::Bstr* subject_public_key = - GetSubjectPublicKeyFromBccEntryPayload(item->asMap()); - if (subject_public_key == nullptr) { - AddValidationMessage(kCborValidateFatal, - "Bcc entry payload has no subject public key."); - return kCborValidateFatal; - } - - // Now parse the serialized subject public key. - parse_result = cppbor::parse(subject_public_key->value()); - item = std::move(std::get<0>(parse_result)); - error_message = std::move(std::get<2>(parse_result)); - if (item == nullptr || !error_message.empty()) { - AddValidationMessage( - kCborValidateFatal, - "Unable to parse serialized subject public key: " + error_message); - return kCborValidateFatal; - } - const cppbor::Map* subject_public_key_info = item->asMap(); - if (subject_public_key_info == nullptr) { - AddValidationMessage(kCborValidateFatal, - "Invalid subject public key type. Expected Map."); - return kCborValidateFatal; - } - return ProcessSubjectPublicKeyInfo(*subject_public_key_info, fmt_msgs, - entry_public_key_info); + return message_status_; } std::string BccValidator::GetFormattedMessage() const { @@ -557,7 +1095,7 @@ std::string BccValidator::GetFormattedMessage() const { if (parsed_item == nullptr) { return ""; } - return msg_ss_.str(); + return FormatString(msg_ss_.str()); } } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/src/cbor_validator.cpp b/oemcrypto/util/src/cbor_validator.cpp index 608f287..aff3939 100644 --- a/oemcrypto/util/src/cbor_validator.cpp +++ b/oemcrypto/util/src/cbor_validator.cpp @@ -6,12 +6,7 @@ // #include "cbor_validator.h" -#include - -#include -#include -#include -#include +#include namespace wvoec { namespace util { @@ -135,5 +130,37 @@ std::string CborValidator::CheckMapEntry(const cppbor::Map& map, } return ""; } + +std::string CborValidator::FormatString(const std::string& input) { + std::stringstream ss; + int indent = 0; + for (size_t i = 0; i < input.length(); ++i) { + char current = input[i]; + if (current == '[' || current == '{') { + if (i > 0 && input[i - 1] != ':') { + ss << std::string(indent, ' ') << current << std::endl; + } else { + ss << std::string(1, ' ') << current << std::endl; + } + indent += 4; + } else if (current == ']' || current == '}') { + indent -= 4; + ss << std::string(indent, ' ') << current; + } else if (current == ',') { + ss << ',' << std::endl; + } else { + // Handle key-value pairs + if (current != ' ') { // skip any spaces + ss << std::string(indent, ' ') << current; + while (i + 1 < input.length() && input[i + 1] != ',' && + input[i + 1] != '{' && input[i + 1] != '[' && + input[i + 1] != ']' && input[i + 1] != '}') { + ss << input[++i]; + } + } + } + } + return ss.str(); +} } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/src/device_info_validator.cpp b/oemcrypto/util/src/device_info_validator.cpp index 9877f43..fafdf5b 100644 --- a/oemcrypto/util/src/device_info_validator.cpp +++ b/oemcrypto/util/src/device_info_validator.cpp @@ -8,14 +8,15 @@ #include +#include "prov4_validation_helper.h" #include "string_conversions.h" namespace wvoec { namespace util { namespace { -// Number of required device info properties returned from TEE for DeviceInfo -// version v3. -constexpr uint32_t kNumTeeDeviceInfoEntriesV3 = 14; +const std::string kComponent = "DeviceInfo"; + +// Device info properties returned from TEE for DeviceInfo version v3. const std::vector kDeviceInfoKeysV3 = {"brand", "manufacturer", "product", @@ -31,19 +32,441 @@ const std::vector kDeviceInfoKeysV3 = {"brand", "security_level", "fused"}; -struct AttestationIdEntry { - const char* id; - bool alwaysValidate; -}; +bool isValidYYYYMM(const std::string& date) { + // Check if the string has exactly 6 characters + if (date.size() != 6) { + return false; + } + // Check if all characters are digits + for (char c : date) { + if (!std::isdigit(c)) { + return false; + } + } + // Extract year and month as integers + int year = std::stoi(date.substr(0, 4)); // YYYY + int month = std::stoi(date.substr(4, 2)); // MM + // Check if year is within a reasonable range (e.g., 1000 to 9999) + if (year < 1000 || year > 9999) { + return false; + } + // Check if month is valid (01-12) + if (month < 1 || month > 12) { + return false; + } + return true; +} -// Attestation Id and whether it is required. -constexpr AttestationIdEntry kAttestationIdEntrySet[] = {{"brand", false}, - {"manufacturer", true}, - {"product", true}, - {"model", true}, - {"device", false}}; +bool isValidYYYYMMDD(const std::string& date) { + // Check if the string has exactly 8 characters + if (date.size() != 8) { + return false; + } + // Check if all characters are digits + for (char c : date) { + if (!std::isdigit(c)) { + return false; + } + } + // Extract year, month, and day as integers + int year = std::stoi(date.substr(0, 4)); // YYYY + int month = std::stoi(date.substr(4, 2)); // MM + int day = std::stoi(date.substr(6, 2)); // DD + if (!isValidYYYYMM(date.substr(0, 6))) return false; + // Check if year is within a reasonable range (e.g., 1000 to 9999) + if (year < 1000 || year > 9999) { + return false; + } + // Check if month is valid (01-12) + if (month < 1 || month > 12) { + return false; + } + // Check if day is valid based on the month + if (day < 1 || day > 31) { + return false; + } + // Additional check for days in specific months + if ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30) { + return false; // April, June, September, November have 30 days + } + if (month == 2) { // February + // Simple leap year check + bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); + if (day > 29 || (day == 29 && !isLeapYear)) { + return false; // February can't have more than 29 days, and only 29 in + // leap years + } + } + return true; +} } // namespace +std::string DeviceInfo::ToString() const { + std::stringstream ss; + ss << "{"; + PrintField(ss, "brand", brand); + PrintField(ss, "manufacturer", manufacturer); + PrintField(ss, "product", product); + PrintField(ss, "model", model); + PrintField(ss, "device", device); + PrintField(ss, "vb_state", vb_state); + PrintField(ss, "bootloader_state", bootloader_state); + PrintBstrField(ss, "vbmeta_digest", vbmeta_digest); + PrintField(ss, "os_version", os_version); + PrintField(ss, "system_patch_level", system_patch_level); + PrintField(ss, "boot_patch_level", boot_patch_level); + PrintField(ss, "vendor_patch_level", vendor_patch_level); + PrintField(ss, "security_level", security_level); + PrintField(ss, "fused", fused); + PrintField(ss, "board", board); + PrintField(ss, "version", version); + PrintField(ss, "att_id_state", att_id_state); + ss << " }"; + return ss.str(); +} + +CborMessageStatus DeviceInfoValidator::BuildDeviceInfo( + DeviceInfo& device_info, const cppbor::Map* device_info_map) { + std::set previous_keys; + for (auto const& entry : *device_info_map) { + if (!entry.first->asTstr()) { + AddValidationMessage( + kCborValidateError, + "Unexpected entry key type. Expected TSTR, but got " + + CppborMajorTypeToString(entry.first->type())); + continue; + } + const std::string& key = entry.first->asTstr()->value(); + if (previous_keys.find(key) != previous_keys.end()) { + AddValidationMessage(kCborValidateError, + "Duplicate device info entry: " + key); + continue; + } + previous_keys.insert(key); + if (key == "brand") { + if (entry.second->asTstr() == nullptr) { + device_info.brand.first = kEmpty; + } else { + device_info.brand.second = entry.second->asTstr()->value(); + device_info.brand.first = + device_info.brand.second.empty() ? kEmpty : kPresent; + } + } else if (key == "manufacturer") { + if (entry.second->asTstr() == nullptr) { + device_info.manufacturer.first = kEmpty; + } else { + device_info.manufacturer.second = entry.second->asTstr()->value(); + device_info.manufacturer.first = + device_info.manufacturer.second.empty() ? kEmpty : kPresent; + } + } else if (key == "product") { + if (entry.second->asTstr() == nullptr) { + device_info.product.first = kEmpty; + } else { + device_info.product.second = entry.second->asTstr()->value(); + device_info.product.first = + device_info.product.second.empty() ? kEmpty : kPresent; + } + } else if (key == "model") { + if (entry.second->asTstr() == nullptr) { + device_info.model.first = kEmpty; + } else { + device_info.model.second = entry.second->asTstr()->value(); + device_info.model.first = + device_info.model.second.empty() ? kEmpty : kPresent; + } + } else if (key == "device") { + if (entry.second->asTstr() == nullptr) { + device_info.device.first = kEmpty; + } else { + device_info.device.second = entry.second->asTstr()->value(); + device_info.device.first = + device_info.device.second.empty() ? kEmpty : kPresent; + } + } else if (key == "vb_state") { + if (entry.second->asTstr() == nullptr) { + device_info.vb_state.first = kEmpty; + } else { + device_info.vb_state.second = entry.second->asTstr()->value(); + device_info.vb_state.first = + device_info.vb_state.second.empty() ? kEmpty : kPresent; + } + } else if (key == "bootloader_state") { + if (entry.second->asTstr() == nullptr) { + device_info.bootloader_state.first = kEmpty; + } else { + device_info.bootloader_state.second = entry.second->asTstr()->value(); + device_info.bootloader_state.first = + device_info.bootloader_state.second.empty() ? kEmpty : kPresent; + } + } else if (key == "vbmeta_digest") { + if (entry.second->asBstr() == nullptr) { + device_info.vbmeta_digest.first = kEmpty; + } else { + device_info.vbmeta_digest.second = entry.second->asBstr()->value(); + device_info.vbmeta_digest.first = + device_info.vbmeta_digest.second.empty() ? kEmpty : kPresent; + } + } else if (key == "os_version") { + if (entry.second->asTstr() == nullptr) { + device_info.os_version.first = kEmpty; + } else { + device_info.os_version.second = entry.second->asTstr()->value(); + device_info.os_version.first = + device_info.os_version.second.empty() ? kEmpty : kPresent; + } + } else if (key == "system_patch_level") { + if (entry.second->asUint() == nullptr) { + device_info.system_patch_level.first = kEmpty; + } else { + device_info.system_patch_level.second = + std::to_string(entry.second->asUint()->value()); + device_info.system_patch_level.first = + device_info.system_patch_level.second.empty() ? kEmpty : kPresent; + } + } else if (key == "boot_patch_level") { + if (entry.second->asUint() == nullptr) { + device_info.boot_patch_level.first = kEmpty; + } else { + device_info.boot_patch_level.second = + std::to_string(entry.second->asUint()->value()); + device_info.boot_patch_level.first = + device_info.boot_patch_level.second.empty() ? kEmpty : kPresent; + } + } else if (key == "vendor_patch_level") { + if (entry.second->asUint() == nullptr) { + device_info.vendor_patch_level.first = kEmpty; + } else { + device_info.vendor_patch_level.second = + std::to_string(entry.second->asUint()->value()); + device_info.vendor_patch_level.first = + device_info.vendor_patch_level.second.empty() ? kEmpty : kPresent; + } + } else if (key == "security_level") { + if (entry.second->asTstr() == nullptr) { + device_info.security_level.first = kEmpty; + } else { + device_info.security_level.second = entry.second->asTstr()->value(); + device_info.security_level.first = + device_info.security_level.second.empty() ? kEmpty : kPresent; + } + } else if (key == "fused") { + if (entry.second->asUint() == nullptr) { + device_info.fused.first = kEmpty; + } else { + device_info.fused.second = + std::to_string(entry.second->asUint()->value()); + device_info.fused.first = + device_info.fused.second.empty() ? kEmpty : kPresent; + } + } else if (key == "board") { + if (entry.second->asTstr() == nullptr) { + device_info.board.first = kEmpty; + } else { + device_info.board.second = entry.second->asTstr()->value(); + device_info.board.first = + device_info.board.second.empty() ? kEmpty : kPresent; + } + } else if (key == "version") { + if (entry.second->asUint() == nullptr) { + device_info.version.first = kEmpty; + } else { + device_info.version.second = + std::to_string(entry.second->asUint()->value()); + device_info.version.first = + device_info.version.second.empty() ? kEmpty : kPresent; + } + } else if (key == "att_id_state") { + if (entry.second->asTstr() == nullptr) { + device_info.att_id_state.first = kEmpty; + } else { + device_info.att_id_state.second = entry.second->asTstr()->value(); + device_info.att_id_state.first = + device_info.att_id_state.second.empty() ? kEmpty : kPresent; + } + } + } + return kCborValidateOk; +} + +CborMessageStatus DeviceInfo::ValidateV1Fields( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + CborMessageStatus cur_status = + ValidateRequiredField("security_level", kComponent, security_level, msgs); + ApplyStatus(status, cur_status); + cur_status = + ValidateRequiredField("att_id_state", kComponent, att_id_state, msgs); + ApplyStatus(status, cur_status); + return status; +} + +CborMessageStatus DeviceInfo::ValidateV2Fields( + bool is_tee_device_info, + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + CborMessageStatus cur_status; + // TEE IRPC instances require all entries to be present in device info. + // Non-TEE instances may omit `os_version`. + if (is_tee_device_info) { + cur_status = + ValidateRequiredField("os_version", kComponent, os_version, msgs); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("brand", kComponent, brand, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateRequiredField("product", kComponent, product, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateRequiredField("device", kComponent, device, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateRequiredField("vb_state", kComponent, vb_state, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = vb_state.second; + if (value != "green" && value != "yellow" && value != "orange") { + msgs.push_back(std::make_pair( + kCborValidateError, + kComponent + ": unexpected value for vb_state (" + value + ")")); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("bootloader_state", kComponent, + bootloader_state, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = bootloader_state.second; + if (value != "locked" && value != "unlocked") { + msgs.push_back(std::make_pair( + kCborValidateError, kComponent + + ": unexpected value for bootloader_state (" + + value + ")")); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = + ValidateRequiredField("vbmeta_digest", kComponent, vbmeta_digest, msgs); + ApplyStatus(status, cur_status); + + cur_status = + ValidateRequiredField("security_level", kComponent, security_level, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = security_level.second; + if (value != "tee" && value != "strongbox") { + msgs.push_back(std::make_pair( + kCborValidateError, kComponent + + ": unexpected value for security_level (" + + value + ")")); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("fused", kComponent, fused, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = fused.second; + if (value != "1" && value != "0") { + msgs.push_back(std::make_pair( + kCborValidateError, + kComponent + ": unexpected value for fused (" + value + ")")); + ApplyStatus(status, kCborValidateError); + } + } + return status; +} + +CborMessageStatus DeviceInfo::ValidateV3Fields( + bool is_tee_device_info, + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + CborMessageStatus cur_status; + // Checks for the required fields that only apply to v3: system_patch_level, + // boot_patch_level, vendor_patch_level + cur_status = ValidateRequiredField("system_patch_level", kComponent, + system_patch_level, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = system_patch_level.second; + if (!isValidYYYYMM(value)) { + msgs.push_back(std::make_pair( + kCborValidateError, kComponent + + ": invalid value for system_patch_level (" + + value + "), should be YYYYMM")); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("boot_patch_level", kComponent, + boot_patch_level, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = boot_patch_level.second; + if (!isValidYYYYMMDD(value)) { + msgs.push_back(std::make_pair( + kCborValidateError, kComponent + + ": invalid value for boot_patch_level (" + + value + "), should be YYYYMMDD")); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateRequiredField("vendor_patch_level", kComponent, + vendor_patch_level, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + const std::string& value = vendor_patch_level.second; + if (!isValidYYYYMMDD(value)) { + msgs.push_back(std::make_pair( + kCborValidateError, kComponent + + ": invalid value for vendor_patch_level (" + + value + "), should be YYYYMMDD")); + ApplyStatus(status, kCborValidateError); + } + } + cur_status = ValidateV2Fields(is_tee_device_info, msgs); + ApplyStatus(status, cur_status); + return status; +} + +CborMessageStatus DeviceInfo::Validate( + std::vector>& msgs, bool is_gms, + int version_number) const { + CborMessageStatus status = kCborParseOk; + CborMessageStatus cur_status; + // AOSP and CE devices. + if (!is_gms) { + cur_status = + ValidateImportantField("manufacturer", kComponent, manufacturer, msgs); + ApplyStatus(status, cur_status); + cur_status = ValidateImportantField("model", kComponent, model, msgs); + ApplyStatus(status, cur_status); + if (fused.first != kPresent) { + msgs.push_back(std::make_pair( + kCborValidateWarning, + "DeviceInfo: missing field fused. Treat this as an error if it is " + "from a device that uses a de-generated BCC, in which case fused is " + "a required field.")); + ApplyStatus(status, kCborValidateWarning); + } + return status; + } + // GMS device requires more fields. + bool is_tee_device_info = + (security_level.first == kPresent && security_level.second == "tee"); + if (version_number == 3) { + cur_status = ValidateV3Fields(is_tee_device_info, msgs); + ApplyStatus(status, cur_status); + } else if (version_number == 2) { + cur_status = ValidateV2Fields(is_tee_device_info, msgs); + ApplyStatus(status, cur_status); + } else if (version_number == 1) { + cur_status = ValidateV1Fields(msgs); + ApplyStatus(status, cur_status); + } else { + msgs.push_back({kCborValidateFatal, "Unrecognized device info version: " + + std::to_string(version_number)}); + return kCborValidateFatal; + } + return status; +} + CborMessageStatus DeviceInfoValidator::Parse( const std::vector& device_info) { message_status_ = CborValidator::Parse(device_info); @@ -71,157 +494,33 @@ CborMessageStatus DeviceInfoValidator::Validate() { AddValidationMessage(kCborValidateError, "Device info ordering is non-canonical."); } - const cppbor::Item* security_level = - GetMapEntry(*device_info_map, "security_level"); - const bool is_tee_device_info = security_level && security_level->asTstr() && - security_level->asTstr()->value() == "tee"; - std::set previous_keys; - switch (version_number_) { - case 3: - if (is_tee_device_info && - device_info_map->size() != kNumTeeDeviceInfoEntriesV3) { - AddValidationMessage( - kCborValidateError, - "Incorrect number of TEE device info entries. Expected " + - std::to_string(kNumTeeDeviceInfoEntriesV3) + " but got " + - std::to_string(device_info_map->size())); - } - // TEE IRPC instances require all entries to be present in device info. - // Non-TEE instances may omit `os_version`. - if (!is_tee_device_info && - (device_info_map->size() != kNumTeeDeviceInfoEntriesV3 && - device_info_map->size() != kNumTeeDeviceInfoEntriesV3 - 1)) { - AddValidationMessage( - kCborValidateError, - "Incorrect number of non-TEE device info entries. Expected " + - std::to_string(kNumTeeDeviceInfoEntriesV3 - 1) + " but got " + - std::to_string(device_info_map->size())); - } - for (auto const& entry : *device_info_map) { - if (!entry.first->asTstr()) { - AddValidationMessage( - kCborValidateError, - "Unexpected entry key type. Expected TSTR, but got " + - CppborMajorTypeToString(entry.first->type())); - continue; - } - const std::string& key = entry.first->asTstr()->value(); - if (previous_keys.find(key) != previous_keys.end()) { - AddValidationMessage(kCborValidateError, - "Duplicate device info entry: " + key); - } - previous_keys.insert(key); - if (std::find(kDeviceInfoKeysV3.begin(), kDeviceInfoKeysV3.end(), - key) == kDeviceInfoKeysV3.end()) { - AddValidationMessage(kCborValidateError, - "Unrecognized device info entry: " + key); - } - } - // Checks for the required fields that only apply to v3. - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, - "system_patch_level"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, - "boot_patch_level"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, - "vendor_patch_level"); - // Fall through - CORE_UTIL_FALLTHROUGH; - case 2: - for (const auto& entry : kAttestationIdEntrySet) { - if (entry.alwaysValidate) { - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, entry.id); - } - } - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, "vb_state"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, - "bootloader_state"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::BSTR, "vbmeta_digest"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, - "system_patch_level"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, - "boot_patch_level"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, - "vendor_patch_level"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::UINT, "fused"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, "security_level"); - if (is_tee_device_info) { - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, "os_version"); - } - break; - case 1: - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, "security_level"); - CheckDeviceInfoMapEntry(*device_info_map, cppbor::TSTR, "att_id_state"); - break; - default: - AddValidationMessage( - kCborValidateFatal, - "Unrecognized version: " + std::to_string(version_number_)); - return message_status_; - } + DeviceInfo device_info; + CborMessageStatus cur_status = BuildDeviceInfo(device_info, device_info_map); + if (cur_status == kCborValidateFatal) return cur_status; + // Print the parse device info. + msg_ss_ << device_info.ToString() << "\n"; + + std::vector> msgs; + cur_status = device_info.Validate(msgs, is_gms_, version_number_); + ApplyStatus(message_status_, cur_status); + for (const auto& msg : msgs) { + AddValidationMessage(msg.first, msg.second); + } if (message_status_ == kCborParseOk) message_status_ = kCborValidateOk; return message_status_; } -void DeviceInfoValidator::CheckDeviceInfoMapEntry( - const cppbor::Map& device_info, cppbor::MajorType major_type, - const std::string& entry_name) { - const std::string error = CheckMapEntry(device_info, major_type, entry_name); - if (!error.empty()) { - AddValidationMessage(kCborValidateError, error); - } -} - std::string DeviceInfoValidator::GetFormattedMessage() const { if (message_status_ == kCborUninitialized || - message_status_ == kCborParseError || - message_status_ == kCborValidateFatal) { + message_status_ == kCborParseError) { return std::string(); } const cppbor::Item* parsed_item = std::get<0>(parse_result()).get(); if (parsed_item == nullptr) { return ""; } - // Writes YAML-formatted output to |msg_ss_|. - std::stringstream msg_ss; - msg_ss << "---\n"; - msg_ss << "DEVICE INFO MAP:\n"; - - for (auto const& entry : *(parsed_item->asMap())) { - auto const& entry_value = entry.second; - // Device info map only allows TSTR key type. - if (!entry.first->asTstr()) continue; - const std::string& name = entry.first->asTstr()->value(); - msg_ss << " " << name << ": "; - switch (entry_value->type()) { - case cppbor::TSTR: { - const std::string val = entry_value->asTstr()->value().empty() - ? "" - : entry_value->asTstr()->value(); - msg_ss << val << "\n"; - break; - } - case cppbor::UINT: - msg_ss << std::to_string(entry_value->asUint()->value()) << "\n"; - break; - case cppbor::NINT: - msg_ss << std::to_string(entry_value->asNint()->value()) << "\n"; - break; - case cppbor::BSTR: { - const std::vector& bytes = entry_value->asBstr()->value(); - const std::string val = - bytes.empty() ? "" : wvutil::b2a_hex(bytes); - msg_ss << val << "\n"; - break; - } - default: - msg_ss << "Unsupported type (" - << CppborMajorTypeToString(entry_value->type()) << ")\n"; - break; - } - } - msg_ss << "...\n"; - return msg_ss.str(); + return FormatString(msg_ss_.str()); } } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/src/prov4_validation_helper.cpp b/oemcrypto/util/src/prov4_validation_helper.cpp new file mode 100644 index 0000000..447db25 --- /dev/null +++ b/oemcrypto/util/src/prov4_validation_helper.cpp @@ -0,0 +1,25 @@ +// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +#include "prov4_validation_helper.h" + +namespace wvoec { +namespace util { +std::string StatusToString(FieldStatus status) { + if (status == FieldStatus::kAbsent) { + return ""; + } + if (status == FieldStatus::kEmpty) { + return ""; + } + return "present"; +} + +void ApplyStatus(CborMessageStatus& status, CborMessageStatus new_status) { + if (new_status > status) { + status = new_status; + } +} +} // namespace util +} // namespace wvoec diff --git a/oemcrypto/util/src/signed_csr_payload_validator.cpp b/oemcrypto/util/src/signed_csr_payload_validator.cpp index c3923d5..020d958 100644 --- a/oemcrypto/util/src/signed_csr_payload_validator.cpp +++ b/oemcrypto/util/src/signed_csr_payload_validator.cpp @@ -13,24 +13,164 @@ namespace wvoec { namespace util { namespace { -enum CoseKeyAlgorithm : int { - AES_GCM_256 = 3, - HMAC_256 = 5, - ES256 = -7, // ECDSA with SHA-256 - EDDSA = -8, - ECDH_ES_HKDF_256 = -25, - ES384 = -35, // ECDSA with SHA-384 -}; - -void AddMessages(std::stringstream& ss, - const std::vector& fmt_msgs, int indent) { - const std::string spaces = std::string(indent * 2, ' '); - for (auto& msg : fmt_msgs) { - ss << spaces << msg << "\n"; - } -} +const std::string kCsrPayloadVersion = "3"; +constexpr size_t kMaxChallengeSize = 64; } // namespace +std::string CertificateType::ToString() const { + std::stringstream ss; + ss << "{"; + ss << " type:"; + if (type.first != kPresent) { + ss << StatusToString(type.first) << ","; + } else { + ss << type.second << ","; + } + ss << " }"; + return ss.str(); +} + +CborMessageStatus CertificateType::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "CertificateType"; + CborMessageStatus cur_status = + ValidateRequiredField("type", component, type, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + if (type.second != "widevine" && type.second != "keymint" && + type.second != "rkp-vm") { + msgs.push_back(std::make_pair( + kCborValidateError, + component + ": Invalid certificate type " + type.second)); + ApplyStatus(status, kCborValidateError); + } + } + return status; +} + +std::string SignedDataProtected::ToString() const { + std::stringstream ss; + ss << "{"; + ss << " algorithm:"; + if (algorithm.first != kPresent) { + ss << StatusToString(algorithm.first) << ","; + } else { + if (algorithm.second == DEVICE_KEY_ALGORITHM_EDDSA) { + ss << "EdDSA" << ","; + } else if (algorithm.second == DEVICE_KEY_ALGORITHM_ES256) { + ss << "ECDSA_SHA256" << ","; + } else if (algorithm.second == DEVICE_KEY_ALGORITHM_ES384) { + ss << "ECDSA_SHA384" << ","; + } else { + ss << "unknown(" << algorithm.second << ")" << ","; + } + } + ss << " }"; + return ss.str(); +} + +CborMessageStatus SignedDataProtected::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "SignedDataProtected"; + CborMessageStatus cur_status = + ValidateRequiredField("algorithm", component, algorithm, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + if (algorithm.second != DEVICE_KEY_ALGORITHM_EDDSA && + algorithm.second != DEVICE_KEY_ALGORITHM_ES256 && + algorithm.second != DEVICE_KEY_ALGORITHM_ES384) { + msgs.push_back(std::make_pair(kCborValidateError, + component + ": Invalid algorithm " + + std::to_string(algorithm.second))); + ApplyStatus(status, kCborValidateError); + } + } + return status; +} + +// CsrPayload = [ ; CBOR Array defining the payload for CSR. +// version: 3, ; The CsrPayload CDDL Schema version. +// CertificateType: "widevine" ; The type of certificate being requested. +// DeviceInfo, ; Defined in Android DeviceInfo.aidl +// KeysToSign: [] ; Empty list +// ] +std::string CsrPayload::ToString() const { + std::stringstream ss; + ss << "["; + PrintField(ss, "version", version); + PrintCborField(ss, "certificate_type", certificate_type); + PrintCborField(ss, "device_info", device_info); + ss << " keys_to_sign:["; + for (auto& key : keys_to_sign) { + PrintCborField(ss, "keys_to_sign", std::make_pair(kAbsent, key)); + } + ss << " ],"; + ss << " ]"; + return ss.str(); +} + +CborMessageStatus CsrPayload::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "CsrPayload"; + CborMessageStatus cur_status = + ValidateRequiredField("version", component, version, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk && version.second != kCsrPayloadVersion) { + msgs.push_back(std::make_pair( + kCborValidateError, component + ": Invalid version " + version.second + + ". Expected " + kCsrPayloadVersion)); + ApplyStatus(status, kCborValidateError); + } + cur_status = + ValidateRequiredField("device_info", component, device_info, msgs); + ApplyStatus(status, cur_status); + // Validation of device_info is done in DeviceInfoValidator separately for + // now. + return status; +} + +// DataToBeSigned = [ +// challenge: bstr .size (0..64), +// bstr .cbor CsrPayload, +// ] +std::string DataToBeSigned::ToString() const { + std::stringstream ss; + ss << "["; + PrintBstrField(ss, "challenge", challenge); + PrintCborField(ss, "csr_payload", csr_payload); + ss << " ]"; + return ss.str(); +} + +CborMessageStatus DataToBeSigned::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "DataToBeSigned"; + CborMessageStatus cur_status = + ValidateRequiredField("challenge", component, challenge, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk && + challenge.second.size() > kMaxChallengeSize) { + msgs.push_back(std::make_pair(kCborValidateError, + "Unexpected challenge size: " + + std::to_string(challenge.second.size()) + + ". Expected no more than " + + std::to_string(kMaxChallengeSize))); + ApplyStatus(status, kCborValidateError); + } + cur_status = + ValidateRequiredField("csr_payload", component, csr_payload, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + cur_status = csr_payload.second.Validate(msgs); + ApplyStatus(status, cur_status); + } + return status; +} + // clang-format off // Signed CSR payload CBOR data to be verified: // SignedData = [ @@ -41,134 +181,154 @@ void AddMessages(std::stringstream& ss, // signature: bstr ; PureEd25519(priv_key, Sig_structure) / // ; ECDSA(priv_key, Sig_structure) // ] -// -// DataToBeSigned = [ -// challenge: bstr .size (0..64), -// bstr .cbor CsrPayload, -// ] -// -// CsrPayload = [ ; CBOR Array defining the payload for CSR. -// version: 3, ; The CsrPayload CDDL Schema version. -// CertificateType: "widevine" ; The type of certificate being requested. -// DeviceInfo, ; Defined in Android DeviceInfo.aidl -// KeysToSign: [] ; Empty list -// ] -// -// Sig_structure = [ -// context: "Signature1", -// protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 / AlgorithmES384 }, -// external_aad: bstr .size 0, -// payload: bstr .cbor DataToBeSigned / nil, -// ] // clang-format on +std::string SignedCsrPayload::ToString() const { + std::stringstream ss; + ss << "SignedCSRpayload = ["; + PrintCborField(ss, "protected", protected_data); + PrintField(ss, "unprotected", unprotected); + PrintCborField(ss, "payload", payload); + PrintBstrField(ss, "signature", signature); + ss << " ]"; + return ss.str(); +} + +CborMessageStatus SignedCsrPayload::Validate( + std::vector>& msgs) const { + CborMessageStatus status = kCborParseOk; + const std::string component = "SignedCsrPayload"; + CborMessageStatus cur_status = + ValidateRequiredField("protected", component, protected_data, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + cur_status = protected_data.second.Validate(msgs); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("payload", component, payload, msgs); + ApplyStatus(status, cur_status); + if (cur_status == kCborValidateOk) { + cur_status = payload.second.Validate(msgs); + ApplyStatus(status, cur_status); + } + cur_status = ValidateRequiredField("signature", component, signature, msgs); + ApplyStatus(status, cur_status); + // Skip CoseSign1 signature verification since the validator doesn't have + // verifying keys. + return status; +} // Caller ensures the pointer is not NULL. -CborMessageStatus SignedCsrPayloadValidator::ValidateProtectedParams( - const cppbor::Bstr* protected_params) { - auto parse_result = cppbor::parse(protected_params); - std::unique_ptr parsed_protected_params = - std::move(std::get<0>(parse_result)); - const std::string error_message = std::move(std::get<2>(parse_result)); - if (!parsed_protected_params || !error_message.empty()) { - AddValidationMessage(kCborValidateFatal, - "Unable to parse protectedParams: " + error_message); - return message_status_; - } - // |parsed_protected_params| is a CBOR map of 1 entry - const cppbor::Map* protected_params_map = parsed_protected_params->asMap(); - if (!protected_params_map) { - AddValidationMessage( - kCborValidateFatal, - "ProtectedParams must be a CBOR map. Actual type: " + - CppborMajorTypeToString(parsed_protected_params->type())); - return message_status_; - } - if (protected_params_map->size() == 0) { - AddValidationMessage(kCborValidateFatal, "ProtectedParams is empty."); - return message_status_; - } - if (protected_params_map->size() > 1) { +CborMessageStatus SignedCsrPayloadValidator::ProcessSignedDataProtected( + const cppbor::Map* protected_map, SignedDataProtected* protected_data) { + if (protected_map->size() > 1) { AddValidationMessage(kCborValidateWarning, - "ProtectedParams expects 1 entry, but got " + - std::to_string(protected_params_map->size())); + "Protected data map expects 1 entry, but got " + + std::to_string(protected_map->size())); } - // TODO(b/314141962): Replace this with the map lookup function in cppbor - // library - bool algo_found = false; - for (auto const& entry : *protected_params_map) { - if (!entry.first->asInt()) { - AddValidationMessage(kCborValidateWarning, - "Unsupported key type: " + - CppborMajorTypeToString(entry.first->type())); - } else if (entry.first->asInt()->value() != 1) { - AddValidationMessage(kCborValidateWarning, - "Unsupported key value: " + - std::to_string(entry.first->asInt()->value())); - } else { - auto& algorithm = entry.second; - if (!algorithm) { - AddValidationMessage(kCborValidateFatal, "Algorithm value is missing."); - return message_status_; - } - if (!algorithm->asInt()) { - AddValidationMessage(kCborValidateFatal, - "Unsupported signature algorithm value type: " + - CppborMajorTypeToString(algorithm->type())); - return message_status_; - } - std::string kv = "1: "; - const int64_t algo = algorithm->asInt()->value(); - if (algo == EDDSA) - kv += "EDDSA"; - else if (algo == ES256) - kv += "ES256"; - else if (algo == ES384) - kv += "ES384"; - else { - kv += std::to_string(algo); - AddValidationMessage( - kCborValidateFatal, - "Unsupported signature algorithm value: " + std::to_string(algo)); - return message_status_; - } - AddMessages(msg_ss_, {std::move(kv)}, 1); - algo_found = true; + for (size_t index = 0; index < protected_map->size(); ++index) { + std::pair&, + const std::unique_ptr&> + entry = (*protected_map)[index]; + if (entry.first->type() != cppbor::NINT && + entry.first->type() != cppbor::UINT) { + AddValidationMessage( + kCborValidateWarning, + "Invalid key type in protected data map in signed CSR payload: " + + CppborMajorTypeToString(entry.first->type())); + continue; + } + const int64_t map_key = entry.first->asInt()->value(); + if (map_key == 1) { + if (entry.second->type() != cppbor::NINT && + entry.second->type() != cppbor::UINT) { + AddValidationMessage(kCborValidateError, + "Invalid value type in protected data map for " + "key 1: " + + CppborMajorTypeToString(entry.second->type())); + continue; + } + protected_data->algorithm.first = kPresent; + protected_data->algorithm.second = entry.second->asInt()->value(); + } else { + AddValidationMessage(kCborValidateWarning, + "Unsupported key value in protected data map: " + + std::to_string(map_key)); } - } - if (!algo_found) { - AddValidationMessage(kCborValidateFatal, - "ProtectedParams has no signature algorithm."); } return message_status_; } // Caller ensures the pointer is not NULL. -CborMessageStatus SignedCsrPayloadValidator::ValidateDataToBeSigned( - const cppbor::Bstr* data) { - if (data->value().empty()) { - AddValidationMessage(kCborValidateFatal, "Payload to be signed is empty."); - return message_status_; +CborMessageStatus SignedCsrPayloadValidator::ProcessCsrPayload( + const cppbor::Array* csr_payload_array, CsrPayload* csr_payload) { + if (csr_payload_array->size() < 4U) { + AddValidationMessage(kCborValidateFatal, + "CSR payload must contain 4 elements. Actual size: " + + std::to_string(csr_payload_array->size())); + return kCborValidateFatal; } - auto parse_result = cppbor::parse(data); - std::unique_ptr parsed_payload_to_be_signed = - std::move(std::get<0>(parse_result)); - std::string error_message = std::move(std::get<2>(parse_result)); - if (!parsed_payload_to_be_signed || !error_message.empty()) { + // |csr_payload_array| is an array of 4 elements. + const cppbor::Uint* version = csr_payload_array->get(0)->asUint(); + if (version != nullptr) { + csr_payload->version.first = kPresent; + csr_payload->version.second = std::to_string(version->value()); + } else { AddValidationMessage( - kCborValidateFatal, - "Unable to parse the payload to be signed: " + error_message); - return message_status_; + kCborValidateError, + "CSR payload version must be an unsigned integer. Actual type: " + + CppborMajorTypeToString(csr_payload_array->get(0)->type())); } - // Verify that |parsed_payload_to_be_signed| is a valid array. - const cppbor::Array* payload_to_be_signed_array = - parsed_payload_to_be_signed->asArray(); - if (!payload_to_be_signed_array) { + const cppbor::Tstr* certificate_type = csr_payload_array->get(1)->asTstr(); + if (certificate_type != nullptr) { + if (certificate_type->value().empty()) { + csr_payload->certificate_type.first = kEmpty; + } else { + csr_payload->certificate_type.first = kPresent; + CertificateType& certificate_type_ref = + csr_payload->certificate_type.second; + certificate_type_ref.type.second = certificate_type->value(); + certificate_type_ref.type.first = + certificate_type_ref.type.second.empty() ? kEmpty : kPresent; + } + } else { AddValidationMessage( - kCborValidateFatal, - "Payload to be signed must be a CBOR array. Actual type: " + - CppborMajorTypeToString(parsed_payload_to_be_signed->type())); - return message_status_; + kCborValidateError, + "Certificate type must be Tstr. Actual type: " + + CppborMajorTypeToString(csr_payload_array->get(1)->type())); } + + const cppbor::Map* device_info_map = csr_payload_array->get(2)->asMap(); + if (device_info_map != nullptr) { + if (device_info_map->size() == 0) { + csr_payload->device_info.first = kEmpty; + } else { + // Dummy device info as a placeholder for now. + // TODO: parse the device info. + DeviceInfo device_info; + csr_payload->device_info.first = kPresent; + csr_payload->device_info.second = std::move(device_info); + } + } else { + AddValidationMessage( + kCborValidateError, + "Device info must be a CBOR map. Actual type: " + + CppborMajorTypeToString(csr_payload_array->get(2)->type())); + } + + const cppbor::Array* keys = csr_payload_array->get(3)->asArray(); + if (!keys) { + AddValidationMessage( + kCborValidateError, + "Keys must be a CBOR array. Actual type: " + + CppborMajorTypeToString(csr_payload_array->get(3)->type())); + } + return message_status_; +} + +// Caller ensures the pointer is not NULL. +CborMessageStatus SignedCsrPayloadValidator::ProcessDataToBeSigned( + const cppbor::Array* payload_to_be_signed_array, + DataToBeSigned* payload_to_be_signed) { if (payload_to_be_signed_array->size() != 2U) { AddValidationMessage( kCborValidateFatal, @@ -177,39 +337,27 @@ CborMessageStatus SignedCsrPayloadValidator::ValidateDataToBeSigned( std::to_string(payload_to_be_signed_array->size())); return message_status_; } - // Element 0: challenge. - std::string msg = "- Challenge: "; const cppbor::Bstr* challenge = payload_to_be_signed_array->get(0)->asBstr(); - if (!challenge) { - AddValidationMessage(kCborValidateFatal, - "Challenge must be Bstr. Actual type: " + - CppborMajorTypeToString( - payload_to_be_signed_array->get(0)->type())); - return message_status_; + if (challenge != nullptr) { + if (!challenge->value().empty()) { + payload_to_be_signed->challenge.first = kPresent; + payload_to_be_signed->challenge.second = challenge->value(); + } else { + payload_to_be_signed->challenge.first = kEmpty; + } } - if (challenge->value().size() > 64) { - AddValidationMessage( - kCborValidateError, - "Challenge size must be between 0 and 64 bytes inclusive. " - "However, challenge is " + - std::to_string(challenge->value().size()) + " bytes long."); - } - msg += wvutil::b2a_hex(challenge->value()); - AddMessages(msg_ss_, {std::move(msg)}, 1); - // Element 1: CsrPayload. - AddMessages(msg_ss_, {"- CsrPayload:"}, 1); const cppbor::Bstr* csr_payload = payload_to_be_signed_array->get(1)->asBstr(); if (!csr_payload) { AddValidationMessage(kCborValidateFatal, "CSR payload is missing."); return message_status_; } - parse_result = cppbor::parse(csr_payload); + auto parse_result = cppbor::parse(csr_payload); std::unique_ptr parsed_csr_payload = std::move(std::get<0>(parse_result)); - error_message = std::move(std::get<2>(parse_result)); + auto error_message = std::move(std::get<2>(parse_result)); if (!parsed_csr_payload) { AddValidationMessage(kCborValidateFatal, "Unable to parse CSR payload: " + error_message); @@ -222,63 +370,15 @@ CborMessageStatus SignedCsrPayloadValidator::ValidateDataToBeSigned( CppborMajorTypeToString(parsed_csr_payload->type())); return message_status_; } - if (parsed_csr_payload->asArray()->size() != 4U) { - AddValidationMessage( - kCborValidateFatal, - "CSR payload must contain 4 elements. Actual size: " + - std::to_string(parsed_csr_payload->asArray()->size())); - return message_status_; + if (parsed_csr_payload->asArray()->size() == 0) { + payload_to_be_signed->csr_payload.first = kEmpty; + } else { + payload_to_be_signed->csr_payload.first = kPresent; + CborMessageStatus status = + ProcessCsrPayload(parsed_csr_payload->asArray(), + &payload_to_be_signed->csr_payload.second); + ApplyStatus(message_status_, status); } - // |parsed_csr_payload| is an array of 4 elements. - const cppbor::Uint* version = parsed_csr_payload->asArray()->get(0)->asUint(); - if (!version) { - AddValidationMessage(kCborValidateFatal, - "CSR payload version must be an unsigned integer."); - return message_status_; - } - AddMessages(msg_ss_, {"- version: " + std::to_string(version->value())}, 2); - if (version->value() != 3U) { - AddValidationMessage(kCborValidateError, - "CSR payload version must be must be equal to 3."); - } - - const cppbor::Tstr* certificate_type = - parsed_csr_payload->asArray()->get(1)->asTstr(); - if (!certificate_type) { - // Certificate type is allowed to be extended by vendor, i.e. we can't - // enforce its value. - AddValidationMessage( - kCborValidateFatal, - "Certificate type must be Tstr. Actual type: " + - CppborMajorTypeToString( - parsed_csr_payload->asArray()->get(1)->type())); - return message_status_; - } - AddMessages(msg_ss_, {"- certificate_type: " + certificate_type->value()}, 2); - - const cppbor::Map* device_info = - parsed_csr_payload->asArray()->get(2)->asMap(); - if (!device_info) { - AddValidationMessage( - kCborValidateFatal, - "Device info must be a CBOR map. Actual type: " + - CppborMajorTypeToString( - parsed_csr_payload->asArray()->get(2)->type())); - return message_status_; - } - AddMessages(msg_ss_, {"- device_info: " + cppbor::prettyPrint(device_info)}, - 2); - - const cppbor::Array* keys = parsed_csr_payload->asArray()->get(3)->asArray(); - if (!keys) { - AddValidationMessage( - kCborValidateFatal, - "Keys must be a CBOR array. Actual type: " + - CppborMajorTypeToString( - parsed_csr_payload->asArray()->get(3)->type())); - return message_status_; - } - AddMessages(msg_ss_, {"- keys_to_sign: " + cppbor::prettyPrint(keys)}, 2); return message_status_; } @@ -288,16 +388,15 @@ CborMessageStatus SignedCsrPayloadValidator::Validate() { std::get<0>(parse_result()).get(); if (!parsed_signed_csr_payload) { AddValidationMessage(kCborValidateFatal, "Signed CSR payload is empty."); - return message_status_; + return kCborValidateFatal; } - // Verify that |parsed_signed_csr_payload| is a valid array. if (!parsed_signed_csr_payload->asArray()) { AddValidationMessage( kCborValidateFatal, "Signed CSR payload must be a CBOR array. Actual type: " + CppborMajorTypeToString(parsed_signed_csr_payload->type())); - return message_status_; + return kCborValidateFatal; } const cppbor::Array* signed_csr_payload_array = parsed_signed_csr_payload->asArray(); @@ -305,43 +404,78 @@ CborMessageStatus SignedCsrPayloadValidator::Validate() { AddValidationMessage(kCborValidateFatal, "Invalid CoseSign1 size. Actual: " + std::to_string(signed_csr_payload_array->size())); - return message_status_; + return kCborValidateFatal; } - // Writes YAML-formatted output to |msg_ss_| during validation. - msg_ss_.str(std::string()); - msg_ss_ << "---" - << "\n"; - + // Parse each element of the array. + CborMessageStatus status = kCborValidateOk; + SignedCsrPayload signed_csr_payload; // Element 0: protected params. - msg_ss_ << "- Protected params:\n"; const cppbor::Bstr* protected_params = signed_csr_payload_array->get(0)->asBstr(); - CborMessageStatus status = ValidateProtectedParams(protected_params); - if (status == kCborValidateFatal) return kCborValidateFatal; + if (!protected_params) { + AddValidationMessage( + kCborValidateFatal, + "Signed csr payload protected data type must be Bstr. Actual type: " + + CppborMajorTypeToString(signed_csr_payload_array->get(0)->type())); + return kCborValidateFatal; + } + // Parse and verify the protected data. + const std::vector& encoded_protected_data = + signed_csr_payload_array->get(0)->asBstr()->value(); + if (encoded_protected_data.empty()) { + AddValidationMessage(kCborValidateFatal, + "Empty signed csr payload protected data."); + return kCborValidateFatal; + } + auto parse_protected_data_result = cppbor::parse(encoded_protected_data); + std::unique_ptr protected_data_item = + std::move(std::get<0>(parse_protected_data_result)); + std::string error_message = + std::move(std::get<2>(parse_protected_data_result)); + if (protected_data_item == nullptr || !error_message.empty()) { + AddValidationMessage( + kCborValidateFatal, + "Unable to parse signed csr payload protected: " + error_message); + return kCborValidateFatal; + } + if (protected_data_item->type() != cppbor::MAP) { + AddValidationMessage( + kCborValidateFatal, + "Unexpected signed csr payload protected type: " + + CppborMajorTypeToString(protected_data_item->type())); + return kCborValidateFatal; + } + const cppbor::Map* protected_map = protected_data_item->asMap(); + if (protected_map == nullptr) { + AddValidationMessage(kCborValidateFatal, + "Signed csr payload protected map is null."); + return kCborValidateFatal; + } + if (protected_map->size() == 0) { + signed_csr_payload.protected_data.first = kEmpty; + } else { + signed_csr_payload.protected_data.first = kPresent; + status = ProcessSignedDataProtected( + protected_map, &signed_csr_payload.protected_data.second); + if (status == kCborValidateFatal) return status; + } // Element 1: unprotected params map. - std::string msg = "- Unprotected params: "; const cppbor::Map* unprotected_params = signed_csr_payload_array->get(1)->asMap(); if (!unprotected_params) { AddValidationMessage( - kCborValidateFatal, + kCborValidateError, "UnprotectedParams must be a CBOR map. Actual type: " + CppborMajorTypeToString(signed_csr_payload_array->get(1)->type())); - return message_status_; - } - if (unprotected_params->size() == 0) { - msg += ""; } else { - msg += "non-null map"; - AddValidationMessage(kCborValidateWarning, - "UnprotectedParams is expected to be empty."); + // Unprotected data is supposed to be empty and can be ignored. + signed_csr_payload.unprotected.first = kEmpty; + signed_csr_payload.unprotected.second = "{}"; } - msg_ss_ << msg << "\n"; // Element 2: payload (DataToBeSigned). - msg_ss_ << "- Payload:\n"; const cppbor::Bstr* payload_to_be_signed = signed_csr_payload_array->get(2)->asBstr(); if (!payload_to_be_signed) { @@ -351,29 +485,58 @@ CborMessageStatus SignedCsrPayloadValidator::Validate() { CppborMajorTypeToString(signed_csr_payload_array->get(2)->type())); return message_status_; } - status = ValidateDataToBeSigned(payload_to_be_signed); - if (status == kCborValidateFatal) return kCborValidateFatal; + auto parse_payload_to_be_signed_result = cppbor::parse(payload_to_be_signed); + std::unique_ptr parsed_payload_to_be_signed_item = + std::move(std::get<0>(parse_payload_to_be_signed_result)); + error_message = std::move(std::get<2>(parse_payload_to_be_signed_result)); + if (!parsed_payload_to_be_signed_item || !error_message.empty()) { + AddValidationMessage( + kCborValidateFatal, + "Unable to parse the payload to be signed: " + error_message); + return kCborValidateFatal; + } + // Verify that |parsed_payload_to_be_signed_item| is a valid array. + const cppbor::Array* payload_to_be_signed_array = + parsed_payload_to_be_signed_item->asArray(); + if (!payload_to_be_signed_array) { + AddValidationMessage( + kCborValidateFatal, + "Payload to be signed must be a CBOR array. Actual type: " + + CppborMajorTypeToString(parsed_payload_to_be_signed_item->type())); + return kCborValidateFatal; + } + if (payload_to_be_signed_array->size() == 0) { + signed_csr_payload.payload.first = kEmpty; + } else { + signed_csr_payload.payload.first = kPresent; + status = ProcessDataToBeSigned(payload_to_be_signed_array, + &signed_csr_payload.payload.second); + if (status == kCborValidateFatal) return kCborValidateFatal; + } // Element 3: signature. - std::string sig_msg = "- Signature: "; const cppbor::Bstr* signature = signed_csr_payload_array->get(3)->asBstr(); if (!signature) { AddValidationMessage( kCborValidateFatal, "CoseSign1 signature must be Bstr. Actual type: " + CppborMajorTypeToString(signed_csr_payload_array->get(3)->type())); - return message_status_; + return kCborValidateFatal; } - // Skip CoseSign1 signature verification since the validator doesn't have - // verifying keys. - if (signature->value().empty()) { - sig_msg += ""; - AddValidationMessage(kCborValidateError, "CoseSign1 signature is missing."); - } else { - sig_msg += wvutil::b2a_hex(signature->value()); + signed_csr_payload.signature.second = signature->value(); + signed_csr_payload.signature.first = + signed_csr_payload.signature.second.empty() ? kEmpty : kPresent; + + // Print the parsed signed csr payload. + msg_ss_ << signed_csr_payload.ToString() << "\n"; + + // Start validation. + std::vector> msgs; + status = signed_csr_payload.Validate(msgs); + ApplyStatus(message_status_, status); + for (const auto& msg : msgs) { + AddValidationMessage(msg.first, msg.second); } - msg_ss_ << sig_msg << "\n"; - msg_ss_ << "...\n"; if (message_status_ == kCborParseOk) message_status_ = kCborValidateOk; return message_status_; } @@ -387,7 +550,7 @@ std::string SignedCsrPayloadValidator::GetFormattedMessage() const { if (parsed_item == nullptr) { return ""; } - return msg_ss_.str(); + return FormatString(msg_ss_.str()); } } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/test/bcc_validator_unittest.cpp b/oemcrypto/util/test/bcc_validator_unittest.cpp index ca92e6d..d05e1d6 100644 --- a/oemcrypto/util/test/bcc_validator_unittest.cpp +++ b/oemcrypto/util/test/bcc_validator_unittest.cpp @@ -8,6 +8,7 @@ #include #include "bcc_validator.h" +#include "log.h" using ::testing::AllOf; using ::testing::Ge; @@ -17,60 +18,227 @@ using ::testing::Le; namespace wvoec { namespace util { namespace { -// Self-signed phase 1 BCC generated by OPK reference implementation. +// Phase 2 DICE BCC generated by OPK reference implementation. const std::vector kBcc = { + 0x83, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, 0x41, 0xf1, 0x0b, 0x40, 0xff, + 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, 0x5a, 0x97, 0xa6, 0x80, 0xee, + 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, 0xe5, 0xfb, 0x10, 0x84, 0x43, + 0xa1, 0x01, 0x27, 0xa0, 0x58, 0xf8, 0xaa, 0x01, 0x68, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x20, 0x30, 0x02, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x31, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, + 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x58, 0x20, 0x3c, 0xfe, 0x6e, 0x28, 0x8b, 0x53, 0x31, 0x64, 0xb2, 0x16, + 0x26, 0x4c, 0x5f, 0x8e, 0x76, 0xfd, 0xb9, 0x25, 0x8e, 0x8c, 0xf5, 0x80, + 0xfe, 0xa5, 0x74, 0xbb, 0x0c, 0x5a, 0xef, 0xe3, 0x21, 0xce, 0x3a, 0x00, + 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, + 0xb3, 0x16, 0x96, 0xda, 0x0e, 0x6c, 0x46, 0x26, 0x1e, 0x52, 0x9b, 0x43, + 0x9b, 0x68, 0xd0, 0x32, 0x5e, 0x31, 0x39, 0xf9, 0x69, 0x28, 0xec, 0x03, + 0xeb, 0x06, 0x4c, 0xf3, 0x60, 0xf1, 0xd3, 0x0e, 0x3a, 0x00, 0x47, 0x44, + 0x52, 0x58, 0x20, 0x38, 0x0c, 0x43, 0xc2, 0xc5, 0x36, 0x5a, 0x91, 0xb4, + 0x2d, 0x85, 0x22, 0xb4, 0xb9, 0x6e, 0x43, 0xd2, 0xd0, 0x3e, 0x2f, 0xc4, + 0x1f, 0xb7, 0xb3, 0x4c, 0x6b, 0xfd, 0x90, 0xc7, 0x80, 0x42, 0x84, 0x3a, + 0x00, 0x47, 0x44, 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x68, + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, 0x01, 0x11, + 0x72, 0x62, 0x31, 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x2d, + 0xd1, 0xac, 0x94, 0xbe, 0x4b, 0x89, 0x98, 0xba, 0xec, 0xb6, 0x01, 0xaf, + 0xaf, 0xda, 0x01, 0x8f, 0xeb, 0x03, 0xd2, 0x8f, 0x42, 0x12, 0x55, 0xe4, + 0x4b, 0xe2, 0xdf, 0x47, 0x68, 0x27, 0x6a, 0x3a, 0x00, 0x47, 0x44, 0x56, + 0x41, 0x01, 0x58, 0x40, 0xd7, 0xe8, 0x9b, 0x9b, 0x8f, 0x3f, 0xe7, 0x66, + 0x24, 0x87, 0x48, 0xf4, 0xbd, 0x47, 0x3b, 0x85, 0xfb, 0x2c, 0x0e, 0xed, + 0x7d, 0xf4, 0xa6, 0xb5, 0x30, 0x77, 0xea, 0x92, 0x63, 0xc0, 0x1e, 0x8b, + 0x40, 0xec, 0x71, 0x66, 0xf8, 0xe2, 0x92, 0x07, 0x67, 0x08, 0x25, 0x70, + 0x4a, 0x06, 0x41, 0x72, 0x21, 0xdf, 0xd4, 0xa7, 0x1a, 0xeb, 0xe9, 0x5f, + 0x11, 0x30, 0x5b, 0xaa, 0x09, 0xe3, 0x24, 0x00, 0x84, 0x43, 0xa1, 0x01, + 0x27, 0xa0, 0x58, 0xf7, 0xaa, 0x01, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x31, 0x02, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x32, 0x3a, + 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, + 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xe6, + 0xc1, 0x67, 0xa8, 0x6d, 0x92, 0x16, 0xb8, 0x9c, 0xd1, 0xc4, 0xd4, 0xd3, + 0xf3, 0xc1, 0x22, 0x95, 0x80, 0x49, 0xd0, 0xb3, 0x50, 0x9f, 0x1d, 0xec, + 0x6f, 0xa8, 0x6c, 0xd2, 0xbd, 0x1a, 0x68, 0x3a, 0x00, 0x47, 0x44, 0x58, + 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x8d, 0x76, 0x93, + 0x9d, 0x2f, 0x0e, 0x5f, 0xbd, 0x36, 0x58, 0x51, 0x53, 0xc4, 0xa0, 0xaf, + 0xdb, 0x91, 0x41, 0x6a, 0x62, 0xf0, 0x03, 0x6a, 0x77, 0x8b, 0x2e, 0x5f, + 0xa7, 0x29, 0x94, 0x69, 0x9d, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20, + 0xc0, 0x0b, 0xa4, 0x78, 0xac, 0xa9, 0xb6, 0x96, 0x64, 0xaa, 0x55, 0xf6, + 0x52, 0xe2, 0xa6, 0x7b, 0xd7, 0x6f, 0xd5, 0xe5, 0xc1, 0xbd, 0xef, 0x97, + 0xf3, 0x0e, 0xea, 0xbc, 0x4b, 0x9e, 0xb7, 0xec, 0x3a, 0x00, 0x47, 0x44, + 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x68, 0x57, 0x69, 0x64, + 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x62, 0x31, + 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x35, 0x65, 0xd2, 0xaf, + 0x10, 0xf0, 0x67, 0x3e, 0x58, 0xf9, 0xfc, 0xc0, 0x6d, 0x46, 0xd2, 0x61, + 0x34, 0xa6, 0xf1, 0xd5, 0x0d, 0x7b, 0x6e, 0x4f, 0xd7, 0x13, 0xcb, 0x1d, + 0xd6, 0xef, 0x2a, 0x23, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x58, + 0x40, 0xa6, 0x67, 0x96, 0xf6, 0x31, 0x68, 0x45, 0x49, 0x7c, 0x38, 0x3f, + 0xde, 0x91, 0x02, 0xe3, 0x2a, 0x91, 0xc8, 0x0b, 0x3c, 0xdf, 0x2b, 0x18, + 0xcf, 0x9f, 0x06, 0xc0, 0xbe, 0x58, 0xbe, 0x12, 0x2c, 0xaa, 0x32, 0xa1, + 0x34, 0x0d, 0xf2, 0x8b, 0xa5, 0x87, 0x17, 0x66, 0x61, 0xd9, 0xdc, 0x08, + 0x52, 0x86, 0x51, 0x6f, 0x63, 0xfc, 0xaf, 0x7e, 0xc7, 0xeb, 0xa6, 0x73, + 0x19, 0xb1, 0x1a, 0xc9, 0x06}; +// Phase 1 self-signed BCC generated by OPK reference implementation. +const std::vector kDegeneratedBcc = { 0x82, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, 0x41, 0xf1, 0x0b, 0x40, 0xff, 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, 0x5a, 0x97, 0xa6, 0x80, 0xee, 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, 0xe5, 0xfb, 0x10, 0x84, 0x43, - 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x40, 0xa4, 0x01, 0x60, 0x02, 0x60, 0x3a, - 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, - 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, - 0x41, 0xf1, 0x0b, 0x40, 0xff, 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, - 0x5a, 0x97, 0xa6, 0x80, 0xee, 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, - 0xe5, 0xfb, 0x10, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, - 0x73, 0x02, 0x36, 0xaa, 0x6d, 0x52, 0x50, 0x67, 0x43, 0xc4, 0x0b, 0xf8, - 0x3f, 0x35, 0x2a, 0xd8, 0x44, 0x09, 0xf4, 0x1d, 0xca, 0x91, 0x12, 0x27, - 0x01, 0xdf, 0x73, 0xb7, 0x9b, 0x31, 0x28, 0x8e, 0xae, 0x9b, 0xc6, 0x7a, - 0xdc, 0x07, 0xab, 0x69, 0xd2, 0x85, 0x9a, 0x15, 0x8b, 0xe3, 0x5b, 0xf2, - 0x94, 0x95, 0xee, 0x49, 0x74, 0xc5, 0x85, 0x62, 0x3d, 0x46, 0x4c, 0xeb, - 0x11, 0x89, 0x68, 0x02}; + 0xa1, 0x01, 0x27, 0xa0, 0x58, 0xf8, 0xaa, 0x01, 0x68, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x20, 0x30, 0x02, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x31, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, + 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, 0x41, 0xf1, 0x0b, 0x40, 0xff, + 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, 0x5a, 0x97, 0xa6, 0x80, 0xee, + 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, 0xe5, 0xfb, 0x10, 0x3a, 0x00, + 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, + 0xb3, 0x16, 0x96, 0xda, 0x0e, 0x6c, 0x46, 0x26, 0x1e, 0x52, 0x9b, 0x43, + 0x9b, 0x68, 0xd0, 0x32, 0x5e, 0x31, 0x39, 0xf9, 0x69, 0x28, 0xec, 0x03, + 0xeb, 0x06, 0x4c, 0xf3, 0x60, 0xf1, 0xd3, 0x0e, 0x3a, 0x00, 0x47, 0x44, + 0x52, 0x58, 0x20, 0x38, 0x0c, 0x43, 0xc2, 0xc5, 0x36, 0x5a, 0x91, 0xb4, + 0x2d, 0x85, 0x22, 0xb4, 0xb9, 0x6e, 0x43, 0xd2, 0xd0, 0x3e, 0x2f, 0xc4, + 0x1f, 0xb7, 0xb3, 0x4c, 0x6b, 0xfd, 0x90, 0xc7, 0x80, 0x42, 0x84, 0x3a, + 0x00, 0x47, 0x44, 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x68, + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, 0x01, 0x11, + 0x72, 0x62, 0x31, 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x2d, + 0xd1, 0xac, 0x94, 0xbe, 0x4b, 0x89, 0x98, 0xba, 0xec, 0xb6, 0x01, 0xaf, + 0xaf, 0xda, 0x01, 0x8f, 0xeb, 0x03, 0xd2, 0x8f, 0x42, 0x12, 0x55, 0xe4, + 0x4b, 0xe2, 0xdf, 0x47, 0x68, 0x27, 0x6a, 0x3a, 0x00, 0x47, 0x44, 0x56, + 0x41, 0x01, 0x58, 0x40, 0x3a, 0xda, 0xff, 0x7f, 0x11, 0xc4, 0xd8, 0x62, + 0x15, 0x06, 0x03, 0x1a, 0x9b, 0x4d, 0x23, 0xf1, 0x97, 0x33, 0x94, 0x67, + 0xfa, 0xef, 0x29, 0xe4, 0x18, 0x34, 0x38, 0xad, 0x1d, 0x0d, 0x91, 0x17, + 0x3a, 0xe3, 0x6b, 0xd0, 0x50, 0xc9, 0x86, 0x8c, 0x9b, 0x62, 0x6b, 0xac, + 0x8e, 0xa4, 0xa7, 0x4b, 0x94, 0x6b, 0xc7, 0xce, 0xf4, 0xe4, 0xe5, 0x12, + 0x1d, 0xf6, 0x19, 0xf9, 0x4d, 0x5b, 0x9a, 0x00}; +// Key bytes all zero const std::vector kBccWrongEntryKey = { - 0x82, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, - 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, 0x41, 0xf1, 0x0b, 0x40, 0xff, - 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, 0x5a, 0x97, 0xa6, 0x80, 0xee, - 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, 0xe5, 0xfb, 0x10, 0x84, 0x43, - 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x40, 0xa4, 0x01, 0x60, 0x02, 0x60, 0x3a, - 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, - 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, - 0x89, 0x1d, 0xff, 0xb3, 0x3b, 0xe2, 0xdc, 0xc6, 0xbc, 0xbd, 0xc7, 0xcd, - 0x3f, 0x9c, 0x43, 0xf6, 0xdd, 0xea, 0x58, 0x53, 0x45, 0x8f, 0x87, 0x17, - 0x0a, 0xe4, 0x06, 0xf2, 0xbe, 0x14, 0x69, 0x13, 0x3d, 0x1d, 0xd0, 0x52, - 0x8f, 0x56, 0x4b, 0x0f, 0xad, 0x2e, 0xf0, 0xbf, 0xbb, 0xd1, 0x35, 0x9c, - 0x5a, 0xe8, 0x67, 0xbe, 0xec, 0xff, 0x9d, 0xfe, 0xac, 0x8d, 0x47, 0x4e, - 0x6d, 0xd1, 0xd3, 0x02}; + 0x83, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x58, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x43, + 0xa1, 0x01, 0x27, 0xa0, 0x58, 0xf8, 0xaa, 0x01, 0x68, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x20, 0x30, 0x02, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x31, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, + 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x58, 0x20, 0x3c, 0xfe, 0x6e, 0x28, 0x8b, 0x53, 0x31, 0x64, 0xb2, 0x16, + 0x26, 0x4c, 0x5f, 0x8e, 0x76, 0xfd, 0xb9, 0x25, 0x8e, 0x8c, 0xf5, 0x80, + 0xfe, 0xa5, 0x74, 0xbb, 0x0c, 0x5a, 0xef, 0xe3, 0x21, 0xce, 0x3a, 0x00, + 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, + 0xb3, 0x16, 0x96, 0xda, 0x0e, 0x6c, 0x46, 0x26, 0x1e, 0x52, 0x9b, 0x43, + 0x9b, 0x68, 0xd0, 0x32, 0x5e, 0x31, 0x39, 0xf9, 0x69, 0x28, 0xec, 0x03, + 0xeb, 0x06, 0x4c, 0xf3, 0x60, 0xf1, 0xd3, 0x0e, 0x3a, 0x00, 0x47, 0x44, + 0x52, 0x58, 0x20, 0x38, 0x0c, 0x43, 0xc2, 0xc5, 0x36, 0x5a, 0x91, 0xb4, + 0x2d, 0x85, 0x22, 0xb4, 0xb9, 0x6e, 0x43, 0xd2, 0xd0, 0x3e, 0x2f, 0xc4, + 0x1f, 0xb7, 0xb3, 0x4c, 0x6b, 0xfd, 0x90, 0xc7, 0x80, 0x42, 0x84, 0x3a, + 0x00, 0x47, 0x44, 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x68, + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, 0x01, 0x11, + 0x72, 0x62, 0x31, 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x2d, + 0xd1, 0xac, 0x94, 0xbe, 0x4b, 0x89, 0x98, 0xba, 0xec, 0xb6, 0x01, 0xaf, + 0xaf, 0xda, 0x01, 0x8f, 0xeb, 0x03, 0xd2, 0x8f, 0x42, 0x12, 0x55, 0xe4, + 0x4b, 0xe2, 0xdf, 0x47, 0x68, 0x27, 0x6a, 0x3a, 0x00, 0x47, 0x44, 0x56, + 0x41, 0x01, 0x58, 0x40, 0xd7, 0xe8, 0x9b, 0x9b, 0x8f, 0x3f, 0xe7, 0x66, + 0x24, 0x87, 0x48, 0xf4, 0xbd, 0x47, 0x3b, 0x85, 0xfb, 0x2c, 0x0e, 0xed, + 0x7d, 0xf4, 0xa6, 0xb5, 0x30, 0x77, 0xea, 0x92, 0x63, 0xc0, 0x1e, 0x8b, + 0x40, 0xec, 0x71, 0x66, 0xf8, 0xe2, 0x92, 0x07, 0x67, 0x08, 0x25, 0x70, + 0x4a, 0x06, 0x41, 0x72, 0x21, 0xdf, 0xd4, 0xa7, 0x1a, 0xeb, 0xe9, 0x5f, + 0x11, 0x30, 0x5b, 0xaa, 0x09, 0xe3, 0x24, 0x00, 0x84, 0x43, 0xa1, 0x01, + 0x27, 0xa0, 0x58, 0xf7, 0xaa, 0x01, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x31, 0x02, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x32, 0x3a, + 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, + 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0xe6, + 0xc1, 0x67, 0xa8, 0x6d, 0x92, 0x16, 0xb8, 0x9c, 0xd1, 0xc4, 0xd4, 0xd3, + 0xf3, 0xc1, 0x22, 0x95, 0x80, 0x49, 0xd0, 0xb3, 0x50, 0x9f, 0x1d, 0xec, + 0x6f, 0xa8, 0x6c, 0xd2, 0xbd, 0x1a, 0x68, 0x3a, 0x00, 0x47, 0x44, 0x58, + 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, 0x8d, 0x76, 0x93, + 0x9d, 0x2f, 0x0e, 0x5f, 0xbd, 0x36, 0x58, 0x51, 0x53, 0xc4, 0xa0, 0xaf, + 0xdb, 0x91, 0x41, 0x6a, 0x62, 0xf0, 0x03, 0x6a, 0x77, 0x8b, 0x2e, 0x5f, + 0xa7, 0x29, 0x94, 0x69, 0x9d, 0x3a, 0x00, 0x47, 0x44, 0x52, 0x58, 0x20, + 0xc0, 0x0b, 0xa4, 0x78, 0xac, 0xa9, 0xb6, 0x96, 0x64, 0xaa, 0x55, 0xf6, + 0x52, 0xe2, 0xa6, 0x7b, 0xd7, 0x6f, 0xd5, 0xe5, 0xc1, 0xbd, 0xef, 0x97, + 0xf3, 0x0e, 0xea, 0xbc, 0x4b, 0x9e, 0xb7, 0xec, 0x3a, 0x00, 0x47, 0x44, + 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x68, 0x57, 0x69, 0x64, + 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, 0x01, 0x11, 0x72, 0x62, 0x31, + 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x35, 0x65, 0xd2, 0xaf, + 0x10, 0xf0, 0x67, 0x3e, 0x58, 0xf9, 0xfc, 0xc0, 0x6d, 0x46, 0xd2, 0x61, + 0x34, 0xa6, 0xf1, 0xd5, 0x0d, 0x7b, 0x6e, 0x4f, 0xd7, 0x13, 0xcb, 0x1d, + 0xd6, 0xef, 0x2a, 0x23, 0x3a, 0x00, 0x47, 0x44, 0x56, 0x41, 0x01, 0x58, + 0x40, 0xa6, 0x67, 0x96, 0xf6, 0x31, 0x68, 0x45, 0x49, 0x7c, 0x38, 0x3f, + 0xde, 0x91, 0x02, 0xe3, 0x2a, 0x91, 0xc8, 0x0b, 0x3c, 0xdf, 0x2b, 0x18, + 0xcf, 0x9f, 0x06, 0xc0, 0xbe, 0x58, 0xbe, 0x12, 0x2c, 0xaa, 0x32, 0xa1, + 0x34, 0x0d, 0xf2, 0x8b, 0xa5, 0x87, 0x17, 0x66, 0x61, 0xd9, 0xdc, 0x08, + 0x52, 0x86, 0x51, 0x6f, 0x63, 0xfc, 0xaf, 0x7e, 0xc7, 0xeb, 0xa6, 0x73, + 0x19, 0xb1, 0x1a, 0xc9, 0x06}; const std::vector kBccMissingIssuer = { - 0x82, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x83, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, 0x41, 0xf1, 0x0b, 0x40, 0xff, 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, 0x5a, 0x97, 0xa6, 0x80, 0xee, 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, 0xe5, 0xfb, 0x10, 0x84, 0x43, - 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x3e, 0xa3, 0x02, 0x60, 0x3a, 0x00, 0x47, - 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, - 0x20, 0x06, 0x21, 0x58, 0x20, 0x02, 0xab, 0xbe, 0x80, 0x02, 0x41, 0xf1, - 0x0b, 0x40, 0xff, 0xd5, 0xf0, 0xd0, 0x26, 0x65, 0x70, 0xdc, 0x5a, 0x97, - 0xa6, 0x80, 0xee, 0x15, 0x95, 0xec, 0x26, 0x36, 0x70, 0x77, 0xe5, 0xfb, - 0x10, 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x58, 0x40, 0xf9, 0x46, - 0x36, 0xbd, 0x95, 0x75, 0xc2, 0x3d, 0xf9, 0xa2, 0xbe, 0x60, 0x8e, 0xbf, - 0x64, 0x89, 0xdf, 0xb9, 0x9c, 0x3c, 0x17, 0x36, 0x23, 0x9a, 0x68, 0x1a, - 0x34, 0x36, 0x51, 0x89, 0x59, 0xf2, 0x54, 0x62, 0xd3, 0x8f, 0xeb, 0x9b, - 0x75, 0x3e, 0xe9, 0xfc, 0xe3, 0xc2, 0x8f, 0x84, 0xb1, 0x71, 0xcd, 0x29, - 0x12, 0x65, 0xeb, 0xab, 0x28, 0x4b, 0xe2, 0x3e, 0x1b, 0xd8, 0x17, 0xdb, - 0x97, 0x0f}; + 0xa1, 0x01, 0x27, 0xa0, 0x58, 0xf8, 0xaa, 0x01, 0x68, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x20, 0x30, 0x02, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x20, 0x31, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, + 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, 0x06, 0x21, + 0x58, 0x20, 0x3c, 0xfe, 0x6e, 0x28, 0x8b, 0x53, 0x31, 0x64, 0xb2, 0x16, + 0x26, 0x4c, 0x5f, 0x8e, 0x76, 0xfd, 0xb9, 0x25, 0x8e, 0x8c, 0xf5, 0x80, + 0xfe, 0xa5, 0x74, 0xbb, 0x0c, 0x5a, 0xef, 0xe3, 0x21, 0xce, 0x3a, 0x00, + 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x20, + 0xb3, 0x16, 0x96, 0xda, 0x0e, 0x6c, 0x46, 0x26, 0x1e, 0x52, 0x9b, 0x43, + 0x9b, 0x68, 0xd0, 0x32, 0x5e, 0x31, 0x39, 0xf9, 0x69, 0x28, 0xec, 0x03, + 0xeb, 0x06, 0x4c, 0xf3, 0x60, 0xf1, 0xd3, 0x0e, 0x3a, 0x00, 0x47, 0x44, + 0x52, 0x58, 0x20, 0x38, 0x0c, 0x43, 0xc2, 0xc5, 0x36, 0x5a, 0x91, 0xb4, + 0x2d, 0x85, 0x22, 0xb4, 0xb9, 0x6e, 0x43, 0xd2, 0xd0, 0x3e, 0x2f, 0xc4, + 0x1f, 0xb7, 0xb3, 0x4c, 0x6b, 0xfd, 0x90, 0xc7, 0x80, 0x42, 0x84, 0x3a, + 0x00, 0x47, 0x44, 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, 0x71, 0x68, + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, 0x01, 0x11, + 0x72, 0x62, 0x31, 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x20, 0x2d, + 0xd1, 0xac, 0x94, 0xbe, 0x4b, 0x89, 0x98, 0xba, 0xec, 0xb6, 0x01, 0xaf, + 0xaf, 0xda, 0x01, 0x8f, 0xeb, 0x03, 0xd2, 0x8f, 0x42, 0x12, 0x55, 0xe4, + 0x4b, 0xe2, 0xdf, 0x47, 0x68, 0x27, 0x6a, 0x3a, 0x00, 0x47, 0x44, 0x56, + 0x41, 0x01, 0x58, 0x40, 0xd7, 0xe8, 0x9b, 0x9b, 0x8f, 0x3f, 0xe7, 0x66, + 0x24, 0x87, 0x48, 0xf4, 0xbd, 0x47, 0x3b, 0x85, 0xfb, 0x2c, 0x0e, 0xed, + 0x7d, 0xf4, 0xa6, 0xb5, 0x30, 0x77, 0xea, 0x92, 0x63, 0xc0, 0x1e, 0x8b, + 0x40, 0xec, 0x71, 0x66, 0xf8, 0xe2, 0x92, 0x07, 0x67, 0x08, 0x25, 0x70, + 0x4a, 0x06, 0x41, 0x72, 0x21, 0xdf, 0xd4, 0xa7, 0x1a, 0xeb, 0xe9, 0x5f, + 0x11, 0x30, 0x5b, 0xaa, 0x09, 0xe3, 0x24, 0x00, 0x84, 0x43, 0xa1, 0x01, + 0x27, 0xa0, 0x58, 0xf0, 0xaa, 0x01, 0x60, 0x02, 0x67, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x20, 0x32, 0x3a, 0x00, 0x47, 0x44, 0x59, 0x6a, 0x61, 0x6e, + 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x31, 0x35, 0x3a, 0x00, 0x47, 0x44, + 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27, 0x04, 0x81, 0x02, 0x20, + 0x06, 0x21, 0x58, 0x20, 0xe6, 0xc1, 0x67, 0xa8, 0x6d, 0x92, 0x16, 0xb8, + 0x9c, 0xd1, 0xc4, 0xd4, 0xd3, 0xf3, 0xc1, 0x22, 0x95, 0x80, 0x49, 0xd0, + 0xb3, 0x50, 0x9f, 0x1d, 0xec, 0x6f, 0xa8, 0x6c, 0xd2, 0xbd, 0x1a, 0x68, + 0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20, 0x3a, 0x00, 0x47, 0x44, 0x50, + 0x58, 0x20, 0x8d, 0x76, 0x93, 0x9d, 0x2f, 0x0e, 0x5f, 0xbd, 0x36, 0x58, + 0x51, 0x53, 0xc4, 0xa0, 0xaf, 0xdb, 0x91, 0x41, 0x6a, 0x62, 0xf0, 0x03, + 0x6a, 0x77, 0x8b, 0x2e, 0x5f, 0xa7, 0x29, 0x94, 0x69, 0x9d, 0x3a, 0x00, + 0x47, 0x44, 0x52, 0x58, 0x20, 0xc0, 0x0b, 0xa4, 0x78, 0xac, 0xa9, 0xb6, + 0x96, 0x64, 0xaa, 0x55, 0xf6, 0x52, 0xe2, 0xa6, 0x7b, 0xd7, 0x6f, 0xd5, + 0xe5, 0xc1, 0xbd, 0xef, 0x97, 0xf3, 0x0e, 0xea, 0xbc, 0x4b, 0x9e, 0xb7, + 0xec, 0x3a, 0x00, 0x47, 0x44, 0x53, 0x57, 0xa2, 0x3a, 0x00, 0x01, 0x11, + 0x71, 0x68, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x3a, 0x00, + 0x01, 0x11, 0x72, 0x62, 0x31, 0x39, 0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, + 0x20, 0x35, 0x65, 0xd2, 0xaf, 0x10, 0xf0, 0x67, 0x3e, 0x58, 0xf9, 0xfc, + 0xc0, 0x6d, 0x46, 0xd2, 0x61, 0x34, 0xa6, 0xf1, 0xd5, 0x0d, 0x7b, 0x6e, + 0x4f, 0xd7, 0x13, 0xcb, 0x1d, 0xd6, 0xef, 0x2a, 0x23, 0x3a, 0x00, 0x47, + 0x44, 0x56, 0x41, 0x01, 0x58, 0x40, 0x5a, 0x77, 0x3b, 0x51, 0x81, 0xad, + 0x48, 0x54, 0x39, 0x86, 0x89, 0xd9, 0x0c, 0x87, 0x0a, 0x1b, 0x8c, 0x17, + 0xd8, 0x14, 0xad, 0xfd, 0x64, 0x46, 0x71, 0x97, 0xa2, 0xd5, 0x15, 0x52, + 0x1f, 0x87, 0xee, 0x48, 0x55, 0x4c, 0xba, 0x01, 0xcb, 0x18, 0xa4, 0x26, + 0x89, 0xb7, 0x6e, 0x91, 0xc8, 0x21, 0x68, 0x1e, 0xad, 0x4a, 0x95, 0x33, + 0xe7, 0xaa, 0x68, 0xe5, 0x06, 0x4d, 0xfa, 0xcf, 0x73, 0x03}; } // namespace +static void DumpValidatorOutput(const BccValidator& validator) { + const std::string out = validator.GetFormattedMessage(); + LOGI("%s", out.c_str()); + for (auto& msg : validator.GetValidateMessages()) { + LOGE("Error code %d: %s", msg.first, msg.second.c_str()); + } +} + TEST(OEMCryptoBccValidatorTest, BccParseError) { const std::vector bcc_bad(kBcc.begin(), kBcc.end() - 1); BccValidator validator; @@ -89,8 +257,25 @@ TEST(OEMCryptoBccValidatorTest, Bcc) { result = validator.Validate(); EXPECT_THAT(result, AllOf(Ge(kCborValidateOk), Le(kCborValidateWarning))); const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("key encoding format: DEVICE_KEY_BYTE_STRING")); - EXPECT_THAT(out, HasSubstr("key algorithm type: EDDSA")); + EXPECT_THAT(out, HasSubstr("key_type:byte_string")); + EXPECT_THAT(out, HasSubstr("signature_algorithm:EdDSA")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } +} + +TEST(OEMCryptoBccValidatorTest, DegeneratedBcc) { + BccValidator validator; + CborMessageStatus result = validator.Parse(kDegeneratedBcc); + EXPECT_EQ(kCborParseOk, result); + result = validator.Validate(); + EXPECT_THAT(result, AllOf(Ge(kCborValidateOk), Le(kCborValidateWarning))); + const std::string out = validator.GetFormattedMessage(); + EXPECT_THAT(out, HasSubstr("key_type:byte_string")); + EXPECT_THAT(out, HasSubstr("signature_algorithm:EdDSA")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoBccValidatorTest, BccWrongEntryKey) { @@ -101,12 +286,17 @@ TEST(OEMCryptoBccValidatorTest, BccWrongEntryKey) { EXPECT_EQ(result, kCborValidateError); // Non-fatal validation error should be able to return formatted output. const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("key encoding format: DEVICE_KEY_BYTE_STRING")); - EXPECT_THAT(out, HasSubstr("key algorithm type: EDDSA")); + EXPECT_THAT(out, HasSubstr("key_type:byte_string")); + EXPECT_THAT(out, HasSubstr("key_bytes:000000")); const std::vector> msgs = validator.GetValidateMessages(); - EXPECT_EQ(1u, msgs.size()); + // Expect more than 1 validation errors caused by wrong entry key including + // invalid key, signature error, etc + EXPECT_GE(msgs.size(), 1u); EXPECT_EQ(kCborValidateError, msgs[0].first); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoBccValidatorTest, BccParseThreeTimes) { @@ -135,13 +325,16 @@ TEST(OEMCryptoBccValidatorTest, BccMissingIssuer) { result = validator.Validate(); EXPECT_EQ(result, kCborValidateError); const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("key encoding format: DEVICE_KEY_BYTE_STRING")); - EXPECT_THAT(out, HasSubstr("key algorithm type: EDDSA")); + EXPECT_THAT(out, HasSubstr("key_type:byte_string")); + EXPECT_THAT(out, HasSubstr("signature_algorithm:EdDSA")); const std::vector> msgs = validator.GetValidateMessages(); EXPECT_EQ(1u, msgs.size()); EXPECT_EQ(kCborValidateError, msgs[0].first); - EXPECT_THAT(msgs[0].second, HasSubstr("Missing Issuer")); + EXPECT_THAT(msgs[0].second, HasSubstr("missing required field issuer")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/test/device_info_validator_unittest.cpp b/oemcrypto/util/test/device_info_validator_unittest.cpp index 2e4e022..9454d97 100644 --- a/oemcrypto/util/test/device_info_validator_unittest.cpp +++ b/oemcrypto/util/test/device_info_validator_unittest.cpp @@ -8,6 +8,7 @@ #include #include "device_info_validator.h" +#include "log.h" using ::testing::AllOf; using ::testing::Ge; @@ -30,7 +31,7 @@ cppbor::Map BuildDeviceInfoMap(int version) { .add("model", "model") .add("vb_state", "green") .add("bootloader_state", "unlocked") - .add("vbmeta_digest", cppbor::Bstr(std::vector())) + .add("vbmeta_digest", cppbor::Bstr(std::vector(32, 0xCC))) .add("os_version", "os_version") .add("system_patch_level", 202312) .add("boot_patch_level", 20231201) @@ -61,6 +62,14 @@ std::vector BuildDeviceInfo(int version) { } } // namespace +static void DumpValidatorOutput(const DeviceInfoValidator& validator) { + const std::string out = validator.GetFormattedMessage(); + LOGI("%s", out.c_str()); + for (auto& msg : validator.GetValidateMessages()) { + LOGE("Error code %d: %s", msg.first, msg.second.c_str()); + } +} + TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoParseError) { const std::vector device_info = BuildDeviceInfo(kDeviceVersion3); const std::vector device_info_bad(device_info.begin(), @@ -87,6 +96,9 @@ TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoNotMap) { EXPECT_EQ(1u, msgs.size()); EXPECT_EQ(kCborValidateFatal, msgs[0].first); EXPECT_THAT(msgs[0].second, HasSubstr("Device info is not a CBOR map")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoDeviceInfoValidatorTest, @@ -95,8 +107,7 @@ TEST(OEMCryptoDeviceInfoValidatorTest, cppbor::Map() .add("brand", "brand") .add("manufacturer", "manufacturer") - .add(123, 456) // Non-Tstr key type - .add("system_patch_level", "not a uint") // Non-uint value type + .add(123, 456) // Non-Tstr key type .canonicalize() .encode(); DeviceInfoValidator validator(kDeviceVersion3); @@ -112,25 +123,22 @@ TEST(OEMCryptoDeviceInfoValidatorTest, return p.second.find("Unexpected entry key type") != std::string::npos; }); EXPECT_EQ(true, unexpected_key_type_found); - const bool unexpected_value_type_found = std::any_of( - msgs.begin(), msgs.end(), - [](const std::pair& p) { - return p.second.find("system_patch_level has the wrong type") != - std::string::npos; - }); - EXPECT_EQ(true, unexpected_value_type_found); - const bool missing_model_found = std::any_of( - msgs.begin(), msgs.end(), - [](const std::pair& p) { - return p.second.find("model is missing") != std::string::npos; - }); + const bool missing_model_found = + std::any_of(msgs.begin(), msgs.end(), + [](const std::pair& p) { + return p.second.find("missing important field model") != + std::string::npos; + }); EXPECT_EQ(true, missing_model_found); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV3NonCanonical) { const cppbor::Map map = BuildDeviceInfoMap(kDeviceVersion3); const std::vector device_info = map.encode(); - DeviceInfoValidator validator(kDeviceVersion3); + DeviceInfoValidator validator(kDeviceVersion3, true /* is_gms */); CborMessageStatus result = validator.Parse(device_info); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); @@ -141,43 +149,97 @@ TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV3NonCanonical) { EXPECT_EQ(kCborValidateError, msgs[0].first); EXPECT_THAT(msgs[0].second, HasSubstr("Device info ordering is non-canonical")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV3) { const std::vector device_info = BuildDeviceInfo(kDeviceVersion3); - DeviceInfoValidator validator(kDeviceVersion3); + DeviceInfoValidator validator(kDeviceVersion3, true /* is_gms */); CborMessageStatus result = validator.Parse(device_info); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); EXPECT_THAT(result, AllOf(Ge(kCborValidateOk), Le(kCborValidateWarning))); const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("manufacturer: manufacturer")); - EXPECT_THAT(out, HasSubstr("model: model")); - EXPECT_THAT(out, HasSubstr("fused: 0")); + EXPECT_THAT(out, HasSubstr("manufacturer:manufacturer")); + EXPECT_THAT(out, HasSubstr("model:model")); + EXPECT_THAT(out, HasSubstr("fused:0")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } +} + +TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV3InvalidFields) { + cppbor::Map device_info_map = + cppbor::Map() + .add("brand", "brand") + .add("manufacturer", "manufacturer") + .add("product", "product") + .add("model", "model") + .add("vb_state", "invalid_green") // invalid value + .add("bootloader_state", "invalid_unlocked") // invalid value + .add("vbmeta_digest", cppbor::Bstr(std::vector(32, 0xCC))) + .add("os_version", "os_version") + .add("system_patch_level", 100) // invalid value, expects "YYYYMM" + .add("boot_patch_level", + 12345678) // invalid value, expectes "YYYYMMDD" + .add("vendor_patch_level", + "20231201") // invalid value, expects YYYYMMDD in int + .add("security_level", "tee") + .add("device", "device") + .add("fused", 9); // invalid value, expects 0 or 1 + auto device_info = device_info_map.canonicalize().encode(); + DeviceInfoValidator validator(kDeviceVersion3, true /* is_gms */); + CborMessageStatus result = validator.Parse(device_info); + EXPECT_EQ(kCborParseOk, result); + result = validator.Validate(); + EXPECT_THAT(result, Ge(kCborValidateError)); + const std::vector> msgs = + validator.GetValidateMessages(); + std::string out = ""; + for (auto& msg : msgs) { + out += (msg.second + "\n"); + } + EXPECT_THAT(out, HasSubstr("invalid value for system_patch_level")); + EXPECT_THAT(out, HasSubstr("invalid value for boot_patch_level")); + EXPECT_THAT(out, HasSubstr("missing required field vendor_patch_level")); + EXPECT_THAT(out, HasSubstr("unexpected value for vb_state")); + EXPECT_THAT(out, HasSubstr("unexpected value for bootloader_state")); + EXPECT_THAT(out, HasSubstr("unexpected value for fused")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV2) { const std::vector device_info = BuildDeviceInfo(kDeviceVersion2); - DeviceInfoValidator validator(kDeviceVersion2); + DeviceInfoValidator validator(kDeviceVersion2, true /* is_gms */); CborMessageStatus result = validator.Parse(device_info); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); EXPECT_THAT(result, AllOf(Ge(kCborValidateOk), Le(kCborValidateWarning))); const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("manufacturer: manufacturer")); - EXPECT_THAT(out, HasSubstr("model: model")); - EXPECT_THAT(out, HasSubstr("fused: 0")); - EXPECT_THAT(out, HasSubstr("version: 2")); + EXPECT_THAT(out, HasSubstr("manufacturer:manufacturer")); + EXPECT_THAT(out, HasSubstr("model:model")); + EXPECT_THAT(out, HasSubstr("fused:0")); + EXPECT_THAT(out, HasSubstr("version:2")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV1MissingField) { - const std::vector device_info = cppbor::Map() - .add("brand", "brand") - .add("security_level", "tee") - .add("version", 1) - .canonicalize() - .encode(); - DeviceInfoValidator validator(kDeviceVersion1); + const std::vector device_info = + cppbor::Map() + .add("manufacturer", "manufacturer") + .add("model", "model") + .add("brand", "brand") + .add("security_level", "tee") + .add("version", 1) + .canonicalize() + .encode(); + DeviceInfoValidator validator(kDeviceVersion1, true /* is_gms */); CborMessageStatus result = validator.Parse(device_info); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); @@ -186,19 +248,50 @@ TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV1MissingField) { validator.GetValidateMessages(); EXPECT_EQ(1u, msgs.size()); EXPECT_EQ(kCborValidateError, msgs[0].first); - EXPECT_THAT(msgs[0].second, HasSubstr("att_id_state is missing")); + EXPECT_THAT(msgs[0].second, HasSubstr("missing required field att_id_state")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoV1) { - DeviceInfoValidator validator(kDeviceVersion1); + DeviceInfoValidator validator(kDeviceVersion1, true /* is_gms */); const std::vector device_info = BuildDeviceInfo(kDeviceVersion1); CborMessageStatus result = validator.Parse(device_info); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); EXPECT_THAT(result, AllOf(Ge(kCborValidateOk), Le(kCborValidateWarning))); const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("board: board")); - EXPECT_THAT(out, HasSubstr("version: 1")); + EXPECT_THAT(out, HasSubstr("board:board")); + EXPECT_THAT(out, HasSubstr("version:1")); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } +} + +TEST(OEMCryptoDeviceInfoValidatorTest, DeviceInfoMissingFused) { + const std::vector device_info_bad = + cppbor::Map() + .add("model", "model") + .add("manufacturer", "manufacturer") + .canonicalize() + .encode(); + DeviceInfoValidator validator(kDeviceVersion1, false /* is_gms */); + CborMessageStatus result = validator.Parse(device_info_bad); + EXPECT_EQ(kCborParseOk, result); + result = validator.Validate(); + EXPECT_EQ(kCborValidateWarning, result); + const std::vector> msgs = + validator.GetValidateMessages(); + const bool missing_fused_found = std::any_of( + msgs.begin(), msgs.end(), + [](const std::pair& p) { + return p.second.find("missing field fused") != std::string::npos; + }); + EXPECT_EQ(true, missing_fused_found); + if (result >= kCborValidateWarning) { + DumpValidatorOutput(validator); + } } } // namespace util } // namespace wvoec diff --git a/oemcrypto/util/test/signed_csr_payload_validator_unittest.cpp b/oemcrypto/util/test/signed_csr_payload_validator_unittest.cpp index f5c4c7f..2eccb70 100644 --- a/oemcrypto/util/test/signed_csr_payload_validator_unittest.cpp +++ b/oemcrypto/util/test/signed_csr_payload_validator_unittest.cpp @@ -7,6 +7,7 @@ #include #include +#include "log.h" #include "signed_csr_payload_validator.h" using ::testing::AllOf; @@ -86,6 +87,14 @@ std::vector GetDefaultSignedCsrPayload() { .add(cppbor::Bstr(GetDefaultSignature())) .encode(); } + +static void DumpValidatorOutput(const SignedCsrPayloadValidator& validator) { + const std::string out = validator.GetFormattedMessage(); + LOGI("%s", out.c_str()); + for (auto& msg : validator.GetValidateMessages()) { + LOGE("Error code %d: %s", msg.first, msg.second.c_str()); + } +} } // namespace TEST(OEMCryptoSignedCsrPayloadValidatorTest, SignedCsrPayloadParseError) { @@ -119,7 +128,8 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, ProtectedDataNotMap) { validator.GetValidateMessages(); EXPECT_EQ(1u, msgs.size()); EXPECT_EQ(kCborValidateFatal, msgs[0].first); - EXPECT_THAT(msgs[0].second, HasSubstr("ProtectedParams must be a CBOR map")); + EXPECT_THAT(msgs[0].second, + HasSubstr("Unexpected signed csr payload protected type: ARRAY")); } TEST(OEMCryptoSignedCsrPayloadValidatorTest, ProtectedDataMapMissingKey) { @@ -135,12 +145,13 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, ProtectedDataMapMissingKey) { CborMessageStatus result = validator.Parse(signed_csr_payload); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); - EXPECT_THAT(result, kCborValidateFatal); + EXPECT_THAT(result, kCborValidateError); const std::vector> msgs = validator.GetValidateMessages(); EXPECT_EQ(1u, msgs.size()); - EXPECT_EQ(kCborValidateFatal, msgs[0].first); - EXPECT_THAT(msgs[0].second, HasSubstr("ProtectedParams is empty")); + EXPECT_EQ(kCborValidateError, msgs[0].first); + EXPECT_THAT(msgs[0].second, HasSubstr("missing required field protected")); + DumpValidatorOutput(validator); } TEST(OEMCryptoSignedCsrPayloadValidatorTest, ProtectedDataMapKeyWarnings) { @@ -163,7 +174,7 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, ProtectedDataMapKeyWarnings) { const bool unexpected_key_type_found = std::any_of( msgs.begin(), msgs.end(), [](const std::pair& p) { - return p.second.find("Unsupported key type") != std::string::npos; + return p.second.find("Invalid key type") != std::string::npos; }); EXPECT_EQ(true, unexpected_key_type_found); const bool unexpected_key_value_found = std::any_of( @@ -172,13 +183,14 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, ProtectedDataMapKeyWarnings) { return p.second.find("Unsupported key value") != std::string::npos; }); EXPECT_EQ(true, unexpected_key_value_found); - const bool unexpected_entry_found = - std::any_of(msgs.begin(), msgs.end(), - [](const std::pair& p) { - return p.second.find("ProtectedParams expects 1 entry") != - std::string::npos; - }); + const bool unexpected_entry_found = std::any_of( + msgs.begin(), msgs.end(), + [](const std::pair& p) { + return p.second.find("Protected data map expects 1 entry") != + std::string::npos; + }); EXPECT_EQ(true, unexpected_entry_found); + DumpValidatorOutput(validator); } TEST(OEMCryptoSignedCsrPayloadValidatorTest, InvalidChallengeAndPayload) { @@ -212,16 +224,13 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, InvalidChallengeAndPayload) { const bool challenge_error_found = std::any_of( msgs.begin(), msgs.end(), [](const std::pair& p) { - return p.second.find("Challenge size must be between 0 and 64 bytes") != - std::string::npos; + return p.second.find("Unexpected challenge size") != std::string::npos; }); EXPECT_EQ(true, challenge_error_found); const bool csr_payload_error_found = std::any_of( msgs.begin(), msgs.end(), [](const std::pair& p) { - return p.second.find( - "CSR payload version must be must be equal to 3") != - std::string::npos; + return p.second.find("Invalid version") != std::string::npos; }); EXPECT_EQ(true, csr_payload_error_found); } @@ -250,11 +259,11 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, KeysToSignEmptyList) { CborMessageStatus result = validator.Parse(signed_csr_payload); EXPECT_EQ(kCborParseOk, result); result = validator.Validate(); - EXPECT_THAT(result, kCborValidateFatal); + EXPECT_THAT(result, kCborValidateError); const std::vector> msgs = validator.GetValidateMessages(); EXPECT_EQ(1u, msgs.size()); - EXPECT_EQ(kCborValidateFatal, msgs[0].first); + EXPECT_EQ(kCborValidateError, msgs[0].first); EXPECT_THAT(msgs[0].second, HasSubstr("Keys must be a CBOR array")); } @@ -275,7 +284,7 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, SignatureMissing) { validator.GetValidateMessages(); EXPECT_EQ(1u, msgs.size()); EXPECT_EQ(kCborValidateError, msgs[0].first); - EXPECT_THAT(msgs[0].second, HasSubstr("CoseSign1 signature is missing")); + EXPECT_THAT(msgs[0].second, HasSubstr("missing required field signature")); } TEST(OEMCryptoSignedCsrPayloadValidatorTest, ValidateOk) { @@ -285,10 +294,9 @@ TEST(OEMCryptoSignedCsrPayloadValidatorTest, ValidateOk) { result = validator.Validate(); EXPECT_THAT(result, AllOf(Ge(kCborValidateOk), Le(kCborValidateWarning))); const std::string out = validator.GetFormattedMessage(); - EXPECT_THAT(out, HasSubstr("1: ES256")); - EXPECT_THAT(out, HasSubstr("version: 3")); - EXPECT_THAT(out, HasSubstr("certificate_type: widevine")); - EXPECT_THAT(out, HasSubstr("keys_to_sign: []")); + EXPECT_THAT(out, HasSubstr("algorithm:ECDSA_SHA256")); + EXPECT_THAT(out, HasSubstr("version:3")); + EXPECT_THAT(out, HasSubstr("type:widevine")); } } // namespace util } // namespace wvoec diff --git a/util/include/file_store.h b/util/include/file_store.h index 9563b5e..26dbf78 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -7,63 +7,118 @@ #ifndef WVCDM_UTIL_FILE_STORE_H_ #define WVCDM_UTIL_FILE_STORE_H_ -#include +#include + #include #include #include -#include "disallow_copy_and_assign.h" #include "platform.h" #include "util_common.h" +#include "wv_class_utils.h" namespace wvutil { +// Fixed filename for ATSC DRM certificate pre-installed +// on ATSC devices for ATSC licenses. static const std::string kAtscCertificateFileName = "atsccert.bin"; +// General filename for either global or unmapped app-origin +// DRM certificates. static const std::string kCertificateFileName = "cert1.bin"; +// File extension for DRM and OEM certificate files. static const std::string kCertificateFileNameExt = ".bin"; -static const std::string kCertificateFileNamePrefix = "cert1_"; +// Filename prefix for mapped (scoped) DRM certificate filenames +// specific to a particular app-origin. +static const std::string kScopedCertificateFilenamePrefix = "cert1_"; +// TODO(b/376533901): Replace this constant with +// kScopedCertificateFilenamePrefix in source code.. +static const std::string kCertificateFileNamePrefix = + kScopedCertificateFilenamePrefix; +// Legacy general filename for either global or unmapped app-origin +// DRM certificates. static const std::string kLegacyCertificateFileName = "cert.bin"; -static const std::string kLegacyCertificateFileNamePrefix = "cert"; +// Legacy filename prefix for mapped (scoped) DRM certificate filenames +// specific to a particular app-origin. +static const std::string kLegacyScopedCertificateFilenamePrefix = "cert"; +// TODO(b/376533901): Replace this constant with +// kLegacyScopedCertificateFilenamePrefix in source code.. +static const std::string kLegacyCertificateFileNamePrefix = + kLegacyScopedCertificateFilenamePrefix; +// Filename for global OEM certificates. static const std::string kOemCertificateFileName = "oemcert.bin"; -static const std::string kOemCertificateFileNamePrefix = "oemcert_"; -// File class. The implementation is platform dependent. +// File interface. The implementation is platform dependent. class File { public: + WVCDM_DISALLOW_COPY_AND_MOVE(File); File() {} virtual ~File() {} virtual ssize_t Read(char* buffer, size_t bytes) = 0; virtual ssize_t Write(const char* buffer, size_t bytes) = 0; - - friend class FileSystem; - CORE_DISALLOW_COPY_AND_ASSIGN(File); }; +// File system base class. The implementation is platform dependent. class FileSystem { public: + WVCDM_DISALLOW_COPY_AND_MOVE(FileSystem); FileSystem(); FileSystem(const std::string& origin, void* extra_data); virtual ~FileSystem(); + // Concreate implementation of FileSystem. + // Depending on the platform, this may be vendor or Widevine implemented. class Impl; - // defines as bit flag - enum OpenFlags { - kNoFlags = 0, - kCreate = 1, - kReadOnly = 2, // defaults to read and write access - kTruncate = 4 - }; + // Flags for calls to Open. + static constexpr int kNoFlags = 0; + // Create file if does not already exist, open file if it does exist. + static constexpr int kCreate = (1 << 0); + // Open file as read-only; typically should not be used with kCreate. + static constexpr int kReadOnly = (1 << 1); + // Open file and truncated. May be used with kCreate; should not + // be used with kReadOnly. + static constexpr int kTruncate = (1 << 2); virtual std::unique_ptr Open(const std::string& file_path, int flags); - virtual bool Exists(const std::string& file_path); - virtual bool Exists(const std::string& file_path, int* errno_value); - virtual bool Remove(const std::string& file_path); + // Checks if the |path| exists. The |path| may be a file or directory. + // Return true if an entry in the file system exists; false otherwise. + virtual bool Exists(const std::string& path); + // Same as above, except the optional parameter of |errno_value| should + // be set to 0 or the value of C errno when attempting to check + // the existence of a file. + virtual bool Exists(const std::string& path, int* errno_value); + + // Removes the specified |path|. + // + // If |path| is a regular file, the file should be removed. + // If |path| is a directory, both the directory and the directory + // contents should be removed. + // + // Implementation must support a |path| containing a single wildcard + // character in the filename component of the path. + // + // Return value: + // - true : File/directory was removed, or file/directory did not exist + // - false : File/directory could not be removed, or other error. + virtual bool Remove(const std::string& path); + + // Obtain the size of a file in bytes. |file_path| must be a file, + // and not a directory. + // + // Return value: + // - non-negative : size of file in bytes if file exists + // - negative : file does not exist, or error occurred. virtual ssize_t FileSize(const std::string& file_path); - // Return the filenames stored at dir_path. - // dir_path will be stripped from the returned names. + // Return the entries stored at |dir_path| (includes both files + // and directories). + // + // Return value: + // - true : Directory exists, and directory entry names are stored + // in |names|; |names| may be empty if directory was empty. + // - false : Directory does not exist, |dir_path| is not a directory, + // or error was encountered. virtual bool List(const std::string& dir_path, std::vector* names); @@ -78,8 +133,6 @@ class FileSystem { std::unique_ptr impl_; std::string origin_; std::string identifier_; - - CORE_DISALLOW_COPY_AND_ASSIGN(FileSystem); }; } // namespace wvutil diff --git a/util/test/file_store_unittest.cpp b/util/test/file_store_unittest.cpp index a62bfc0..ad30ac2 100644 --- a/util/test/file_store_unittest.cpp +++ b/util/test/file_store_unittest.cpp @@ -1,9 +1,14 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. - #include "file_store.h" +#include + +#include +#include +#include + #include #include @@ -11,18 +16,20 @@ #include "test_vectors.h" namespace wvutil { - namespace { -const std::string kTestDirName = "test_dir"; -const std::string kTestFileName = "test.txt"; -const std::string kTestFileName2 = "test2.txt"; -const std::string kTestFileName3 = "test3.other"; -const std::string kTestFileNameExt = ".txt"; -const std::string kTestFileNameExt3 = ".other"; -const std::string kTestIdentifier1 = "some_identifier"; -const std::string kTestIdentifier2 = "some_other_identifier"; -const std::string kWildcard = "*"; -const std::string kUnderscore = "_"; +constexpr char kTestFilename[] = "sample.txt"; + +constexpr char kTestIdentifier1[] = "some_identifier"; +constexpr char kTestIdentifier2[] = "some_other_identifier"; + +constexpr int kNoError = 0; +constexpr int kEntryDoesNotExist = ENOENT; + +bool StartsWith(const std::string& haystack, const std::string& needle) { + if (needle.empty()) return true; + if (haystack.size() < needle.size()) return false; + return haystack.find(needle) == 0; +} } // namespace class FileTest : public testing::Test { @@ -32,7 +39,19 @@ class FileTest : public testing::Test { void TearDown() override { RemoveTestDir(); } void RemoveTestDir() { - EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); + ASSERT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)) + << "Failed to update test directory: " << wvcdm::test_vectors::kTestDir; + } + + std::string PathJoin(const std::string& base_path, + const std::string& add_path) { + if (base_path.empty()) return add_path; + std::string path = base_path; + if (path.back() != '/') { + path.push_back('/'); + } + path.append(add_path); + return path; } FileSystem file_system_; @@ -40,336 +59,505 @@ class FileTest : public testing::Test { TEST_F(FileTest, FileExists) { int errno_value = -1; - EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)); + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)) + << "path = " << wvcdm::test_vectors::kExistentFile; EXPECT_TRUE( - file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value)); - EXPECT_EQ(0, errno_value); - EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)); + file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value)) + << "path = " << wvcdm::test_vectors::kExistentFile; + EXPECT_EQ(kNoError, errno_value); +} - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)); +TEST_F(FileTest, FileDoesNotExist) { + int errno_value = -1; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)) + << "path = " << wvcdm::test_vectors::kNonExistentFile; EXPECT_FALSE( - file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value)); - EXPECT_EQ(ENOENT, errno_value); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)); + file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value)) + << "path = " << wvcdm::test_vectors::kNonExistentFile; + EXPECT_EQ(kEntryDoesNotExist, errno_value); +} + +TEST_F(FileTest, DirectoryExists) { + int errno_value = -1; + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)) + << "path = " << wvcdm::test_vectors::kExistentDir; + EXPECT_TRUE( + file_system_.Exists(wvcdm::test_vectors::kExistentDir, &errno_value)) + << "path = " << wvcdm::test_vectors::kExistentDir; + EXPECT_EQ(kNoError, errno_value); +} + +TEST_F(FileTest, DirectoryDoesNotExist) { + int errno_value = -1; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)) + << "path = " << wvcdm::test_vectors::kNonExistentDir; + EXPECT_FALSE( + file_system_.Exists(wvcdm::test_vectors::kNonExistentDir, &errno_value)) + << "path = " << wvcdm::test_vectors::kNonExistentDir; + EXPECT_EQ(kEntryDoesNotExist, errno_value); } TEST_F(FileTest, RemoveDir) { - EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)) + << "path = " << wvcdm::test_vectors::kTestDir; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)) + << "path = " << wvcdm::test_vectors::kTestDir; } TEST_F(FileTest, OpenFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; - EXPECT_TRUE(file_system_.Remove(path)); + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); + EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path; std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; } TEST_F(FileTest, RemoveDirAndFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); - EXPECT_TRUE(file_system_.Remove(path)); - EXPECT_FALSE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path; + EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path; file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); - RemoveTestDir(); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); - EXPECT_FALSE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + ASSERT_NO_FATAL_FAILURE(RemoveTestDir()); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)) + << "path = " << path; + EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path; } TEST_F(FileTest, RemoveWildcardFiles) { - std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; - std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; - std::string wildcard_path = - wvcdm::test_vectors::kTestDir + kWildcard + kTestFileNameExt; + const std::string path1 = + PathJoin(wvcdm::test_vectors::kTestDir, "first.txt"); + const std::string path2 = + PathJoin(wvcdm::test_vectors::kTestDir, "second.txt"); + const std::string wildcard_path = + PathJoin(wvcdm::test_vectors::kTestDir, "*.txt"); std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (1): " << path1; file = file_system_.Open(path2, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (2): " << path2; - EXPECT_TRUE(file_system_.Exists(path1)); - EXPECT_TRUE(file_system_.Exists(path2)); - EXPECT_TRUE(file_system_.Remove(wildcard_path)); - EXPECT_FALSE(file_system_.Exists(path1)); - EXPECT_FALSE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path1)) << "path = " << path1; + EXPECT_TRUE(file_system_.Exists(path2)) << "path = " << path2; + EXPECT_TRUE(file_system_.Remove(wildcard_path)) + << "wildcard_path = " << wildcard_path; + EXPECT_FALSE(file_system_.Exists(path1)) << "path = " << path1; + EXPECT_FALSE(file_system_.Exists(path2)) << "path = " << path2; } TEST_F(FileTest, FileSize) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); file_system_.Remove(path); - std::string write_data = CdmRandom::RandomData(600); - size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system_.Exists(path)); + constexpr size_t kDataSize = 600; + const std::string write_data = CdmRandom::RandomData(kDataSize); + ASSERT_EQ(write_data.size(), kDataSize); - EXPECT_EQ(static_cast(write_data_size), file_system_.FileSize(path)); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + + EXPECT_EQ(file->Write(write_data.data(), write_data.size()), + write_data.size()); + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + + EXPECT_EQ(static_cast(kDataSize), file_system_.FileSize(path)) + << "path = " << path; } TEST_F(FileTest, WriteReadBinaryFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); file_system_.Remove(path); - std::string write_data = CdmRandom::RandomData(600); - size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system_.Exists(path)); + constexpr size_t kDataSize = 600; + const std::string write_data = CdmRandom::RandomData(kDataSize); + ASSERT_EQ(write_data.size(), kDataSize); + + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + + constexpr ssize_t kExpectedFileSizeResult = static_cast(kDataSize); + EXPECT_EQ(file->Write(write_data.data(), write_data.size()), + kExpectedFileSizeResult) + << "path = " << path; + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; - std::string read_data; - read_data.resize(file_system_.FileSize(path)); - size_t read_data_size = read_data.size(); file = file_system_.Open(path, FileSystem::kReadOnly); - ASSERT_TRUE(file); - EXPECT_EQ(file->Read(&read_data[0], read_data_size), read_data_size); + ASSERT_TRUE(file) << "Failed to re-open file: " << path; + + std::string read_data(kDataSize, '\0'); + ; + ASSERT_EQ(file->Read(&read_data[0], read_data.size()), + kExpectedFileSizeResult) + << "path = " << path; EXPECT_EQ(write_data, read_data); } TEST_F(FileTest, ListFiles) { - std::vector names; + const std::string kTxtFilename1 = "data.txt"; + const std::string kTxtFilename2 = "other.txt"; + const std::string kBinFilename = "sample.bin"; - std::string not_path("zzz"); - std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; - std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; - std::string path3 = wvcdm::test_vectors::kTestDir + kTestFileName3; - std::string path_dir = wvcdm::test_vectors::kTestDir; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + const std::string path1 = PathJoin(dir_path, kTxtFilename1); + const std::string path2 = PathJoin(dir_path, kTxtFilename2); + const std::string path3 = PathJoin(dir_path, kBinFilename); + // Create files. std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (1): " << path1; file = file_system_.Open(path2, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (2): " << path2; file = file_system_.Open(path3, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (3): " << path3; + file.reset(); // Close file EXPECT_TRUE(file_system_.Exists(path1)); EXPECT_TRUE(file_system_.Exists(path2)); EXPECT_TRUE(file_system_.Exists(path3)); - // Ask for non-existent path. - EXPECT_FALSE(file_system_.List(not_path, &names)); + std::vector names; + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; - // Valid path, but no way to return names. - EXPECT_FALSE(file_system_.List(path_dir, nullptr)); + size_t expected_file_count = 3; + EXPECT_EQ(names.size(), expected_file_count); - // Valid path, valid return. - EXPECT_TRUE(file_system_.List(path_dir, &names)); - - // Should find three files. Order not important. - EXPECT_EQ(3u, names.size()); + // Should find the three files. Order not important. EXPECT_THAT(names, ::testing::UnorderedElementsAre( - kTestFileName, kTestFileName2, kTestFileName3)); + kTxtFilename1, kTxtFilename2, kBinFilename)); - std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; - EXPECT_TRUE(file_system_.Remove(wild_card_path)); - EXPECT_TRUE(file_system_.List(path_dir, &names)); + // Remove .txt files. + const std::string txt_wildcard_path = PathJoin(dir_path, "*.txt"); - EXPECT_EQ(1u, names.size()); - EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); + EXPECT_TRUE(file_system_.Remove(txt_wildcard_path)) + << "txt_wildcard_path = " << txt_wildcard_path; + EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; - std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; - EXPECT_TRUE(file_system_.Remove(wild_card_path2)); - EXPECT_TRUE(file_system_.List(path_dir, &names)); + expected_file_count = 1; + ASSERT_EQ(names.size(), expected_file_count); + EXPECT_EQ(names.front(), kBinFilename); - EXPECT_EQ(0u, names.size()); + const std::string bin_wildcard_path = PathJoin(dir_path, "*.bin"); + EXPECT_TRUE(file_system_.Remove(bin_wildcard_path)) + << "bin_wildcard_path = " << bin_wildcard_path; + + // All files should be removed, but listing should still succeed. + EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; + expected_file_count = 0; + EXPECT_EQ(expected_file_count, names.size()); } -TEST_F(FileTest, CreateGlobalCertificates) { - // Clear directory +TEST_F(FileTest, ListFiles_NotAPath) { + const std::string not_path("zzz/xxx"); std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + // Ask for non-existent path. + EXPECT_FALSE(file_system_.List(not_path, &names)); +} + +TEST_F(FileTest, ListFiles_NullParameter) { + const std::string dir_path = wvcdm::test_vectors::kTestDir; + const std::string path = PathJoin(dir_path, kTestFilename); + + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + file.reset(); // Close file. + + // Valid path, but no way to return names. + EXPECT_FALSE(file_system_.List(dir_path, nullptr)); +} + +// On certain platforms, the FileSystem may perform special +// name translations on certificate filenames which make them behave +// differently from non-certificate filenames. +TEST_F(FileTest, CreateGlobalCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires global file system"; + + const std::string dir_path = wvcdm::test_vectors::kTestDir; + + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. + std::vector names; + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - // Create certificates and verify that they exist - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); + // Create certificates and verify that they exist std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create certificate file: " + << certificate_path; + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create legacy certificate file: " + << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << "certificate_path = " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << "legacy_certificate_path = " << legacy_certificate_path; - EXPECT_TRUE(file_system_.List(path_dir, &names)); + ASSERT_TRUE(file_system_.List(dir_path, &names)); // Should find two files. Order not important. - EXPECT_EQ(2u, names.size()); + constexpr size_t kExpectedCount = 2; + EXPECT_EQ(kExpectedCount, names.size()); EXPECT_THAT(names, ::testing::UnorderedElementsAre( kCertificateFileName, kLegacyCertificateFileName)); } +// On certain platforms, the FileSystem may perform special +// name translations on certificate filenames which make them behave +// differently from non-certificate filenames. TEST_F(FileTest, CreateCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires starting with a global file system"; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); - // Create Global certificates + // Create Global certificates. std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create global certificate: " + << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create global legacy certificate: " + << legacy_certificate_path; + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << "Global certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << "Global legacy certificate: " << legacy_certificate_path; + + // Switch to first identifier. + file_system_.set_identifier(kTestIdentifier1); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1; + + // Global certificates should not be visible once identifier has been + // specified. + EXPECT_FALSE(file_system_.Exists(certificate_path)) + << kTestIdentifier1 << " certificate: " << certificate_path; + EXPECT_FALSE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path; // Create certificates with first identifier - file_system_.set_identifier(kTestIdentifier1); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. + + // Verify they now exist. + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << kTestIdentifier1 << " certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path; + + // Switch to second identifier. + file_system_.set_identifier(kTestIdentifier2); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2; + + // Global and first identifier certificates should not be + // visible. + EXPECT_FALSE(file_system_.Exists(certificate_path)) + << kTestIdentifier2 << " certificate: " << certificate_path; + EXPECT_FALSE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path; // Create certificates with second identifier - file_system_.set_identifier(kTestIdentifier2); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + // Verify they now exist. + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << kTestIdentifier2 << " certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path; - EXPECT_TRUE(file_system_.List(path_dir, &names)); + // FileSystem::List is expected to still return all certificate files + // (both global and scoped). + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; // Should find six files. Order not important. + constexpr size_t kExpectedTotalCertCount = 6; + ASSERT_EQ(names.size(), kExpectedTotalCertCount); + bool is_global_certificate_present = false; bool is_global_legacy_certificate_present = false; size_t certificate_count = 0; size_t legacy_certificate_count = 0; - EXPECT_EQ(6u, names.size()); - for (size_t i = 0; i < names.size(); ++i) { - if (names[i].size() > kCertificateFileName.size()) { - if (names[i].compare(0, kCertificateFileNamePrefix.size(), - kCertificateFileNamePrefix) == 0) - ++certificate_count; - else if (names[i].compare(0, kLegacyCertificateFileNamePrefix.size(), - kLegacyCertificateFileNamePrefix) == 0) - ++legacy_certificate_count; - } else if (names[i].compare(kCertificateFileName) == 0) { - is_global_certificate_present = true; - } else if (names[i].compare(kLegacyCertificateFileName) == 0) { + for (const auto& filename : names) { + if (filename == kLegacyCertificateFileName) { is_global_legacy_certificate_present = true; + } else if (filename == kCertificateFileName) { + is_global_certificate_present = true; + } else if (StartsWith(filename, kScopedCertificateFilenamePrefix)) { + certificate_count++; + } else if (StartsWith(filename, kLegacyScopedCertificateFilenamePrefix)) { + legacy_certificate_count++; } else { - EXPECT_TRUE(false); + ADD_FAILURE() << "Unexpected filename: " << filename; } } - EXPECT_EQ(2, certificate_count); - EXPECT_EQ(2, legacy_certificate_count); - EXPECT_TRUE(is_global_certificate_present); - EXPECT_TRUE(is_global_legacy_certificate_present); + constexpr size_t kExpectedScopedCertCount = 2; + EXPECT_EQ(certificate_count, kExpectedScopedCertCount) + << "Missing certificates"; + EXPECT_EQ(legacy_certificate_count, kExpectedScopedCertCount) + << "Missing legacy certificates"; + EXPECT_TRUE(is_global_certificate_present) + << "Missing global certificate: " << kCertificateFileName; + EXPECT_TRUE(is_global_legacy_certificate_present) + << "Missing legacy global certificate: " << kLegacyCertificateFileName; } +// On certain platforms, the FileSystem may perform special +// name translations on certificate file names which make them behave +// differently from non-certificate file names. TEST_F(FileTest, RemoveCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires starting with a global file system"; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); - // Create Global certificates + // Create Global certificates. std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create global certificate: " + << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create global legacy certificate: " + << legacy_certificate_path; + file.reset(); // Close file. + + // Switch to first identifier. + file_system_.set_identifier(kTestIdentifier1); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1; // Create certificates with first identifier - file_system_.set_identifier(kTestIdentifier1); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. + + // Switch to second identifier. + file_system_.set_identifier(kTestIdentifier2); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2; // Create certificates with second identifier - file_system_.set_identifier(kTestIdentifier2); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); - - EXPECT_TRUE(file_system_.List(path_dir, &names)); - - EXPECT_EQ(6u, names.size()); + // FileSystem::List is expected to still return all certificate files + // (both global and scoped). + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; + // Should find six files. Order not important. + constexpr size_t kExpectedTotalCertCount = 6; + ASSERT_EQ(names.size(), kExpectedTotalCertCount); + std::set removed_certs; // Remove all even number listed files for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 0) { - EXPECT_TRUE( - file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); - } + if ((i % 2) != 0) continue; + const std::string& cert_filename = names[i]; + const std::string cert_path = PathJoin(dir_path, cert_filename); + ASSERT_TRUE(file_system_.Remove(cert_path)) + << "Failed to remove cert: " << cert_path; + removed_certs.insert(cert_filename); } // Verify that they have been removed - for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 1) { - EXPECT_TRUE( - file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + for (const std::string& cert_filename : names) { + const std::string cert_path = PathJoin(dir_path, cert_filename); + if (removed_certs.find(cert_filename) == removed_certs.end()) { + // Ensure still exists. + ASSERT_TRUE(file_system_.Exists(cert_path)) + << "Cert missing: " << cert_filename; } else { - EXPECT_FALSE( - file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + ASSERT_FALSE(file_system_.Exists(cert_path)) + << "Cert not removed: " << cert_filename; } } - // Remove all odd number listed files - for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 1) { - EXPECT_TRUE( - file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); - } + // Remove all remaining. + for (const std::string& cert_filename : names) { + if (removed_certs.find(cert_filename) != removed_certs.end()) continue; + const std::string cert_path = PathJoin(dir_path, cert_filename); + ASSERT_TRUE(file_system_.Remove(cert_path)) + << "Failed to remove cert: " << cert_path; } // Verify that all have been removed - for (size_t i = 0; i < names.size(); ++i) { - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + for (const std::string& cert_filename : names) { + const std::string cert_path = PathJoin(dir_path, cert_filename); + EXPECT_FALSE(file_system_.Exists(cert_path)) + << "Cert not removed: " << cert_filename; } } - } // namespace wvutil diff --git a/util/test/test_clock.cpp b/util/test/test_clock.cpp index 33edd9c..61fec1f 100644 --- a/util/test/test_clock.cpp +++ b/util/test/test_clock.cpp @@ -20,9 +20,9 @@ class FakeClock : public TestSleep::CallBack { FakeClock() { auto now = std::chrono::system_clock().now(); now_ = now.time_since_epoch() / std::chrono::milliseconds(1); - TestSleep::set_callback(this); + TestSleep::AddCallback(this); } - ~FakeClock() { TestSleep::set_callback(nullptr); } + ~FakeClock() { TestSleep::RemoveCallback(this); } void ElapseTime(int64_t milliseconds) { now_ += milliseconds; } int64_t now() const { return now_; } diff --git a/util/test/test_sleep.cpp b/util/test/test_sleep.cpp index f52e571..300461c 100644 --- a/util/test/test_sleep.cpp +++ b/util/test/test_sleep.cpp @@ -26,7 +26,7 @@ namespace wvutil { bool TestSleep::real_sleep_ = true; -TestSleep::CallBack* TestSleep::callback_ = nullptr; +std::unordered_set TestSleep::callbacks_; int TestSleep::total_clock_rollback_seconds_ = 0; void TestSleep::Sleep(unsigned int seconds) { @@ -52,7 +52,7 @@ void TestSleep::Sleep(unsigned int seconds) { milliseconds = total_real - fake_clock; fake_clock += milliseconds; } - if (callback_ != nullptr) callback_->ElapseTime(milliseconds); + for (auto* cb : callbacks_) cb->ElapseTime(milliseconds); } void TestSleep::SleepUntil(int64_t desired_time) { @@ -80,9 +80,8 @@ void TestSleep::SetFakeClock(int64_t time_seconds) { // by the current time on a real clock, and then the command line // re-initializes it to 0, then delta is negative. int64_t delta = time_seconds - Clock().GetCurrentTime(); - if (callback_ != nullptr) { - callback_->ElapseTime(delta * 1000); - } else { + for (auto* cb : callbacks_) cb->ElapseTime(delta * 1000); + if (callbacks_.empty()) { LOGE("Setting fake clock with no callback. This won't work."); } } @@ -130,8 +129,8 @@ bool TestSleep::RollbackSystemTime(int seconds) { // For both real and fake sleep we still update the callback and we still keep // track of the total amount of time slept. total_clock_rollback_seconds_ += seconds; - if (callback_ != nullptr) { - callback_->ElapseTime(-1000 * static_cast(seconds)); + for (auto* cb : callbacks_) { + cb->ElapseTime(-1000 * static_cast(seconds)); } return true; } diff --git a/util/test/test_sleep.h b/util/test/test_sleep.h index f20e27a..2c0ebdd 100644 --- a/util/test/test_sleep.h +++ b/util/test/test_sleep.h @@ -9,6 +9,8 @@ #include +#include + namespace wvutil { class TestSleep { @@ -67,13 +69,18 @@ class TestSleep { static bool real_sleep() { return real_sleep_; } // The callback is notified whenever sleep is called. - static void set_callback(CallBack* callback) { callback_ = callback; } + static void AddCallback(CallBack* callback) { + callbacks_.insert(callback); + } + static void RemoveCallback(CallBack* callback) { + callbacks_.erase(callback); + } private: // Controls if the test sleep should use real sleep. static bool real_sleep_; // Called when the clock should advance. - static CallBack* callback_; + static std::unordered_set callbacks_; // The sum of all calls to RollBackSystemTime. Kept so we can undo all changes // at the end of a test. static int total_clock_rollback_seconds_;